View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.module.jbpm;
8   
9   import org.mule.MessageExchangePattern;
10  import org.mule.api.MuleMessage;
11  import org.mule.api.config.MuleProperties;
12  import org.mule.module.bpm.MessageService;
13  import org.mule.module.bpm.Process;
14  import org.mule.util.ClassUtils;
15  
16  import java.util.HashMap;
17  import java.util.Map;
18  import java.util.Map.Entry;
19  
20  import org.jbpm.api.JbpmException;
21  import org.jbpm.api.activity.ActivityExecution;
22  import org.jbpm.api.listener.EventListener;
23  import org.jbpm.api.listener.EventListenerExecution;
24  import org.jbpm.api.model.OpenExecution;
25  import org.jbpm.internal.log.Log;
26  import org.jbpm.jpdl.internal.activity.JpdlActivity;
27  import org.jbpm.pvm.internal.env.EnvironmentImpl;
28  import org.jbpm.pvm.internal.model.ExecutionImpl;
29  import org.jbpm.pvm.internal.script.ScriptManager;
30  
31  public class MuleSendActivity extends JpdlActivity implements EventListener
32  {
33      /**
34       * Mule endpoint to send a message to.  This may be a URI or logical name (for a global endpoint).
35       */
36      private String endpoint;
37  
38      /**
39       * Exchange pattern (REQUEST-RESPONSE, ONE-WAY, etc.).  Default is REQUEST-RESPONSE.
40       */
41      private MessageExchangePattern mep = MessageExchangePattern.REQUEST_RESPONSE;
42      
43      /** 
44       * Expected response type in the case of a synchronous call; if the response payload is not assignable to this class, an exception will be thrown.
45       */
46      private Class responsePayloadClass;
47  
48      /**
49       * Variable into which the synchronous response will be stored.  If null, the response will not be stored at all.
50       */
51      private String responseVariableName;
52      
53      /**
54       * payloadSource may be a literal value or it may be an expression which references process variables.
55       */
56      private String payloadExpression;
57  
58      private static final Log log = Log.getLog(MuleSendActivity.class.getName());
59  
60      public void execute(ActivityExecution execution) throws Exception
61      {
62          perform(execution);
63          ((ExecutionImpl) execution).historyAutomatic();
64      }
65  
66      public void notify(EventListenerExecution execution) throws Exception
67      {
68          perform(execution);
69      }
70  
71      public void perform(OpenExecution execution) throws Exception
72      {
73          MessageService mule = EnvironmentImpl.getCurrent().get(MuleMessageService.class);
74          if (mule == null)
75          {
76              throw new JbpmException("The Mule MessageService is not available from the ProcessEngine, you may need to add it to your jbpm.cfg.xml file");
77          }
78  
79          Object payloadObject = null;
80          if (payloadExpression == null)
81          {
82              payloadObject = execution.getVariable(Process.PROCESS_VARIABLE_DATA);
83              if (payloadObject == null)
84              {
85                  payloadObject = execution.getVariable(Process.PROCESS_VARIABLE_INCOMING);
86              }
87          }
88          else
89          {
90              // The payloadSource may be specified using an expression (e.g.,
91              // #{myObject.myStuff.myField} would first retrieve the process
92              // variable "myObject" and then call .getMyStuff().getMyField()
93              payloadObject = ScriptManager.getScriptManager().evaluateExpression(payloadExpression, null);
94          }
95          if (payloadObject == null)
96          {
97              throw new IllegalArgumentException("Payload for message is null.  Payload source is \""
98                                                 + payloadExpression + "\"");
99          }
100 
101         Map props = new HashMap();
102 
103         props.put(Process.PROPERTY_PROCESS_TYPE, ((ExecutionImpl) execution).getProcessDefinition().getName());
104         props.put(Process.PROPERTY_PROCESS_ID, execution.getId());
105         String state = Jbpm.getState(execution.getProcessInstance());
106         props.put("MULE_BPM_PROCESS_STATE", state);
107         log.debug("process state: " + state);        
108 
109         // Set process vars as properties on outgoing Mule messages.
110         for (Entry<String, ?> var : execution.getVariables().entrySet())
111         {
112             if (!var.getKey().startsWith(MuleProperties.PROPERTY_PREFIX))
113             {
114                 log.debug("process var: " + var.getKey() + " = " + var.getValue());
115                 props.put(var.getKey(), var.getValue());
116             }
117         }
118 
119         // Just in case the endpoint itself is an expression
120         endpoint = (String) ScriptManager.getScriptManager().evaluateExpression(endpoint, null);
121         MuleMessage response = mule.generateMessage(endpoint, payloadObject, props, mep);
122 
123         if (mep.hasResponse() && response != null)
124         {
125             Object responsePayload = response.getPayload();
126     
127             // Validate expected response type
128             if (responsePayloadClass != null)
129             {
130                 log.debug("Validating response type = " + responsePayload.getClass() + ", expected = " + responsePayloadClass);
131                 if (!responsePayloadClass.isAssignableFrom(responsePayload.getClass()))
132                 {
133                     throw new JbpmException("Response message is of type " + responsePayload.getClass() + " but expected type is " + responsePayloadClass);
134                 }
135             }
136             
137             if (responseVariableName != null)
138             {
139                 if (responsePayload != null)
140                 {
141                     execution.setVariable(responseVariableName, responsePayload);
142                 }
143                 else
144                 {
145                     log.info("Synchronous message was sent to endpoint " + endpoint + ", but no response was returned.");
146                 }
147             }
148         }
149     }
150     
151     public void setEndpoint(String endpoint)
152     {
153         this.endpoint = endpoint;
154     }
155 
156     public void setMessageExchangePattern(String mepString)
157     {
158         if (mepString != null)
159         {
160             this.mep = MessageExchangePattern.fromString(mepString);
161         }
162     }
163 
164     public String getPayloadExpression()
165     {
166         return payloadExpression;
167     }
168 
169     public void setPayloadExpression(String payloadExpression)
170     {
171         this.payloadExpression = payloadExpression;
172     }
173 
174     public String getResponseVariableName()
175     {
176         return responseVariableName;
177     }
178 
179     public void setResponseVariableName(String responseVariableName)
180     {
181         this.responseVariableName = responseVariableName;
182     }
183 
184     public void setResponsePayloadClass(String className)
185     {
186         if (className != null)
187         {
188             try
189             {
190                 responsePayloadClass = ClassUtils.loadClass(className, this.getClass());
191             }
192             catch (ClassNotFoundException e)
193             {
194                 log.error("Expected message type not valid: " + e.getMessage());
195             }
196         }
197     }
198 
199     public Class getResponsePayloadClass()
200     {
201         return responsePayloadClass;
202     }
203 }