All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jadex.bpmn.runtime.handler.SubProcessActivityHandler Maven / Gradle / Ivy

Go to download

The Jadex BPMN kernel provides a workflow kernel for the standardized business process modeling notation. The kernel relies on annotated BPMN diagrams, which include detailed execution information.

There is a newer version: 4.0.267
Show newest version
package jadex.bpmn.runtime.handler;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import jadex.bpmn.model.MActivity;
import jadex.bpmn.model.MBpmnModel;
import jadex.bpmn.model.MDataEdge;
import jadex.bpmn.model.MParameter;
import jadex.bpmn.model.MSubProcess;
import jadex.bpmn.runtime.IActivityHandler;
import jadex.bpmn.runtime.ProcessThread;
import jadex.bpmn.runtime.ProcessThreadValueFetcher;
import jadex.bridge.ClassInfo;
import jadex.bridge.ComponentTerminatedException;
import jadex.bridge.IComponentIdentifier;
import jadex.bridge.IInternalAccess;
import jadex.bridge.component.IExecutionFeature;
import jadex.bridge.service.RequiredServiceInfo;
import jadex.bridge.service.search.SServiceProvider;
import jadex.bridge.service.types.cms.CreationInfo;
import jadex.bridge.service.types.cms.IComponentManagementService;
import jadex.bridge.service.types.cms.IComponentManagementService.CMSIntermediateResultEvent;
import jadex.bridge.service.types.cms.IComponentManagementService.CMSStatusEvent;
import jadex.commons.IResultCommand;
import jadex.commons.IValueFetcher;
import jadex.commons.SReflect;
import jadex.commons.future.IIntermediateResultListener;
import jadex.javaparser.IParsedExpression;
import jadex.javaparser.SJavaParser;

/**
 *  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 IInternalAccess instance, final ProcessThread thread)
	{
//		System.out.println(instance.getComponentIdentifier().getLocalName()+": sub "+activity);

		MSubProcess	proc	= (MSubProcess)activity;
		final List start = proc.getStartActivities();
		String tmpfile = (String)thread.getPropertyValue("file");
		if(tmpfile == null)
		{
			tmpfile = (String)thread.getPropertyValue("filename");
		}
		final String	file	= tmpfile;
	
		// Internal subprocess (when no file is given and has start activities).
		// 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()))
			{
				final String itername = proc.getPropertyValue(MSubProcess.MULTIINSTANCE_ITERATOR).getValue();
				Object val = thread.getParameterValue(itername);
				final Iterator it = SReflect.getIterator(val);
		
//				System.out.println("parallel: "+thread.getInstance().getComponentIdentifier().getLocalName()+" "+thread.getId()+" "+activity+" "+it.hasNext()+" "+val);
				
				// If empty parallel activity (i.e. no items at all) continue process.
				if(!it.hasNext())
				{
					wait = false;
				}
				else
				{
					while(it.hasNext())
					{
						Object	value	= it.next();
						for(int i=0; i it = SReflect.getIterator(val);
				// If empty looping activity (i.e. no items at all) continue process.
				
				IResultCommand cmd = new IResultCommand()
				{
					public Boolean execute(Void args)
					{
						Boolean ret = it.hasNext()? Boolean.TRUE: Boolean.FALSE;
						if(it.hasNext())
						{
							Object elem = it.next();
							for(MActivity st: start)
							{
								ProcessThread subthread = new ProcessThread(st, thread, instance, false);
								thread.addThread(subthread);
								subthread.setOrCreateParameterValue(itername, elem); // Hack!!! parameter not declared?
							}
						}
						return ret;
					}
				};
				
				// After all subthreads have finished set wait to false and continue main
				if(!cmd.execute(null).booleanValue())
				{
					wait = false;
				}
				else
				{
					thread.setLoopCommand(cmd);
				}
			}
			// just simple process without multi property
			else
			{
				for(int i=0; i handlers = activity.getEventHandlers();
				for(int i=0; timer==null && handlers!=null && i0)
		{
			// 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; i0)
				info.setArguments(args);
			
			IComponentIdentifier	parent	= thread.hasPropertyValue("parent")
				? (IComponentIdentifier)thread.getPropertyValue("parent")
				: instance.getComponentIdentifier();
			if(info.getParent()==null && parent!=null)
				info.setParent(parent);
			
			String[] imps = instance.getModel().getAllImports();
			if(info.getImports()==null && imps!=null)
				info.setImports(imps);
				
//					System.out.println("parent is: "+parent.getAddresses());	

			cms.createComponent(info, null, file)
				.addResultListener(instance.getComponentFeature(IExecutionFeature.class).createResultListener(new IIntermediateResultListener()
			{
				protected SubprocessResultHandler handler = new SubprocessResultHandler(thread, activity);	
					
				public void intermediateResultAvailable(CMSStatusEvent cse)
				{
					if(cse instanceof CMSIntermediateResultEvent)
					{
						String	param	= ((CMSIntermediateResultEvent)cse).getName();
						Object	value	= ((CMSIntermediateResultEvent)cse).getValue();
						
						if(activity.getParameters()!=null && activity.getParameters().get(param)!=null)
						{
							String	dir	= activity.getParameters().get(param).getDirection();
							if(MParameter.DIRECTION_INOUT.equals(dir) || MParameter.DIRECTION_OUT.equals(dir))
							{
								thread.setParameterValue(param, value);
							}
						}
						
						// todo: need to distinguish between collection and normal parameters
						handler.handleProcessResult(param, null, value);
					}
				}
				
				public void finished()
				{
//							System.out.println("end0: "+instance.getComponentIdentifier()+" "+file+" "+thread.getParameterValue("$results"));
					handler.updateParameters(thread, activity);
					
					thread.setNonWaiting();
					getBpmnFeature(instance).step(activity, instance, thread, null);
				}
				
				public void resultAvailable(Collection cses)
				{
					for(CMSStatusEvent cse: cses)
					{
						intermediateResultAvailable(cse);
					}
					finished();
				}
				
				public void exceptionOccurred(final Exception exception)
				{
					// Hack!!! Ignore exception, when component already terminated.
					if(!(exception instanceof ComponentTerminatedException)
						|| !instance.getComponentIdentifier().equals(((ComponentTerminatedException)exception).getComponentIdentifier()))
					{
//								System.out.println("end2: "+instance.getComponentIdentifier()+" "+file+" "+exception);
//								exception.printStackTrace();
						thread.setNonWaiting();
						thread.setException(exception);
						getBpmnFeature(instance).step(activity, instance, thread, null);
					}
				}
				
				public String toString()
				{
					return "lis: "+instance.getComponentIdentifier()+" "+file;
				}
			}));
		}
		
		// Empty subprocess.
		else if((start==null || start.isEmpty()) && (file==null || file.length()==0))
		{
			// If no activity in sub process, step immediately. 
			getBpmnFeature(instance).step(activity, instance, thread, null);
		}
		
		// Inconsistent subprocess.
		else
		{
			throw new RuntimeException("External subprocess may not have inner activities: "+activity+", "+instance);
		}
	}

	
	public static class SubprocessResultHandler
	{
		protected ProcessThread thread;
		protected MActivity activity;
		
//		protected boolean finished = false;
//		protected int opencalls = 0;
		final List queue;

		/**
		 * 
		 */
		public SubprocessResultHandler(ProcessThread thread, MActivity activity)
		{
			this.thread = thread;
			this.activity = activity;
			this.queue = new ArrayList();
		}
		
		/**
		 * 
		 */
		public void handleProcessResult(String param, Object key, Object value)
		{
//			opencalls++;

			// Todo: event handlers should also react to internal subprocesses???
			List handlers = activity.getEventHandlers();
			
			MActivity handler = null;
			if(handlers!=null)
			{
				for(int i=0; i type = new ClassInfo(typename).getType(thread.getInstance().getClassLoader());
								if(SReflect.isSupertype(type, value.getClass()))
								{
									handler = act;
								}
							}
							else
							{
								handler = act;
							}
						}
					}
					else
					{
						String trig = null;
						if(act.hasProperty(MBpmnModel.SIGNAL_EVENT_TRIGGER))
						{
							trig = (String)thread.getPropertyValue(MBpmnModel.SIGNAL_EVENT_TRIGGER, act);
						}
						
						if(act.getActivityType().equals(MBpmnModel.EVENT_INTERMEDIATE_SIGNAL) &&
						   (trig == null || param.equals(trig)))
						{
							handler = act;
						}
					}
				}
			}		
	
			if(handler!=null)
			{
				final boolean isseq = handler.hasProperty(MActivity.ISSEQUENTIAL);
				
				// parent in seq mode is subproc thread to let it wait until all handler processing is done (hack?)
				ProcessThread newthread = new ProcessThread(handler, isseq? thread: thread.getParent(), thread.getInstance())
				{
					public void notifyFinished() 
					{
//						opencalls--;
						
						if(isseq)
						{
							queue.remove(this);
							ProcessThread next = queue.size()>0? queue.get(0): null;
							if(next!=null)
							{
								next.setWaiting(false);
							}
//							else if(opencalls==0 && finished)
//							{
////								if(fresultparam!=null)
////									context.setParameterValue(fresultparam, results);
//								ret.setResult(null);
//							}
						}
					}
				};
				thread.copy(newthread);
//				ProcessThread newthread	= thread.createCopy();
				
//				updateParameters(newthread, activity);
				
				if(isseq)
				{
					// Set waiting if not first thread
					if(queue.size()>0)
					{	
						newthread.setWaiting(true);
					}
					queue.add(newthread);
				}
				
				newthread.setActivity(handler);
				if(handler.hasParameter(MActivity.RETURNPARAM))
				{
					newthread.setParameterValue(MActivity.RETURNPARAM, value);
				}
				
				// add newthread on suprocess thread in case of sequential execution.
				// this will let the subprocess wait until all child processes have
				// been finished - is kind of a hack
				if(isseq)
				{
					thread.addThread(newthread);
				}
				else
				{
					thread.getParent().addThread(newthread);
				}
			}
		}
		
		/**
		 *  Update the parameter values after a step.
		 * @param activity
		 * @param thread
		 * @param instance
		 */
		protected static void updateParameters(ProcessThread thread, MActivity activity)
		{
			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