1 /*
2 * $Id: AbstractMessageSplitter.java 9327 2007-10-24 13:18:33Z holger $
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.config.MuleProperties;
14 import org.mule.umo.UMOException;
15 import org.mule.umo.UMOMessage;
16 import org.mule.umo.UMOSession;
17 import org.mule.umo.endpoint.UMOEndpoint;
18 import org.mule.umo.routing.CouldNotRouteOutboundMessageException;
19 import org.mule.umo.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
26 * split the contents of a received message into sub parts that can be processed by
27 * other components. Each Part is fired as a separate event to each endpoint on the
28 * router. The endpoints can have filters on them to receive only certain message
29 * parts.
30 */
31 public abstract class AbstractMessageSplitter extends FilteringOutboundRouter
32 {
33 // Determines if the same endpoint will be matched multiple times until a
34 // match is not found. This should be set by overriding classes.
35 protected boolean multimatch = true;
36
37 // flag which, if true, makes the splitter honour settings such as remoteSync and
38 // synchronous on the endpoint
39 protected boolean honorSynchronicity = false;
40
41 public UMOMessage route(UMOMessage message, UMOSession session, boolean synchronous)
42 throws RoutingException
43 {
44 String correlationId = (String) propertyExtractor.getProperty(
45 MuleProperties.MULE_CORRELATION_ID_PROPERTY, message);
46
47 this.initialise(message);
48
49 UMOEndpoint endpoint;
50 UMOMessage result = null;
51 List list = getEndpoints();
52 int correlationSequence = 1;
53 for (Iterator iterator = list.iterator(); iterator.hasNext();)
54 {
55 endpoint = (UMOEndpoint) iterator.next();
56 message = getMessagePart(message, endpoint);
57 // TODO MULE-1378
58 if (message == null)
59 {
60 // Log a warning if there are no messages for a given endpoint
61 logger.warn("Message part is null for endpoint: " + endpoint.getEndpointURI().toString());
62 }
63
64 // We'll keep looping to get all messages for the current endpoint
65 // before moving to the next endpoint
66 // This can be turned off by setting the multimatch flag to false
67 while (message != null)
68 {
69 if (honorSynchronicity)
70 {
71 synchronous = endpoint.isSynchronous();
72 }
73 try
74 {
75 if (enableCorrelation != ENABLE_CORRELATION_NEVER)
76 {
77 boolean correlationSet = message.getCorrelationId() != null;
78 if (!correlationSet && (enableCorrelation == ENABLE_CORRELATION_IF_NOT_SET))
79 {
80 message.setCorrelationId(correlationId);
81 }
82
83 // take correlation group size from the message
84 // properties, set by concrete message splitter
85 // implementations
86 final int groupSize = message.getCorrelationGroupSize();
87 message.setCorrelationGroupSize(groupSize);
88 message.setCorrelationSequence(correlationSequence++);
89 }
90
91 if (honorSynchronicity)
92 {
93 message.setBooleanProperty(MuleProperties.MULE_REMOTE_SYNC_PROPERTY,
94 endpoint.isRemoteSync());
95 }
96
97 if (synchronous)
98 {
99 result = send(session, message, endpoint);
100 }
101 else
102 {
103 dispatch(session, message, endpoint);
104 }
105 }
106 catch (UMOException e)
107 {
108 throw new CouldNotRouteOutboundMessageException(message, endpoint, e);
109 }
110
111 if (!multimatch)
112 {
113 break;
114 }
115
116 message = this.getMessagePart(message, endpoint);
117 }
118 }
119
120 // we are done with splitting & routing
121 this.cleanup();
122
123 return result;
124 }
125
126 /**
127 * This method can be implemented to split the message up before
128 * {@link #getMessagePart(UMOMessage, UMOEndpoint)} method is called.
129 *
130 * @param message the message being routed
131 */
132 protected void initialise(UMOMessage message)
133 {
134 // nothing to do; subclasses need to implement this
135 }
136
137 /**
138 * This method is called after all parts of the original message have been processed;
139 * typically this is the case after {@link #getMessagePart(UMOMessage, UMOEndpoint)}
140 * returned <code>null</code>.
141 */
142 protected void cleanup()
143 {
144 // nothing to do; subclasses need to implement this
145
146 // MULE-2600 note: this method (as well as initialise()) should be abstract to force
147 // proper implementation by the subclass, but doing so would break compatibility with
148 // exisiting custom splitters..
149 }
150
151 public boolean isHonorSynchronicity()
152 {
153 return honorSynchronicity;
154 }
155
156 /**
157 * Sets the flag indicating whether the splitter honurs endpoint settings
158 *
159 * @param honorSynchronicity flag setting
160 */
161 public void setHonorSynchronicity(boolean honorSynchronicity)
162 {
163 this.honorSynchronicity = honorSynchronicity;
164 }
165
166 /**
167 * Retrieves a specific message part for the given endpoint. the message will
168 * then be routed via the provider. <p/> <strong>NOTE:</strong>Implementations
169 * must provide proper synchronization for shared state (payload, properties,
170 * etc.)
171 *
172 * @param message the current message being processed
173 * @param endpoint the endpoint that will be used to route the resulting message
174 * part
175 * @return the message part to dispatch
176 */
177 protected abstract UMOMessage getMessagePart(UMOMessage message, UMOEndpoint endpoint);
178 }