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

jadex.base.service.cms.DecoupledComponentManagementService Maven / Gradle / Ivy

Go to download

The Jadex platform base package contains functionality useful for constructing platforms.

The newest version!
package jadex.base.service.cms;

import jadex.bridge.ComponentCreationException;
import jadex.bridge.ComponentIdentifier;
import jadex.bridge.ComponentTerminatedException;
import jadex.bridge.IComponentIdentifier;
import jadex.bridge.IComponentInstance;
import jadex.bridge.IComponentStep;
import jadex.bridge.IExternalAccess;
import jadex.bridge.IInternalAccess;
import jadex.bridge.IResourceIdentifier;
import jadex.bridge.ISearchConstraints;
import jadex.bridge.ServiceCall;
import jadex.bridge.modelinfo.IModelInfo;
import jadex.bridge.modelinfo.SubcomponentTypeInfo;
import jadex.bridge.service.IServiceIdentifier;
import jadex.bridge.service.RequiredServiceInfo;
import jadex.bridge.service.annotation.Service;
import jadex.bridge.service.annotation.ServiceComponent;
import jadex.bridge.service.annotation.ServiceIdentifier;
import jadex.bridge.service.annotation.ServiceShutdown;
import jadex.bridge.service.annotation.ServiceStart;
import jadex.bridge.service.component.ComponentFactorySelector;
import jadex.bridge.service.search.SServiceProvider;
import jadex.bridge.service.search.ServiceNotFoundException;
import jadex.bridge.service.types.clock.IClockService;
import jadex.bridge.service.types.cms.CMSComponentDescription;
import jadex.bridge.service.types.cms.CreationInfo;
import jadex.bridge.service.types.cms.ICMSComponentListener;
import jadex.bridge.service.types.cms.IComponentDescription;
import jadex.bridge.service.types.cms.IComponentManagementService;
import jadex.bridge.service.types.execution.IExecutionService;
import jadex.bridge.service.types.factory.IComponentAdapter;
import jadex.bridge.service.types.factory.IComponentAdapterFactory;
import jadex.bridge.service.types.factory.IComponentFactory;
import jadex.bridge.service.types.library.ILibraryService;
import jadex.bridge.service.types.message.IMessageService;
import jadex.bridge.service.types.remote.IRemoteServiceManagementService;
import jadex.commons.ResourceInfo;
import jadex.commons.SUtil;
import jadex.commons.Tuple;
import jadex.commons.Tuple2;
import jadex.commons.collection.LRU;
import jadex.commons.collection.MultiCollection;
import jadex.commons.collection.SCollection;
import jadex.commons.future.CollectionResultListener;
import jadex.commons.future.CounterResultListener;
import jadex.commons.future.DefaultResultListener;
import jadex.commons.future.DelegationResultListener;
import jadex.commons.future.ExceptionDelegationResultListener;
import jadex.commons.future.Future;
import jadex.commons.future.IFuture;
import jadex.commons.future.IResultListener;
import jadex.kernelbase.IBootstrapFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

/**
 *  Abstract default implementation of component management service.
 */
@Service
public abstract class DecoupledComponentManagementService implements IComponentManagementService
{
	//-------- constants --------

//	/** The component counter. Used for generating unique component ids. */
//	public static int compcnt = 0;

	//-------- attributes --------

	/** The agent. */
	@ServiceComponent
	protected IInternalAccess agent;
	
	@ServiceIdentifier
	protected IServiceIdentifier sid;
	
	/** The logger. */
	protected Logger logger;

	/** The components (id->component adapter). */
	protected Map adapters;
	
	/** The cleanup commands for the components (component id -> cleanup command). */
	protected Map ccs;
	
	/** The cleanup futures for the components (component id -> cleanup future). */
	protected Map>> cfs;
	
	/** The listeners. */
	protected MultiCollection listeners;
	
	/** The result (kill listeners). */
	protected Map resultlisteners;
	
	/** The execution service (cached to avoid using futures). */
	protected IExecutionService	exeservice;
	
	/** The message service (cached to avoid using futures). */
	protected IMessageService	msgservice;
	
//	/** The marshal service (cached to avoid using futures). */
//	protected IMarshalService	marshalservice;
	
	/** The root component. */
	protected IComponentAdapter root;
	
	/** The init adapters and descriptions, i.e. adapters and desc of initing components, 
	 *  are only visible for the component and child components in their init. */
	protected Map initinfos;
	
	/** Number of non-daemon children for each autoshutdown component (cid->Integer). */
	protected Map childcounts;
	
	/**	The local filename cache (tuple(parent filename, child filename) -> local typename)*/
	protected Map localtypes;
	
	/** The cached factories. */
	protected Collection factories;
	
	/** The bootstrap component factory. */
	protected IBootstrapFactory componentfactory;
	
	/** The default copy parameters flag for service calls. */
	protected boolean copy;
	
	/** The realtime timeout flag. */
	protected boolean realtime;
	
	/** The locked components. */
	protected Map lockentries;
	
	/** The time service. */
	protected IClockService clockservice;
	
	/** Flag to enable unique id generation. */
	protected boolean uniqueids;
	
	/** The cid count. */
	protected Map cidcounts;
	
    //-------- constructors --------

    /**
     *  Create a new component execution service.
     *  @param exta	The service provider.
     */
    public DecoupledComponentManagementService(IComponentAdapter root)
	{
    	this(root, null, true, true, false);
    }
    
    /**
     *  Create a new component execution service.
     *  @param exta	The service provider.
     */
    public DecoupledComponentManagementService(IComponentAdapter root, 
    	IBootstrapFactory componentfactory, boolean copy, boolean realtime, boolean uniqueids)
	{
		this.root = root;
		this.componentfactory = componentfactory;
		this.copy = copy;
		this.realtime = realtime;
		this.uniqueids = uniqueids;
		
		// Todo: why some collections synchronized? single thread access!?
		this.adapters = SCollection.createHashMap();
		this.ccs = SCollection.createLinkedHashMap();
		this.cfs = SCollection.createLinkedHashMap();
//		this.logger = Logger.getLogger(AbstractComponentAdapter.getLoggerName(exta.getComponentIdentifier())+".cms");
		this.listeners = SCollection.createMultiCollection();
		this.resultlisteners = SCollection.createHashMap();
		this.initinfos = SCollection.createHashMap();
		this.childcounts = SCollection.createHashMap();
		this.localtypes	= new LRU(100);
		this.lockentries = SCollection.createHashMap();
		this.cidcounts = new HashMap();
   }
    
	/**
	 *  Get the component instance from an adapter.
	 */
	public abstract IComponentInstance getComponentInstance(IComponentAdapter adapter);

	/**
	 *  Get the component adapter factory.
	 */
	public abstract IComponentAdapterFactory getComponentAdapterFactory();
	
	/**
	 *  Invoke kill on adapter.
	 */
	public abstract IFuture killComponent(IComponentAdapter adapter);
	
	/**
	 *  Cancel the execution.
	 */
	public abstract IFuture cancel(IComponentAdapter adapter);

	/**
	 *  Do a step.
	 */
	public abstract IFuture doStep(IComponentAdapter adapter);
	
    //-------- IComponentManagementService interface --------
    
	/**
	 *  Load a component model.
	 *  @param name The component name.
	 *  @return The model info of the 
	 */
	public IFuture loadComponentModel(final String filename, final IResourceIdentifier rid)
	{
//		if(filename!=null && filename.indexOf("Remote")!=-1)
//			System.out.println("cache miss: "+filename);
		
		final Future ret = new Future();
		
		if(filename==null)
		{
			ret.setException(new IllegalArgumentException("Filename must not null"));
		}
		else
		{
			SServiceProvider.getService(agent.getServiceContainer(), ILibraryService.class, RequiredServiceInfo.SCOPE_PLATFORM)
				.addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
			{
				public void customResultAvailable(final ILibraryService ls)
				{
					IFuture fut = SServiceProvider.getService(agent.getServiceContainer(), new ComponentFactorySelector(filename, null, rid));
					fut.addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
					{
						public void customResultAvailable(IComponentFactory factory)
						{
							factory.loadModel(filename, null, rid)
								.addResultListener(new DelegationResultListener(ret));
						}
						
						public void exceptionOccurred(Exception exception)
						{
							if(exception instanceof ServiceNotFoundException)
							{
								ret.setResult(null);
							}
							else
							{
								super.exceptionOccurred(exception);
							}
						}
					}));
				}
			}));
		}
		return ret;
	}
	
	/**
	 *  Create a new component on the platform.
	 *  @param name The component name.
	 *  @param model The model identifier (e.g. file name).
	 *  @param info	The creation info, if any.
	 *  @param listener The result listener (if any). Will receive the id of the component as result, when the component has been created.
	 *  @param resultlistener The kill listener (if any). Will receive the results of the component execution, after the component has terminated.
	 */
	public IFuture createComponent(final String name, final String modelname, CreationInfo info, 
		final IResultListener>> resultlistener)
	{			
		if(modelname==null)
			return new Future(new IllegalArgumentException("Modelname must not null."));

		final IComponentIdentifier creator = ServiceCall.getInstance().getCaller();

//		if(modelname.indexOf("jadex/micro/testcases/securetrans/ProviderAgent.class")!=-1)
//			System.out.println("create: "+modelname);
		
//		final DebugException	de	= new DebugException();
	
//		System.out.println("create component: "+modelname+" "+name);
		
		final Future inited = new Future();
		final Future resfut = new Future();
		
		final CreationInfo cinfo = new CreationInfo(info);	// Dummy default info, if null. Must be cloned as localtype is set on info later.
		
		final IntermediateResultListener reslis = new IntermediateResultListener(resultlistener);
		
		if(cinfo.getParent()!=null)
		{
			// Lock the parent while creating
			final String lockkey = SUtil.createUniqueId("lock");
			LockEntry kt = lockentries.get(cinfo.getParent());
			if(kt==null)
			{
				kt= new LockEntry(cinfo.getParent());
				lockentries.put(cinfo.getParent(), kt);
			}
			kt.addLocker(lockkey);
			inited.addResultListener(createResultListener(new IResultListener()
			{
				public void resultAvailable(IComponentIdentifier result)
				{
					LockEntry kt = lockentries.get(cinfo.getParent());
					if(kt!=null)
					{
						kt.removeLocker(lockkey);
						if(kt.getLockerCount()==0)
							lockentries.remove(cinfo.getParent());
					}
				}
				public void exceptionOccurred(Exception exception)
				{
					LockEntry kt = lockentries.get(cinfo.getParent());
					if(kt!=null)
					{
						kt.removeLocker(lockkey);
						if(kt.getLockerCount()==0)
							lockentries.remove(cinfo.getParent());
					}
				}
			}));
		}
		
		if(cinfo.getParent()!=null && isRemoteComponent(cinfo.getParent()))
		{				
			getRemoteCMS(cinfo.getParent()).addResultListener(createResultListener(
				new ExceptionDelegationResultListener(inited)
			{
				public void customResultAvailable(IComponentManagementService rcms)
				{
					rcms.createComponent(name, modelname, cinfo, resultlistener).addResultListener(new DelegationResultListener(inited));
				}
			}));
		}
		else
		{
	//		System.out.println("create start1: "+model+" "+cinfo.getParent());
			
			if(name!=null && name.indexOf('@')!=-1)
			{
				inited.setException(new ComponentCreationException("No '@' allowed in component name.", ComponentCreationException.REASON_WRONG_ID));
			}
			else
			{
				getAddresses().addResultListener(createResultListener(new ExceptionDelegationResultListener(inited)
				{
					public void customResultAvailable(final String[] addresses)
					{
						// Load the model with fitting factory.
						getResourceIdentifier(cinfo).addResultListener(createResultListener(new ExceptionDelegationResultListener(inited)
						{
							public void customResultAvailable(final IResourceIdentifier rid)
							{
//								System.out.println("loading: "+modelname+" "+rid);
								resolveFilename(modelname, cinfo, rid).addResultListener(createResultListener(new ExceptionDelegationResultListener(inited)
								{
									public void customResultAvailable(final String model)
									{
										getComponentFactory(model, cinfo, rid)
											.addResultListener(createResultListener(new ExceptionDelegationResultListener(inited)
										{
											public void customResultAvailable(final IComponentFactory factory)
											{
												factory.loadModel(model, cinfo.getImports(), rid)
													.addResultListener(createResultListener(new ExceptionDelegationResultListener(inited)
												{
													public void exceptionOccurred(Exception exception)
													{
														super.exceptionOccurred(exception);
													}
														
													public void customResultAvailable(final IModelInfo lmodel)
													{
														if(lmodel.getReport()!=null)
														{
															inited.setException(new ComponentCreationException("Errors loading model: "+model+"\n"+lmodel.getReport().getErrorText(), 
																ComponentCreationException.REASON_MODEL_ERROR));
														}
														else
														{
															factory.getComponentType(model, cinfo.getImports(), rid)
																.addResultListener(createResultListener(new ExceptionDelegationResultListener(inited)
															{
																public void customResultAvailable(final String type)
																{
																	// Create id and adapter.
																	
																	final ComponentIdentifier cid;
																	
																	final IComponentAdapter pad = getParentAdapter(cinfo);
																	IExternalAccess parent = getComponentInstance(pad).getExternalAccess();
					
																	IComponentIdentifier pacid = parent.getComponentIdentifier();
																	String paname = pacid.getName().replace('@', '.');
																	
																	cid = (ComponentIdentifier)generateComponentIdentifier(name!=null? name: lmodel.getName(), paname, addresses);
																	
//																	if(name!=null)
//																	{
//																		cid = new ComponentIdentifier(name+"@"+paname, addresses);
//																		if(adapters.containsKey(cid) || initinfos.containsKey(cid))
//																		{
//		//																	de.printStackTrace();
//																			inited.setException(new ComponentCreationException("Component "+cid+" already exists.", ComponentCreationException.REASON_COMPONENT_EXISTS, cid));
//																			return;
//		//																	throw new RuntimeException("Component "+cid+" already exists.");
//																		}
////																		if(msgservice!=null)
////																		{
////																			cid.setAddresses(msgservice.getAddresses());
////																		}
//																	}
//																	else
//																	{
//																		cid = (ComponentIdentifier)generateComponentIdentifier(lmodel.getName(), paname, addresses, lmodel.getName());
//																	}
																	
																	initinfos.put(cid, new InitInfo(null, null, cinfo, null, resfut, null));
																	
																	Boolean master = cinfo.getMaster()!=null? cinfo.getMaster(): lmodel.getMaster(cinfo.getConfiguration());
																	Boolean daemon = cinfo.getDaemon()!=null? cinfo.getDaemon(): lmodel.getDaemon(cinfo.getConfiguration());
																	Boolean autosd = cinfo.getAutoShutdown()!=null? cinfo.getAutoShutdown(): lmodel.getAutoShutdown(cinfo.getConfiguration());
																	final CMSComponentDescription ad = new CMSComponentDescription(cid, type, master, daemon, autosd, 
																		lmodel.getFullName(), cinfo.getLocalType(), lmodel.getResourceIdentifier(), clockservice.getTime(), creator);
																	
																	logger.info("Starting component: "+cid.getName());
							//										System.err.println("Pre-Init: "+cid);
																	
																	resfut.addResultListener(createResultListener(new IResultListener()
																	{
																		public void resultAvailable(Void result)
																		{
																			logger.info("Started component: "+cid.getName());
							//												System.err.println("Post-Init: "+cid);
							
																			// Create the component instance.
																			final IComponentAdapter adapter;
																			
		//																	System.out.println("created: "+ad);
																			
																			// Init successfully finished. Add description and adapter.
																			InitInfo	info	= initinfos.get(cid);
																			adapter = info.getAdapter();
																			
																			// Init finished. Set to suspended until parent registration is finished.
																			// not set to suspend to allow other initing sibling components invoking services
				//															ad.setState(IComponentDescription.STATE_SUSPENDED);
																			
					//														System.out.println("adding cid: "+cid+" "+ad.getMaster()+" "+ad.getDaemon()+" "+ad.getAutoShutdown());
																			adapters.put(cid, adapter);
																			// Removed in resumeComponent()
				//																initinfos.remove(cid);
																			
																			CMSComponentDescription padesc	= (CMSComponentDescription)pad.getDescription();
//																			InitInfo painfo = getParentInfo(cinfo);
//																			if(painfo!=null && painfo.getDescription()!=null)
//																			{
//																				padesc = (CMSComponentDescription)painfo.getDescription();
//																			}
//																			else
//																			{
//																				padesc = (CMSComponentDescription)getDescription(getParentIdentifier(cinfo));
//																			}
																			padesc.addChild(cid);
																			
																			Boolean dae = ad.getDaemon();
					//														if(padesc.isAutoShutdown() && !ad.isDaemon())
					//														if(pas!=null && pas.booleanValue() && (dae==null || !dae.booleanValue()))
																			// cannot check parent shutdown state because could be still uninited
																			if(dae==null || !dae.booleanValue())
																			{
																				Integer	childcount	= (Integer)childcounts.get(padesc.getName());
																				int cc = childcount!=null ? childcount.intValue()+1 : 1;
																				childcounts.put(padesc.getName(), new Integer(cc));
					//															System.out.println("childcount+:"+padesc.getName()+" "+cc);
																			}
																			
																			// Register component at parent.
																			getComponentInstance(pad).componentCreated(ad, lmodel)
																				.addResultListener(createResultListener(new IResultListener()
																			{
																				public void resultAvailable(Void result)
																				{
							//														System.err.println("Registered at parent: "+cid);
																					
																					// Registration finished -> reactivate component.
					//																// Note: Must be set to suspended because otherwise
																					// any call to wakeup would immediately start executing the component.
					//																if(isInitSuspend(cinfo, lmodel))
					//																{
																						// not set to suspend to allow other initing sibling components invoking services
					//																	ad.setState(CMSComponentDescription.STATE_SUSPENDED);
					//																}
					//																else
					//																{
					//																	ad.setState(CMSComponentDescription.STATE_ACTIVE);
					//																}
																					
																					// todo: can be called after listener has (concurrently) deregistered
																					// notify listeners without holding locks
																					notifyListenersAdded(cid, ad);
																							
			//																		System.out.println("created: "+cid.getLocalName());//+" "+(parent!=null?parent.getComponentIdentifier().getLocalName():"null"));
							//														System.out.println("added: "+descs.size()+", "+aid);
																					
																					resultlisteners.put(cid, reslis);
//																								if(resultlistener!=null)
//																									resultlisteners.put(cid, resultlistener);
																					
																					inited.setResult(cid);
																					
																					Future>	killfut;
																					killfut	= (Future>)cfs.get(cid);
																					if(killfut!=null)
																					{
																						// Remove init infos otherwise done in resume()
																						List	cids	= new ArrayList();
																						cids.add(cid);
																						for(int i=0; i0)
																			{
																				CounterResultListener>	crl	= new CounterResultListener>(children.length, true,
																					createResultListener(new IResultListener()
																					{
																						public void resultAvailable(Void result)
																						{
																							cleanup.run();
																						}
																						
																						public void exceptionOccurred(Exception exception)
																						{
																							cleanup.run();
																						}
																					}
																				));
																				
																				for(int i=0; i0 ? lmodel.getConfigurationNames()[0] : null;
																						
																	factory.createComponentInstance(ad, getComponentAdapterFactory(), lmodel, 
																		config, cinfo.getArguments(), parent, cinfo.getRequiredServiceBindings(), copy, realtime, reslis, resfut)
																		.addResultListener(createResultListener(new IResultListener>()
																	{
																		public void resultAvailable(Tuple2 comp)
																		{
																			// Store (invalid) desc, adapter and info for children
																			// 0: description, 1: adapter, 2: creation info, 3: model, 4: initfuture, 5: component instance
				//															System.out.println("infos: "+ad.getName());
																			InitInfo ii = getInitInfo(cid);
																			ii.setDescription(ad);
																			ii.setInfo(cinfo);
																			ii.setInstance(comp.getFirstEntity());
																			ii.setAdapter(comp.getSecondEntity());
																			ii.setModel(lmodel);
		//																	initinfos.put(cid, new Object[]{ad, comp.getSecondEntity(), cinfo, lmodel, resfut, comp.getFirstEntity()});
																			
																			try
																			{
																				// Start the init procedure by waking up the adapter.
																				getComponentAdapterFactory().initialWakeup(comp.getSecondEntity());
																			}
																			catch(RuntimeException e)
																			{
																				exceptionOccurred(e);
																			}
																		}
																		
																		public void exceptionOccurred(Exception exception)
																		{
																			// Init problem might be notified already in other future.
																			if(!resfut.isDone())
																			{
																				inited.setExceptionIfUndone(exception);
																			}
																		}
																	}));
																}
															}));
														}
													}
												}));
											}
										}));
									}
								}));
							}
						}));
					}
				}));
			}
		}
		return inited;
	}
	
	/**
	 *  Find the file name and local component type name
	 *  for a component to be started.
	 */
	protected IFuture	resolveFilename(final String modelname, final CreationInfo cinfo, final IResourceIdentifier rid)
	{
		final Future	ret	= new Future();
		SServiceProvider.getService(agent.getServiceContainer(), ILibraryService.class, RequiredServiceInfo.SCOPE_PLATFORM)
			.addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
		{
			public void customResultAvailable(ILibraryService libservice)
			{
				libservice.getClassLoader(rid).addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
				{
					public void customResultAvailable(ClassLoader cl)
					{
						String	filename	= modelname;
						
						if(cinfo.getParent()!=null)
						{
							// Try to find file for local type.
							String	localtype	= modelname!=null ? modelname : cinfo.getLocalType();
							filename	= null;
							IComponentAdapter pad = getParentAdapter(cinfo);
							IExternalAccess parent = getComponentInstance(pad).getExternalAccess();
							final SubcomponentTypeInfo[] subcomps = parent.getModel().getSubcomponentTypes();
							for(int i=0; filename==null && i0)
							{
								Tuple	key	= new Tuple(parent.getModel().getFullName(), filename);
								if(localtypes.containsKey(key))
								{
									cinfo.setLocalType((String)localtypes.get(key));
								}
								else
								{
									ResourceInfo	info	= SUtil.getResourceInfo0(filename, cl);
									if(info!=null)
									{
										for(int i=0; cinfo.getLocalType()==null && i getComponentFactory(final String model, final CreationInfo cinfo, final IResourceIdentifier rid)
	{
		final Future ret = new Future();
		
		boolean nofac = false;
		if(factories==null)
		{
			nofac = true;
		}
		else if(factories.size()==0)
		{
			factories = null;
		}
		
		if(nofac)
		{
			IFuture> fut = SServiceProvider.getServices(agent.getServiceContainer(), IComponentFactory.class, RequiredServiceInfo.SCOPE_PLATFORM);
			fut.addResultListener(createResultListener(new ExceptionDelegationResultListener, IComponentFactory>(ret)
			{
				public void customResultAvailable(Collection facts)
				{
					factories = facts;//(Collection)result;
					getComponentFactory(model, cinfo, rid).addResultListener(new DelegationResultListener(ret));
				}
			}));
		}
		else
		{
//			System.out.println("create start2: "+model+" "+cinfo.getParent());
						
			selectComponentFactory(factories==null? null: (IComponentFactory[])factories.toArray(new IComponentFactory[factories.size()]), model, cinfo, rid, 0)
				.addResultListener(createResultListener(new DelegationResultListener(ret)
			{
//				public void customResultAvailable(Object result)
//				{
//					System.out.println("res: "+result);
//					super.customResultAvailable(result);
//				}
					
				public void exceptionOccurred(Exception exception)
				{
//					System.out.println("factory ex: "+exception);
					IFuture> fut = SServiceProvider.getServices(agent.getServiceContainer(), IComponentFactory.class, RequiredServiceInfo.SCOPE_PLATFORM);
					fut.addResultListener(createResultListener(new ExceptionDelegationResultListener, IComponentFactory>(ret)
					{
						public void customResultAvailable(Collection facts)
						{	
							factories = facts;
							for(Iterator it=factories.iterator(); it.hasNext(); )
							{
								Object o = it.next();
//								System.out.println("is: "+o+" "+(o instanceof IComponentFactory));
							}
							selectComponentFactory((IComponentFactory[])factories.toArray(new IComponentFactory[factories.size()]), model, cinfo, rid, 0)
								.addResultListener(new DelegationResultListener(ret));
						}
					}));
				}
			}));
		}
		return ret;
	}
	
	/**
	 *  Selects a component factory from a collection of factories.
	 *  Uses the isLoadable factory method to determine if the
	 *  model can be loaded.
	 *  @param factories The collection of factories.
	 *  @param model The model file name.
	 *  @param cinfo The creaion info.
	 *  @param cl The classloader.
	 *  @return The component factory.
	 */
	protected IFuture selectComponentFactory(final IComponentFactory[] factories, 
		final String model, final CreationInfo cinfo, final IResourceIdentifier rid, final int idx)
	{
		final Future ret = new Future();
		
		if(factories!=null && factories.length>0)
		{
			factories[idx].isLoadable(model, cinfo.getImports(), rid)
				.addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
			{
				public void customResultAvailable(Boolean res)
				{
					if(res.booleanValue())
					{
						ret.setResult(factories[idx]);
					}
					else if(idx+1(ret));
					}
					else
					{
						selectFallbackFactory(model, cinfo, rid).addResultListener(createResultListener(new DelegationResultListener(ret)));
					}
				}		
			}));
		}
		else
		{
			selectFallbackFactory(model, cinfo, rid).addResultListener(createResultListener(new DelegationResultListener(ret)));
		}
		
		return ret;
	}
	
	/**
	 *  Select the fallback factory.
	 */
	protected IFuture selectFallbackFactory(final String model, final CreationInfo cinfo, final IResourceIdentifier rid)
	{
		final Future ret = new Future();
		
		if(componentfactory!=null)
		{
			componentfactory.isLoadable(model, cinfo.getImports(), rid)
				.addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
			{
				public void customResultAvailable(Boolean res)
				{
					if(res.booleanValue())
					{
						ret.setResult(componentfactory);
					}
					else
					{
						ret.setException(new ComponentCreationException("No factory found for: "+model, ComponentCreationException.REASON_NO_COMPONENT_FACTORY));
					}
				}
			}));
		}
		else
		{
			ret.setException(new ComponentCreationException("No factory found for: "+model, ComponentCreationException.REASON_NO_COMPONENT_FACTORY));
		}
		
		return ret;
	}

	/**
	 *  Get the info of the parent component.
	 */
	protected InitInfo getParentInfo(CreationInfo cinfo)
	{
		final IComponentIdentifier paid = getParentIdentifier(cinfo);
		return getInitInfo(paid);
	}
	
	/**
	 *  Get the adapter of the parent component.
	 */
	protected IComponentAdapter getParentAdapter(CreationInfo cinfo)
	{
		final IComponentIdentifier paid = getParentIdentifier(cinfo);
		IComponentAdapter adapter;
		adapter = (IComponentAdapter)adapters.get(paid);
		if(adapter==null)
			adapter = getParentInfo(cinfo).getAdapter();
		return adapter;
	}
	
	/**
	 *  Get the desc of the parent component.
	 */
	protected CMSComponentDescription getParentDescription(CreationInfo cinfo)
	{
		final IComponentIdentifier paid = getParentIdentifier(cinfo);
		CMSComponentDescription desc = adapters.containsKey(paid)
			? (CMSComponentDescription)((IComponentAdapter)adapters.get(paid)).getDescription()
			: (CMSComponentDescription)getParentInfo(cinfo).getDescription();
		return desc;
	}
		
	/**
	 *  Test if a component identifier is a remote component.
	 */
	protected boolean isRemoteComponent(IComponentIdentifier cid)
	{
		return !cid.getPlatformName().equals(root.getComponentIdentifier().getName());
	}
	
	/**
	 *  Destroy (forcefully terminate) an component on the platform.
	 *  @param cid	The component to destroy.
	 */
	public IFuture> destroyComponent(final IComponentIdentifier cid)
	{
//		if(cid.toString().indexOf("MegaParallel")!=-1)
//			System.out.println("destroy: "+cid.getName());
//		else if(getDescription(cid)==null) 
//			System.out.println("destroy: null");
//		if(cid.getParent()==null)
//		{
//			System.out.println("Platform kill called:_"+cid.getName());
//			Thread.dumpStack();
//		}
		
		boolean contains = false;
		boolean locked = false;
		Future> tmp;
		
		contains = cfs.containsKey(cid);
		tmp = contains? (Future>)cfs.get(cid): new Future>();
//			System.out.println("destroy0: "+cid+" "+cfs.containsKey(cid));
//			Thread.currentThread().dumpStack();
		
		// If destroyComponent has not called before
		if(!contains)
		{
			cfs.put(cid, tmp);
		}
		
		// Is the component locked?
		LockEntry kt = lockentries.get(cid);
		if(kt!=null && kt.getLockerCount()>0)
		{
			kt.setKillFuture(tmp);
			locked = true;
		}

		final Future> ret = tmp;
		
		if(!contains && !locked)
		{
			destroyComponent(cid, ret);
		}
//		else if("Application".equals(getDescription(cid).getType()))
//			System.out.println("no destroy: "+contains+", "+locked);
		
		return ret;
	}

	/**
	 *  Internal destroy method that performs the actual work.
	 *	@param cid The component to destroy.
	 *  @param ret The future to be informed.
	 */
	protected void destroyComponent(final IComponentIdentifier cid,	final Future> ret)
	{
		if(isRemoteComponent(cid))
		{
			getRemoteCMS(cid).addResultListener(new ExceptionDelegationResultListener>(ret)
			{
				public void customResultAvailable(IComponentManagementService rcms)
				{
//					final IComponentManagementService rcms = (IComponentManagementService)result;
					rcms.destroyComponent(cid).addResultListener(new DelegationResultListener>(ret));
				}
			});
		}
		else
		{
			IComponentAdapter ad;
			InitInfo infos;
			ad = (IComponentAdapter)adapters.get(cid);
			infos = getInitInfo(cid);
			// Terminate component that is shut down during init.
//			if(infos!=null && infos.length>0 && !((IFuture)infos[4]).isDone())
			if(infos!=null && !infos.getInitFuture().isDone())
			{
				// Propagate failed component init.
				ad	= infos.getAdapter();
				if(ad==null || ad.getException()!=null)
				{
//					if(cid.toString().indexOf("Mandelbrot")!=-1)
//						System.out.println("init future exception: "+cid.getName());
					infos.getInitFuture().setException(ad.getException());
				}
				
				// Component terminated from outside: wait for init to complete, will be removed as cleanup future is registered (cfs).
				else
				{
//					if(cid.toString().indexOf("Mandelbrot")!=-1)
//						System.out.println("Queued component termination during init: "+cid.getName());
					logger.info("Queued component termination during init: "+cid.getName());
				}
			}
			// Terminate normally inited component.
			else 
			{
				final IComponentAdapter adapter = ad;
				
				// Kill subcomponents
				if(adapter==null)
				{
//					if(cid.toString().indexOf("Mandelbrot")!=-1)
//						System.out.println("Terminating component structure adapter is null: "+cid.getName());
//					
					// Todo: need to kill children!? How to reproduce this case!?
					logger.info("Terminating component structure adapter is null: "+cid.getName());
					exitDestroy(cid, null, new ComponentTerminatedException(cid, "Component does not exist."), null);
				}
				else
				{
//					if(cid.toString().indexOf("Mandelbrot")!=-1)
//						System.out.println("Terminating component structure: "+cid.getName());
//					
					logger.info("Terminating component structure: "+cid.getName());
					final CMSComponentDescription	desc = (CMSComponentDescription)adapter.getDescription();
					IComponentIdentifier[] achildren = desc.getChildren();
					
//					System.out.println("kill childs: "+cid+" "+SUtil.arrayToString(achildren));
					
					destroyComponentLoop(cid, achildren, achildren.length-1).addResultListener(createResultListener(new IResultListener>()
					{
						public void resultAvailable(List result)
						{
//							if(cid.toString().indexOf("Mandelbrot")!=-1)
//								System.out.println("Terminated component structure: "+cid.getName());
							
							logger.info("Terminated component structure: "+cid.getName());
							CleanupCommand	cc	= null;
							IFuture	fut	= null;
							synchronized(adapters)
							{
								try
								{
									IComponentAdapter adapter = (IComponentAdapter)adapters.get(cid);
									// Component may be already killed (e.g. when autoshutdown).
									if(adapter!=null)
									{
//										if(cid.toString().indexOf("Mandelbrot")!=-1)
//											System.out.println("destroy1: "+cid.getName());
//										
										// todo: does not work always!!! A search could be issued before components had enough time to kill itself!
										// todo: killcomponent should only be called once for each component?
										if(!ccs.containsKey(cid))
										{
//											if(cid.toString().indexOf("Mandelbrot")!=-1)
//												System.out.println("killing a: "+cid);
											
											cc	= new CleanupCommand(cid);
											ccs.put(cid, cc);
											logger.info("Terminating component: "+cid.getName());
											fut	= killComponent(adapter);
		//									component.killComponent(cc);	
										}
										else
										{
//											if(cid.toString().indexOf("Mandelbrot")!=-1)
//												System.out.println("killing b: "+cid);
											
											cc = (CleanupCommand)ccs.get(cid);
										}
									}
								}
								catch(Throwable e)
								{
									e.printStackTrace();
								}
							}
							
							// Add listener outside synchronized block to avoid deadlocks
							if(fut!=null && cc!=null)
							{
								// Cannot use invoke later during platform shutdown
								IResultListener lis = cid.getParent()==null? cc: createResultListener(cc);
								fut.addResultListener(lis);
							}
							
							if(cc==null)
							{
								// Todo: what is this case?
								exitDestroy(cid, desc, new RuntimeException("No cleanup command for component "+cid+": "+desc.getState()), null);
							}
							else
							{
								// Resume component to be killed in case it is currently suspended.
								resumeComponent(cid);
							}
						}
						
						public void exceptionOccurred(Exception exception)
						{
//							System.out.println("ex: "+exception);
							exitDestroy(cid, desc, exception, null);
						}
					}));
				}
			}
		}
	}
	
	/**
	 *  Exit the destroy method by setting description state and resetting maps.
	 */
	protected void exitDestroy(IComponentIdentifier cid, IComponentDescription desc, Exception ex, Map results)
	{
//		Thread.dumpStack();
		Future>	ret;
		if(desc instanceof CMSComponentDescription)
		{
			((CMSComponentDescription)desc).setState(IComponentDescription.STATE_TERMINATED);
		}
		ccs.remove(cid);
		ret	= (Future>)cfs.remove(cid);
		
		if(ret!=null)
		{
			if(ex!=null)
			{
				ret.setException(ex);
			}
			else
			{
				ret.setResult(results);
			}
		}
	}
	
	/**
	 *  Loop for destroying subcomponents.
	 */
	protected IFuture> destroyComponentLoop(final IComponentIdentifier cid, final IComponentIdentifier[] achildren, final int i)
	{
		final Future> ret = new Future>();
		
		if(achildren.length>0)
		{
			final List exceptions = new ArrayList();
			destroyComponent(achildren[i]).addResultListener(createResultListener(new IResultListener>()
			{
				public void resultAvailable(Map result)
				{
					if(i>0)
					{
						destroyComponentLoop(cid, achildren, i-1).addResultListener(
							createResultListener(new DelegationResultListener>(ret)));
					}
					else
					{
						ret.setResult(exceptions);
					}
				}
				
				public void exceptionOccurred(Exception exception)
				{
					exceptions.add(exception);
					resultAvailable(null);
//					ret.setException(exception);
				}
			}));
		}
		else
		{
			ret.setResult(null);
		}
		
		return ret;
	}

	/**
	 *  Suspend the execution of an component.
	 *  @param cid The component identifier.
	 */
	public IFuture suspendComponent(final IComponentIdentifier cid)
	{
		final Future ret = new Future();
		
		if(isRemoteComponent(cid))
		{
			getRemoteCMS(cid).addResultListener(createResultListener(
				new ExceptionDelegationResultListener(ret)
			{
				public void customResultAvailable(IComponentManagementService rcms)
				{
					rcms.suspendComponent(cid).addResultListener(createResultListener(new DelegationResultListener(ret)));
				}
			}));
		}
		else
		{
			CMSComponentDescription desc;
			final IComponentAdapter adapter = (IComponentAdapter)adapters.get(cid);
			if(adapter==null)
			{
				ret.setException(new RuntimeException("Component identifier not registered: "+cid));
				return ret;
			}
			
			// Suspend subcomponents
			desc = (CMSComponentDescription)adapter.getDescription();
			IComponentIdentifier[] achildren = desc.getChildren();
//				for(Iterator it=children.getCollection(componentid).iterator(); it.hasNext(); )
			for(int i=0; i(ret)));
//					exeservice.cancel(adapter).addResultListener(new DelegationResultListener(ret));
			
			notifyListenersChanged(cid, desc);
		}
		
		return ret;
	}
	
	/**
	 *  Resume the execution of an component.
	 *  @param componentid The component identifier.
	 */
	public IFuture resumeComponent(IComponentIdentifier cid)
	{
		return resumeComponent(cid, false);
	}
	
	/**
	 *  Resume the execution of an component.
	 *  @param componentid The component identifier.
	 */
	public IFuture resumeComponent(final IComponentIdentifier cid, final boolean initresume)
	{
//		System.out.println("resume: "+cid);
		final Future ret = new Future();
		
		if(isRemoteComponent(cid))
		{
			assert !initresume;
			getRemoteCMS(cid).addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
			{
				public void customResultAvailable(IComponentManagementService rcms)
				{
					rcms.resumeComponent(cid).addResultListener(createResultListener(new DelegationResultListener(ret)));
				}
			}));
		}
		else
		{
			// Resume subcomponents
			final CMSComponentDescription desc = (CMSComponentDescription)getDescription(cid);
			IComponentIdentifier[] achildren = desc!=null ? desc.getChildren() : null;

			if(desc!=null)
			{
				IResultListener lis = createResultListener(new CounterResultListener(achildren.length, true, new DefaultResultListener()
				{
					public void resultAvailable(Void result)
					{
						IComponentAdapter adapter = (IComponentAdapter)adapters.get(cid);
						boolean	changed	= false;
						if(adapter==null && !initresume)	// Might be killed after init but before init resume
						{
							ret.setException(new RuntimeException("Component identifier not registered: "+cid));
						}
						else if(adapter!=null)
						{
							// Hack for startup.
							if(initresume)
							{
								boolean	wakeup	= false;
								IComponentInstance instance	= null;
								Future>	destroy	= null;
								// Not killed during init.
								if(!cfs.containsKey(cid))
								{
									InitInfo ii = removeInitInfo(cid);
		//							System.out.println("removed: "+cid+" "+ii);
									if(ii!=null && ii.getInstance()!=null)
									{
										instance = ii.getInstance();
										boolean	suspend = isInitSuspend(ii.getInfo(), ii.getModel());
										
										if(suspend)
										{
											desc.setState(IComponentDescription.STATE_SUSPENDED);
											changed	= true;
										}
										wakeup	= !suspend;
									}
								}
									
								// Killed after init but before init resume -> execute queued destroy.
								else if(initinfos.containsKey(cid))
								{
									removeInitInfo(cid);
									destroy	= (Future>)cfs.remove(cid);
								}									
								
								if(instance!=null)
								{
									try
									{
										final IComponentInstance	ci	= instance;
										instance.getExternalAccess().scheduleImmediate(new IComponentStep()
										{
											public IFuture execute(IInternalAccess ia)
											{
												ci.startBehavior();
												return IFuture.DONE;
											}
										});
									}
									catch(ComponentTerminatedException e)
									{
										// Ignore when killed in mean time.
									}
								}
								if(wakeup)
								{
									try
									{
										adapter.wakeup();
									}
									catch(ComponentTerminatedException e)
									{
										// Ignore when killed in mean time.
									}
								}
								if(destroy!=null)
								{
									destroyComponent(cid, destroy);
								}
							}
							else
							{
								boolean	wakeup	= false;
								if(IComponentDescription.STATE_SUSPENDED.equals(desc.getState()))
								{
									wakeup	= true;
									desc.setState(IComponentDescription.STATE_ACTIVE);
									changed	= true;
								}
								if(wakeup)
								{
									adapter.wakeup();
								}
							}
							
							if(changed)
								notifyListenersChanged(cid, desc);
						
							ret.setResult(null);
//							ret.setResult(desc);
						}
					}
				}));
				
				for(int i=0; i stepComponent(final IComponentIdentifier cid)
	{
		final Future ret = new Future();
		
		if(isRemoteComponent(cid))
		{
			getRemoteCMS(cid).addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
			{
				public void customResultAvailable(IComponentManagementService rcms)
				{
					rcms.stepComponent(cid).addResultListener(createResultListener(new DelegationResultListener(ret)));
				}
			}));
		}
		else
		{
			final IComponentAdapter adapter = (IComponentAdapter)adapters.get(cid);
			if(adapter==null)
			{
				ret.setException(new RuntimeException("Component identifier not registered: "+cid));
				return ret;
			}
			if(!IComponentDescription.STATE_SUSPENDED.equals(adapter.getDescription().getState()))
			{
				ret.setException(new RuntimeException("Only suspended components can be stepped: "+cid+" "+adapter.getDescription().getState()));
				return ret;
			}
			
			doStep(adapter).addResultListener(new DelegationResultListener(ret));
		}
		
		return ret;
	}

	/**
	 *  Set breakpoints for a component.
	 *  Replaces existing breakpoints.
	 *  To add/remove breakpoints, use current breakpoints from component description as a base.
	 *  @param cid The component identifier.
	 *  @param breakpoints The new breakpoints (if any).
	 */
	public IFuture setComponentBreakpoints(final IComponentIdentifier cid, final String[] breakpoints)
	{
		final Future ret = new Future();
		
		if(isRemoteComponent(cid))
		{
			getRemoteCMS(cid).addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
			{
				public void customResultAvailable(IComponentManagementService rcms)
				{
					rcms.setComponentBreakpoints(cid, breakpoints).addResultListener(
						createResultListener(new DelegationResultListener(ret)));
				}
			}));
		}
		else
		{
			CMSComponentDescription ad = (CMSComponentDescription)getDescription(cid);
			ad.setBreakpoints(breakpoints);
			
			notifyListenersChanged(cid, ad);
			
			ret.setResult(null);
		}
		
		return ret;
	}

	//-------- listener methods --------
	
	/**
     *  Add an component listener.
     *  The listener is registered for component changes.
     *  @param comp  The component to be listened on (or null for listening on all components).
     *  @param listener  The listener to be added.
     */
    public IFuture addComponentListener(IComponentIdentifier comp, ICMSComponentListener listener)
    {
		listeners.put(comp, listener);
		return IFuture.DONE;
    }
    
    /**
     *  Remove a listener.
     *  @param comp  The component to be listened on (or null for listening on all components).
     *  @param listener  The listener to be removed.
     */
    public IFuture removeComponentListener(IComponentIdentifier comp, ICMSComponentListener listener)
    {
		listeners.remove(comp, listener);
		return IFuture.DONE;
    }
    
    /**
	 *  Add a result listener. Also intermediate result listeners can be
	 *  added. In this case results are immediately fed back when set.
	 *  @param listener The result (or intermediate) result listener.
	 */
	public IFuture addComponentResultListener(IResultListener>> listener, IComponentIdentifier cid)
	{
		Future ret = new Future();
		IntermediateResultListener lis = (IntermediateResultListener)resultlisteners.get(cid);
		if(lis!=null)
		{
			lis.addListener(listener);
			ret.setResult(null);
		}
		else
		{
			ret.setException(new RuntimeException("Component has no registered listener: "+cid));
		}
		return ret;
	}
	
	/**
	 *  Add a previously added result listener. 
	 *  @param listener The result (or intermediate) result listener.
	 */
	public IFuture removeComponentResultListener(IResultListener>> listener, IComponentIdentifier cid)
	{
		Future ret = new Future();
		IntermediateResultListener lis = (IntermediateResultListener)resultlisteners.get(cid);
		if(lis!=null)
		{
			lis.removeListener(listener);
			ret.setResult(null);
		}
		else
		{
			ret.setException(new RuntimeException("Component has no registered listener: "+cid));
		}
		return ret;
	}

    
    //-------- helper classes --------

	/**
	 *  Command that is executed on component cleanup.
	 */
	class CleanupCommand implements IResultListener
	{
		protected IComponentIdentifier cid;
		
		public CleanupCommand(IComponentIdentifier cid)
		{
//			System.out.println("CleanupCommand created");
			this.cid = cid;
		}
		
		public void resultAvailable(Void result)
		{
			doCleanup(null);
		}
		
		public void exceptionOccurred(Exception exception)
		{
			doCleanup(exception);
		}

		protected void doCleanup(Exception exception)
		{
			boolean	killparent	= false;
			IComponentAdapter adapter = null;
			IComponentAdapter pad = null;
			CMSComponentDescription desc;
			Map results = null;
			logger.info("Terminated component: "+cid.getName());
//			System.out.println("CleanupCommand: "+cid);
//			boolean shutdown = false;

//					System.out.println("CleanupCommand remove called for: "+cid);
			adapter = (IComponentAdapter)adapters.remove(cid);
			if(adapter==null)
				throw new RuntimeException("Component Identifier not registered: "+cid);
			
//				if(cid.getName().indexOf("Peer")==-1)
//					System.out.println("removed adapter: "+adapter.getComponentIdentifier().getLocalName()+" "+cid+" "+adapters);
			
			desc	= (CMSComponentDescription)adapter.getDescription();
			results = getComponentInstance(adapter).getResults();
			
//				desc.setState(IComponentDescription.STATE_TERMINATED);
//				ccs.remove(cid);
//				cfs.remove(cid);
			
			// Deregister destroyed component at parent.
			if(desc.getName().getParent()!=null)
			{
				// Stop execution of component. When root component services are already shutdowned.
				cancel(adapter);
//						exeservice.cancel(adapter);
				
				killparent = desc.getMaster()!=null && desc.getMaster().booleanValue();
				CMSComponentDescription padesc = (CMSComponentDescription)getDescription(desc.getName().getParent());
				if(padesc!=null)
				{
					padesc.removeChild(desc.getName());
					Boolean pas = padesc.getAutoShutdown();
					Boolean dae = desc.getDaemon();
//							if(pas!=null && pas.booleanValue() && (dae==null || !dae.booleanValue()))
					if(dae==null || !dae.booleanValue())
//							if(padesc.isAutoShutdown() && !desc.isDaemon())
					{
						Integer	childcount	= (Integer)childcounts.get(padesc.getName());
//								assert childcount!=null && childcount.intValue()>0;
						if(childcount!=null)
						{
							int cc = childcount.intValue()-1;
							if(cc>0)
								childcounts.put(padesc.getName(), new Integer(cc));
							else
								childcounts.remove(padesc.getName());
//									System.out.println("childcount-: "+padesc.getName()+" "+cc);
						}
						// todo: could fail when parent is still in init phase. 
						// Should test for init phase and remember that it has to be killed.
						killparent = killparent || (pas!=null && pas.booleanValue() 
							&& (childcount==null || childcount.intValue()<=1));
					}
				}
				pad	= (IComponentAdapter)adapters.get(desc.getName().getParent());
			}
			
			// Must be executed out of sync block due to deadlocks
			// agent->cleanupcommand->space.componentRemoved (holds adapter mon -> needs space mone)
			// space executor->general loop->distributed percepts->(holds space mon -> needs adapter mon for getting external access)
			if(pad!=null)
			{
				try
				{
					getComponentInstance(pad).componentDestroyed(desc);
				}
				catch(ComponentTerminatedException cte)
				{
					// Parent just killed: ignore.
				}
			}
			// else parent has just been killed.
			
			exitDestroy(cid, desc, exception, results);

			notifyListenersRemoved(cid, desc, results);
			
			// Use adapter exception before cleanup exception as it probably happened first.
			Exception	ex	= adapter.getException()!=null ? adapter.getException() : exception;
//			if(exceptions!=null && exceptions.containsKey(cid))
//			{
//				ex	= (Exception)exceptions.get(cid);
//				exceptions.remove(cid);
//			}
			IntermediateResultListener reslis = resultlisteners.remove(cid);
//			System.out.println("kill lis: "+cid+" "+reslis+" "+results+" "+ex);
			if(reslis!=null)	// null for platform.
			{
				if(ex!=null)
				{
					reslis.exceptionOccurred(ex);
				}
				else
				{
					reslis.finished();
	//					reslis.resultAvailable(results);
				}
			
				if(ex!=null && !reslis.isInitial())
				{
					// Unhandled component exception
					// Todo: delegate printing to parent component (if any).
					adapter.getLogger().severe("Fatal error, component '"+cid+"' will be removed.");
					ex.printStackTrace();
				}
			}
			
//			System.out.println("CleanupCommand end.");
			
			// Kill parent is autoshutdown or child was master.
			if(pad!=null && killparent)
			{
//				System.out.println("killparent: "+pad.getComponentIdentifier());
				destroyComponent(pad.getComponentIdentifier());
			}
		}
	}
	
	//-------- internal methods --------
	
	/**
	 *  Get the external access of a component.
	 *  @param cid The component identifier.
	 *  @param listener The result listener.
	 */
	public IFuture getExternalAccess(final IComponentIdentifier cid)
	{
		return getExternalAccess(cid, false);
	}
	
	/**
	 *  Get the external access of a component.
	 *  @param cid The component identifier.
	 *  @param listener The result listener.
	 */
	protected IFuture getExternalAccess(final IComponentIdentifier cid, boolean internal)
	{
//		System.out.println("getExternalAccess: "+this+", "+cid);
		final Future ret = new Future();
		
		if(cid==null)
		{
			ret.setException(new IllegalArgumentException("Identifier is null."));
			return ret;
		}
		
		if(isRemoteComponent(cid))
		{
//			System.out.println("getExternalAccess: remote");
			agent.getServiceContainer().searchService(IRemoteServiceManagementService.class, RequiredServiceInfo.SCOPE_PLATFORM)
				.addResultListener(new ExceptionDelegationResultListener(ret)
			{
				public void customResultAvailable(IRemoteServiceManagementService rms)
				{
					rms.getExternalAccessProxy(cid).addResultListener(new DelegationResultListener(ret));
				}
			});
	
	//		getRemoteCMS(cid).addResultListener(new ExceptionDelegationResultListener(ret)
	//		{
	//			public void customResultAvailable(IComponentManagementService rcms)
	//			{
	//				rcms.getExternalAccess(cid).addResultListener(new DelegationResultListener(ret));
	//			}
	//		});
		}
		else
		{
//			System.out.println("getExternalAccess: local");
			IComponentAdapter adapter = null;
//				System.out.println("getExternalAccess: adapters");
			boolean delayed = false;
			adapter = (IComponentAdapter)adapters.get(cid);
			
			if(adapter==null)
			{
				// Hack? Allows components to getExternalAccess in init phase
				InitInfo ii = getInitInfo(cid);
				if(ii!=null)
				{
//					if(!internal && (ii.getAdapter()==null || ii.getAdapter().isExternalThread())) // cannot work because of decoupling
					if(!internal && (ii.getAdapter()==null || !ServiceCall.getInstance().getCaller().equals(cid)))
					{
//							System.out.println("getExternalAccess: delayed");
						delayed = true;
						IFuture fut = ii.getInitFuture();
						fut.addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
						{
							public void customResultAvailable(Void result)
							{
								try
								{
									ret.setResult(getComponentInstance(getComponentAdapter(cid)).getExternalAccess());
								}
								catch(Exception e)
								{
									ret.setException(e);
								}
							}
						}));
					}
					else
					{
//							System.out.println("getExternalAccess: not delayed");
						adapter = ii.getAdapter();
					}
				}
			}
			
			if(adapter!=null)
			{
				try
				{
					ret.setResult(getComponentInstance(adapter).getExternalAccess());
				}
				catch(Exception e)
				{
					ret.setException(e);
				}
			}
			else if(!delayed)
			{
				ret.setException(new RuntimeException("No local component found for component identifier: "+cid));
			}
			
		}
		
		return ret;
	}
	
	/**
	 *  Find the class loader for a new (local) component.
	 *  Use parent component class loader for local parents
	 *  and current platform class loader for remote or no parents.
	 *  @param cid	The component id.
	 *  @return	The class loader.
	 */
	protected IFuture	getResourceIdentifier(final CreationInfo ci)
	{
		final Future	ret	= new Future();
		
		// User supplied resource identifier.
		if(ci!=null && ci.getResourceIdentifier()!=null)
		{
			ret.setResult(ci.getResourceIdentifier());
		}
		
		// Local parent //(but not platform -> platform now has valid rid).
		else if(ci!=null 
//			&& !ci.getParent().equals(root.getComponentIdentifier())
			&& (ci.getParent()==null || !isRemoteComponent(ci.getParent()))
//			&& !initinfos.containsKey(ci.getParent())	// does not work during init as external access is not available!?
//			&& !Boolean.TRUE.equals(ci.getPlatformloader()))
			)
		{
			getExternalAccess(ci.getParent()==null? root.getComponentIdentifier(): ci.getParent(), true)
				.addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
			{
				public void customResultAvailable(IExternalAccess ea)
				{
//					System.err.println("Model class loader: "+ea.getModel().getName()+", "+ea.getModel().getClassLoader());
//						classloadercache.put(ci.getParent(), ea.getModel().getClassLoader());
					ret.setResult(ea.getModel().getResourceIdentifier());
				}
			}));
		}
		
		// Remote or no parent or platform as parent
		else
		{
			// null resource identifier for searching in all current libservice resources.
			ret.setResult(null);
		}
		return ret;
	}

	
	/**
	 *  Get the component adapter for a component identifier.
	 *  @param aid The component identifier.
	 *  @param listener The result listener.
	 */
    // Todo: Hack!!! remove?
	public IComponentAdapter getComponentAdapter(IComponentIdentifier cid)
	{
		IComponentAdapter ret;
		ret = (IComponentAdapter)adapters.get(cid);
		// Hack, to retrieve description from component itself in init phase
		if(ret==null)
		{
			InitInfo ii= getInitInfo(cid);
			if(ii!=null)
				ret	= ii.getAdapter();
		}
		// Hack, to retrieve root adapter in bootstrapping phase.
		if(cid.equals(root.getComponentIdentifier()))
		{
			ret	= root;
		}
		return ret;
	}

	//-------- parent/child component accessors --------
	
	/**
	 *  Get the parent component of a component.
	 *  @param cid The component identifier.
	 *  @return The parent component identifier.
	 */
	public IComponentIdentifier getParentIdentifier(CreationInfo ci)
	{
		IComponentIdentifier rt = root.getComponentIdentifier();
		IComponentIdentifier ret = ci==null? rt: ci.getParent()==null? rt: ci.getParent(); 
//		System.out.println("parent id: "+ret);
		return ret;
	}
	
	/**
	 *  Get the parent component of a component.
	 *  @param cid The component identifier.
	 *  @return The parent component identifier.
	 */
	public IFuture getParent(final IComponentIdentifier cid)
	{
		final Future	ret	= new Future();
		
		if(isRemoteComponent(cid))
		{
			getRemoteCMS(cid).addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
			{
				public void customResultAvailable(IComponentManagementService rcms)
				{
					rcms.getParent(cid).addResultListener(createResultListener(new DelegationResultListener(ret)));
				}
			}));
		}
		else
		{
			CMSComponentDescription desc = (CMSComponentDescription)getDescription(cid);
			ret.setResult(desc!=null? desc.getName().getParent(): null);
		}
		return ret;
	}
	
	/**
	 *  Get the children components of a component.
	 *  @param cid The component identifier.
	 *  @return The children component identifiers.
	 */
	public IFuture getChildren(final IComponentIdentifier cid)
	{
		final Future	ret	= new Future();
		
		if(isRemoteComponent(cid))
		{
			getRemoteCMS(cid).addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
			{
				public void customResultAvailable(IComponentManagementService rcms)
				{
					rcms.getChildren(cid).addResultListener(createResultListener(new DelegationResultListener(ret)));
				}
				public void exceptionOccurred(Exception exception)
				{
					super.exceptionOccurred(exception);
				}
			}));
		}
		else
		{
	//		System.out.println("getChildren: "+this+" "+isValid());
			IComponentIdentifier[] tmp;
			CMSComponentDescription desc = (CMSComponentDescription)getDescription(cid);
//			System.out.println("desc: "+desc.getName()+" "+desc.hashCode());
			tmp = desc!=null? desc.getChildren()!=null? desc.getChildren(): 
			IComponentIdentifier.EMPTY_COMPONENTIDENTIFIERS: IComponentIdentifier.EMPTY_COMPONENTIDENTIFIERS;
//			System.out.println(getServiceIdentifier()+" "+desc.getName()+" "+SUtil.arrayToString(tmp));
			ret.setResult(tmp);
			
			// Nice style to check for valid?
	//		checkValid().addResultListener(new IResultListener()
	//		{
	//			public void resultAvailable(Object source, Object result)
	//			{
	//				CMSComponentDescription desc = (CMSComponentDescription)descs.get(cid);
	//				IComponentIdentifier[] tmp = desc!=null? desc.getChildren()!=null? desc.getChildren(): 
	//					IComponentIdentifier.EMPTY_COMPONENTIDENTIFIERS: IComponentIdentifier.EMPTY_COMPONENTIDENTIFIERS;
	//				ret.setResult(tmp);
	//			}
	//			
	//			public void exceptionOccurred(Object source, Exception exception)
	//			{
	//				ret.setException(exception);
	//			}
	//		});
		}
		
		return ret;
	}

	
	/**
	 *  Get the children components of a component.
	 *  @param cid The component identifier.
	 *  @return The children component descriptions.
	 */
	public IFuture getChildrenDescriptions(final IComponentIdentifier cid)
	{
		final Future	ret	= new Future();
		
		if(isRemoteComponent(cid))
		{
			getRemoteCMS(cid).addResultListener(createResultListener(
				new ExceptionDelegationResultListener(ret)
			{
				public void customResultAvailable(IComponentManagementService rcms)
				{
					rcms.getChildrenDescriptions(cid).addResultListener(createResultListener(new DelegationResultListener(ret)));
				}
				public void exceptionOccurred(Exception exception)
				{
					super.exceptionOccurred(exception);
				}
			}));
		}
		else
		{
			CMSComponentDescription desc = (CMSComponentDescription)getDescription(cid);
			IComponentIdentifier[] tmp = desc!=null? desc.getChildren()!=null? desc.getChildren(): 
				IComponentIdentifier.EMPTY_COMPONENTIDENTIFIERS: IComponentIdentifier.EMPTY_COMPONENTIDENTIFIERS;
			IComponentDescription[]	descs	= new IComponentDescription[tmp.length];
			for(int i=0; i getComponentDescription(final IComponentIdentifier cid)
	{
		final Future ret = new Future();
		
		if(isRemoteComponent(cid))
		{
			getRemoteCMS(cid).addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
			{
				public void customResultAvailable(IComponentManagementService rcms)
				{
					rcms.getComponentDescription(cid).addResultListener(createResultListener(new DelegationResultListener(ret)));
				}
			}));
		}
		else
		{
			if(msgservice==null)
			{
				CMSComponentDescription desc = (CMSComponentDescription)getDescription(cid);
				
				// Hack, to retrieve description from component itself in init phase
				if(desc==null)
				{
					InitInfo ii= getInitInfo(cid);
					if(ii!=null)
						desc = (CMSComponentDescription)ii.getDescription();
				}
				
				if(desc!=null)
				{
					// addresses required for communication across platforms.
					// ret.setName(refreshComponentIdentifier(aid));
//					desc.setName(rcid);
					desc = (CMSComponentDescription)((CMSComponentDescription)desc).clone();
				}
				
				if(desc!=null)
				{
					ret.setResult(desc);
				}
				else
				{
					ret.setException(new RuntimeException("No description available for: "+cid));
				}
			}
			else
			{
				msgservice.updateComponentIdentifier(cid).addResultListener(new ExceptionDelegationResultListener(ret)
				{
					public void customResultAvailable(IComponentIdentifier rcid)
					{
	//					System.out.println("desc: "+SUtil.arrayToString(rcid.getAddresses()));
						CMSComponentDescription desc = (CMSComponentDescription)getDescription(cid);
	
						// Hack, to retrieve description from component itself in init phase
						if(desc==null)
						{
							InitInfo ii= getInitInfo(cid);
							if(ii!=null)
								desc = (CMSComponentDescription)ii.getDescription();
						}
						
						if(desc!=null)
						{
							// addresses required for communication across platforms.
							// ret.setName(refreshComponentIdentifier(aid));
							desc.setName(rcid);
							desc = (CMSComponentDescription)((CMSComponentDescription)desc).clone();
						}
						
						if(desc!=null)
						{
							ret.setResult(desc);
						}
						else
						{
							ret.setException(new RuntimeException("No description available for: "+cid));
						}
					}
				});
			}
		}			
		
		return ret;
	}
	
	/**
	 *  Get the component descriptions.
	 *  @return The component descriptions.
	 */
	public IFuture getComponentDescriptions()
	{
		Future fut = new Future();
		
		IComponentDescription[] ret = new IComponentDescription[adapters.size()];
		int i=0;
		for(Iterator it=adapters.values().iterator(); i getComponentIdentifiers()
	{
		final Future fut = new Future();
		
		getAddresses().addResultListener(createResultListener(
			new ExceptionDelegationResultListener(fut)
		{
			public void customResultAvailable(String[] addresses)
			{
				IComponentIdentifier[] ret;
				
				ret = (IComponentIdentifier[])adapters.keySet().toArray(new IComponentIdentifier[adapters.size()]);
				
				if(ret.length>0)
				{
					if(!Arrays.equals(ret[0].getAddresses(), addresses))
					{
						// addresses required for inter-platform comm.
						for(int i=0; i getRootIdentifier()
	{
		return new Future(root.getComponentIdentifier());
	}
	
	/**
	 *  Search for components matching the given description.
	 *  @return An array of matching component descriptions.
	 */
	public IFuture searchComponents(IComponentDescription adesc, ISearchConstraints con)
	{
		return searchComponents(adesc, con, false);
	}
	
	/**
	 *  Search for components matching the given description.
	 *  @return An array of matching component descriptions.
	 */
	public IFuture searchComponents(final IComponentDescription adesc, final ISearchConstraints con, boolean remote)
	{
		final Future fut = new Future();
		
//		System.out.println("search: "+components);
		final List ret = new ArrayList();

		// If name is supplied, just lookup description.
		if(adesc!=null && adesc.getName()!=null)
		{
			CMSComponentDescription ad = (CMSComponentDescription)getDescription(adesc.getName());
			if(ad!=null && ad.getName().equals(adesc.getName()))
			{
				// Todo: addresses reuqired for interplatform comm.
//				ad.setName(refreshComponentIdentifier(ad.getName()));
				CMSComponentDescription	desc	= (CMSComponentDescription)ad.clone();
				ret.add(desc);
			}
		}

		// Otherwise search for matching descriptions.
		else
		{
			for(Iterator it=adapters.values().iterator(); it.hasNext(); )
			{
				CMSComponentDescription	test	= (CMSComponentDescription)((IComponentAdapter)it.next()).getDescription();
				if(adesc==null ||
					(adesc.getOwnership()==null || adesc.getOwnership().equals(test.getOwnership()))
//						&& (adesc.getName().getParent()==null || adesc.getName().getParent().equals(test.getParent()))
					&& (adesc.getType()==null || adesc.getType().equals(test.getType()))
					&& (adesc.getState()==null || adesc.getState().equals(test.getState()))
//						&& (adesc.getProcessingState()==null || adesc.getProcessingState().equals(test.getProcessingState()))
					&& (adesc.getModelName()==null || adesc.getModelName().equals(test.getModelName())))					
				{
					ret.add(test);
				}
			}
		}

		//System.out.println("searched: "+ret);
		
//		System.out.println("Started search: "+ret);
//		open.add(fut);
		if(remote)
		{
			IFuture> futi = SServiceProvider.getServices(agent.getServiceContainer(), IComponentManagementService.class, RequiredServiceInfo.SCOPE_GLOBAL);
			futi.addResultListener(createResultListener(new IResultListener>()
			{
				public void resultAvailable(Collection result)
				{
//					System.out.println("cms: "+coll);
					// Ignore search failures of remote dfs
					IResultListener lis = createResultListener(new CollectionResultListener(result.size(), true, 
						new IResultListener>()
					{
						public void resultAvailable(Collection result)
						{
							// Add all services of all remote dfs
							for(Iterator it=result.iterator(); it.hasNext(); )
							{
								IComponentDescription[] res = it.next();
								if(res!=null)
								{
									for(int i=0; i it=result.iterator(); it.hasNext(); )
					{
						IComponentManagementService remotecms = it.next();
						if(remotecms!=DecoupledComponentManagementService.this)
						{
							remotecms.searchComponents(adesc, con, false).addResultListener(lis);
						}
						else
						{
							lis.resultAvailable(null);
						}
					}
				}
				
				public void exceptionOccurred(Exception exception)
				{
//					open.remove(fut);
					fut.setResult((CMSComponentDescription[])ret.toArray(new CMSComponentDescription[ret.size()]));
				}
			}));
		}
		else
		{
//			open.remove(fut);
//			System.out.println("Local search: "+ret+" "+open);
			fut.setResult((CMSComponentDescription[])ret.toArray(new CMSComponentDescription[ret.size()]));
		}
		
		return fut;
	}
	
	/**
	 *  Create a component identifier that is allowed on the platform.
	 *  @param name The base name.
	 *  @return The component identifier.
	 */
	public IComponentIdentifier generateComponentIdentifier(String localname, String platformname, String[] addresses)
	{
		ComponentIdentifier ret = null;

		if(platformname==null)
			platformname = ((IComponentIdentifier)agent.getServiceContainer().getId()).getName();
		ret = new ComponentIdentifier(localname+"@"+platformname, addresses);
		
		if(uniqueids || adapters.containsKey(ret) || initinfos.containsKey(ret))
		{
			String key = localname+"@"+platformname;
			
			do
			{
				Integer cnt = cidcounts.get(key);
				if(cnt==null)
				{
					cidcounts.put(key, new Integer(new Integer(1)));
					ret = new ComponentIdentifier(localname+"@"+platformname, addresses);
				}
				else
				{
					cidcounts.put(key, new Integer(cnt.intValue()+1));
					ret = new ComponentIdentifier(localname+cnt+"@"+platformname, addresses); // Hack?!
				}
			}
			while(adapters.containsKey(ret) || initinfos.containsKey(ret));
		}
		
		return ret;
	}
	
	/**
	 *  Set the state of a component (i.e. update the component description).
	 *  Currently only switching between suspended/waiting is allowed.
	 */
	// hack???
	public void	setComponentState(IComponentIdentifier comp, String state)
	{
		assert IComponentDescription.STATE_SUSPENDED.equals(state) : "wrong state: "+comp+", "+state;
		
		CMSComponentDescription	desc	= null;
		desc	= (CMSComponentDescription)getDescription(comp);
		desc.setState(state);			
		
		notifyListenersChanged(comp, desc);
	}

	//-------- IService interface --------
	
	/**
	 *  Start the service.
	 *  @return A future that is done when the service has completed starting.  
	 */
	@ServiceStart
	public IFuture startService()
	{
		final Future	ret	= new Future();
		
		logger = agent.getLogger();
		componentfactory.startService(agent, sid.getResourceIdentifier()).addResultListener(new DelegationResultListener(ret)
		{
			public void customResultAvailable(Void result)
			{
				SServiceProvider.getService(agent.getServiceContainer(), IExecutionService.class, RequiredServiceInfo.SCOPE_PLATFORM)
				.addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
				{
					public void customResultAvailable(IExecutionService result)
					{
						exeservice	= result;
						
//						SServiceProvider.getService(agent.getServiceContainer(), IMarshalService.class, RequiredServiceInfo.SCOPE_PLATFORM)
//							.addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
//						{
//							public void customResultAvailable(IMarshalService result)
//							{
//								marshalservice	= result;
						
								SServiceProvider.getService(agent.getServiceContainer(), IMessageService.class, RequiredServiceInfo.SCOPE_PLATFORM)
									.addResultListener(createResultListener(new IResultListener()
								{
									public void resultAvailable(IMessageService result)
									{
										msgservice	= result;
										cont();
									}
									
									public void exceptionOccurred(Exception exception)
									{
										cont();
									}
									
									protected void cont()
									{
										SServiceProvider.getService(agent.getServiceContainer(), IClockService.class, RequiredServiceInfo.SCOPE_PLATFORM)
											.addResultListener(new ExceptionDelegationResultListener(ret)
										{
											public void customResultAvailable(IClockService result)
											{
												clockservice	= result;
										
												// add root adapter and register root component
												if(root!=null)
												{
													getAddresses().addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
													{
														public void customResultAvailable(String[] addresses)
														{
															((ComponentIdentifier)root.getComponentIdentifier()).setAddresses(addresses);
															adapters.put(root.getComponentIdentifier(), root);
															ret.setResult(null);
														}
													}));
												}
											}
										});	
									}
								}));
//							}
//						}));
					}
				}));
			}
		});
		
		return ret;
	}
	
	/**
	 *  Shutdown the service.
	 *  @return A future that is done when the service has completed its shutdown.  
	 */
	@ServiceShutdown
	public IFuture	shutdownService()
	{
//		System.out.println(": "+this);
//		this.adapters	= null;	// required for final cleanup command
//		this.ccs	= null;	// required for final cleanup command
//		this.cfs	= null;	// required for final cleanup command
//		this.logger	= null;	// required for final cleanup command
//		this.listeners	= null;	// required for final cleanup command
//		this.killresultlisteners	= null;	// required for final cleanup command
//		this.root	= null;	// required for final cleanup command
//		this.initinfos	= null;	// required for final cleanup command
		
		this.childcounts	= null;
		this.componentfactory	= null;
		this.exeservice	= null;
		this.agent	= null;
		this.factories	= null;
		this.localtypes	= null;
//		this.marshalservice	= null;
		this.msgservice	= null;
		
		/*final Future ret = new Future();
		final  long shutdowntime = 10000; // todo: shutdowntime and MAX_SHUTDOWM_TIME
		
		// Step 1: Find existing components.
		getComponentDescriptions().addResultListener(new IResultListener()
		{
			public void resultAvailable(Object source, Object result)
			{
				// Step 2: Kill existing components excepts daemons.
				final List comps = new ArrayList(Arrays.asList((IComponentDescription[])result));
				for(int i=comps.size()-1; i>-1; i--)
				{
					if(((CMSComponentDescription)comps.get(i)).isDaemon())
						comps.remove(i);
				}
				
				killComponents(comps, shutdowntime, new IResultListener()
				{
					public void resultAvailable(Object source, Object result)
					{
						// Step 3: Find remaining components.
						getComponentDescriptions().addResultListener(new IResultListener()
						{
							public void resultAvailable(Object source, Object result)
							{
								// Step 4: Kill remaining components.
								killComponents(Arrays.asList((IComponentDescription[])result), shutdowntime, new DelegationResultListener(ret));
							}

							public void exceptionOccurred(Object source, Exception exception)
							{
								ret.setException(exception);
							}
						});		
					}
					
					public void exceptionOccurred(Object source, Exception exception)
					{
						ret.setException(exception);
					}
				});
			}

			public void exceptionOccurred(Object source, Exception exception)
			{
				ret.setException(exception);
			}
		});
		
		return ret;*/
		return IFuture.DONE;
	}
	
	/**
	 *  Test if a component should be suspended after init is done.
	 *  @param cinfo	The creation info.
	 *  @param lmodel	The model of the component.
	 *  @return	True, if the component should be suspended
	 */
	protected boolean isInitSuspend(CreationInfo cinfo, IModelInfo lmodel)
	{
		boolean pasuspend = false;
		InitInfo painfo = getParentInfo(cinfo);
		
		// Parent also still in init.
		if(painfo!=null && painfo.getModel()!=null)
		{
			pasuspend	= isInitSuspend(painfo.getInfo(), painfo.getModel());
		}
		
		// Parent already running.
		else
		{
			CMSComponentDescription	padesc = (CMSComponentDescription)getDescription(getParentIdentifier(cinfo));
			pasuspend = IComponentDescription.STATE_SUSPENDED.equals(padesc.getState());
		}
		// Suspend when set to suspend or when parent is also suspended or when specified in model.
//		boolean	debugging = lmodel.getProperty("debugging")==null? false: ((Boolean)lmodel.getProperty("debugging")).booleanValue();
		boolean	debugging = lmodel.getSuspend(cinfo.getConfiguration())==null? false: lmodel.getSuspend(cinfo.getConfiguration()).booleanValue();
		boolean sus = cinfo.getSuspend()==null? false: cinfo.getSuspend().booleanValue();
		boolean	suspend	= sus || pasuspend || debugging;
		return suspend;
	}

//	/**
//	 *  Get the msgservice.
//	 *  @return the msgservice.
//	 */
//	public IMessageService getMessageService()
//	{
//		return msgservice;
//	}

	/**
	 *  Get the exeservice.
	 *  @return the exeservice.
	 */
	public IExecutionService getExecutionService()
	{
		return exeservice;
	}
	
	/**
	 *  Get the description for a component (if any).
	 */
	protected IComponentDescription	getDescription(IComponentIdentifier cid)
	{
		IComponentAdapter	adapter	= (IComponentAdapter)adapters.get(cid);
		// Hack? Allows components to getExternalAccess in init phase
		if(adapter==null)
		{
			InitInfo ii = getInitInfo(cid);
			if(ii!=null)
				adapter = ii.getAdapter();
		}
		return adapter!=null ? adapter.getDescription() : null;
	}
	
	//-------- service handling --------
	
	/**
	 *  Notify the cms listeners of a change.
	 */
	protected void notifyListenersChanged(final IComponentIdentifier cid, final IComponentDescription origdesc)
	{
		updateComponentDescription((CMSComponentDescription)origdesc).addResultListener(createResultListener(new DefaultResultListener()
		{
			public void resultAvailable(IComponentDescription newdesc)
			{
				ICMSComponentListener[]	alisteners;
				Set	slisteners	= new HashSet(listeners.getCollection(null));
				slisteners.addAll(listeners.getCollection(cid));
				alisteners	= (ICMSComponentListener[])slisteners.toArray(new ICMSComponentListener[slisteners.size()]);
				// todo: can be called after listener has (concurrently) deregistered
				
//				System.out.println("comp changed: "+desc+" "+listeners);
//				logger.info("Component changed: "+desc+" "+listeners);
				
				for(int i=0; i()
					{
						public void resultAvailable(Void result)
						{
						}
						
						public void exceptionOccurred(Exception exception)
						{
//							System.out.println("prob: "+exception);
							removeComponentListener(cid, lis);
						}
					}));
				}
			}
		}));
	}
	
	/**
	 *  Notify the cms listeners of a removal.
	 */
	protected void notifyListenersRemoved(final IComponentIdentifier cid, final IComponentDescription origdesc, final Map results)
	{
		updateComponentDescription((CMSComponentDescription)origdesc).addResultListener(createResultListener(new IResultListener()
		{
			public void resultAvailable(IComponentDescription newdesc)
			{
				ICMSComponentListener[]	alisteners;
				
				Set	slisteners	= new HashSet(listeners.getCollection(null));
				slisteners.addAll(listeners.getCollection(cid));
				alisteners	= (ICMSComponentListener[])slisteners.toArray(new ICMSComponentListener[slisteners.size()]);
				// todo: can be called after listener has (concurrently) deregistered
				
		//		System.out.println("comp changed: "+desc+" "+listeners);
		//		logger.info("Component changed: "+desc+" "+listeners);
				
				for(int i=0; i()
					{
						public void resultAvailable(Void result)
						{
						}
						
						public void exceptionOccurred(Exception exception)
						{
		//					System.out.println("prob: "+exception);
							removeComponentListener(cid, lis);
						}
					}));
				}
			}
			
			public void exceptionOccurred(Exception exception)
			{
				resultAvailable(origdesc);
			}
		}));
	}
	
	/**
	 *  Create result listener that tolerates when agent is null at shutdown.
	 */
	protected IResultListener createResultListener(IResultListener listener)
	{
		return agent==null? listener: agent.createResultListener(listener);
	}
	
	/**
	 *  Notify the cms listeners of an addition.
	 */
	protected void notifyListenersAdded(final IComponentIdentifier cid, final IComponentDescription origdesc)
	{
		updateComponentDescription((CMSComponentDescription)origdesc).addResultListener(createResultListener(new DefaultResultListener()
		{
			public void resultAvailable(IComponentDescription newdesc)
			{
				ICMSComponentListener[]	alisteners;
				Set	slisteners	= new HashSet(listeners.getCollection(null));
				slisteners.addAll(listeners.getCollection(cid));
				alisteners	= (ICMSComponentListener[])slisteners.toArray(new ICMSComponentListener[slisteners.size()]);
				// todo: can be called after listener has (concurrently) deregistered
				
		//		System.out.println("comp changed: "+desc+" "+listeners);
		//		logger.info("Component changed: "+desc+" "+listeners);
				
				for(int i=0; i()
					{
						public void resultAvailable(Void result)
						{
						}
						
						public void exceptionOccurred(Exception exception)
						{
		//					System.out.println("prob: "+exception);
							removeComponentListener(cid, lis);
						}
					}));
				}
			}
		}));
	}
	
	/**
	 *  Update a component description according to another one.
	 */
	protected IFuture updateComponentDescription(final CMSComponentDescription origdesc)
	{
		final Future ret = new Future();
		
		if(msgservice==null)
		{
			ret.setResult(origdesc);
		}
		else
		{
			msgservice.updateComponentIdentifier(origdesc.getName())
				.addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
			{
				public void customResultAvailable(IComponentIdentifier newcid)
				{
					CMSComponentDescription newdesc = (CMSComponentDescription)((CMSComponentDescription)origdesc).clone();
					newdesc.setName(newcid);
					ret.setResult(newdesc);
				}
			}));
		}
			
		return ret;
	}
	
	/**
	 *  Get the remote component management system for a specific component id.
	 */
	protected IFuture	getRemoteCMS(final IComponentIdentifier cid)
	{
		final Future	ret	= new Future();
		SServiceProvider.getService(agent.getServiceContainer(), IRemoteServiceManagementService.class, RequiredServiceInfo.SCOPE_PLATFORM)
			.addResultListener(createResultListener(new ExceptionDelegationResultListener(ret)
		{
			public void customResultAvailable(IRemoteServiceManagementService rms)
			{
				rms.getServiceProxy(cid, IComponentManagementService.class, RequiredServiceInfo.SCOPE_PLATFORM)
					.addResultListener(createResultListener(new DelegationResultListener(ret)));
			}
		}));
		return ret;
	}
	
	/**
	 *  Get the addresses.
	 */
	protected IFuture getAddresses()
	{
		if(msgservice!=null)
		{
			return msgservice.getAddresses();
		}
		else
		{
			return new Future((String[])null);
		}
	}
	
	/**
	 *  Get the init info for a component identifier.
	 */
	protected InitInfo getInitInfo(IComponentIdentifier cid)
	{
		return (InitInfo)initinfos.get(cid);
	}
	
	/**
	 *  Put an init info.
	 */
	protected void putInitInfo(IComponentIdentifier cid, InitInfo info)
	{
		initinfos.put(cid, info);
	}
	
	/**
	 *  Remove an init info.
	 */
	protected InitInfo removeInitInfo(IComponentIdentifier cid)
	{
		return (InitInfo)initinfos.remove(cid);
	}
	
	/**
	 *  Struct that stores information about initing components.
	 */
	static class InitInfo
	{
		//-------- attributes --------
		
		// 0: description, 1: adapter, 2: creation info, 3: model, 4: initfuture, 5: component instance
		
		/** The component description. */
		protected IComponentDescription description;
		
		/** The adapter. */
		protected IComponentAdapter adapter;
		
		/** The creation info. */
		protected CreationInfo info;
		
		/** The model. */
		protected IModelInfo model;
		
		/** The init future. */
		protected Future initfuture;
		
		/** The component instance. */
		protected IComponentInstance instance;

		//-------- constructors --------
		
		/**
		 *  Create a new init info.
		 */
		public InitInfo(IComponentDescription description,
			IComponentAdapter adapter, CreationInfo info, IModelInfo model,
			Future initfuture, IComponentInstance instance)
		{
			this.description = description;
			this.adapter = adapter;
			this.info = info;
			this.model = model;
			this.initfuture = initfuture;
			this.instance = instance;
		}

		//-------- methods --------
		
		/**
		 *  Get the description.
		 *  @return The description.
		 */
		public IComponentDescription getDescription()
		{
			return description;
		}

		/**
		 *  Set the description.
		 *  @param description The description to set.
		 */
		public void setDescription(IComponentDescription description)
		{
			this.description = description;
		}

		/**
		 *  Get the adapter.
		 *  @return The adapter.
		 */
		public IComponentAdapter getAdapter()
		{
			return adapter;
		}

		/**
		 *  Set the adapter.
		 *  @param adapter The adapter to set.
		 */
		public void setAdapter(IComponentAdapter adapter)
		{
			this.adapter = adapter;
		}

		/**
		 *  Get the info.
		 *  @return The info.
		 */
		public CreationInfo getInfo()
		{
			return info;
		}

		/**
		 *  Set the info.
		 *  @param info The info to set.
		 */
		public void setInfo(CreationInfo info)
		{
			this.info = info;
		}

		/**
		 *  Get the model.
		 *  @return The model.
		 */
		public IModelInfo getModel()
		{
			return model;
		}

		/**
		 *  Set the model.
		 *  @param model The model to set.
		 */
		public void setModel(IModelInfo model)
		{
			this.model = model;
		}

		/**
		 *  Get the initfuture.
		 *  @return The initfuture.
		 */
		public Future getInitFuture()
		{
			return initfuture;
		}

		/**
		 *  Set the initfuture.
		 *  @param initfuture The initfuture to set.
		 */
		public void setInitFuture(Future initfuture)
		{
			this.initfuture = initfuture;
		}

		/**
		 *  Get the instance.
		 *  @return The instance.
		 */
		public IComponentInstance getInstance()
		{
			return instance;
		}

		/**
		 *  Set the instance.
		 *  @param instance The instance to set.
		 */
		public void setInstance(IComponentInstance instance)
		{
			this.instance = instance;
		}
	}
	
	/**
	 *  Entry that represents a lock for a component.
	 *  Is used to lock the parent while a child is created.
	 */
	class LockEntry
	{
		//-------- attributes --------
		
		/** The locked component. */
		protected IComponentIdentifier locked;
		
		/** The components that have a lock. */
		protected Set lockers;
		
		/** The kill flag. */
		protected Future> killfuture;
		
		//-------- constructors --------
		
		/**
		 *  Create a new lock entry.
		 */
		public LockEntry(IComponentIdentifier locked)
		{
			this.locked = locked;
		}
		
		//-------- methods --------
		
		/**
		 *  Add a locker id.
		 *  @param locker The locker id.
		 */
		public void addLocker(String locker)
		{
			if(lockers==null)
				lockers = new HashSet();
			lockers.add(locker);
		}
		
		/**
		 *  Remove a locker id.
		 *  @param locker The locker id.
		 */
		public void removeLocker(String locker)
		{
			lockers.remove(locker);
			if(lockers.isEmpty() && killfuture!=null)
				destroyComponent(locked, killfuture);
		}
		
		/**
		 *  Get the locker count.
		 *  @return The number of lockers.
		 */
		public int getLockerCount()
		{
			return lockers==null? 0: lockers.size();
		}

		/**
		 *  Get the killfuture.
		 *  @return the killfuture.
		 */
		public Future> getKillFuture()
		{
			return killfuture;
		}

		/**
		 *  Set the killfuture.
		 *  @param killfuture The killfuture to set.
		 */
		public void setKillFuture(Future> killfuture)
		{
			this.killfuture = killfuture;
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy