/** * Update the waiting threads according to the wakeup reason (dispatched element). The * corresponding waiting activity/thread is notified. */ public void updateWaitingThreads() { if (waittimes != null) { // IClockService clock = // (IClockService)interpreter.getServiceProvider().getService(IClockService.class); IClockService clock = interpreter.getClockService(); for (Iterator it = waittimes.keySet().iterator(); it.hasNext(); ) { ProcessThread thread = (ProcessThread) it.next(); if (((Number) waittimes.get(thread)).longValue() <= clock.getTime()) { it.remove(); assert thread.isWaiting(); BpmnPlanBodyInstance.this.notify( thread.getActivity(), thread, AbstractEventIntermediateTimerActivityHandler.TIMER_EVENT); } } } Object dispelem = state.getAttributeValue(rplan, OAVBDIRuntimeModel.plan_has_dispatchedelement); // System.out.println("dispatched: "+dispelem); if (dispelem != null) { for (Iterator it = context.getAllThreads().iterator(); it.hasNext(); ) { ProcessThread thread = (ProcessThread) it.next(); try { if (thread.isWaiting() && thread.getWaitFilter().filter(dispelem)) { BpmnPlanBodyInstance.this.notify(thread.getActivity(), thread, getFlyweight(dispelem)); } } catch (Exception e) { // just catch filter exceptions. } } } }
/** * Get the current timeout of the process, i.e. the remaining time of the closest due intermediate * timer event. * * @return The current timeout or -1 for no timeout. */ public long getTimeout() { long mindur = -1; if (waittimes != null) { String pool = getPool(getLastState()); if (!POOL_UNDEFINED.equals(pool)) { IClockService clock = interpreter.getClockService(); // IClockService clock = // (IClockService)interpreter.getServiceProvider().getService(IClockService.class); for (Iterator it = waittimes.keySet().iterator(); it.hasNext(); ) { ProcessThread thread = (ProcessThread) it.next(); if (thread.belongsTo(pool, null)) { long time = Math.max(((Number) waittimes.get(thread)).longValue() - clock.getTime(), 0); mindur = mindur == -1 ? time : time < mindur ? time : mindur; } } } } return mindur; }
/** * 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); } } }
/** Must be called on process execution thread! Gets infos about the current threads. */ protected ProcessThreadInfo[] getThreadInfos() { List ret = null; ThreadContext tc = instance.getThreadContext(); Set threads = tc.getAllThreads(); if (threads != null) { ret = new ArrayList(); for (Iterator it = threads.iterator(); it.hasNext(); ) { ProcessThread pt = (ProcessThread) it.next(); ret.add( new ProcessThreadInfo( pt.getId(), pt.getActivity(), // pt.getLastEdge(), pt.getException(), pt.isWaiting(), pt.getData() == null ? new HashMap() : new HashMap(pt.getData()))); } } return (ProcessThreadInfo[]) ret.toArray(new ProcessThreadInfo[ret.size()]); }
/** * Get the cumulated wait abstraction for all threads. * * @return The wait abstraction. */ public Object getWaitAbstraction() { Object ret = null; String pool = getPool(getLastState()); if (!POOL_UNDEFINED.equals(pool)) { ret = getState().createObject(OAVBDIRuntimeModel.waitabstraction_type); boolean empty = true; for (Iterator it = context.getAllThreads().iterator(); it.hasNext(); ) { ProcessThread pt = (ProcessThread) it.next(); if (pt.isWaiting() && pt.belongsTo(pool, null)) { MActivity act = pt.getActivity(); if (MBpmnModel.EVENT_INTERMEDIATE_MESSAGE.equals(act.getActivityType())) { String type = (String) pt.getWaitInfo(); if (type == null) throw new RuntimeException("Message type not specified: " + type); SFlyweightFunctionality.addMessageEvent(ret, type, state, rcapa); empty = false; } else if (MBpmnModel.EVENT_INTERMEDIATE_SIGNAL.equals(act.getActivityType())) { String type = (String) pt.getWaitInfo(); if (type == null) throw new RuntimeException("Internal event type not specified: " + type); SFlyweightFunctionality.addInternalEvent(ret, type, state, rcapa); empty = false; } else if (MBpmnModel.EVENT_INTERMEDIATE_RULE.equals(act.getActivityType())) { String type = (String) pt.getWaitInfo(); if (type == null) throw new RuntimeException("Rule type not specified: " + type); SFlyweightFunctionality.addCondition(ret, type, state, rcapa); empty = false; } else if (MBpmnModel.EVENT_INTERMEDIATE_MULTIPLE.equals(act.getActivityType())) { List edges = pt.getActivity().getOutgoingSequenceEdges(); Object[] was = (Object[]) pt.getWaitInfo(); for (int i = 0; i < edges.size(); i++) { MSequenceEdge edge = (MSequenceEdge) edges.get(i); MActivity nextact = edge.getTarget(); if (MBpmnModel.EVENT_INTERMEDIATE_MESSAGE.equals(nextact.getActivityType())) { String type = (String) was[i]; if (type == null) throw new RuntimeException("Message type not specified: " + type); SFlyweightFunctionality.addMessageEvent(ret, type, state, rcapa); empty = false; } else if (MBpmnModel.EVENT_INTERMEDIATE_SIGNAL.equals(nextact.getActivityType())) { String type = (String) was[i]; if (type == null) throw new RuntimeException("Internal event type not specified: " + type); SFlyweightFunctionality.addInternalEvent(ret, type, state, rcapa); empty = false; } else if (MBpmnModel.EVENT_INTERMEDIATE_RULE.equals(nextact.getActivityType())) { String type = (String) was[i]; if (type == null) throw new RuntimeException("Rule type not specified: " + type); SFlyweightFunctionality.addCondition(ret, type, state, rcapa); empty = false; } else if (MBpmnModel.EVENT_INTERMEDIATE_TIMER.equals(nextact.getActivityType())) { // nothing to do with waitqueue. } else { throw new RuntimeException("Unknown event: " + nextact); } } } // todo: condition wait // todo: time wait?! } } if (empty) { state.dropObject(ret); ret = null; } } return ret; }
/** * 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); } }