View Javadoc

1   /*
2    * $Id: ProcessMessageDispatcher.java 19710 2010-09-23 16:29:07Z tcarlson $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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.transport.bpm;
12  
13  import org.mule.DefaultMuleMessage;
14  import org.mule.api.MuleEvent;
15  import org.mule.api.MuleMessage;
16  import org.mule.api.config.MuleProperties;
17  import org.mule.api.endpoint.OutboundEndpoint;
18  import org.mule.api.transport.DispatchException;
19  import org.mule.api.transport.PropertyScope;
20  import org.mule.config.i18n.MessageFactory;
21  import org.mule.module.bpm.Process;
22  import org.mule.transport.AbstractMessageDispatcher;
23  import org.mule.transport.NullPayload;
24  import org.mule.util.StringUtils;
25  
26  import java.util.HashMap;
27  import java.util.Map;
28  
29  /**
30   * Initiates or advances a workflow process from an outgoing Mule event.
31   * 
32   * @deprecated It is recommended to configure BPM as a component rather than a transport for 3.x
33   */
34  public class ProcessMessageDispatcher extends AbstractMessageDispatcher
35  {
36      private ProcessConnector connector;
37  
38      public ProcessMessageDispatcher(OutboundEndpoint endpoint)
39      {
40          super(endpoint);
41          this.connector = (ProcessConnector)endpoint.getConnector();
42      }
43  
44      /**
45       * Performs a synchronous action on the BPMS.
46       * 
47       * @return an object representing the new state of the process
48       */
49      @Override
50      public MuleMessage doSend(MuleEvent event) throws Exception
51      {
52          Object process = processAction(event);
53  
54          if (process != null)
55          {
56              MuleMessage msg = new DefaultMuleMessage(process, connector.getMuleContext());
57              msg.setProperty(Process.PROPERTY_PROCESS_ID, connector.getBpms().getId(process), PropertyScope.SESSION);
58              return msg;
59          }
60          else
61          {
62              throw new DispatchException(
63                  MessageFactory.createStaticMessage("Synchronous process invocation must return the new process state."),
64                  event, this);
65          }
66      }
67  
68      /**
69       * Performs an asynchronous action on the BPMS.
70       */
71      @Override
72      public void doDispatch(MuleEvent event) throws Exception
73      {
74          processAction(event);
75      }
76  
77      protected Object processAction(MuleEvent event) throws Exception
78      {
79          // An object representing the new state of the process
80          Object process;
81  
82          // Create a map of process variables based on the message properties.
83          Map processVariables = new HashMap();
84          if (event != null)
85          {
86              populateProcessVariables(event, processVariables, PropertyScope.INVOCATION);
87              populateProcessVariables(event, processVariables, PropertyScope.OUTBOUND);
88  
89              Object payload = event.getMessage().getPayload();
90              if (payload != null && !(payload instanceof NullPayload))
91              {
92                  // Store the message's payload as a process variable.
93                  processVariables.put(Process.PROCESS_VARIABLE_INCOMING, payload);
94  
95                  // Store the endpoint on which the message was received as a process variable.
96                  String originatingEndpoint = event.getMessage().getInboundProperty(MuleProperties.MULE_ORIGINATING_ENDPOINT_PROPERTY);
97                  if (StringUtils.isNotEmpty(originatingEndpoint))
98                  {
99                      processVariables.put(Process.PROCESS_VARIABLE_INCOMING_SOURCE, originatingEndpoint);
100                 }
101             }
102         }
103 
104         // Retrieve the parameters
105         Object processType = event.getMessage().getSessionProperty(Process.PROPERTY_PROCESS_TYPE);
106         if (processType == null)
107         {
108             processType = event.getMessage().getInvocationProperty(Process.PROPERTY_PROCESS_TYPE);
109         }
110         if (processType == null)
111         {
112             processType = event.getMessage().getInboundProperty(Process.PROPERTY_PROCESS_TYPE);
113         }
114         processVariables.remove(Process.PROPERTY_PROCESS_TYPE);
115 
116         String processIdField = connector.getProcessIdField();
117         if (StringUtils.isEmpty(processIdField))
118         {
119             processIdField = Process.PROPERTY_PROCESS_ID;
120         }
121 
122         Object processId;
123         processId = event.getMessage().getSessionProperty(processIdField);
124         if (processId == null)
125         {
126             processId = event.getMessage().getInvocationProperty(processIdField); 
127         }
128         if (processId == null)
129         {
130             processId = event.getMessage().getInboundProperty(processIdField); 
131         }
132         processVariables.remove(processIdField);
133 
134         // Default action is "advance"
135         String action = event.getMessage().getInvocationProperty(Process.PROPERTY_ACTION, Process.ACTION_ADVANCE);
136         processVariables.remove(Process.PROPERTY_ACTION);
137 
138         Object transition = event.getMessage().getInvocationProperty(Process.PROPERTY_TRANSITION);
139         processVariables.remove(Process.PROPERTY_TRANSITION);
140 
141         // Decode the URI, for example:
142         // bpm://testProcess/4561?action=advance
143         String temp;
144         temp = event.getEndpoint().getEndpointURI().getHost();
145         if (StringUtils.isNotEmpty(temp))
146         {
147             processType = temp;
148         }
149         temp = event.getEndpoint().getEndpointURI().getPath();
150         if (StringUtils.isNotEmpty(temp))
151         {
152             // Strip the leading "/" from the path.
153             if (temp.startsWith("/"))
154             {
155                 temp = StringUtils.right(temp, temp.length() - 1);
156             }
157             // If there are any remaining "/", we don't know what to do with them.
158             if (temp.indexOf("/") != -1)
159             {
160                 throw new IllegalArgumentException("Unexpected format in the path of the URL: " + temp);
161             }
162             processId = temp;
163         }
164 
165         // //////////////////////////////////////////////////////////////////////
166 
167         logger.debug("Message received: payload = " + event.getMessage().getPayload().getClass().getName() + " processType = " + processType + " processId = " + processId + " action = " + action);
168         
169         // Start a new process.
170         if (processId == null || action.equals(Process.ACTION_START))
171         {
172             if (processType != null)
173             {
174                 process = connector.getBpms().startProcess(processType, transition, processVariables);
175                 if ((process != null) && logger.isInfoEnabled())
176                 {
177                     logger.info("New process started, ID = " + connector.getBpms().getId(process));
178                 }
179             }
180             else
181             {
182                 throw new IllegalArgumentException("Process type is missing, cannot start a new process.");
183             }
184         }
185 
186         // Don't advance the process, just update the process variables.
187         else if (action.equals(Process.ACTION_UPDATE))
188         {
189             if (processId != null)
190             {
191                 process = connector.getBpms().updateProcess(processId, processVariables);
192                 if ((process != null) && logger.isInfoEnabled())
193                 {
194                     logger.info("Process variables updated, ID = " + connector.getBpms().getId(process));
195                 }
196             }
197             else
198             {
199                 throw new IllegalArgumentException("Process ID is missing, cannot update process.");
200             }
201         }
202 
203         // Abort the running process (end abnormally).
204         else if (action.equals(Process.ACTION_ABORT))
205         {
206             if (processId != null)
207             {
208                 connector.getBpms().abortProcess(processId);
209                 process = NullPayload.getInstance();
210                 logger.info("Process aborted, ID = " + processId);
211             }
212             else
213             {
214                 throw new IllegalArgumentException("Process ID is missing, cannot abort process.");
215             }
216         }
217 
218         // Advance the already-running process one step.
219         else
220         {
221             if (processId != null)
222             {
223                 process = connector.getBpms().advanceProcess(processId, transition, processVariables);
224                 if ((process != null) && logger.isInfoEnabled())
225                 {
226                     logger.info("Process advanced, ID = " + connector.getBpms().getId(process)
227                                     + ", new state = " + connector.getBpms().getState(process));
228                 }
229             }
230             else
231             {
232                 throw new IllegalArgumentException("Process ID is missing, cannot advance process.");
233             }
234         }
235 
236         return process;
237     }
238 
239     protected void populateProcessVariables(MuleEvent event, Map processVariables, PropertyScope propertyScope)
240     {
241         for (String propertyName : event.getMessage().getPropertyNames(propertyScope))
242         {
243             // The session property can become rather large and causes problems with DB persistence.
244             if (!propertyName.equals(MuleProperties.MULE_SESSION_PROPERTY))
245             {
246                 processVariables.put(propertyName, event.getMessage().getProperty(propertyName, propertyScope));
247             }
248         }
249     }
250 }