package jadex.bpmn.runtime.handler; import jadex.bpmn.model.MActivity; import jadex.bpmn.model.MParameter; import jadex.bpmn.model.MSubProcess; import jadex.bpmn.runtime.BpmnInterpreter; import jadex.bpmn.runtime.ProcessThread; import jadex.bpmn.runtime.ProcessThreadValueFetcher; import jadex.bpmn.runtime.ThreadContext; import jadex.bridge.CreationInfo; import jadex.bridge.IComponentManagementService; import jadex.commons.IFuture; import jadex.commons.SReflect; import jadex.commons.concurrent.DefaultResultListener; import jadex.commons.concurrent.IResultListener; import jadex.commons.service.SServiceProvider; import jadex.javaparser.IValueFetcher; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; /** * Handler for (embedded) sub processes. */ public class SubProcessActivityHandler extends DefaultActivityHandler { /** * Execute an activity. * @param activity The activity to execute. * @param instance The process instance. * @param thread The process thread. */ public void execute(final MActivity activity, final BpmnInterpreter instance, final ProcessThread thread) { // System.out.println(instance.getComponentIdentifier().getLocalName()+": sub "+activity); MSubProcess proc = (MSubProcess) activity; List start = proc.getStartActivities(); final String file = (String)thread.getPropertyValue("file"); // Internal subprocess. // Todo: cancel timer on normal/exception exit if(start!=null && file==null) { // thread.setWaitingState(ProcessThread.WAITING_FOR_SUBPROCESS); // thread.setWaiting(true); boolean wait = true; if(MSubProcess.SUBPROCESSTYPE_PARALLEL.equals(proc.getSubprocessType())) { // Todo: use subcontext? Iterator it = SReflect.getIterator(thread.getPropertyValue("items")); // If empty parallel activity (i.e. no items at all) continue process. if(!it.hasNext()) { wait = false; } else { ThreadContext subcontext = new ThreadContext(proc, thread); thread.getThreadContext().addSubcontext(subcontext); while(it.hasNext()) { Object value = it.next(); for(int i=0; i<start.size(); i++) { ProcessThread subthread = new ProcessThread((MActivity)start.get(i), subcontext, instance); subthread.setParameterValue("item", value); // Hack!!! parameter not declared? subcontext.addThread(subthread); } } } } else if(MSubProcess.SUBPROCESSTYPE_LOOPING.equals(proc.getSubprocessType())) { throw new UnsupportedOperationException("Looping subprocess not yet supported: "+activity+", "+instance); } else { ThreadContext subcontext = new ThreadContext(proc, thread); thread.getThreadContext().addSubcontext(subcontext); for(int i=0; i<start.size(); i++) { ProcessThread subthread = new ProcessThread((MActivity)start.get(i), subcontext, instance); subcontext.addThread(subthread); } } if(wait) { // todo: support more than one timer? MActivity timer = null; List handlers = activity.getEventHandlers(); for(int i=0; timer==null && handlers!=null && i<handlers.size(); i++) { MActivity handler = (MActivity)handlers.get(i); if(handler.getActivityType().equals("EventIntermediateTimer")) { timer = handler; } } if(timer!=null) { instance.getActivityHandler(timer).execute(timer, instance, thread); } else { thread.setWaiting(true); } } else { thread.setNonWaiting(); instance.getStepHandler(activity).step(activity, instance, thread, null); } } // External subprocess else if((start==null || start.isEmpty()) && file!=null) { // Extract arguments from in/inout parameters. final Map args = new HashMap(); List params = activity.getParameters(new String[]{MParameter.DIRECTION_IN, MParameter.DIRECTION_INOUT}); if(params!=null && !params.isEmpty()) { // args = new HashMap(); for(int i=0; i<params.size(); i++) { MParameter param = (MParameter)params.get(i); args.put(param.getName(), thread.getParameterValue(param.getName())); } } // System.out.println("start: "+instance.getComponentIdentifier()+" "+file); thread.setWaiting(true); SServiceProvider.getService(instance.getServiceProvider(), IComponentManagementService.class) .addResultListener(instance.createResultListener(new DefaultResultListener() { public void resultAvailable(Object source, Object result) { IComponentManagementService cms = (IComponentManagementService)result; IFuture ret = cms.createComponent(null, file, new CreationInfo(null, args, instance.getComponentIdentifier(), false, instance.getModelElement().getAllImports()), new IResultListener() { public void resultAvailable(Object source, final Object result) { instance.getComponentAdapter().invokeLater(new Runnable() { public void run() { // System.out.println("end1: "+instance.getComponentIdentifier()+" "+file); // Store results in out parameters. Map results = (Map)result; thread.setParameterValue("$results", results); // Hack??? List params = activity.getParameters(new String[]{MParameter.DIRECTION_OUT, MParameter.DIRECTION_INOUT}); if(params!=null && !params.isEmpty()) { IValueFetcher fetcher =null; for(int i=0; i<params.size(); i++) { MParameter param = (MParameter)params.get(i); if(param.getInitialValue()!=null) { if(fetcher==null) fetcher = new ProcessThreadValueFetcher(thread, false, instance.getValueFetcher()); try { thread.setParameterValue(param.getName(), param.getInitialValue().getValue(fetcher)); } catch(RuntimeException e) { throw new RuntimeException("Error evaluating parameter value: "+instance+", "+activity+", "+param.getName()+", "+param.getInitialValue(), e); } } else if(results.containsKey(param.getName())) { thread.setParameterValue(param.getName(), results.get(param.getName())); } } } thread.setNonWaiting(); instance.getStepHandler(activity).step(activity, instance, thread, null); } }); } public void exceptionOccurred(Object source, final Exception exception) { instance.getComponentAdapter().invokeLater(new Runnable() { public void run() { // System.out.println("end2: "+instance.getComponentIdentifier()+" "+file+" "+exception); thread.setNonWaiting(); thread.setException(exception); instance.getStepHandler(activity).step(activity, instance, thread, null); } }); } public String toString() { return "lis: "+instance.getComponentIdentifier()+" "+file; } }); IResultListener lis = new IResultListener() { public void resultAvailable(Object source, Object result) { // todo: save component id } public void exceptionOccurred(Object source, Exception exception) { } }; ret.addResultListener(lis); } })); } // Empty subprocess. else if((start==null || start.isEmpty()) && file==null) { // If no activity in sub process, step immediately. instance.getStepHandler(activity).step(activity, instance, thread, null); } // Inconsistent subprocess. else { throw new RuntimeException("External subprocess may not have inner activities: "+activity+", "+instance); } } }