package jadex.micro.examples.mandelbrot; import jadex.bridge.CreationInfo; import jadex.bridge.IComponentIdentifier; import jadex.bridge.IComponentManagementService; import jadex.commons.Future; import jadex.commons.IFuture; import jadex.commons.SUtil; import jadex.commons.Tuple; import jadex.commons.concurrent.CollectionResultListener; import jadex.commons.concurrent.CounterResultListener; import jadex.commons.concurrent.DefaultResultListener; import jadex.commons.concurrent.DelegationResultListener; import jadex.commons.concurrent.IResultListener; import jadex.commons.service.BasicService; import jadex.commons.service.SServiceProvider; import java.awt.Rectangle; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.swing.SwingUtilities; /** * Generate service implementation. */ public class GenerateService extends BasicService implements IGenerateService { //-------- attributes -------- /** The agent. */ protected GenerateAgent agent; /** The generate panel. */ protected GeneratePanel panel; //-------- constructors -------- /** * Create a new service. */ public GenerateService(GenerateAgent agent, GeneratePanel panel) { super(agent.getServiceProvider().getId(), IGenerateService.class, null); this.agent = agent; this.panel = panel; } //-------- methods -------- /** * Generate a specific area using a defined x and y size. */ public IFuture generateArea(final AreaData data) { final Future ret = new Future(); SwingUtilities.invokeLater(new Runnable() { public void run() { panel.updateProperties(data); } }); SServiceProvider.getService(agent.getServiceProvider(), IDisplayService.class) .addResultListener(new DefaultResultListener() { public void resultAvailable(Object source, Object result) { final IDisplayService ds = (IDisplayService)result; getCalculateServices(agent, data.getParallel()).addResultListener(new IResultListener() { public void resultAvailable(Object source, Object result) { distributeWork(data, (List)result, ds, ret); } public void exceptionOccurred(Object source, Exception exception) { } }); } }); return ret; } /** * Get (and create) the calculate services. */ protected static IFuture getCalculateServices(final GenerateAgent agent, final int par) { final Future ret = new Future(); SServiceProvider.getServices(agent.getServiceProvider(), ICalculateService.class, false, true) .addResultListener(agent.createResultListener(new DelegationResultListener(ret) { public void customResultAvailable(Object source, Object result) { List sers = (List)result; // Start additional components if necessary if(sers.size()<par) { final int num = par-sers.size(); // System.out.println("Starting new calculator agents: "+num); final CollectionResultListener lis = new CollectionResultListener(num, true, agent.createResultListener(new DefaultResultListener() { public void resultAvailable(Object source, Object result) { SServiceProvider.getServices(agent.getServiceProvider(), ICalculateService.class, false, true) .addResultListener(agent.createResultListener(new DelegationResultListener(ret))); } })); SServiceProvider.getService(agent.getServiceProvider(), IComponentManagementService.class, false, true) .addResultListener(agent.createResultListener(agent.createResultListener(new DelegationResultListener(ret) { public void customResultAvailable(Object source, Object result) { IComponentManagementService cms = (IComponentManagementService)result; // System.out.println("test: "+agent.getArgument("delay")); Object delay = agent.getArgument("delay"); if(delay==null) delay = new Long(5000); for(int i=0; i<num; i++) { cms.createComponent(null, "jadex/micro/examples/mandelbrot/CalculateAgent.class", new CreationInfo(SUtil.createHashMap(new String[]{"delay"}, new Object[]{delay}), agent.getParent().getComponentIdentifier()), null) .addResultListener(agent.createResultListener(lis)); } } }))); } else { ret.setResult(sers); } } })); return ret; } /** * Distribute the work to different worker services. */ protected void distributeWork(final AreaData data, Collection sers, final IDisplayService ds, final Future ret) { if(sers==null || sers.size()==0) throw new IllegalArgumentException("Calculate services must not be null"); List services = new ArrayList(sers); int numx = Math.max((int)Math.sqrt((double)data.getSizeX()*data.getSizeY()*data.getMax()/(data.getTaskSize()*data.getTaskSize()*256)), 1); int numy = numx; // System.out.println("Number of tasks: "+numx+", "+numy+", max="+data.getMax()+" tasksize="+data.getTaskSize()); final int sizex = data.getSizeX()/numx; final int sizey = data.getSizeY()/numy; int restx = data.getSizeX()-numx*sizex; int resty = data.getSizeY()-numy*sizey; // If rest if too large add more chunks numx += restx/sizex; numy += resty/sizey; restx = restx%sizex; resty = resty%sizey; double xdiv = restx==0? numx: ((double)restx)/sizex+numx; double ydiv = resty==0? numy: ((double)resty)/sizey+numy; final double xdiff = (data.getXEnd()-data.getXStart())/xdiv; final double ydiff = (data.getYEnd()-data.getYStart())/ydiv; if(restx>0) numx++; if(resty>0) numy++; // System.out.println("ad: "+data+" "+numx+" "+restx+" "+xdiff); double x1 = data.getXStart(); double y1 = data.getYStart(); data.setData(new int[data.getSizeX()][data.getSizeY()]); final CounterResultListener lis = new CounterResultListener(numx*numy, new IResultListener() { public void resultAvailable(Object source, Object result) { ret.setResult(data); } public void exceptionOccurred(Object source, Exception exception) { System.out.println("ex: "+exception); } }) { public void intermediateResultAvailable(Object source, Object result) { AreaData ad = (AreaData)result; int xs = (int)((Number)((Tuple)ad.getId()).getEntity(0)).intValue()*sizex; int ys = (int)((Number)((Tuple)ad.getId()).getEntity(1)).intValue()*sizey; SwingUtilities.invokeLater(new Runnable() { public void run() { panel.getStatusBar().setText("Finished: "+getCnt()+"("+getNumber()+")"); } }); if(ds!=null) { ds.displayIntermediateResult(new ProgressData((IComponentIdentifier)source, ad.getId(), new Rectangle(xs, ys, ad.getSizeX(), ad.getSizeY()), true, data.getSizeX(), data.getSizeY())); } // System.out.println("x:y: end "+xs+" "+ys); // System.out.println("partial: "+SUtil.arrayToString(ad.getData())); for(int yi=0; yi<ad.getSizeY(); yi++) { for(int xi=0; xi<ad.getSizeX(); xi++) { try { data.getData()[xs+xi][ys+yi] = ad.getData()[xi][yi]; } catch(Exception e) { e.printStackTrace(); } } } } }; for(int yi=0; yi<numy; yi++) { for(int xi=0; xi<numx; xi++) { // System.out.println("x:y: start "+x1+" "+(x1+xdiff)+" "+y1+" "+(y1+ydiff)+" "+xdiff); int idx = (xi+(yi*numx))%services.size(); ICalculateService cs = (ICalculateService)services.get(idx); AreaData ad = new AreaData(x1, xi==numx-1 && restx>0 ? x1+(xdiff*restx/sizex): x1+xdiff, y1, yi==numy-1 && resty>0 ? y1+(ydiff*resty/sizey) : y1+ydiff, xi==numx-1 && restx>0 ? restx : sizex, yi==numy-1 && resty>0 ? resty : sizey, data.getMax(), 0, 0, new Tuple(new Integer(xi), new Integer(yi)), null); // System.out.println("x:y: "+xi+" "+yi+" "+ad); // System.out.println("calculateArea: "+cs.getServiceIdentifier().getProviderId()); cs.calculateArea(ad).addResultListener(agent.createResultListener(new CalculateListener(agent, lis, ad, cs.getServiceIdentifier().getProviderId()))); if(ds!=null) { ds.displayIntermediateResult(new ProgressData((IComponentIdentifier)cs.getServiceIdentifier().getProviderId(), ad.getId(), new Rectangle(xi*sizex, yi*sizey, ad.getSizeX(), ad.getSizeY()), false, data.getSizeX(), data.getSizeY())); } x1 += xdiff; } x1 = data.getXStart(); y1 += ydiff; } } } /** * Listener for calculate service that can reassign a task. */ class CalculateListener implements IResultListener { /** The agent. */ protected GenerateAgent agent; /** The listener. */ protected IResultListener listener; /** The data. */ protected AreaData data; /** The provider id. */ protected Object providerid; /** * Create a new listener. */ public CalculateListener(GenerateAgent agent, IResultListener listener, AreaData data, Object providerid) { this.agent = agent; this.listener = listener; this.data = data; this.providerid = providerid; } /** * Called when the result is available. * @param source The source component. * @param result The result. */ public void resultAvailable(Object source, Object result) { // Hack!!! Provide provider id. listener.resultAvailable(providerid, result); } /** * Called when an exception occurred. * @param source The source component. * @param exception The exception. */ public void exceptionOccurred(Object source, Exception exception) { // System.out.println("Recal start: "+data.getId()); GenerateService.getCalculateServices(agent, 1).addResultListener(new IResultListener() { public void resultAvailable(Object source, Object result) { // System.out.println("Recal end: "+data.getId()); ICalculateService cs = (ICalculateService)((Collection)result).iterator().next(); // System.out.println("(re)calculateArea: "+cs.getServiceIdentifier().getProviderId()); cs.calculateArea(data).addResultListener(agent.createResultListener(CalculateListener.this)); } public void exceptionOccurred(Object source, Exception exception) { System.out.println("Recal no success: "+data.getId()); exception.printStackTrace(); listener.exceptionOccurred(source, exception); } }); } }