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

jadex.platform.service.execution.AsyncExecutionService Maven / Gradle / Ivy

package jadex.platform.service.execution;

import java.util.Map;

import jadex.bridge.IInternalAccess;
import jadex.bridge.component.impl.AbstractComponentFeature;
import jadex.bridge.service.BasicService;
import jadex.bridge.service.RequiredServiceInfo;
import jadex.bridge.service.search.SServiceProvider;
import jadex.bridge.service.types.execution.IExecutionService;
import jadex.bridge.service.types.threadpool.IThreadPoolService;
import jadex.commons.SUtil;
import jadex.commons.collection.SCollection;
import jadex.commons.concurrent.Executor;
import jadex.commons.concurrent.IExecutable;
import jadex.commons.future.CounterResultListener;
import jadex.commons.future.DelegationResultListener;
import jadex.commons.future.Future;
import jadex.commons.future.IFuture;
import jadex.commons.future.IResultListener;

/**
 *  The asynchronous executor service that executes all tasks in separate executors.
 */
public class AsyncExecutionService	extends BasicService implements IExecutionService
{
	/**
	 *  The possible states of the service.
	 */
	public enum State
	{
		CREATED, RUNNING, SHUTDOWN
	}
	
	//-------- attributes --------
	
	/** The threadpool. */
	protected IThreadPoolService threadpool;
	
	/** The currently waiting tasks (task->executor). */
	protected Map executors;
		
	/** The idle future. */
	protected Future idlefuture;
	
	/** The state. */
	protected State state;
	
	/** The component. */
	protected IInternalAccess component;
	
	/** The running (i.e. non-blocked) executors. */
	protected Map runningexes;
	
	//-------- constructors --------
	
	/**
	 *  Create a new asynchronous executor service. 
	 */
	public AsyncExecutionService(IInternalAccess component)//, int max)
	{
		this(component, null);
	}
	
	/**
	 *  Create a new asynchronous executor service. 
	 */
	public AsyncExecutionService(IInternalAccess component, Map properties)//, int max)
	{
		super(component.getComponentIdentifier(), IExecutionService.class, properties);

		this.component = component;
		this.executors	= SCollection.createHashMap();
		this.runningexes = SCollection.createHashMap();
		this.state	= State.CREATED;
	}

	//-------- methods --------
	
	/**
	 *  Execute a task in its own thread.
	 *  @param task The task to execute.
	 *  (called from arbitrary threads)
	 */
	public synchronized void execute(final IExecutable task)
	{	
		if(!customIsValid())
		{
			throw new RuntimeException("Not running. Cannot execute: "+task);
		}
		
		Executor exe = executors.get(task);

		if(exe==null)
		{
			exe = new Executor(threadpool, task)
			{
				// Hack!!! overwritten to know, when executor ends.
				public void run()
				{
					synchronized(AsyncExecutionService.this)
					{
//						System.err.println("non-idle: "+runningexes.keySet());
						runningexes.put(task, this);
					}
					
					try
					{
						super.run();
					}
					catch(Throwable e)
					{
						// Shouldn't happen. If it does, it will break simulation time.
						System.err.println("Uncatched exception in executable "+executable+": "+SUtil.getExceptionStacktrace(e));
					}
					
					Future idf = null;
					
					synchronized(AsyncExecutionService.this)
					{
						synchronized(this)
						{
							// Do not remove when a new executor has already been added for the task.
							// isRunning() refers to running state of executor!
							if(!this.isRunning() && executors!=null && executors.get(task)==this)	
							{
								if(executors!=null && this.getThreadCount()==0)
								{
									executors.remove(task);
								}
								runningexes.remove(task);
//									System.err.println("after task: "+state+", "+runningexes.keySet());
								
								// When no more executable threads, inform idle commands.				
								if(state==State.RUNNING && idlefuture!=null && runningexes.isEmpty())
								{
									idf = idlefuture;
									idlefuture = null;
//										System.err.println("idle");
								}
							}
							else if(executors!=null && executors.get(task)!=this && runningexes.get(task)==this)
							{
								runningexes.remove(task);								
							}
						}
					}
					
					if(idf!=null)
					{
						idf.setResult(null);
					}
				}

				// Hack!!! Skip shutdown of platform executor for "boot unstrapping" -> executor will finish after no more steps
				public IFuture shutdown()
				{
					if(task instanceof AbstractComponentFeature && ((AbstractComponentFeature)task).getComponent().getComponentIdentifier().equals(getServiceIdentifier().getProviderId()))
					{
						return IFuture.DONE;
					}
					else
					{
						return super.shutdown();
					}
				}
			};
			executors.put(task, exe);
		}
	
		if(state==State.RUNNING)
		{
			boolean	exec = exe.execute();
			if(exec)
			{
				runningexes.put(task, exe);
			}
		}
	}
	
	/**
	 *  Cancel a task. Triggers the task to
	 *  be not executed in future. 
	 *  @param task The task to execute.
	 *  @param listener The listener.
	 */
	public synchronized IFuture cancel(final IExecutable task)
	{
		// todo: repair me: problem is that method can interfere with execute?!
		final Future ret = new Future();
		
		if(!customIsValid())
		{
			throw new RuntimeException("Not running. Cannot cancel: "+task);
		}
		else
		{
			final Executor exe = (Executor)executors.get(task);
			if(exe!=null)
			{
				IResultListener lis = new IResultListener()
				{
					public void resultAvailable(Void result)
					{
						// todo: do not call listener with holding lock
						synchronized(AsyncExecutionService.this)
						{
							ret.setResult(result);
							if(executors!=null)	
							{
								executors.remove(task);
							}
						}
					}
	
					public void exceptionOccurred(Exception exception)
					{
						// todo: do not call future with holding lock
						synchronized(AsyncExecutionService.this)
						{
							ret.setException(exception);
							if(executors!=null)	
							{
								executors.remove(task);
							}
						}
					}
				};
				exe.shutdown().addResultListener(lis);
			}
			else
			{
				ret.setResult(null);
			}
		}
		
		return ret;
	}
	
	/**
	 *  Get the currently running tasks.
	 */
	public synchronized IExecutable[]	getRunningTasks()
	{
		return (IExecutable[])runningexes.keySet().toArray(new IExecutable[runningexes.size()]);
	}
	
	/**
	 *  Start the execution service.
	 *  Resumes all scheduled tasks. 
	 */
	public synchronized IFuture	startService()
	{
		final  Future ret = new Future();
		
		super.startService().addResultListener(new DelegationResultListener(ret)
		{
			public void customResultAvailable(Void result)
			{
				if(state!=State.CREATED)
				{
					ret.setException(new RuntimeException("Cannot init service in "+state));
				}
				else
				{
					SServiceProvider.getService(component, IThreadPoolService.class, RequiredServiceInfo.SCOPE_PLATFORM, false)
						.addResultListener(new IResultListener()
					{
						public void resultAvailable(IThreadPoolService result)
						{
							try
							{
								threadpool = result;
								state	= State.RUNNING;
								ret.setResult(null);
							}
							catch(RuntimeException e)
							{
								ret.setException(e);
							}
						}
						
						public void exceptionOccurred(Exception exception)
						{
							ret.setException(exception);
						}
					});
				}
			}
		});
		
		return ret;
	}

	/**
	 *  Shutdown the executor service.
	 *  // todo: make callable more than once
	 */
	public synchronized IFuture	shutdownService()
	{
		final Future ret	= new Future();
		
		super.shutdownService().addResultListener(new DelegationResultListener(ret)
		{
			public void customResultAvailable(Void result)
			{
				if(state==State.SHUTDOWN)
				{
					ret.setException((new RuntimeException("Already shutdowned.")));
				}
				else
				{
					state = State.SHUTDOWN;
					
					IExecutable[] keys = (IExecutable[])executors.keySet()
						.toArray(new IExecutable[executors.size()]);
					
					if(keys.length>0)
					{
						// One listener counts until all executors have shutdowned.
						final IResultListener lis = new CounterResultListener(keys.length, new DelegationResultListener(ret));
						for(int i=0; i getNextIdleFuture()
	{
		Future ret;
		if(state==State.SHUTDOWN)
		{
			ret = new Future(new RuntimeException("Shutdown"));
		}
		else
		{
			if(idlefuture==null)
				idlefuture = new Future();
			ret = idlefuture;
		}
		return ret;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy