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

jadex.micro.mandelbrot.generate.GenerateService Maven / Gradle / Ivy

The newest version!
package jadex.micro.mandelbrot.generate;

import java.awt.Rectangle;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import jadex.common.ClassInfo;
import jadex.core.IComponent;
import jadex.execution.IExecutionFeature;
import jadex.future.Future;
import jadex.future.IFuture;
import jadex.future.IIntermediateFuture;
import jadex.future.IntermediateFuture;
import jadex.micro.mandelbrot.calculate.ICalculateService;
import jadex.micro.mandelbrot.display.IDisplayService;
import jadex.micro.mandelbrot.model.AreaData;
import jadex.micro.mandelbrot.model.IFractalAlgorithm;
import jadex.micro.mandelbrot.model.PartDataChunk;
import jadex.micro.taskdistributor.IIntermediateTaskDistributor;
import jadex.model.annotation.OnStart;
import jadex.providedservice.IService;
import jadex.providedservice.annotation.Service;
import jadex.providedservice.annotation.ServiceComponent;
import jadex.providedservice.impl.search.ServiceNotFoundException;
import jadex.providedservice.impl.search.ServiceQuery;
import jadex.requiredservice.IRequiredServiceFeature;

/**
 *  Generate service implementation. 
 */
@Service
public class GenerateService implements IGenerateService
{
	//-------- constants --------
	
	/** The available algorithms. */
	/*public static IFractalAlgorithm[] ALGORITHMS = new IFractalAlgorithm[] 
	{
		new MandelbrotAlgorithm(),
		new LyapunovAlgorithm()
	};*/
	
	//-------- attributes --------
	
	/** The agent. */
	@ServiceComponent
	protected IComponent agent;
	
	protected IGenerateGui ggui;
	
	/** The current calculator count (for selecting the next). */
	protected int curcalc;
	
	/** The number of maximum retries for calculations. */
	protected int maxretries = 1;
	
	protected IFractalAlgorithm defalgo;
	
	//-------- methods --------
	
	@OnStart
	public void onStart() throws Exception
	{
		Object pagent = agent.getPojo();
		
		if(pagent instanceof IGenerateGui)
			ggui = (IGenerateGui)pagent;
		else
			System.out.println("gen gui interface not found");
		
		IDisplayService ds = agent.getFeature(IRequiredServiceFeature.class).getService(IDisplayService.class).get();
		List> algos = ds.getAlgorithms().get();
		defalgo = algos.get(0).getConstructor().newInstance(new Object[0]);
	}
	
	public IIntermediateTaskDistributor getTaskDistributor()
	{
		//System.out.println("search task distri");
		IIntermediateTaskDistributor ret = agent.getFeature(IRequiredServiceFeature.class).searchService(new ServiceQuery(IIntermediateTaskDistributor.class)).get();
		//System.out.println("found task distri: "+ret);
		return ret;
	}
	
	/**
	 *  Calculate and display the default image from current settings.
	 * /
	public IFuture calcDefaultImage()
	{
		panel.calcDefaultImage();
		return IFuture.DONE;
	}*/
	
	/**
	 *  Generate a specific area using a defined x and y size.
	 */
	//public IFuture generateArea(final AreaData data)
	public IFuture generateArea(AreaData data)
	{
		//System.out.println("generateArea data: "+data);
		//System.out.println("default data: "+ALGORITHMS[0].getDefaultSettings());
		
		if(data==null)
		{
			System.out.println("generateArea without selection definition");
		}
		else if(data.getDisplayId()==null)
		{
			System.out.println("generateArea without displayid: "+data);
		}
		
		//GenerateAgent ga = (GenerateAgent)agent.getFeature(IPojoComponentFeature.class).getPojoAgent();
		//if(ga.getCalculateService()==null)
		//	return new Future(new RuntimeException("No calculate service available"));

		if(data==null)
		{
			//System.out.println("no generate info supplied, using defaults.");
			data = defalgo.getDefaultSettings();
		}
		else
		{
			IFractalAlgorithm alg = data.getAlgorithm(agent.getClass().getClassLoader());
			if(alg==null)
			{
				//System.out.println("no algorithm set, using: "+ALGORITHMS[0]);
				alg = defalgo;
				data.setAlgorithmClass(new ClassInfo(alg.getClass()));
			}
			AreaData defaults = alg.getDefaultSettings();
			
			if(data.getSizeX()==0)
			{
				//System.out.println("no sizex");
				data.setSizeX(defaults.getSizeX());
			}
			if(data.getSizeY()==0)
			{
				//System.out.println("no sizey");
				data.setSizeY(defaults.getSizeY());
			}
			if(data.getMax()==0)
			{
				//System.out.println("no max");
				data.setMax(defaults.getMax());
			}
			if(data.getTaskSize()==0)
			{
				//System.out.println("no tasksize");
				data.setTaskSize(defaults.getTaskSize());
			}
			if(data.getChunkCount()==0)
			{
				//System.out.println("no chunk count");
				data.setChunkCount(defaults.getChunkCount());
			}
			
			// if same assume that all has to be set
			if(data.getXStart()==data.getXEnd())
			{
				//System.out.println("no x start end");
				data.setXStart(defaults.getXStart());
				data.setXEnd(defaults.getXEnd());
			}
			if(data.getYStart()==data.getYEnd())
			{
				//System.out.println("no y start end");
				data.setYStart(defaults.getYStart());
				data.setYEnd(defaults.getYEnd());
			}
			
			// todo: off?
		}
		
		// Update own gui settings
		if(ggui!=null)
			ggui.updateData(data);
		
		return distributeWork(data);
	}
	
	/**
	 *  Distribute the work to available or newly created calculation services.
	 */
	//protected IFuture	distributeWork(final AreaData data)
	protected IFuture	distributeWork(final AreaData data)
	{
		final Future ret = new Future<>();	

		// Split area into work units.
		final Set	areas = new HashSet<>();	// {AreaData}
		long task = (long)data.getTaskSize()*data.getTaskSize()*256;
		long pic = (long)data.getSizeX()*data.getSizeY()*data.getMax();
		int numx = (int)Math.max(Math.round(Math.sqrt((double)pic/task)), 1);
		int numy = (int)Math.max(Math.round((double)pic/(task*numx)), 1);
		
//		numx = 1;
//	    numy = 1;

//		final long	time	= System.nanoTime();	
		//System.out.println("Number of tasks: "+numx+", "+numy+", max="+data.getMax()+" tasksize="+data.getTaskSize());
		
		double	areawidth	= data.getXEnd() - data.getXStart();
		double	areaheight	= data.getYEnd() - data.getYStart();
		int	numx0	=numx;
		
		int	resty	= data.getSizeY();
		for(; numy>0; numy--)
		{
			int	sizey	= (int)Math.round((double)resty/numy);
			double	ystart	= data.getYStart() + areaheight*(((double)data.getSizeY()-resty)/data.getSizeY());
			double	yend	= data.getYStart() + areaheight*(((double)data.getSizeY()-(resty-sizey))/data.getSizeY()); 

			int	restx	= data.getSizeX();
			for(numx=numx0; numx>0; numx--)
			{
				int	sizex	= (int)Math.round((double)restx/numx);
				double	xstart	= data.getXStart() + areawidth*(((double)data.getSizeX()-restx)/data.getSizeX()); 
				double	xend	= data.getXStart() + areawidth*(((double)data.getSizeX()-(restx-sizex))/data.getSizeX()); 
				
//				System.out.println("x:y: start "+x1+" "+(x1+xdiff)+" "+y1+" "+(y1+ydiff)+" "+xdiff);
				areas.add(new AreaData(xstart, xend, ystart, yend, sizex, sizey)
					.setXOffset(data.getSizeX()-restx).setYOffset(data.getSizeY()-resty)
					.setMax(data.getMax()).setAlgorithmClass(data.getAlgorithmClass()).setDisplayId(data.getDisplayId()).setChunkCount(data.getChunkCount())
				);
					//data.getMax(), 0, data.getAlgorithmClass(), null, null, data.getDisplayId(), data.getChunkCount()));
//				System.out.println("x:y: "+xi+" "+yi+" "+ad);
				restx	-= sizex;
			}
			resty	-= sizey;
		}

		// Create array for holding results.
		//data.setData(new short[data.getSizeX()][data.getSizeY()]);
		
		// Assign tasks to service pool.
		final int number = areas.size();
		
		//System.out.println("tasks: "+areas);
		
		//manager.setMax(data.getParallel());
		
		int[] cnt = new int[1];
		performTasks(areas, true, data).next(ad ->
		{
			if(ad.fetchData()==null)
				return;
			
			if(ggui!=null)
				ggui.updateStatus(++cnt[0], number);
		}).finished(Void -> ret.setResult(null)).catchEx(ret);
		
		/*performTasks(areas, true, data).addResultListener(agent.getFeature(IExecutionFeature.class).createResultListener(
			new IntermediateEmptyResultListener()
		{
			int	cnt	= 0;
			
			public void exceptionOccurred(Exception exception)
			{
				//System.out.println("ex in perform tasks: "+exception);
				ret.setExceptionIfUndone(exception);
			}
			
			public void intermediateResultAvailable(AreaData ad)
			{
				if(ad.fetchData()==null)
					return;
				
				if(ggui!=null)
					ggui.updateStatus(++cnt, number);
				
//				int xs = ad.getXOffset();
//				int ys = ad.getYOffset();
				
	//			System.out.println("x:y: end "+xs+" "+ys);
	//			System.out.println("partial: "+SUtil.arrayToString(ad.getData()));
				
				/*for(int yi=0; yi performTasks(Set tasks, boolean retry, Object user)
	{
//		System.out.println("Peforming "+tasks.size()+" tasks");
//		System.out.println("Performing tasks: busy="+busy.size()+", free="+free.size());
		
		// Allocation data binds tasks together to a single result future.
		AllocationData ad = new AllocationData(tasks.size(), retry, user);
		
		for(Iterator it=tasks.iterator(); it.hasNext(); )
		{
			performTask(it.next(), ad).catchEx(ex -> ad.getResult().setExceptionIfUndone(ex));
		}
		
		// finished parts are added via ad.taskFinished(part);
		return ad.getResult();
	}
	
	public Future performTask(AreaData task, AllocationData alda)
	{
		//System.out.println("perform1 task start: "+task+" "+ServiceCall.getCurrentInvocation());
		Future ret = new Future<>();
		
		//final Object task	=	this.tasks.keySet().iterator().next();
		//final AllocationData	ad	= (AllocationData)this.tasks.remove(task);
//		System.out.println("started service: "+service.getId()+", "+task);
		final AreaData complete = (AreaData)alda.getUserData();	// complete area
		final AreaData part = (AreaData)task;					// part
		
//		System.out.println("invoke: "+service);
		IFuture futd = agent.getFeature(IRequiredServiceFeature.class).getService("displayservice");
		futd.then(ds ->
		{
			//System.out.println("perform2 task start: "+task+" "+ServiceCall.getCurrentInvocation());

//			System.out.println("display: "+result);
			//final ProgressData pd = new ProgressData(part.getCalculatorId(), part.getId(),
			//	new Rectangle(part.getXOffset(), part.getYOffset(), part.getSizeX(), part.getSizeY()),
			//	0, complete.getSizeX(), complete.getSizeY(), part.getDisplayId());
			
			// Inform display service that the following area/size is calculated
			ds.displayResult(complete).then(vo ->
			{
				//System.out.println("calc start: "+Thread.currentThread());
				
				getTaskDistributor().publish(part).next(chunk ->
				{
					//System.out.println("generate got chunk (calls display): "+chunk);
					
					chunk.setDisplayId(part.getDisplayId());
					chunk.setArea(new Rectangle(part.getXOffset(), part.getYOffset(), part.getSizeX(), part.getSizeY()));
					chunk.setImageWidth(complete.getSizeX());
					chunk.setImageHeight(complete.getSizeY());
					
					part.addChunk(chunk);
					
					// Inform display service that a chunk is finsihed
					ds.displayIntermediateResult(chunk).then(v2 -> {}
						//System.out.println("da")
						// Use result from calculation service instead of result from display service.
						//ret.setResult(calcresult)
					).catchEx(ex -> {}
						//System.out.println("da2: "+ex)
						// Use result from calculation service instead of exception from display service.
						//ret.setResult(calcresult)
					);
				}).finished(Void ->
				{
					// Add result of task execution.
					alda.taskFinished(part);
					//System.out.println("perform task ended: "+task);
					ret.setResult(part);
				}).catchEx(ex ->
				{
					System.out.println("exception during task execution: "+ex+" "+task);
					
					// retry 
					// todo: abort after some tries
					if(alda.isRetry() && task.getRetryCount() performTask(task, alda).delegateTo(ret)).catchEx(ret);
					}
					else
					{
						ret.setException(ex);
					}
				});
			}).catchEx(ex -> 
			{	
				System.out.println("ex: "+ex);
				ret.setException(ex);
			});
		}).catchEx(ex -> 
		{	
			System.out.println("ex: "+ex); 
			ret.setException(ex);
		});
		
		return ret;
	}
	
	/**
	 * 
	 */
	/*public Future performTask(AreaData task, AllocationData alda)
	{
		Future ret = new Future<>();
		
		//final Object task	=	this.tasks.keySet().iterator().next();
		//final AllocationData	ad	= (AllocationData)this.tasks.remove(task);
//		System.out.println("started service: "+service.getId()+", "+task);
		final AreaData global = (AreaData)alda.getUserData();	// global area
		final AreaData part = (AreaData)task;					// part
		
//		System.out.println("invoke: "+service);
		IFuture futd = agent.getFeature(IRequiredServicesFeature.class).getService("displayservice");
		futd.then(ds ->
		{
//			System.out.println("display: "+result);
			final ProgressData	pd	= new ProgressData(part.getCalculatorId(), part.getId(),
				new Rectangle(part.getXOffset(), part.getYOffset(), part.getSizeX(), part.getSizeY()),
				false, global.getSizeX(), global.getSizeY(), part.getDisplayId());
			
			// Inform display service that a part is calculated
			ds.displayIntermediateResult(pd).then(v ->
			{
				//System.out.println("calc start: "+Thread.currentThread());
				IFuture futc = agent.getFeature(IRequiredServicesFeature.class).getService("calculateservice");
				futc.then(cs -> 
				{
					cs.calculateArea(part).then(calcresult ->
					{
						// Add result of task execution.
						alda.taskFinished(calcresult);
						System.out.println("calc end: "+part);
						pd.setFinished(true);
						// Inform display service that a part is finsihed
						ds.displayIntermediateResult(pd).then(v2 ->
//							System.out.println("da");
							// Use result from calculation service instead of result from display service.
							ret.setResult(calcresult)
						).catchErr(ex ->
//							System.out.println("da2");
							// Use result from calculation service instead of exception from display service.
							ret.setResult(calcresult)
						);
					}).catchErr(ex -> 
					{
//						System.out.println("ex");
						System.out.println("exception during task execution: "+ex);
						performTask(task, alda).delegate(ret);
					});
				}).catchErr(ex ->
				{
					System.out.println("ex: "+ex);
					ret.setException(ex);
				}
				);
			}).catchErr(ex -> 
			{	
				System.out.println("ex: "+ex);
				ret.setException(ex);
			});
		}).catchErr(ex -> 
		{	
			System.out.println("ex: "+ex); 
			ret.setException(ex);
		});
		
		return ret;
	}*/
	
	/**
	 * 
	 */
	protected IFuture getCalculateService()
	{
		ServiceQuery	query	= new ServiceQuery(ICalculateService.class);
		Collection sers = agent.getFeature(IRequiredServiceFeature.class).getLocalServices(query);
		
		// todo: how to identify pool or worker (tagging workers or tagging pools)
		ICalculateService ser = null;
		for(ICalculateService s: sers)
		{
			if(((IService)s).getServiceId().toString().indexOf("Distributed")!=-1)
			{
				ser = s;
				break;
			}
		}
		
		if(ser==null && sers.size()>0)
			ser = sers.iterator().next();
	
		//System.out.println("selected calculator: "+ser);
		
		return ser!=null? new Future(ser): new Future(new ServiceNotFoundException(query));
	}
	
	/**
	 *  Manage all available calculators and calculator pools.
	 *  Tasks are distributed by allocating one by one as long
	 *  as free capacity permits. If no free capacity it will pick
	 *  just the next in order.
	 *  @return The next free calculator service.
	 * /
	protected IFuture getNextCalculateService()
	{
		Future ret = new Future<>();
		
		GenerateAgent ga = (GenerateAgent)agent.getFeature(IPojoComponentFeature.class).getPojoAgent();
		
		// has calcs -> get next free
		if(ga.getCalculateServices().size()>0)
		{
			findFreeCalculatorService(new ArrayList(ga.getCalculateServices()), curcalc, 0)
			.then(tup -> 
			{
				System.out.println("Found: "+curcalc+" "+tup.getSecondEntity()+" "+tup.getFirstEntity());
				curcalc = tup.getSecondEntity();
				ret.setResult(tup.getFirstEntity());
			})
			.catchEx(ex -> ret.setException(ex));
		}
		// no calculators found
		else if(ga.getCalculateServices().size()==0)
		{
			long wait = 2000;
			System.out.println("No calculators found, retrying in: "+wait);
			agent.waitForDelay(2000).then(c -> getNextCalculateService().delegate(ret))
			.catchEx(ex -> getNextCalculateService().delegate(ret));
		}
		
		return ret;
	}*/
	
	/**
	 *  Find a free calculator. Searches linearly for pools and if none is avilable in
	 *  the second round takes all available calculator.
	 *  @param calcs The calculators.
	 *  @param pos The current position.
	 *  @param tried The number of already inspected calculators. 
	 *  @return The calculator.
	 * /
	protected IFuture> findFreeCalculatorService(List calcs, int pos, int tried)
	{
		Future> ret = new Future<>();
		boolean takeany = false;
		
		if(tried==calcs.size())
			takeany = true;
		
		if(pos>=calcs.size())
			pos = 0;
		
		ICalculateService calc = calcs.get(pos);
		if(takeany)
		{
			ret.setResult(new Tuple2(calc, pos+1));
		}
		else
		{
			int fpos = pos;
			ServicePoolHelper.getFreeCapacity(agent, (IService)calc).then(cap ->
			{
				System.out.println("capa: "+calc+" "+cap);
				if(cap>0)
				{
					ret.setResult(new Tuple2(calc, fpos+1));
				}
				else
				{
					findFreeCalculatorService(calcs, fpos+1, tried+1).delegate(ret);
				}
			}).catchEx(ex -> findFreeCalculatorService(calcs, fpos+1, tried+1).delegate(ret));
		}
		
		curcalc++;
		
		return ret;
	}*/
	
	/**
	 *  Handler for a single task allocation.
	 */
	public static class	AllocationData
	{
		//-------- attributes --------
		
		/** The counter for open tasks, i.e. number of assigned and unassigned tasks that are not yet finished. */
		protected int open;
		
		/** The retry flag, i.e. if failed tasks should be assigned again. */
		protected boolean retry;
		
		/** The user data (if any). */
		protected Object user;
		
		/** The result future. */
		protected IntermediateFuture result;
		
		//-------- constructors --------
		
		/**
		 *  Create a new allocation data.
		 */
		public AllocationData(int open, boolean retry, Object user)
		{
			this.open	= open;
			this.retry	= retry;
			this.user	= user;
			this.result	= new IntermediateFuture();
		}
		
		//-------- methods --------
		
		/**
		 *  Get the user data.
		 *  @return The user data (if any).
		 */
		public Object	getUserData()
		{
			return user;
		}
		
		/**
		 *  Get the result.
		 *  @return The intermediate results future.
		 */
		public IntermediateFuture	getResult()
		{
			return result;
		}
				
		/**
		 *  Add an intermediate result.
		 */
		public void	taskFinished(Object result)
		{
			this.result.addIntermediateResult(result);
			open--;
			
			if(open==0)
			{
				this.result.setFinished();
			}
		}
		
		/**
		 *  A task has failed and is not retried.
		 */
		public void	taskFailed(Exception e)
		{
			// Todo: post exception in result?
			e.printStackTrace();
			
			open--;
			if(open==0)
			{
				this.result.setFinished();
			}
		}
		
		/**
		 *  Test if the retry flag is set.
		 *  @return True, if the retry flag is set.
		 */
		public boolean	isRetry()
		{
			return retry;
		}

		/**
		 * @param retry the retry to set
		 */
		public void setRetry(boolean retry)
		{
			this.retry = retry;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy