View Javadoc

1   /*
2    * $Id: ProcessConnector.java 7963 2007-08-21 08:53:15Z dirk.olmes $
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.providers.bpm;
12  
13  import org.mule.config.ConfigurationException;
14  import org.mule.config.i18n.MessageFactory;
15  import org.mule.extras.client.MuleClient;
16  import org.mule.providers.AbstractConnector;
17  import org.mule.umo.UMOException;
18  import org.mule.umo.UMOMessage;
19  import org.mule.umo.lifecycle.InitialisationException;
20  import org.mule.util.ClassUtils;
21  import org.mule.util.StringUtils;
22  
23  import java.util.Map;
24  
25  /**
26   * The BPM provider allows Mule events to initiate and/or advance processes in an
27   * external or embedded Business Process Management System (BPMS). It also allows
28   * executing processes to generate Mule events.
29   */
30  public class ProcessConnector extends AbstractConnector implements MessageService
31  {
32      /** The underlying BPMS */
33      protected BPMS bpms;
34  
35      /** 
36       * If the BPMS instance itself is not provided, it will be instantiated from this class 
37       * (using the default constructor). 
38       */
39      protected String bpmsClass;
40      
41      /** This field will be used to correlate messages with processes. */
42      protected String processIdField;
43  
44      /**
45       * The global receiver allows an endpoint of type "bpm://*" to receive any
46       * incoming message to the BPMS, regardless of the process. If this is false, the
47       * process name must be specified for each endpoint, e.g. "bpm://MyProcess" will
48       * only receive messages for the process "MyProcess".
49       */
50      protected boolean allowGlobalReceiver = false;
51  
52      /**
53       * If false, any message generated by the process is routed from the component on 
54       * which it is received.  If true, a process can send messages to any endpoint
55       * on any component.
56       */
57      protected boolean allowGlobalDispatcher = false;
58  
59      public static final String PROPERTY_ENDPOINT = "endpoint";
60      public static final String PROPERTY_PROCESS_TYPE = "processType";
61      public static final String PROPERTY_PROCESS_ID = "processId";
62      public static final String PROPERTY_ACTION = "action";
63      public static final String PROPERTY_TRANSITION = "transition";
64      public static final String PROPERTY_PROCESS_STARTED = "started";
65      public static final String ACTION_START = "start";
66      public static final String ACTION_ADVANCE = "advance";
67      public static final String ACTION_UPDATE = "update";
68      public static final String ACTION_ABORT = "abort";
69      public static final String PROCESS_VARIABLE_INCOMING = "incoming";
70      public static final String PROCESS_VARIABLE_INCOMING_SOURCE = "incomingSource";
71      public static final String PROCESS_VARIABLE_DATA = "data";
72  
73      public static final String PROTOCOL = "bpm";
74      public static final String GLOBAL_RECEIVER = PROTOCOL + "://*";
75  
76      private MuleClient muleClient = null;
77  
78      public String getProtocol()
79      {
80          return PROTOCOL;
81      }
82  
83      protected void doInitialise() throws InitialisationException
84      {
85          try
86          {
87              if (bpms == null)
88              {
89                  if (bpmsClass != null)
90                  {
91                      logger.info("Instantiating BPMS from the default constructor for " + bpmsClass);
92                      bpms = (BPMS) ClassUtils.instanciateClass(bpmsClass, new Object[0]);
93                  }
94                  else 
95                  {
96                      throw new ConfigurationException(
97                          MessageFactory.createStaticMessage("Either the bpms or bpmsClass property must be set for this connector."));
98                  }
99              }
100 
101             // Set a callback so that the BPMS may generate messages within Mule.
102             bpms.setMessageService(this);
103             
104             // The MuleClient is used as a global dispatcher.  
105             // TODO MULE-1221 It would be cleaner to use something like the dynamic:// transport
106             if ((allowGlobalDispatcher == true) && (muleClient == null))
107             {
108                 muleClient = new MuleClient(false);
109             }
110         }
111         catch (Exception e)
112         {
113             throw new InitialisationException(e, this);
114         }
115     }
116 
117     protected void doDispose()
118     {
119         // template method
120     }
121 
122     protected void doConnect() throws Exception
123     {
124         // template method
125     }
126 
127     protected void doDisconnect() throws Exception
128     {
129         // template method
130     }
131 
132     protected void doStart() throws UMOException
133     {
134         // template method
135     }
136 
137     protected void doStop() throws UMOException
138     {
139         // template method
140     }
141 
142     /**
143      * This method looks for a receiver based on the process name and ID. It searches
144      * iteratively from the narrowest scope (match process name and ID) to the widest
145      * scope (match neither - global receiver) possible.
146      * 
147      * @return ProcessMessageReceiver or null if no match is found
148      */
149     public ProcessMessageReceiver lookupReceiver(String processName, Object processId)
150     {
151         ProcessMessageReceiver receiver = (ProcessMessageReceiver)lookupReceiver(toUrl(processName, processId));
152         if (receiver == null)
153         {
154             receiver = (ProcessMessageReceiver)lookupReceiver(toUrl(processName, null));
155         }
156         if (receiver == null)
157         {
158             receiver = (ProcessMessageReceiver)lookupReceiver(toUrl(null, null));
159         }
160         return receiver;
161     }
162 
163     /**
164      * Generate a URL based on the process name and ID such as "bpm://myProcess/2342"
165      * If the parameters are missing, and <code>allowGlobalReceiver</code> is true,
166      * the GLOBAL_RECEIVER is returned.
167      */
168     public String toUrl(String processName, Object processId)
169     {
170         String url = getProtocol() + "://";
171         if (StringUtils.isNotEmpty(processName))
172         {
173             url += processName;
174             if (processId != null)
175             {
176                 url += "/" + processId;
177             }
178         }
179         else if (isAllowGlobalReceiver())
180         {
181             return GLOBAL_RECEIVER;
182         }
183         else
184         {
185             throw new IllegalArgumentException(
186                 "No valid URL could be created for the given process name and ID: processName = " + processName + ", processId = " + processId);
187         }
188         return url;
189     }
190 
191     public UMOMessage generateMessage(String endpoint,
192                                       Object payloadObject,
193                                       Map messageProperties,
194                                       boolean synchronous) throws Exception
195     {
196         String processName = (String)messageProperties.get(ProcessConnector.PROPERTY_PROCESS_TYPE);
197         Object processId = messageProperties.get(ProcessConnector.PROPERTY_PROCESS_ID);
198 
199         // Look up a receiver for this process.
200         ProcessMessageReceiver receiver = lookupReceiver(processName, processId);
201         if (receiver == null)
202         {
203             throw new ConfigurationException(MessageFactory
204                 .createStaticMessage("No corresponding receiver found for processName = " + processName
205                                 + ", processId = " + processId));
206         }
207 
208         if (synchronous)
209         {
210             // Send the process-generated Mule message synchronously.
211             return receiver.generateSynchronousEvent(endpoint, payloadObject, messageProperties);
212         }
213         else
214         {
215             // Dispatch the process-generated Mule message asynchronously.
216             receiver.generateAsynchronousEvent(endpoint, payloadObject, messageProperties);
217             return null;
218         }
219     }
220 
221     // //////////////////////////////////////////////////////////////////////////
222     // Getters and Setters
223     // //////////////////////////////////////////////////////////////////////////
224 
225     public BPMS getBpms()
226     {
227         return bpms;
228     }
229 
230     public void setBpms(BPMS bpms)
231     {
232         this.bpms = bpms;
233     }
234 
235     public String getBpmsClass()
236     {
237         return bpmsClass;
238     }
239 
240     public void setBpmsClass(String bpmsClass)
241     {
242         this.bpmsClass = bpmsClass;
243     }
244 
245     public MuleClient getMuleClient()
246     {
247         return muleClient;
248     }
249 
250     public boolean isAllowGlobalDispatcher()
251     {
252         return allowGlobalDispatcher;
253     }
254 
255     public void setAllowGlobalDispatcher(boolean allowGlobalDispatcher)
256     {
257         this.allowGlobalDispatcher = allowGlobalDispatcher;
258     }
259 
260     public boolean isAllowGlobalReceiver()
261     {
262         return allowGlobalReceiver;
263     }
264 
265     public void setAllowGlobalReceiver(boolean allowGlobalReceiver)
266     {
267         this.allowGlobalReceiver = allowGlobalReceiver;
268     }
269 
270     public String getProcessIdField()
271     {
272         return processIdField;
273     }
274 
275     public void setProcessIdField(String processIdField)
276     {
277         this.processIdField = processIdField;
278     }
279 }