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