1 /*
2 * $Id: AbstractMessageSplitter.java 11475 2008-03-21 22:46:33Z rossmason $
3 * --------------------------------------------------------------------------------------
4 * Copyright (c) MuleSource, Inc. All rights reserved. http://www.mulesource.com
5 *
6 * The software in this package is published under the terms of the CPAL v1.0
7 * license, a copy of which has been included with this distribution in the
8 * LICENSE.txt file.
9 */
10
11 package org.mule.routing.outbound;
12
13 import org.mule.api.MuleException;
14 import org.mule.api.MuleMessage;
15 import org.mule.api.MuleSession;
16 import org.mule.api.config.MuleProperties;
17 import org.mule.api.endpoint.OutboundEndpoint;
18 import org.mule.api.routing.CouldNotRouteOutboundMessageException;
19 import org.mule.api.routing.RoutingException;
20
21 import java.util.Iterator;
22 import java.util.List;
23
24 /**
25 * <code>AbstractMessageSplitter</code> is an outbound Message Splitter used to split
26 * the contents of a received message into sub parts that can be processed by other
27 * components. Each Part is fired as a separate event to each endpoint on the router. The
28 * endpoints can have filters on them to receive only certain message parts.
29 */
30 public abstract class AbstractMessageSplitter extends FilteringOutboundRouter
31 {
32 // Determines if the same endpoint will be matched multiple times until a
33 // match is not found. This should be set by overriding classes.
34 protected boolean multimatch = true;
35
36 // flag which, if true, makes the splitter honour settings such as remoteSync and
37 // synchronous on the endpoint
38 protected boolean honorSynchronicity = false;
39
40 public MuleMessage route(MuleMessage message, MuleSession session, boolean synchronous)
41 throws RoutingException
42 {
43 String correlationId = messageInfoMapping.getCorrelationId(message);
44
45 this.initialise(message);
46
47 OutboundEndpoint endpoint;
48 MuleMessage result = null;
49 List list = getEndpoints();
50 int correlationSequence = 1;
51 for (Iterator iterator = list.iterator(); iterator.hasNext();)
52 {
53 endpoint = (OutboundEndpoint) iterator.next();
54 message = getMessagePart(message, endpoint);
55 // TODO MULE-1378
56 if (message == null)
57 {
58 // Log a warning if there are no messages for a given endpoint
59 logger.warn("Message part is null for endpoint: " + endpoint.getEndpointURI().toString());
60 }
61
62 // We'll keep looping to get all messages for the current endpoint
63 // before moving to the next endpoint
64 // This can be turned off by setting the multimatch flag to false
65 while (message != null)
66 {
67 if (honorSynchronicity)
68 {
69 synchronous = endpoint.isSynchronous();
70 }
71 try
72 {
73 if (enableCorrelation != ENABLE_CORRELATION_NEVER)
74 {
75 boolean correlationSet = message.getCorrelationId() != null;
76 if (!correlationSet && (enableCorrelation == ENABLE_CORRELATION_IF_NOT_SET))
77 {
78 message.setCorrelationId(correlationId);
79 }
80
81 // take correlation group size from the message
82 // properties, set by concrete message splitter
83 // implementations
84 final int groupSize = message.getCorrelationGroupSize();
85 message.setCorrelationGroupSize(groupSize);
86 message.setCorrelationSequence(correlationSequence++);
87 }
88
89 if (honorSynchronicity)
90 {
91 message.setBooleanProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY,
92 endpoint.isRemoteSync());
93 }
94
95 if (synchronous)
96 {
97 result = send(session, message, endpoint);
98 }
99 else
100 {
101 dispatch(session, message, endpoint);
102 }
103 }
104 catch (MuleException e)
105 {
106 throw new CouldNotRouteOutboundMessageException(message, endpoint, e);
107 }
108
109 if (!multimatch)
110 {
111 break;
112 }
113
114 message = this.getMessagePart(message, endpoint);
115 }
116 }
117
118 // we are done with splitting & routing
119 this.cleanup();
120
121 return result;
122 }
123
124 public boolean isHonorSynchronicity()
125 {
126 return honorSynchronicity;
127 }
128
129 /**
130 * Sets the flag indicating whether the splitter honurs endpoint settings
131 *
132 * @param honorSynchronicity flag setting
133 */
134 public void setHonorSynchronicity(boolean honorSynchronicity)
135 {
136 this.honorSynchronicity = honorSynchronicity;
137 }
138
139 /**
140 * This method can be implemented to split the message up before
141 * {@link #getMessagePart(MuleMessage, OutboundEndpoint)} method is called.
142 *
143 * @param message the message being routed
144 */
145 protected abstract void initialise(MuleMessage message);
146
147 /**
148 * Retrieves a specific message part for the given endpoint. the message will then be
149 * routed via the provider. <p/> <strong>NOTE:</strong>Implementations must provide
150 * proper synchronization for shared state (payload, properties, etc.)
151 *
152 * @param message the current message being processed
153 * @param endpoint the endpoint that will be used to route the resulting message part
154 * @return the message part to dispatch
155 */
156 protected abstract MuleMessage getMessagePart(MuleMessage message, OutboundEndpoint endpoint);
157
158 /**
159 * This method is called after all parts of the original message have been processed;
160 * typically this is the case after {@link #getMessagePart(MuleMessage, OutboundEndpoint)}
161 * returned <code>null</code>.
162 */
163 protected abstract void cleanup();
164
165 }