newTaskInstance = createTask(newTaskDef, processInstance, foe);
newTaskInstance = createTask(newTaskDef, currentProcess, foe);
	private Map transitionTaskFromStack(ITaskInstance currentTask)			throws TransitionException, DefinitionNotFoundException {		if (log.isInfoEnabled()) {			log.info("transitionTask is initialising for TaskInstance "					+ currentTask);		}		if (currentTask.getState() == ITaskInstance.STATE_INITIALISING) {			// run the constructor			try {				doTaskConstruct(currentTask);			} catch (Exception e) {				String emsg = "Error during construction of Task "						+ currentTask;				log.error(emsg, e);				throw new TransitionException(emsg, e);			}		} else {			runTask(currentTask);		}		// check the state of the task now it has been run		if (currentTask.getState() != ITaskInstance.STATE_AWAITINGCOMPLETE) {			// task has some state other than "completed" so exit			if (log.isInfoEnabled()) {				log						.info("transitionTask - task will not be transitioned as it has a state of "								+ currentTask.getState()								+ " - GUID "								+ currentTask.getTaskInstanceId());			}			return new HashMap();		}		// do transition - get outbound routing, check for locks, etc		// make a note of any TaskDef that is SyncLocked by this TaskDef -		// SyncLocked tasks can be run once this task has completed		ITaskDefinition taskDef = currentTask.getTaskDefinition();		List createList = runRouting(taskDef, currentTask);		if (createList.size() == 0 && taskDef.getRoutingOut().size() > 0) {			// routing exists, but none ran.			try {				ITransaction t = stateFactory.beginTransaction();				currentTask.setState(ITaskInstance.STATE_ERRORROUTING);				stateFactory.saveObject(currentTask);				t.commit();			} catch (Exception e) {				log.error(e);				throw new TransitionException(e);			}			throw new TransitionException("Routing exists for TaskInstance "					+ currentTask + " but none ran!");		}		/*		 * we now have a list of tasks to create. Before we start creating them,		 * we need to LOCK the ProcessInstance from changes by other Engine		 * instances. As this can be a little costly (especially when plugged		 * into a DB states provider) there should probably be a config option		 * to specify whether multiple engines are in use to either		 * enable/disable this behaviour.		 */		Map createdTasks = new HashMap();		IProcessInstance processInstance = currentTask.getProcessInstance();		try {            stateFactory.acquireLock(processInstance,this);        } catch (LockException e) {            String emsg = "Failed to aquire an exclusive lock on the Process Instance";            log.error(emsg,e);            throw new TransitionException(emsg,e);        }		ITransaction t;		try {			t = stateFactory.beginTransaction();		} catch (Exception e) {			String emsg = "Failure to create states transaction before creating new tasks";			log.error(emsg, e);			throw new TransitionException(emsg, e);		}		IFOE foeSerial = null;		for (Iterator it = createList.iterator(); it.hasNext();) {			ITaskInstance newTaskInstance;			IRoutingDefinition routingDef = (IRoutingDefinition) it.next();			ITaskDefinition newTaskDef = routingDef.getDestinationTaskDefinition();			try {				IFOE foe;				if (routingDef.getParallel()) {					/*					 * a parallel routing always creates a new FOE					 */					foe = createFOE(processInstance);				} else {					/*					 * Serial routing always re-uses an existing FOE					 */					if (foeSerial == null) {						if (taskDef.isSynchronised()) {							/*							 * As we sync'd, there may be multiple FOEs that are							 * combining, so therefore we need to create a new							 * FOE for execution to continue down.							 */							foeSerial = createFOE(processInstance);						} else {							/*							 * use the FOE of the current task...							 */							foeSerial = currentTask.getFOE();						}					}					foe = foeSerial;				}				newTaskInstance = createTask(newTaskDef, processInstance, foe);			} catch (Exception e) {				// pokemon stylee... catch 'em all				String emsg = "Failed to create new task Instance for task definition "						+ newTaskDef;				log.error(emsg, e);				throw new TransitionException(emsg, e);			}			/*			 * createTask may return an existing task instance in the case of a			 * sync task that is being hit by multiple routings, so we check			 * before we add it to the list of unique tasks created			 */			if (!createdTasks.containsKey(newTaskInstance.getTaskInstanceId())) {				createdTasks.put(newTaskInstance.getTaskInstanceId(),						newTaskInstance);			}		}		/*		 * we need to see if there is an existing SyncTaskInstance that was		 * waiting for this task to complete This check is only necessary when		 * the route taken by the task removes its lock on the synctask, but		 * does not route toward the synctask (escape route)		 */		// get the list of sync tasks that this task can block		Map syncList = taskSync.getPotentialTaskLocks(taskDef);		// iterate over the processInstance's list of tasks, looking for a Sync		// Task that is blocked by the current task		for (Iterator it = currentTask.getProcessInstance().getTaskInstances()				.iterator(); it.hasNext();) {			ITaskInstance checkTask = (ITaskInstance) it.next();			if (syncList.containsKey(checkTask.getTaskDefinition().getId())) {				// sync task found, so add to the create list				if (!createdTasks.containsKey(checkTask.getTaskInstanceId())) {					if (log.isInfoEnabled()) {						log								.info("adding SyncTask "										+ checkTask										+ " that may now be runnable due to completion of taskInstance "										+ currentTask);					}					createdTasks.put(checkTask.getTaskInstanceId(), checkTask);				}			}		}		// remove completed task		try {			currentTask.setState(ITaskInstance.STATE_COMPLETE);			stateFactory.saveObject(currentTask);			stateFactory.deleteObject(currentTask);			t.commit();		} catch (Exception e) {			String emsg = "Failed to commit new tasks and finalise task completion";			log.error(emsg, e);			throw new TransitionException(emsg, e);		}		try {            // unlock processInstance            stateFactory.releaseLock(processInstance, this);        } catch (LockException e) {            String emsg = "Failed to release the exclusive lock on the Process Instance";			log.error(emsg, e);			throw new TransitionException(emsg, e);        }		return createdTasks;	}