Coverage Report - org.mule.module.bpm.Process
 
Classes in this File Line Coverage Branch Coverage Complexity
Process
0%
0/95
0%
0/54
0
 
 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.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  
  * A business process definition.
 40  
  */
 41  
 public class Process implements Initialisable, Disposable, MessageService
 42  
 {
 43  
     /** The underlying BPMS */
 44  
     private final BPMS bpms;
 45  
 
 46  
     /** The logical name of the process.  This is used to look up the running process instance from the BPMS. */
 47  
     private final String name;
 48  
 
 49  
     /** The resource containing the process definition.  This will be used to deploy the process to the BPMS. */
 50  
     private final String resource;
 51  
 
 52  
     /** This field will be used to correlate messages with processes. */
 53  
     protected final String processIdField;
 54  
 
 55  
     protected MuleContext muleContext;
 56  
 
 57  
     /** Needed for exception handling. */
 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  0
     protected transient Log logger = LogFactory.getLog(getClass());
 87  
 
 88  
     public Process(BPMS bpms, String name, String resource, FlowConstruct flowConstruct, MuleContext muleContext)
 89  
     {
 90  0
         this(bpms, name, resource, null, flowConstruct, muleContext);
 91  0
     }
 92  
 
 93  
     public Process(BPMS bpms, String name, String resource, String processIdField, FlowConstruct flowConstruct, MuleContext muleContext)
 94  0
     {
 95  0
         this.bpms = bpms;
 96  0
         this.name = name;
 97  0
         this.resource = resource;
 98  0
         this.processIdField = processIdField;
 99  0
         this.flowConstruct = flowConstruct;
 100  0
         this.muleContext = muleContext;
 101  0
         this.endpointCache = new SimpleEndpointCache(muleContext);
 102  0
     }
 103  
 
 104  
     public void initialise() throws InitialisationException
 105  
     {
 106  
         try
 107  
         {
 108  0
             bpms.deployProcess(resource);
 109  
         }
 110  0
         catch (Exception e)
 111  
         {
 112  0
             throw new InitialisationException(e, this);
 113  0
         }
 114  0
     }
 115  
 
 116  
     public void dispose()
 117  
     {
 118  
         try
 119  
         {
 120  0
             bpms.undeployProcess(resource);
 121  
         }
 122  0
         catch (Exception e)
 123  
         {
 124  0
             logger.warn(e.getMessage());
 125  0
         }
 126  0
     }
 127  
 
 128  
     protected Object processAction(MuleEvent event) throws Exception
 129  
     {
 130  
         // An object representing the new state of the process
 131  
         Object process;
 132  
 
 133  
         // Create a map of process variables based on the message properties.
 134  0
         Map processVariables = new HashMap();
 135  0
         if (event != null)
 136  
         {
 137  0
             populateProcessVariables(event, processVariables, PropertyScope.INVOCATION);
 138  0
             populateProcessVariables(event, processVariables, PropertyScope.INBOUND);
 139  
 
 140  0
             Object payload = event.getMessage().getPayload();
 141  0
             if (payload != null && !(payload instanceof NullPayload))
 142  
             {
 143  
                 // Store the message's payload as a process variable.
 144  0
                 processVariables.put(PROCESS_VARIABLE_INCOMING, payload);
 145  
 
 146  
                 // Store the endpoint on which the message was received as a process variable.
 147  0
                 String originatingEndpoint = event.getMessage().getInboundProperty(MuleProperties.MULE_ORIGINATING_ENDPOINT_PROPERTY);
 148  0
                 if (StringUtils.isNotEmpty(originatingEndpoint))
 149  
                 {
 150  0
                     processVariables.put(PROCESS_VARIABLE_INCOMING_SOURCE, originatingEndpoint);
 151  
                 }
 152  
             }
 153  
         }
 154  
 
 155  0
         String processIdField = getProcessIdField();
 156  0
         if (StringUtils.isEmpty(processIdField))
 157  
         {
 158  0
             processIdField = PROPERTY_PROCESS_ID;
 159  
         }
 160  
 
 161  
         Object processId;
 162  0
         processId = event.getMessage().getSessionProperty(processIdField);
 163  0
         if (processId == null)
 164  
         {
 165  0
             processId = event.getMessage().getInvocationProperty(processIdField); 
 166  
         }
 167  0
         if (processId == null)
 168  
         {
 169  0
             processId = event.getMessage().getInboundProperty(processIdField); 
 170  
         }
 171  0
         processVariables.remove(processIdField);
 172  
 
 173  
         // Default action is "advance"
 174  0
         String action = event.getMessage().getInvocationProperty(PROPERTY_ACTION, ACTION_ADVANCE);
 175  0
         processVariables.remove(PROPERTY_ACTION);
 176  
 
 177  0
         Object transition = event.getMessage().getInvocationProperty(PROPERTY_TRANSITION);
 178  0
         processVariables.remove(PROPERTY_TRANSITION);
 179  
 
 180  
         // //////////////////////////////////////////////////////////////////////
 181  
 
 182  0
         logger.debug("Message received: payload = " + event.getMessage().getPayload().getClass().getName() + " processType = " + name + " processId = " + processId + " action = " + action);
 183  
         
 184  
         // Start a new process.
 185  0
         if (processId == null || action.equals(ACTION_START))
 186  
         {
 187  0
             process = getBpms().startProcess(name, transition, processVariables);
 188  0
             if ((process != null) && logger.isInfoEnabled())
 189  
             {
 190  0
                 logger.info("New process started, ID = " + getBpms().getId(process));
 191  
             }
 192  
         }
 193  
 
 194  
         // Don't advance the process, just update the process variables.
 195  0
         else if (action.equals(ACTION_UPDATE))
 196  
         {
 197  0
             if (processId != null)
 198  
             {
 199  0
                 process = getBpms().updateProcess(processId, processVariables);
 200  0
                 if ((process != null) && logger.isInfoEnabled())
 201  
                 {
 202  0
                     logger.info("Process variables updated, ID = " + getBpms().getId(process));
 203  
                 }
 204  
             }
 205  
             else
 206  
             {
 207  0
                 throw new IllegalArgumentException("Process ID is missing, cannot update process.");
 208  
             }
 209  
         }
 210  
 
 211  
         // Abort the running process (end abnormally).
 212  0
         else if (action.equals(ACTION_ABORT))
 213  
         {
 214  0
             if (processId != null)
 215  
             {
 216  0
                 getBpms().abortProcess(processId);
 217  0
                 process = NullPayload.getInstance();
 218  0
                 logger.info("Process aborted, ID = " + processId);
 219  
             }
 220  
             else
 221  
             {
 222  0
                 throw new IllegalArgumentException("Process ID is missing, cannot abort process.");
 223  
             }
 224  
         }
 225  
 
 226  
         // Advance the already-running process one step.
 227  
         else
 228  
         {
 229  0
             if (processId != null)
 230  
             {
 231  0
                 process = getBpms().advanceProcess(processId, transition, processVariables);
 232  0
                 if ((process != null) && logger.isInfoEnabled())
 233  
                 {
 234  0
                     logger.info("Process advanced, ID = " + getBpms().getId(process)
 235  
                                     + ", new state = " + getBpms().getState(process));
 236  
                 }
 237  
             }
 238  
             else
 239  
             {
 240  0
                 throw new IllegalArgumentException("Process ID is missing, cannot advance process.");
 241  
             }
 242  
         }
 243  
 
 244  0
         return process;
 245  
     }
 246  
 
 247  
     protected void populateProcessVariables(MuleEvent event, Map processVariables, PropertyScope propertyScope)
 248  
     {
 249  0
         for (String propertyName : event.getMessage().getPropertyNames(propertyScope))
 250  
         {
 251  
             // The session property can become rather large and causes problems with DB persistence.
 252  0
             if (!propertyName.equals(MuleProperties.MULE_SESSION_PROPERTY))
 253  
             {
 254  0
                 processVariables.put(propertyName, event.getMessage().getProperty(propertyName, propertyScope));
 255  
             }
 256  
         }
 257  0
     }
 258  
 
 259  
     public MuleMessage generateMessage(String endpoint, Object payload, Map messageProperties, MessageExchangePattern exchangePattern) throws MuleException
 260  
     {
 261  
         MuleMessage message;
 262  0
         if (payload instanceof MuleMessage)
 263  
         {
 264  0
             message = (MuleMessage) payload;
 265  
         }
 266  
         else
 267  
         {
 268  0
             message = new DefaultMuleMessage(payload, muleContext);
 269  
         }
 270  0
         message.addProperties(messageProperties, PropertyScope.INBOUND);
 271  0
         message.addProperties(messageProperties, PropertyScope.INVOCATION);
 272  
 
 273  
         // Use an endpoint cache to prevent memory leaks (see MULE-5422)
 274  0
         OutboundEndpoint ep = endpointCache.getOutboundEndpoint(endpoint, exchangePattern, null);
 275  0
         DefaultMuleEvent event = new DefaultMuleEvent(message, ep, new DefaultMuleSession(flowConstruct, muleContext));
 276  0
         RequestContext.setEvent(event);
 277  
 
 278  
         // Set correlation properties in SESSION scope so that they get propagated to response messages.
 279  0
         if (messageProperties.get(PROPERTY_PROCESS_TYPE) != null)
 280  
         {
 281  0
             event.getMessage().setSessionProperty(PROPERTY_PROCESS_TYPE, messageProperties.get(PROPERTY_PROCESS_TYPE));
 282  
         }
 283  0
         if (messageProperties.get(PROPERTY_PROCESS_ID) != null)
 284  
         {
 285  0
             event.getMessage().setSessionProperty(PROPERTY_PROCESS_ID, messageProperties.get(PROPERTY_PROCESS_ID));
 286  
         }
 287  
         
 288  0
         MuleEvent resultEvent = ep.process(event);
 289  
         
 290  0
         MuleMessage response = null;
 291  0
         if (resultEvent != null)
 292  
         {
 293  0
             response = resultEvent.getMessage();
 294  0
             if (response.getExceptionPayload() != null)
 295  
             {
 296  0
                 throw new DispatchException(MessageFactory.createStaticMessage("Unable to send or route message"), event, ep, response.getExceptionPayload().getRootException());
 297  
             }
 298  
         }        
 299  0
         return response;
 300  
     }
 301  
 
 302  
     public String getProcessIdField()
 303  
     {
 304  0
         return processIdField;
 305  
     }
 306  
 
 307  
     public BPMS getBpms()
 308  
     {
 309  0
         return bpms;
 310  
     }
 311  
 
 312  
     public String getResource()
 313  
     {
 314  0
         return resource;
 315  
     }
 316  
 
 317  
     public String getName()
 318  
     {
 319  0
         return name;
 320  
     }
 321  
 }
 322  
 
 323