1
2
3
4
5
6
7
8
9
10
11 package org.mule.module.bpm;
12
13 import org.mule.DefaultMuleEvent;
14 import org.mule.DefaultMuleMessage;
15 import org.mule.MessageExchangePattern;
16 import org.mule.RequestContext;
17 import org.mule.api.MuleContext;
18 import org.mule.api.MuleEvent;
19 import org.mule.api.MuleException;
20 import org.mule.api.MuleMessage;
21 import org.mule.api.config.MuleProperties;
22 import org.mule.api.construct.FlowConstruct;
23 import org.mule.api.endpoint.EndpointCache;
24 import org.mule.api.endpoint.OutboundEndpoint;
25 import org.mule.api.lifecycle.Disposable;
26 import org.mule.api.lifecycle.Initialisable;
27 import org.mule.api.lifecycle.InitialisationException;
28 import org.mule.api.transport.DispatchException;
29 import org.mule.api.transport.PropertyScope;
30 import org.mule.config.i18n.MessageFactory;
31 import org.mule.endpoint.SimpleEndpointCache;
32 import org.mule.session.DefaultMuleSession;
33 import org.mule.transport.NullPayload;
34 import org.mule.util.StringUtils;
35
36 import java.util.HashMap;
37 import java.util.Map;
38
39 import org.apache.commons.logging.Log;
40 import org.apache.commons.logging.LogFactory;
41
42
43
44
45 public class Process implements Initialisable, Disposable, MessageService
46 {
47
48 private final BPMS bpms;
49
50
51 private final String name;
52
53
54 private final String resource;
55
56
57 protected final String processIdField;
58
59 protected MuleContext muleContext;
60
61
62 private FlowConstruct flowConstruct;
63
64 public static final String BPM_PROPERTY_PREFIX = "BPM_";
65
66 public static final String PROPERTY_ENDPOINT =
67 MuleProperties.PROPERTY_PREFIX + BPM_PROPERTY_PREFIX + "ENDPOINT";
68 public static final String PROPERTY_PROCESS_TYPE =
69 MuleProperties.PROPERTY_PREFIX + BPM_PROPERTY_PREFIX + "PROCESS_TYPE";
70 public static final String PROPERTY_PROCESS_ID =
71 MuleProperties.PROPERTY_PREFIX + BPM_PROPERTY_PREFIX + "PROCESS_ID";
72 public static final String PROPERTY_ACTION =
73 MuleProperties.PROPERTY_PREFIX + BPM_PROPERTY_PREFIX + "ACTION";
74 public static final String PROPERTY_TRANSITION =
75 MuleProperties.PROPERTY_PREFIX + BPM_PROPERTY_PREFIX + "TRANSITION";
76 public static final String PROPERTY_PROCESS_STARTED =
77 MuleProperties.PROPERTY_PREFIX + BPM_PROPERTY_PREFIX + "STARTED";
78
79 public static final String ACTION_START = "start";
80 public static final String ACTION_ADVANCE = "advance";
81 public static final String ACTION_UPDATE = "update";
82 public static final String ACTION_ABORT = "abort";
83
84 public static final String PROCESS_VARIABLE_INCOMING = "incoming";
85 public static final String PROCESS_VARIABLE_INCOMING_SOURCE = "incomingSource";
86 public static final String PROCESS_VARIABLE_DATA = "data";
87
88 protected static final Log logger = LogFactory.getLog(Process.class);
89
90 private final EndpointCache endpointCache;
91
92 public Process(BPMS bpms, String name, String resource, FlowConstruct flowConstruct, MuleContext muleContext)
93 {
94 this(bpms, name, resource, null, flowConstruct, muleContext);
95 }
96
97 public Process(BPMS bpms, String name, String resource, String processIdField, FlowConstruct flowConstruct, MuleContext muleContext)
98 {
99 this.bpms = bpms;
100 this.name = name;
101 this.resource = resource;
102 this.processIdField = processIdField;
103 this.flowConstruct = flowConstruct;
104 this.muleContext = muleContext;
105 this.endpointCache = new SimpleEndpointCache(muleContext);
106 }
107
108 public void initialise() throws InitialisationException
109 {
110 try
111 {
112 bpms.deployProcess(resource);
113 }
114 catch (Exception e)
115 {
116 throw new InitialisationException(e, this);
117 }
118 }
119
120 public void dispose()
121 {
122 try
123 {
124 bpms.undeployProcess(resource);
125 }
126 catch (Exception e)
127 {
128 logger.warn(e.getMessage());
129 }
130 }
131
132 protected Object handleEvent(MuleEvent event) throws Exception
133 {
134
135 Object process;
136
137
138 Map processVariables = new HashMap();
139 if (event != null)
140 {
141 populateProcessVariables(event, processVariables, PropertyScope.INVOCATION);
142 populateProcessVariables(event, processVariables, PropertyScope.INBOUND);
143
144 Object payload = event.getMessage().getPayload();
145 if (payload != null && !(payload instanceof NullPayload))
146 {
147
148 processVariables.put(PROCESS_VARIABLE_INCOMING, payload);
149
150
151 String originatingEndpoint = event.getMessage().getInboundProperty(MuleProperties.MULE_ORIGINATING_ENDPOINT_PROPERTY);
152 if (StringUtils.isNotEmpty(originatingEndpoint))
153 {
154 processVariables.put(PROCESS_VARIABLE_INCOMING_SOURCE, originatingEndpoint);
155 }
156 }
157 }
158
159 String processIdField = getProcessIdField();
160 if (StringUtils.isEmpty(processIdField))
161 {
162 processIdField = PROPERTY_PROCESS_ID;
163 }
164
165 Object processId;
166 processId = event.getMessage().getSessionProperty(processIdField);
167 if (processId == null)
168 {
169 processId = event.getMessage().getInvocationProperty(processIdField);
170 }
171 if (processId == null)
172 {
173 processId = event.getMessage().getInboundProperty(processIdField);
174 }
175 processVariables.remove(processIdField);
176
177
178 String action = event.getMessage().getInvocationProperty(PROPERTY_ACTION, ACTION_ADVANCE);
179 processVariables.remove(PROPERTY_ACTION);
180
181 Object transition = event.getMessage().getInvocationProperty(PROPERTY_TRANSITION);
182 processVariables.remove(PROPERTY_TRANSITION);
183
184
185
186 logger.debug("Message received: payload = " + event.getMessage().getPayload().getClass().getName() + " processType = " + name + " processId = " + processId + " action = " + action);
187
188
189 if (processId == null || action.equals(ACTION_START))
190 {
191 process = getBpms().startProcess(name, transition, processVariables);
192 if ((process != null) && logger.isInfoEnabled())
193 {
194 logger.info("New process started, ID = " + getBpms().getId(process));
195 }
196 }
197
198
199 else if (action.equals(ACTION_UPDATE))
200 {
201 if (processId != null)
202 {
203 process = getBpms().updateProcess(processId, processVariables);
204 if ((process != null) && logger.isInfoEnabled())
205 {
206 logger.info("Process variables updated, ID = " + getBpms().getId(process));
207 }
208 }
209 else
210 {
211 throw new IllegalArgumentException("Process ID is missing, cannot update process.");
212 }
213 }
214
215
216 else if (action.equals(ACTION_ABORT))
217 {
218 if (processId != null)
219 {
220 getBpms().abortProcess(processId);
221 process = NullPayload.getInstance();
222 logger.info("Process aborted, ID = " + processId);
223 }
224 else
225 {
226 throw new IllegalArgumentException("Process ID is missing, cannot abort process.");
227 }
228 }
229
230
231 else
232 {
233 if (processId != null)
234 {
235 process = getBpms().advanceProcess(processId, transition, processVariables);
236 if ((process != null) && logger.isInfoEnabled())
237 {
238 logger.info("Process advanced, ID = " + getBpms().getId(process)
239 + ", new state = " + getBpms().getState(process));
240 }
241 }
242 else
243 {
244 throw new IllegalArgumentException("Process ID is missing, cannot advance process.");
245 }
246 }
247
248 return process;
249 }
250
251 protected void populateProcessVariables(MuleEvent event, Map processVariables, PropertyScope propertyScope)
252 {
253 for (String propertyName : event.getMessage().getPropertyNames(propertyScope))
254 {
255
256 if (!propertyName.equals(MuleProperties.MULE_SESSION_PROPERTY))
257 {
258 processVariables.put(propertyName, event.getMessage().getProperty(propertyName, propertyScope));
259 }
260 }
261 }
262
263
264 public MuleMessage generateMessage(String endpoint, Object payload, Map messageProperties, MessageExchangePattern exchangePattern) throws MuleException
265 {
266 MuleMessage message;
267 if (payload instanceof MuleMessage)
268 {
269 message = (MuleMessage) payload;
270 }
271 else
272 {
273 message = new DefaultMuleMessage(payload, muleContext);
274 }
275 message.addProperties(messageProperties, PropertyScope.OUTBOUND);
276 message.addProperties(messageProperties, PropertyScope.INVOCATION);
277
278
279 OutboundEndpoint ep = endpointCache.getOutboundEndpoint(endpoint, exchangePattern, null);
280 DefaultMuleEvent event = new DefaultMuleEvent(message, ep.getExchangePattern(),
281 new DefaultMuleSession(flowConstruct, muleContext));
282 RequestContext.setEvent(event);
283
284
285 if (messageProperties.get(PROPERTY_PROCESS_TYPE) != null)
286 {
287 event.getMessage().setSessionProperty(PROPERTY_PROCESS_TYPE, messageProperties.get(PROPERTY_PROCESS_TYPE));
288 }
289 if (messageProperties.get(PROPERTY_PROCESS_ID) != null)
290 {
291 event.getMessage().setSessionProperty(PROPERTY_PROCESS_ID, messageProperties.get(PROPERTY_PROCESS_ID));
292 }
293
294 MuleEvent resultEvent = ep.process(event);
295
296 MuleMessage response = null;
297 if (resultEvent != null)
298 {
299 response = resultEvent.getMessage();
300 if (response.getExceptionPayload() != null)
301 {
302 throw new DispatchException(MessageFactory.createStaticMessage("Unable to send or route message"), event, ep, response.getExceptionPayload().getRootException());
303 }
304 }
305 return response;
306 }
307
308 public String getProcessIdField()
309 {
310 return processIdField;
311 }
312
313 public BPMS getBpms()
314 {
315 return bpms;
316 }
317
318 public String getResource()
319 {
320 return resource;
321 }
322
323 public String getName()
324 {
325 return name;
326 }
327 }
328
329