Coverage Report - org.mule.module.jbpm.Jbpm
 
Classes in this File Line Coverage Branch Coverage Complexity
Jbpm
0%
0/108
0%
0/48
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.jbpm;
 8  
 
 9  
 import org.mule.api.NamedObject;
 10  
 import org.mule.api.lifecycle.Disposable;
 11  
 import org.mule.api.lifecycle.Initialisable;
 12  
 import org.mule.module.bpm.BPMS;
 13  
 import org.mule.module.bpm.MessageService;
 14  
 import org.mule.util.IOUtils;
 15  
 
 16  
 import java.io.IOException;
 17  
 import java.io.InputStream;
 18  
 import java.util.Map;
 19  
 import java.util.Properties;
 20  
 import java.util.Set;
 21  
 
 22  
 import org.jbpm.api.Configuration;
 23  
 import org.jbpm.api.Execution;
 24  
 import org.jbpm.api.ProcessEngine;
 25  
 import org.jbpm.api.ProcessInstance;
 26  
 import org.jbpm.api.task.Task;
 27  
 import org.slf4j.Logger;
 28  
 import org.slf4j.LoggerFactory;
 29  
 
 30  
 /**
 31  
  * An implementation of Mule's generic {@link BPMS} interface for JBoss jBPM.
 32  
  */
 33  
 public class Jbpm implements BPMS, Initialisable, Disposable, NamedObject
 34  
 {
 35  
     /**
 36  
      * The initialized jBPM ProcessEngine.
 37  
      */
 38  0
     protected ProcessEngine processEngine = null;
 39  
 
 40  
     /**
 41  
      * The configuration file for jBPM, default is "jbpm.cfg.xml" if not specified.
 42  
      */
 43  
     private String configurationResource;
 44  
 
 45  
     /**
 46  
      * Process definitions to be loaded into jBPM at startup.
 47  
      */
 48  
     private Properties processDefinitions;
 49  
 
 50  
     /**
 51  
      * An optional logical name for the BPMS.
 52  
      */
 53  
     private String name;
 54  
 
 55  
     /**
 56  
      * Indicates whether jBPM has been instantiated by the connector (false) or was
 57  
      * passed in from somewhere else (true).
 58  
      */
 59  0
     protected boolean containerManaged = true;
 60  
 
 61  
     public static final String PROCESS_ENDED = "Process has ended";
 62  
 
 63  
     /**
 64  
      * Given the multi-threaded nature of Mule, sometimes a response message will arrive to advance the
 65  
      * process before the creation of the process has fully terminated (e.g., during in-memory unit tests).
 66  
      * After this amount of time (in ms), we stop waiting and assume there must be some other problem.
 67  
      */
 68  
     public static final int PROCESS_CREATION_WAIT = 3000;
 69  
 
 70  0
     protected static final Logger log = LoggerFactory.getLogger(Jbpm.class);
 71  
 
 72  
     // ///////////////////////////////////////////////////////////////////////////
 73  
     // Lifecycle methods
 74  
     // ///////////////////////////////////////////////////////////////////////////
 75  
 
 76  
     /**
 77  
      * Creates the Mule wrapper for jBPM
 78  
      */
 79  
     public Jbpm()
 80  0
     {
 81  
         // empty
 82  0
     }
 83  
 
 84  
     /**
 85  
      * Creates the Mule wrapper for jBPM
 86  
      * @param configurationResource - The configuration file for jBPM, default is "jbpm.cfg.xml" if not specified.
 87  
      * @param processDefinitions - A list of process definitions to load into jBPM upon initialization.
 88  
      */
 89  
     public Jbpm(String configurationResource, Properties processDefinitions)
 90  0
     {
 91  0
         this.configurationResource = configurationResource;
 92  0
         this.processDefinitions = processDefinitions;
 93  0
     }
 94  
 
 95  
     /**
 96  
      * Creates the Mule wrapper for jBPM
 97  
      *
 98  
      * @param processEngine The already-initialized jBPM ProcessEngine. This is
 99  
      *            useful if you use Spring to configure your jBPM instance.
 100  
      */
 101  
     public Jbpm(ProcessEngine processEngine, Properties processDefinitions)
 102  0
     {
 103  0
         this.processEngine = processEngine;
 104  0
         this.processDefinitions = processDefinitions;
 105  0
     }
 106  
 
 107  
     public void initialise()
 108  
     {
 109  0
         if (processEngine == null)
 110  
         {
 111  0
             Configuration config = new Configuration();
 112  0
             if (configurationResource != null)
 113  
             {
 114  0
                 config.setResource(configurationResource);
 115  
             }
 116  0
             setProcessEngine(config.buildProcessEngine());
 117  0
             containerManaged = false;
 118  
         }
 119  0
         if (processDefinitions != null)
 120  
         {
 121  0
             for (Object def : processDefinitions.values())
 122  
             {
 123  
                 try
 124  
                 {
 125  0
                     deployProcess((String) def);
 126  
                 }
 127  0
                 catch (IOException e)
 128  
                 {
 129  0
                     log.error("Unable to deploy process definition: " + e.getMessage());
 130  0
                 }
 131  
             }
 132  
         }
 133  0
     }
 134  
 
 135  
     public void dispose()
 136  
     {
 137  0
         if (!containerManaged && processEngine != null)
 138  
         {
 139  0
             processEngine.close();
 140  0
             processEngine = null;
 141  
         }
 142  0
     }
 143  
 
 144  
     public void setMessageService(MessageService msgService)
 145  
     {
 146  0
         MuleMessageService serviceProxy = processEngine.get(MuleMessageService.class);
 147  0
         serviceProxy.setMessageService(msgService);
 148  0
     }
 149  
 
 150  
     // ///////////////////////////////////////////////////////////////////////////
 151  
     // Process manipulation
 152  
     // ///////////////////////////////////////////////////////////////////////////
 153  
 
 154  
     /**
 155  
      * Start a new process.
 156  
      *
 157  
      * @return the newly-created ProcessInstance
 158  
      */
 159  
     public Object startProcess(Object processDefinitionKey) throws Exception
 160  
     {
 161  0
         return startProcess(processDefinitionKey, null, null);
 162  
     }
 163  
 
 164  
     /**
 165  
      * Start a new process.
 166  
      *
 167  
      * @return the newly-created ProcessInstance
 168  
      */
 169  
     public Object startProcess(Object processDefinitionKey, Object signalName, Map variables) throws Exception
 170  
     {
 171  0
         ProcessInstance processInstance =
 172  
             processEngine.getExecutionService().startProcessInstanceByKey((String) processDefinitionKey, (Map) variables);
 173  
 
 174  0
         if (processInstance == null)
 175  
         {
 176  0
             throw new IllegalArgumentException("No process definition found for process " + processDefinitionKey);
 177  
         }
 178  
 
 179  0
         return processInstance;
 180  
     }
 181  
 
 182  
     /**
 183  
      * Advance a process instance one step.
 184  
      *
 185  
      * @return the updated ProcessInstance
 186  
      */
 187  
     public Object advanceProcess(Object executionId) throws Exception
 188  
     {
 189  0
         return advanceProcess(executionId, null, null);
 190  
     }
 191  
 
 192  
     /**
 193  
      * Advance a process instance one step.
 194  
      *
 195  
      * @param variables - optional process variables/parameters to set
 196  
      * @return the updated ProcessInstance
 197  
      */
 198  
     public Object advanceProcess(Object executionId, Object signalName, Map variables) throws Exception
 199  
     {
 200  0
         int waitTime = 0;
 201  0
         Execution execution = processEngine.getExecutionService().findExecutionById((String) executionId);
 202  0
         while (execution == null && waitTime < PROCESS_CREATION_WAIT)
 203  
         {
 204  
             // Given the multi-threaded nature of Mule, sometimes a response message will arrive to advance the
 205  
             // process before the creation of the process has fully terminated (e.g., during in-memory unit tests).
 206  
             // We delay for awhile to make sure this is not the case before giving up and throwing an exception.
 207  0
             Thread.sleep(PROCESS_CREATION_WAIT / 10);
 208  0
             waitTime += (PROCESS_CREATION_WAIT / 10);
 209  0
             execution = processEngine.getExecutionService().findExecutionById((String) executionId);
 210  
         }
 211  0
         if (execution == null)
 212  
         {
 213  0
             throw new IllegalArgumentException("No process execution found with id = " + executionId + " (it may have already terminated)");
 214  
         }
 215  
 
 216  
         String processId;
 217  0
         if (execution.getProcessInstance() != null)
 218  
         {
 219  0
             processId = execution.getProcessInstance().getId();
 220  
         }
 221  
         else
 222  
         {
 223  0
             processId = execution.getId();
 224  
         }
 225  
 
 226  
         // Set any process variables.
 227  0
         if (variables != null && !variables.isEmpty())
 228  
         {
 229  0
             processEngine.getExecutionService().setVariables((String) executionId, variables);
 230  
         }
 231  
 
 232  
         // MULE-1690
 233  0
         synchronized (this)
 234  
         {
 235  0
             processEngine.getExecutionService().signalExecutionById((String) executionId, (String) signalName, variables);
 236  0
         }
 237  
 
 238  
         // Refresh process info. from the DB
 239  0
         ProcessInstance process = processEngine.getExecutionService().findProcessInstanceById(processId);
 240  0
         if (process == null)
 241  
         {
 242  
             // The process has already ended, so we return a mock/skeleton ProcessInstance with the expected ID and state = "ended"
 243  0
             process = new EndedProcess(processId);
 244  
         }
 245  0
         return process;
 246  
     }
 247  
 
 248  
     /**
 249  
      * Update the variables for an execution.
 250  
      *
 251  
      * @return the updated ProcessInstance
 252  
      */
 253  
     public Object updateProcess(Object executionId, Map variables) throws Exception
 254  
     {
 255  
         // Get Process ID
 256  
         String processId;
 257  0
         Execution execution = processEngine.getExecutionService().findExecutionById((String) executionId);
 258  0
         if (execution == null)
 259  
         {
 260  0
             throw new IllegalArgumentException("No process execution found with id = " + executionId + " (it may have already terminated)");
 261  
         }
 262  0
         if (execution.getProcessInstance() != null)
 263  
         {
 264  0
             processId = execution.getProcessInstance().getId();
 265  
         }
 266  
         else
 267  
         {
 268  0
             processId = execution.getId();
 269  
         }
 270  
 
 271  
         // Set any process variables.
 272  0
         if (variables != null && !variables.isEmpty())
 273  
         {
 274  0
             processEngine.getExecutionService().setVariables((String) executionId, variables);
 275  
         }
 276  
 
 277  
         // Refresh process info. from the DB
 278  0
         ProcessInstance process = processEngine.getExecutionService().findProcessInstanceById(processId);
 279  0
         if (process == null)
 280  
         {
 281  
             // The process has already ended, so we return a mock/skeleton ProcessInstance with the expected ID and state = "ended"
 282  0
             process = new EndedProcess(processId);
 283  
         }
 284  0
         return process;
 285  
     }
 286  
 
 287  
     /**
 288  
      * Delete a process instance.
 289  
      */
 290  
     public void abortProcess(Object processInstanceId) throws Exception
 291  
     {
 292  0
         processEngine.getExecutionService().endProcessInstance((String) processInstanceId, Execution.STATE_ENDED);
 293  0
     }
 294  
 
 295  
     // ///////////////////////////////////////////////////////////////////////////
 296  
     // Process status / lookup
 297  
     // ///////////////////////////////////////////////////////////////////////////
 298  
 
 299  
     public boolean isProcess(Object obj) throws Exception
 300  
     {
 301  0
         return (obj instanceof ProcessInstance);
 302  
     }
 303  
 
 304  
     public Object getId(Object process) throws Exception
 305  
     {
 306  0
         return ((ProcessInstance) process).getId();
 307  
     }
 308  
 
 309  
     public Object getState(Object process) throws Exception
 310  
     {
 311  0
         return getState((ProcessInstance) process);
 312  
     }
 313  
 
 314  
     public static String getState(ProcessInstance processInstance) throws Exception
 315  
     {
 316  0
         if (processInstance == null || processInstance.isEnded())
 317  
         {
 318  0
             return ProcessInstance.STATE_ENDED;
 319  
         }
 320  
 
 321  0
         Set activities = processInstance.findActiveActivityNames();
 322  0
         String state = null;
 323  
         // Separate concurrent paths of execution with a "/"
 324  0
         for (Object activityName : activities)
 325  
         {
 326  0
             if (state == null)
 327  
             {
 328  0
                 state = (String) activityName;
 329  
             }
 330  
             else
 331  
             {
 332  0
                 state += " / " + activityName;
 333  
             }
 334  
         }
 335  0
         return state;
 336  
     }
 337  
 
 338  
     public boolean hasEnded(Object process) throws Exception
 339  
     {
 340  0
         return process == null ? true : ((ProcessInstance) process).isEnded();
 341  
     }
 342  
 
 343  
     /**
 344  
      * Look up an already-running process instance.
 345  
      *
 346  
      * @return the ProcessInstance
 347  
      */
 348  
     public Object lookupProcess(Object processId) throws Exception
 349  
     {
 350  0
         return processEngine.getExecutionService().findProcessInstanceById((String) processId);
 351  
     }
 352  
 
 353  
     // ///////////////////////////////////////////////////////////////////////////
 354  
     // Miscellaneous
 355  
     // ///////////////////////////////////////////////////////////////////////////
 356  
 
 357  
     public void deployProcess(String processDefinitionFile) throws IOException
 358  
     {
 359  0
         deployProcessFromStream(processDefinitionFile, IOUtils.getResourceAsStream(processDefinitionFile,
 360  
             getClass()));
 361  0
     }
 362  
 
 363  
     public void deployProcessFromStream(String resourceName, InputStream processDefinition)
 364  
         throws IOException
 365  
     {
 366  0
         processEngine.getRepositoryService().createDeployment()
 367  
             .addResourceFromInputStream(resourceName, processDefinition)
 368  
             .deploy();
 369  0
     }
 370  
 
 371  
     public void undeployProcess(String resource) throws Exception
 372  
     {
 373  
         // empty
 374  0
     }
 375  
 
 376  
     public void completeTask(Task task)
 377  
     {
 378  0
         completeTask(task, null, null);
 379  0
     }
 380  
 
 381  
     public void completeTask(Task task, String outcome, Map variables)
 382  
     {
 383  0
         processEngine.getTaskService().completeTask(task.getId(), outcome, variables);
 384  0
     }
 385  
 
 386  
     // ///////////////////////////////////////////////////////////////////////////
 387  
     // Getters and setters
 388  
     // ///////////////////////////////////////////////////////////////////////////
 389  
 
 390  
     public ProcessEngine getProcessEngine()
 391  
     {
 392  0
         return processEngine;
 393  
     }
 394  
 
 395  
     public void setProcessEngine(ProcessEngine processEngine)
 396  
     {
 397  0
         this.processEngine = processEngine;
 398  0
     }
 399  
 
 400  
     public String getConfigurationResource()
 401  
     {
 402  0
         return configurationResource;
 403  
     }
 404  
 
 405  
     public void setConfigurationResource(String configurationResource)
 406  
     {
 407  0
         this.configurationResource = configurationResource;
 408  0
     }
 409  
 
 410  
     public Properties getProcessDefinitions()
 411  
     {
 412  0
         return processDefinitions;
 413  
     }
 414  
 
 415  
     public void setProcessDefinitions(Properties processDefinitions)
 416  
     {
 417  0
         this.processDefinitions = processDefinitions;
 418  0
     }
 419  
 
 420  
     public void setName(String name)
 421  
     {
 422  0
         this.name = name;
 423  0
     }
 424  
 
 425  
     public String getName()
 426  
     {
 427  0
         return name;
 428  
     }
 429  
 }