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