/** * Delegate synchronization to agent. / public void invokeLater(final Runnable action) { // * Redirect to component instance. interpreter.invokeLater(action); * * <p>// Called from outside (e.g. workflow client) // when task is finished // Check if plan * should be set to ready (Hack!!!) // interpreter.invokeLater(new Runnable() // { // public void * run() // { // // The DefaultActivityHandler.step() may rethrow an exception that // // occurred * within task execution. // // It is catched an stored in the plan to be rethrown from the // // * BPMNPlanExecutor.executeStep() method. // // The plan must always be set to ready to transfer * the state // // of the process thread to the plan. // try // { // action.run(); // } // * catch(Throwable t) // { // state.setAttributeValue(rplan, * OAVBDIRuntimeModel.plan_has_exception, t); // } // state.setAttributeValue(rplan, * OAVBDIRuntimeModel.plan_has_processingstate, OAVBDIRuntimeModel.PLANPROCESSINGTATE_READY); // * //// String lane = getLane(getLastState()); //// if(isReady(null, lane)) //// { //// * state.setAttributeValue(rplan, OAVBDIRuntimeModel.plan_has_processingstate, * OAVBDIRuntimeModel.PLANPROCESSINGTATE_READY); //// } // } // }); } * * <p>/** Method that should be called, when an activity is finished and the following activity * should be scheduled. Can safely be called from external threads. * * @param activity The timing event activity. * @param instance The process instance. * @param thread The process thread. * @param event The event that has occurred, if any. */ public void notify(final MActivity activity, final ProcessThread thread, final Object event) { if (isExternalThread()) { getComponentAdapter() .invokeLater( new Runnable() { public void run() { if (isCurrentActivity(activity, thread)) { try { getStepHandler(activity) .step(activity, BpmnPlanBodyInstance.this, thread, event); } catch (Throwable t) { if (state.containsObject(rplan)) state.setAttributeValue(rplan, OAVBDIRuntimeModel.plan_has_exception, t); } thread.setNonWaiting(); if (state.containsObject(rplan)) { // System.out.println("Ready: "+activity+" "+thread); state.setAttributeValue( rplan, OAVBDIRuntimeModel.plan_has_processingstate, OAVBDIRuntimeModel.PLANPROCESSINGTATE_READY); } } else { System.out.println("Nop, due to outdated notify: " + thread + " " + activity); } } }); } else { if (isCurrentActivity(activity, thread)) { try { getStepHandler(activity).step(activity, BpmnPlanBodyInstance.this, thread, event); } catch (Throwable t) { if (state.containsObject(rplan)) state.setAttributeValue(rplan, OAVBDIRuntimeModel.plan_has_exception, t); } thread.setNonWaiting(); if (state.containsObject(rplan)) { // System.out.println("Ready: "+activity+" "+thread); state.setAttributeValue( rplan, OAVBDIRuntimeModel.plan_has_processingstate, OAVBDIRuntimeModel.PLANPROCESSINGTATE_READY); } } else { System.out.println("Nop, due to outdated notify: " + thread + " " + activity); } } }
/** * Make a process step, i.e. find the next edge or activity for a just executed thread. * * @param activity The activity to execute. * @param instance The process instance. * @param thread The process thread. */ public void step( MActivity activity, BpmnInterpreter instance, ProcessThread thread, Object event) { // System.out.println(instance.getComponentIdentifier().getLocalName()+": step "+activity+", // data "+thread.getData()); // Hack!!! Should be in interpreter/thread? thread.updateParametersAfterStep(activity, instance); MNamedIdElement next = null; ThreadContext remove = null; // Context that needs to be removed (if any). Exception ex = thread.getException(); // Store event (if any). if (event != null) { thread.setParameterValue("$event", event); // System.out.println("Event: "+activity+" "+thread+" "+event); } // Timer occurred flow if (AbstractEventIntermediateTimerActivityHandler.TIMER_EVENT.equals(event)) { // Cancel subflows. remove = thread.getThreadContext().getSubcontext(thread); // Continue with timer edge. List outedges = activity.getOutgoingSequenceEdges(); if (outedges != null && outedges.size() == 1) { next = (MSequenceEdge) outedges.get(0); } else if (outedges != null && outedges.size() > 1) { throw new RuntimeException("Cannot determine outgoing edge: " + activity); } } // Find next element and context(s) to be removed. else { boolean outside = false; ThreadContext context = thread.getThreadContext(); while (next == null && !outside) { // Normal flow if (ex == null) { List outgoing = activity.getOutgoingSequenceEdges(); if (outgoing != null && outgoing.size() == 1) { next = (MSequenceEdge) outgoing.get(0); } else if (outgoing != null && outgoing.size() > 1) { throw new UnsupportedOperationException( "Activity has more than one one outgoing edge. Please overridge step() for disambiguation: " + activity); } // else no outgoing edge -> check parent context, if any. } // Exception flow. else { List handlers = activity.getEventHandlers(); for (int i = 0; handlers != null && next == null && i < handlers.size(); i++) { MActivity handler = (MActivity) handlers.get(i); if (handler.getActivityType().equals("EventIntermediateError")) { // Todo: match exception types. // Class clazz = handler.getName()!=null ? SReflect.findClass0(clname, imports, // classloader); next = handler; } } } outside = context.getParent() == null; if (next == null && !outside) { // When last thread or exception, mark current context for removal. if (context.getThreads().size() == 1 || ex != null) { activity = (MActivity) context.getModelElement(); remove = context; context = context.getParent(); // Cancel subprocess handlers. if (activity instanceof MSubProcess) { List handlers = activity.getEventHandlers(); for (int i = 0; handlers != null && i < handlers.size(); i++) { MActivity handler = (MActivity) handlers.get(i); instance .getActivityHandler(handler) .cancel(handler, instance, remove.getInitiator()); } } } // If more threads are available in current context just exit loop. else if (context.getThreads().size() > 1) { outside = true; } } } } // Remove inner context(s), if any. if (remove != null) { thread = remove.getInitiator(); thread.setNonWaiting(); // Todo: Callbacks for aborted threads (to abort external activities) thread.getThreadContext().removeSubcontext(remove); } if (next != null) { // Todo: store exception as parameter!? if (ex != null) thread.setException(null); } else if (ex != null) { if (ex instanceof RuntimeException) throw (RuntimeException) ex; else throw new RuntimeException("Unhandled exception in process: " + activity, ex); } // Perform step settings, i.e. set next edge/activity or remove thread. if (next instanceof MSequenceEdge) { thread.setLastEdge((MSequenceEdge) next); } else if (next instanceof MActivity) { thread.setActivity((MActivity) next); } else if (next == null) { thread.getThreadContext().removeThread(thread); } else { throw new UnsupportedOperationException("Unknown outgoing element type: " + next); } }