Coverage Report - org.mule.transport.bpm.jbpm.Jbpm
 
Classes in this File Line Coverage Branch Coverage Complexity
Jbpm
54%
57/106
38%
9/24
2.043
 
 1  
 /*
 2  
  * $Id: Jbpm.java 10489 2008-01-23 17:53:38Z dfeist $
 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.transport.bpm.jbpm;
 12  
 
 13  
 import org.mule.transport.bpm.BPMS;
 14  
 import org.mule.transport.bpm.MessageService;
 15  
 import org.mule.util.IOUtils;
 16  
 import org.mule.util.NumberUtils;
 17  
 
 18  
 import java.io.IOException;
 19  
 import java.io.InputStream;
 20  
 import java.util.List;
 21  
 import java.util.Map;
 22  
 
 23  
 import org.apache.commons.logging.Log;
 24  
 import org.apache.commons.logging.LogFactory;
 25  
 import org.jbpm.JbpmConfiguration;
 26  
 import org.jbpm.JbpmContext;
 27  
 import org.jbpm.graph.def.ProcessDefinition;
 28  
 import org.jbpm.graph.exe.ProcessInstance;
 29  
 import org.jbpm.taskmgmt.exe.TaskInstance;
 30  
 
 31  
 /**
 32  
  * jBPM's implementation of Mule's generic BPMS interface.
 33  
  * This class should be set as the "bpms" property of the BPM Connector:
 34  
  *
 35  
  *   <connector name="jBpmConnector" className="org.mule.transport.bpm.ProcessConnector">
 36  
  *       <properties>
 37  
  *           <spring-property name="bpms">
 38  
  *              <ref local="jbpm" />
 39  
  *           </spring-property>
 40  
  *       </properties>
 41  
  *   </connector>
 42  
  *
 43  
  *   <bean id="jbpm" class="org.mule.transport.bpm.jbpm.Jbpm" destroy-method="destroy">
 44  
  *       <spring-property name="jbpmConfiguration">
 45  
  *           <ref local="jbpmConfig" />
 46  
  *       </spring-property>
 47  
  *   </bean>
 48  
  */
 49  
 public class Jbpm implements BPMS
 50  
 {
 51  2
     protected static final Log logger = LogFactory.getLog(Jbpm.class);
 52  
 
 53  6
     protected JbpmConfiguration jbpmConfiguration = null;
 54  
 
 55  
     /**
 56  
      * Indicates whether jBPM has been instantiated by the connector (false) or was passed 
 57  
      * in from somewhere else (true).
 58  
      */
 59  
     protected boolean containerManaged;
 60  
     
 61  
     // ///////////////////////////////////////////////////////////////////////////
 62  
     // Lifecycle methods
 63  
     // ///////////////////////////////////////////////////////////////////////////
 64  
 
 65  
     /**
 66  
      * Creates the Mule wrapper for jBPM using a default configuration. 
 67  
      */
 68  
     public Jbpm()
 69  
     {
 70  6
         this(JbpmConfiguration.getInstance());
 71  6
         containerManaged = false;
 72  6
     }
 73  
 
 74  
     /**
 75  
      * Creates the Mule BPM wrapper based on an already-initialized jBPM instance
 76  
      * 
 77  
      * @param jbpmConfiguration - the already-initialized jBPM instance
 78  
      */
 79  
     public Jbpm(JbpmConfiguration jbpmConfiguration)
 80  6
     {
 81  6
         setJbpmConfiguration(jbpmConfiguration);
 82  6
         containerManaged = true;
 83  6
     }
 84  
 
 85  
     public void destroy()
 86  
     {
 87  6
         if (!containerManaged && jbpmConfiguration != null)
 88  
         {
 89  6
             jbpmConfiguration.close();
 90  6
             jbpmConfiguration = null;
 91  
         }
 92  6
     }
 93  
 
 94  
     public void setMessageService(MessageService msgService)
 95  
     {
 96  6
         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
 97  
         try
 98  
         {
 99  6
             MuleMessageService.setMessageService(msgService);
 100  
         }
 101  
         finally
 102  
         {
 103  6
             jbpmContext.close();
 104  6
         }
 105  6
     }
 106  
     
 107  
     // ///////////////////////////////////////////////////////////////////////////
 108  
     // Process manipulation
 109  
     // ///////////////////////////////////////////////////////////////////////////
 110  
 
 111  
     /**
 112  
      * Start a new process.
 113  
      * 
 114  
      * @return the newly-created ProcessInstance
 115  
      */
 116  
     public synchronized Object startProcess(Object processType) throws Exception
 117  
     {
 118  0
         return startProcess(processType, /* transition */null, /* processVariables */null);
 119  
     }
 120  
 
 121  
     /**
 122  
      * Start a new process.
 123  
      * 
 124  
      * @return the newly-created ProcessInstance
 125  
      */
 126  
     public synchronized Object startProcess(Object processType, Object transition, Map processVariables) throws Exception
 127  
     {
 128  
         ProcessInstance processInstance;
 129  
 
 130  6
         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
 131  
         try
 132  
         {
 133  6
             ProcessDefinition processDefinition = jbpmContext.getGraphSession().findLatestProcessDefinition(
 134  
                 (String) processType);
 135  6
             if (processDefinition == null)
 136  
             {
 137  0
                 throw new IllegalArgumentException("No process definition found for process " + processType);
 138  
             }
 139  
 
 140  6
             processInstance = new ProcessInstance(processDefinition);
 141  
 
 142  
             // Set any process variables.
 143  6
             if (processVariables != null && !processVariables.isEmpty())
 144  
             {
 145  6
                 processInstance.getContextInstance().addVariables(processVariables);
 146  
             }
 147  6
             processInstance.getContextInstance().addVariables(processVariables);
 148  
 
 149  
             // Leave the start state.
 150  6
             processInstance.signal();
 151  
 
 152  6
             jbpmContext.save(processInstance);
 153  
 
 154  6
             return processInstance;
 155  
         }
 156  0
         catch (Exception e)
 157  
         {
 158  0
             jbpmContext.setRollbackOnly();
 159  0
             throw e;
 160  
         }
 161  
         finally
 162  
         {
 163  6
             jbpmContext.close();
 164  
         }
 165  
     }
 166  
 
 167  
     /**
 168  
      * Advance a process instance one step.
 169  
      * 
 170  
      * @return the updated ProcessInstance
 171  
      */
 172  
     public synchronized Object advanceProcess(Object processId) throws Exception
 173  
     {
 174  0
         return advanceProcess(processId, /* transition */null, /* processVariables */null);
 175  
     }
 176  
 
 177  
     /**
 178  
      * Advance a process instance one step.
 179  
      * 
 180  
      * @return the updated ProcessInstance
 181  
      */
 182  
     public synchronized Object advanceProcess(Object processId, Object transition, Map processVariables)
 183  
         throws Exception
 184  
     {
 185  
         ProcessInstance processInstance;
 186  
 
 187  6
         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
 188  
         try
 189  
         {
 190  
             // Look up the process instance from the database.
 191  6
             processInstance = jbpmContext.getGraphSession()
 192  
                 .loadProcessInstance(NumberUtils.toLong(processId));
 193  
 
 194  6
             if (processInstance.hasEnded())
 195  
             {
 196  0
                 throw new IllegalStateException(
 197  
                     "Process cannot be advanced because it has already terminated, processId = " + processId);
 198  
             }
 199  
 
 200  
             // Set any process variables.
 201  
             // Note: addVariables() will replace the old value of a variable if it
 202  
             // already exists.
 203  6
             if (processVariables != null && !processVariables.isEmpty())
 204  
             {
 205  6
                 processInstance.getContextInstance().addVariables(processVariables);
 206  
             }
 207  
 
 208  
             // Advance the workflow.
 209  6
             if (transition != null)
 210  
             {
 211  0
                 processInstance.signal((String) transition);
 212  
             }
 213  
             else
 214  
             {
 215  6
                 processInstance.signal();
 216  
             }
 217  
 
 218  
             // Save the process state back to the database.
 219  6
             jbpmContext.save(processInstance);
 220  
 
 221  6
             return processInstance;
 222  
         }
 223  0
         catch (Exception e)
 224  
         {
 225  0
             jbpmContext.setRollbackOnly();
 226  0
             throw e;
 227  
         }
 228  
         finally
 229  
         {
 230  6
             jbpmContext.close();
 231  
         }
 232  
     }
 233  
 
 234  
     /**
 235  
      * Update the variables for a process instance.
 236  
      * 
 237  
      * @return the updated ProcessInstance
 238  
      */
 239  
     public synchronized Object updateProcess(Object processId, Map processVariables) throws Exception
 240  
     {
 241  
         ProcessInstance processInstance;
 242  
 
 243  0
         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
 244  
         try
 245  
         {
 246  
             // Look up the process instance from the database.
 247  0
             processInstance = jbpmContext.getGraphSession()
 248  
                 .loadProcessInstance(NumberUtils.toLong(processId));
 249  
 
 250  
             // Set any process variables.
 251  
             // Note: addVariables() will replace the old value of a variable if it
 252  
             // already exists.
 253  0
             if (processVariables != null && !processVariables.isEmpty())
 254  
             {
 255  0
                 processInstance.getContextInstance().addVariables(processVariables);
 256  
             }
 257  
 
 258  
             // Save the process state back to the database.
 259  0
             jbpmContext.save(processInstance);
 260  
 
 261  0
             return processInstance;
 262  
         }
 263  0
         catch (Exception e)
 264  
         {
 265  0
             jbpmContext.setRollbackOnly();
 266  0
             throw e;
 267  
         }
 268  
         finally
 269  
         {
 270  0
             jbpmContext.close();
 271  
         }
 272  
     }
 273  
 
 274  
     /**
 275  
      * Delete a process instance.
 276  
      */
 277  
     public synchronized void abortProcess(Object processId) throws Exception
 278  
     {
 279  0
         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
 280  
         try
 281  
         {
 282  0
             jbpmContext.getGraphSession().deleteProcessInstance(NumberUtils.toLong(processId));
 283  
         }
 284  0
         catch (Exception e)
 285  
         {
 286  0
             jbpmContext.setRollbackOnly();
 287  0
             throw e;
 288  
         }
 289  
         finally
 290  
         {
 291  0
             jbpmContext.close();
 292  0
         }
 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  16
         return new Long(((ProcessInstance) process).getId());
 307  
     }
 308  
 
 309  
     // By default the process is lazily-initialized so we need to open a new session to the
 310  
     // database before calling process.getRootToken().getNode().getName()
 311  
     public Object getState(Object process) throws Exception
 312  
     {
 313  6
         ProcessInstance processInstance = (ProcessInstance) process;
 314  
 
 315  6
         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
 316  
         try
 317  
         {
 318  
             // Look up the process instance from the database.
 319  6
             processInstance = jbpmContext.getGraphSession()
 320  
                 .loadProcessInstance(processInstance.getId());
 321  6
             return processInstance.getRootToken().getNode().getName();
 322  
         }
 323  
         finally
 324  
         {
 325  6
             jbpmContext.close();
 326  
         }
 327  
     }
 328  
 
 329  
     public boolean hasEnded(Object process) throws Exception
 330  
     {
 331  6
         return ((ProcessInstance) process).hasEnded();
 332  
     }
 333  
 
 334  
     /**
 335  
      * Look up an already-running process instance.
 336  
      * 
 337  
      * @return the ProcessInstance
 338  
      */
 339  
     public Object lookupProcess(Object processId) throws Exception
 340  
     {
 341  
         ProcessInstance processInstance;
 342  
 
 343  0
         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
 344  
         try
 345  
         {
 346  
             // Look up the process instance from the database.
 347  0
             processInstance = jbpmContext.getGraphSession()
 348  
                 .loadProcessInstance(NumberUtils.toLong(processId));
 349  0
             return processInstance;
 350  
         }
 351  
         finally
 352  
         {
 353  0
             jbpmContext.close();
 354  
         }
 355  
     }
 356  
 
 357  
     // ///////////////////////////////////////////////////////////////////////////
 358  
     // Miscellaneous
 359  
     // ///////////////////////////////////////////////////////////////////////////
 360  
 
 361  
     /**
 362  
      * Deploy a new process definition.
 363  
      */
 364  
     public void deployProcess(String processDefinitionFile) throws IOException
 365  
     {
 366  6
         deployProcessFromStream(IOUtils.getResourceAsStream(processDefinitionFile, getClass()));
 367  6
     }
 368  
 
 369  
     public void deployProcessFromStream(InputStream processDefinition)
 370  
         throws IOException
 371  
     {
 372  6
         deployProcess(ProcessDefinition.parseXmlInputStream(processDefinition));
 373  6
     }
 374  
 
 375  
     private void deployProcess(ProcessDefinition processDefinition)
 376  
     {
 377  6
         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
 378  
         try
 379  
         {
 380  6
             jbpmContext.deployProcessDefinition(processDefinition);
 381  
         }
 382  
         finally
 383  
         {
 384  6
             jbpmContext.close();
 385  6
         }
 386  6
     }
 387  
 
 388  
     public List/* <TaskInstance> */loadTasks(ProcessInstance process)
 389  
     {
 390  
         List/* <TaskInstance> */taskInstances;
 391  
 
 392  0
         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
 393  
         try
 394  
         {
 395  0
             taskInstances = jbpmContext.getTaskMgmtSession().findTaskInstancesByToken(
 396  
                 process.getRootToken().getId());
 397  0
             return taskInstances;
 398  
         }
 399  
         finally
 400  
         {
 401  0
             jbpmContext.close();
 402  
         }
 403  
     }
 404  
 
 405  
     public synchronized void completeTask(TaskInstance task)
 406  
     {
 407  0
         completeTask(task, /* transition */null);
 408  0
     }
 409  
 
 410  
     public synchronized void completeTask(TaskInstance task, String transition)
 411  
     {
 412  0
         JbpmContext jbpmContext = jbpmConfiguration.createJbpmContext();
 413  
         try
 414  
         {
 415  0
             task = jbpmContext.getTaskMgmtSession().loadTaskInstance(task.getId());
 416  0
             if (transition != null)
 417  
             {
 418  0
                 task.end(transition);
 419  
             }
 420  
             else
 421  
             {
 422  0
                 task.end();
 423  
             }
 424  
         }
 425  
         finally
 426  
         {
 427  0
             jbpmContext.close();
 428  0
         }
 429  0
     }
 430  
 
 431  
     // ///////////////////////////////////////////////////////////////////////////
 432  
     // Getters and setters
 433  
     // ///////////////////////////////////////////////////////////////////////////
 434  
 
 435  
     public JbpmConfiguration getJbpmConfiguration()
 436  
     {
 437  0
         return jbpmConfiguration;
 438  
     }
 439  
 
 440  
     public void setJbpmConfiguration(JbpmConfiguration jbpmConfiguration)
 441  
     {
 442  12
         this.jbpmConfiguration = jbpmConfiguration;
 443  12
     }
 444  
 }