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

jadex.bridge.component.impl.SubcomponentsComponentFeature Maven / Gradle / Ivy

Go to download

Jadex bridge is a base package for kernels and platforms, i.e., it is used by both and provides commonly used interfaces and classes for active components and their management.

There is a newer version: 4.0.267
Show newest version
package jadex.bridge.component.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import jadex.bridge.ComponentTerminatedException;
import jadex.bridge.IComponentIdentifier;
import jadex.bridge.IExternalAccess;
import jadex.bridge.IInternalAccess;
import jadex.bridge.ISearchConstraints;
import jadex.bridge.ImmediateComponentStep;
import jadex.bridge.component.ComponentCreationInfo;
import jadex.bridge.component.DependencyResolver;
import jadex.bridge.component.IComponentFeatureFactory;
import jadex.bridge.component.IExecutionFeature;
import jadex.bridge.component.IMonitoringComponentFeature;
import jadex.bridge.component.ISubcomponentsFeature;
import jadex.bridge.modelinfo.ComponentInstanceInfo;
import jadex.bridge.modelinfo.ConfigurationInfo;
import jadex.bridge.modelinfo.IModelInfo;
import jadex.bridge.modelinfo.SubcomponentTypeInfo;
import jadex.bridge.modelinfo.UnparsedExpression;
import jadex.bridge.service.RequiredServiceBinding;
import jadex.bridge.service.component.IRequiredServicesFeature;
import jadex.bridge.service.search.ServiceQuery;
import jadex.bridge.service.types.clock.IClockService;
import jadex.bridge.service.types.cms.CMSComponentDescription;
import jadex.bridge.service.types.cms.CMSStatusEvent;
import jadex.bridge.service.types.cms.CreationInfo;
import jadex.bridge.service.types.cms.IComponentDescription;
import jadex.bridge.service.types.cms.PlatformComponent;
import jadex.bridge.service.types.cms.SComponentManagementService;
import jadex.bridge.service.types.monitoring.IMonitoringService.PublishEventLevel;
import jadex.bridge.service.types.monitoring.IMonitoringService.PublishTarget;
import jadex.bridge.service.types.monitoring.MonitoringEvent;
import jadex.commons.MultiException;
import jadex.commons.SUtil;
import jadex.commons.Tuple2;
import jadex.commons.Tuple3;
import jadex.commons.collection.MultiCollection;
import jadex.commons.future.CollectionResultListener;
import jadex.commons.future.DelegationResultListener;
import jadex.commons.future.ExceptionDelegationResultListener;
import jadex.commons.future.Future;
import jadex.commons.future.FutureBarrier;
import jadex.commons.future.IFuture;
import jadex.commons.future.IIntermediateFuture;
import jadex.commons.future.IResultListener;
import jadex.commons.future.ISubscriptionIntermediateFuture;
import jadex.commons.future.IntermediateDefaultResultListener;
import jadex.commons.future.IntermediateDelegationResultListener;
import jadex.commons.future.IntermediateFuture;
import jadex.commons.future.SubscriptionIntermediateFuture;
import jadex.javaparser.SJavaParser;
import jadex.javaparser.SimpleValueFetcher;

/**
 *  This feature provides subcomponents.
 */
public class SubcomponentsComponentFeature extends AbstractComponentFeature implements ISubcomponentsFeature, IInternalSubcomponentsFeature
{
//	/** The number of children. */
//	protected int childcount;
	
	/** Debug flag. */
	protected boolean debug = false;
	
	/**
	 *  Create the feature.
	 */
	public SubcomponentsComponentFeature(IInternalAccess component, ComponentCreationInfo cinfo)
	{
		super(component, cinfo);
//		debug = Boolean.TRUE.equals(component.getArgument("debug"));
	}
	
	/**
	 *  Initialize the feature.
	 */
	public IFuture init()
	{
		final Future ret = new Future();
		
		if(component.getConfiguration()!=null)
		{
			ConfigurationInfo conf = component.getModel().getConfiguration(component.getConfiguration());
			final ComponentInstanceInfo[] components = conf.getComponentInstances();
			createInitialComponents(components).addResultListener(createResultListener(
				new ExceptionDelegationResultListener, Void>(ret)
			{
				public void customResultAvailable(List cids)
				{
					ret.setResult(null);
				}
			}));
		}
		else
		{
			ret.setResult(null);
		}
		
		return ret;
	}	
	
	/**
	 *  Check if the feature potentially executed user code in body.
	 *  Allows blocking operations in user bodies by using separate steps for each feature.
	 *  Non-user-body-features are directly executed for speed.
	 *  If unsure just return true. ;-)
	 */
	public boolean	hasUserBody()
	{
		return false;
	}
	
	/**
	 *  Get the file name of a component type.
	 *  @param ctype The component type.
	 *  @return The file name of this component type.
	 */
	public String getComponentFilename(final String ctype)
	{
		String ret = null;
		
		SubcomponentTypeInfo[] subcomps = getComponent().getModel().getSubcomponentTypes();
		for(int i=0; ret==null && i getFileName(String ctype)
	{
		return new Future(getComponentFilename(ctype));
	}
	
	/**
	 *  Get the local type name of this component as defined in the parent.
	 *  @return The type of this component type.
	 */
	public String getLocalType()
	{
		return getComponent().getDescription().getLocalType();
	}
	
	/**
	 *  Starts a new POJO-component.
	 *  
	 *  @param pojocomponent The pojo object used as component.
	 *  @return The id of the component and the results after the component has been killed.
	 */
	public IFuture addComponent(Object pojocomponent)
	{
		CreationInfo ci = new CreationInfo().setPojo(pojocomponent);
		return getComponent().createComponent(ci, null);
	}
	
	/**
	 *  Starts a new component.
	 *  
	 *  @param infos Start information.
	 *  @return The id of the component and the results after the component has been killed.
	 */
	public IFuture createComponent(CreationInfo info)
	{
		return getComponent().createComponent(info, null);
	}
	
	/**
	 *  Starts a new component while continuously receiving status events (create, result updates, termination).
	 *  
	 *  @param infos Start information.
	 *  @return Status events.
	 * /
	public ISubscriptionIntermediateFuture createComponentWithEvents(CreationInfo info)
	{
		final SubscriptionIntermediateDelegationFuture ret = new SubscriptionIntermediateDelegationFuture<>();
		
		final boolean keepsusp = Boolean.TRUE.equals(info.getSuspend());
		info.setSuspend(true);
		createComponent(info).addResultListener(new IResultListener()
		{
			public void resultAvailable(IExternalAccess result)
			{
				info.setSuspend(keepsusp);
				
				ISubscriptionIntermediateFuture fut = SComponentManagementService.listenToComponent(result.getId(), component);
				FutureFunctionality.connectDelegationFuture(ret, fut);
				
				if (!keepsusp)
					result.resumeComponent();
			}
			
			public void exceptionOccurred(Exception exception)
			{
				ret.setException(exception);
			}
		});
		
		SFuture.avoidCallTimeouts(ret, component);
		return ret;
	}*/
	
	
	public ISubscriptionIntermediateFuture createComponentWithEvents(CreationInfo info)
	{
		try
		{
			info = PlatformComponent.prepare(info);
		}
		catch(Exception e)
		{
			return new SubscriptionIntermediateFuture<>(e);
		}
		
		return SComponentManagementService.createComponent(info, info.getName(), info.getFilename(), getInternalAccess());
	}
	
	/**
	 *  Starts a set of new components, in order of dependencies.
	 *  
	 *  @param infos Start information.
	 *  @return The id of the component and the results after the component has been killed.
	 */
	public IIntermediateFuture createComponents(final CreationInfo... infos)
	{
		if (infos == null || infos.length == 0)
			return new IntermediateFuture<>(new IllegalArgumentException("Creation infos must not be null or empty."));
		FutureBarrier>> modelbar = new FutureBarrier<>();
		
		if(debug)
			System.out.println("createComponents: " + component + " " + Arrays.toString(infos));
		
		final Map>>> tmpmodelmap = new HashMap<>();
		for (int i = 0; i < infos.length; ++i)
		{
			IFuture>> fut = 
				SComponentManagementService.loadModel(infos[i].getFilename(), infos[i], component);
			tmpmodelmap.put(i, fut);
			modelbar.addFuture(fut);
		}
		
		final IntermediateFuture ret = new IntermediateFuture<>();
		
		modelbar.waitFor().addResultListener(new IResultListener()
		{
			public void exceptionOccurred(Exception exception)
			{
				ret.setException(exception);
			}
			
			public void resultAvailable(Void result)
			{
				List> sysinfos = null;
				List> userinfos = new ArrayList<>();
				
				for(int i = 0; i < infos.length; ++i)
				{
					IModelInfo model = tmpmodelmap.get(i).get().getFirstEntity();
					
//					if (isSystemComponent(model))
					if (SComponentManagementService.isSystemComponent(model, infos[i], component.getId()))
					{
						if (sysinfos == null)
							sysinfos = new ArrayList<>();
						sysinfos.add(new Tuple2(infos[i], model));
						continue;
					}
					
					userinfos.add(new Tuple2(infos[i], model));
				}
				
				if(debug)
				{
					System.out.println(component + " starting system subcomponents: " + (sysinfos == null ? "[]" : Arrays.toString(sysinfos.toArray())));
					System.out.println(component + " starting user subcomponents: " + Arrays.toString(userinfos.toArray()));
				}
				
				if(sysinfos != null)
				{
					if(!component.getDescription().isSystemComponent())
					{
						ret.setException(new IllegalArgumentException(component.toString() + " attempted to start system component without being a system component."));
						return;
					}
					
					doCreateComponents(sysinfos).addResultListener(new IntermediateDefaultResultListener()
					{
						public void intermediateResultAvailable(IExternalAccess result)
						{
							ret.addIntermediateResult(result);
						};
						
						public void finished()
						{
							if (userinfos.size() > 0)
								doCreateComponents(userinfos).addResultListener(new IntermediateDelegationResultListener<>(ret));
							else
								ret.setFinished();
						}
						
						public void exceptionOccurred(Exception exception)
						{
							ret.setException(exception);
						}
					});
				}
				else
				{
					if(userinfos.size() > 0)
						doCreateComponents(userinfos).addResultListener(new IntermediateDelegationResultListener<>(ret));
					else
						ret.setFinished();
				}
			}
		});
		return ret;
	}
	
	/**
	 *  Stops a set of components, in order of dependencies.
	 *  
	 *  @param cids The component identifiers.
	 *  @return The id of the component and the results after the component has been killed.
	 */
	public IIntermediateFuture>> killComponents(IComponentIdentifier... cids)
	{
		if(cids == null || cids.length == 0)
			return new IntermediateFuture>>(new IllegalArgumentException("Component identifiers must not be null or empty."));
		
//		boolean subsonly = true;
//		for (IComponentIdentifier cid : cids)
//		{
//			if (!component.getId().equals(cid.getParent()))
//				subsonly = false;
//		}
//		if (subsonly)
//			return killLocalComponents(cids);
		
		final IntermediateFuture>> ret = new IntermediateFuture<>(); 
		
		final List exceptions = new ArrayList<>();
		boolean suicide = false;
		Set killset = new HashSet<>(Arrays.asList(cids));
		Map> killparents = new HashMap<>();
		
		// Enable debug on parent, if any child is in debug set.
		debug	= debug | killset.stream().anyMatch(cid -> 
		{
			IComponentDescription	child	= SComponentManagementService.internalGetComponentDescription(cid);
			return child!=null && PlatformComponent._BROKEN.contains(child.getModelName());
		});
		
		if(debug)
		{
			component.getLogger().severe("Killing subcomponents0: "+component+", "+killset);
			ret.addResultListener(new IResultListener>>>()
			{
				@Override
				public void resultAvailable(Collection>> result)
				{
					component.getLogger().severe("Killing subcomponents0a done: "+component);
				}
				@Override
				public void exceptionOccurred(Exception exception)
				{
					component.getLogger().severe("Killing subcomponents0b failed: "+component+"\n"+SUtil.getExceptionStacktrace(exception));
				}
			});
		}
		
		idloop:
		for(IComponentIdentifier cid : cids)
		{
			IComponentIdentifier parent = cid.getParent();
			while (parent != null)
			{
				if (killset.contains(parent))
					continue idloop;
				parent = parent.getParent();
			}
			
			if(component.getId().equals(cid))
			{
				suicide = true;
				continue;
			}
			
			IComponentIdentifier kp = cid.getParent();
			if(kp == null)
				kp = cid;
			Set kpset = killparents.get(kp);
			if (kpset == null)
			{
				kpset = new LinkedHashSet<>();
				killparents.put(kp, kpset);
			}
			kpset.add(cid);
		}
		
		Set locals = killparents.remove(component.getId());
		if (suicide)
			locals = null;
		
		FutureBarrier compkillbar = new FutureBarrier<>();
		for(Map.Entry> entry : killparents.entrySet())
		{
			if(entry.getValue().size() > 0)
			{
				IExternalAccess exta = component.getExternalAccess(entry.getKey());
				Future donefut = new Future<>();
				compkillbar.addFuture(donefut);
				
				if(debug)
				{
					component.getLogger().severe("Killing subcomponents1: "+component+", "+entry.getValue());
				}

				exta.killComponents(entry.getValue().toArray(new IComponentIdentifier[entry.getValue().size()])).addResultListener(new IntermediateDefaultResultListener>>()
				{
					public void exceptionOccurred(Exception exception)
					{
						if(debug)
						{
							component.getLogger().severe("Killing subcomponents2 failed: "+component+", "+entry.getValue()+"\n"+SUtil.getExceptionStacktrace(exception));
						}
						if (exception instanceof MultiException)
							exceptions.addAll(Arrays.asList(((MultiException)exception).getCauses()));
						else
							exceptions.add(exception);
						donefut.setResult(null);
					}
					
					public void intermediateResultAvailable(Tuple2> result)
					{
						if(debug)
						{
							component.getLogger().severe("Killing subcomponents3: "+component+", "+entry.getValue()+", killed: "+result.getFirstEntity());
						}
						ret.addIntermediateResult(result);
					}
					
					public void finished()
					{
						if(debug)
						{
							component.getLogger().severe("Killing subcomponents4 finished: "+component+", "+entry.getValue());
						}
						donefut.setResult(null);
					}
				});
			}
		}
		
		if(locals != null)
		{
			Future donefut = new Future<>();
			compkillbar.addFuture(donefut);
			
			if(debug)
			{
				component.getLogger().severe("Killing subcomponents5 locals: "+component+", "+locals);
				donefut.addResultListener(new IResultListener()
				{
					@Override
					public void resultAvailable(Void result)
					{
						component.getLogger().severe("Killing subcomponents5a locals done: "+component+", "+exceptions);
					}
					@Override
					public void exceptionOccurred(Exception exception)
					{
						component.getLogger().severe("Killing subcomponents5b locals failed: "+component+"\n"+SUtil.getExceptionStacktrace(exception));
					}
				});
			}

			killLocalComponents(locals.toArray(new IComponentIdentifier[locals.size()])).addResultListener(new IntermediateDefaultResultListener>>()
			{
				public void exceptionOccurred(Exception exception)
				{
					if(debug)
					{
						component.getLogger().severe("Killing subcomponents5c locals failed: "+component+"\n"+SUtil.getExceptionStacktrace(exception));
					}

					if(exception instanceof MultiException)
						exceptions.addAll(Arrays.asList(((MultiException)exception).getCauses()));
					else
						exceptions.add(exception);
					donefut.setResult(null);
				}
				
				public void intermediateResultAvailable(Tuple2> result)
				{
					ret.addIntermediateResult(result);
				}
				
				public void finished()
				{
					donefut.setResult(null);
				}
			});
		}
		
		if(suicide)
		{
			Future donefut = new Future<>();
			compkillbar.addFuture(donefut);
			component.killComponent().addResultListener(new IResultListener>()
			{
				public void resultAvailable(Map result)
				{
					ret.addIntermediateResult(new Tuple2>(component.getId(), result));
					donefut.setResult(null);
				}
				public void exceptionOccurred(Exception exception)
				{
					if (exception instanceof MultiException)
						exceptions.addAll(Arrays.asList(((MultiException)exception).getCauses()));
					else
						exceptions.add(exception);
					donefut.setResult(null);
				}
			});
		}
		
		compkillbar.waitFor().addResultListener(new IResultListener()
		{
			public void resultAvailable(Void result)
			{
				if(exceptions.size() > 0)
					ret.setException(new MultiException(exceptions));
				else
					ret.setFinished();
			}
			
			public void exceptionOccurred(Exception exception)
			{
			}
		});
		
		return ret;
	}
	
//	/**
//	 *  Starts a new child as subcomponent.
//	 *  
//	 *  @param infos Start information.
//	 *  @return The id of the component and the results after the component has been killed.
//	 */
//	public IFuture createChild(CreationInfo info)
//	{
//		if (info.getParent() != null && !component.getId().equals(info.getParent()))
//			return new Future<>(new IllegalArgumentException("Subcomponent cannot be created if parent is specified: " + info + ", specified parent " + info.getParent()));
//		
//		info.setParent(component.getId());
//		return component.createComponent(info, null);
//	}
	
	protected IIntermediateFuture doCreateComponents(List> infos)
	{
		final IntermediateFuture ret = new IntermediateFuture<>();
		
		DependencyResolver dr = new DependencyResolver<>();
		final MultiCollection instances = new MultiCollection<>();
		
//		boolean lineardeps = true;
//		for (Tuple2 tup : infos)
//		{
//			IModelInfo model = tup.getSecondEntity();
//			if (!SUtil.arrayEmptyOrNull(model.getPredecessors()) ||
//				!SUtil.arrayEmptyOrNull(model.getSuccessors()))
//			{
//				lineardeps = false;
//				break;
//			}
//		}
		boolean lineardeps = false;
		
		if(debug)
			System.out.println("Starting subcomponent set for " + component + " uses linear dependencies: " + lineardeps);
		
//		for (Map.Entry>>> entry : modelmap.entrySet())
		for(int i = 0; i < infos.size(); ++i)
		{
			String[] prevdep = lineardeps && i > 0 ? new String[] { infos.get(i - 1).getSecondEntity().getFullName() } : null;
			addComponentToLevels(dr, infos.get(i).getFirstEntity(), infos.get(i).getSecondEntity(), instances, prevdep);
		}
		
		final List> levels = dr.resolveDependenciesWithLevel();
		
		int[] levelnum = new int[1];
		levelnum[0] = -1;
//		System.out.println("LEVELS " + levels.size());
//		int iii = 0;
//		for (Set level : levels)
//		{
//			System.out.println("Level " + iii + ": " + Arrays.toString(level.toArray()));
//			++iii;
//		}
		IResultListener levelrl = new IResultListener()
		{
			public void exceptionOccurred(Exception exception)
			{
				ret.setExceptionIfUndone(exception);
			}
			
			public void resultAvailable(Void result)
			{
//				if (levels.size() > 1)
//				{
//					System.out.println("LEVELS: " + Arrays.toString(levels.toArray()));
//					for (Set level : levels)
//						System.out.println(Arrays.toString(level.toArray()));
//					System.out.println("################### WARNING: MORE THAN ONE LEVEL ####################");
//					SUtil.sleep(2000);
//				}
				++levelnum[0];
				if (levelnum[0] < levels.size())
				{
					FutureBarrier levelbar = new FutureBarrier<>();
					Set level = levels.get(levelnum[0]);
					for (String mname : level)
					{
						Collection insts = instances.get(mname);
						if (insts != null)
						{
							for (CreationInfo inst : insts)
							{
								IFuture createfut = createComponent(inst);
								levelbar.addFuture(createfut);
								createfut.addResultListener(new IResultListener()
								{
									public void exceptionOccurred(Exception exception)
									{
										ret.setExceptionIfUndone(exception);
									}
									
									public void resultAvailable(IExternalAccess result)
									{
										if (debug)
											System.out.println("Started: " + result);
										ret.addIntermediateResultIfUndone(result);
									};
								});
							}
						}
						else if (debug)
						{
							System.out.println("Skipping unresolvable dependency: " + mname);
						}
					}
					levelbar.waitFor().addResultListener(this);
				}
				else
				{
					if (!ret.isDone())
						ret.setFinished();
				}
			}
		};
		levelrl.resultAvailable(null);
		
		return ret;
	}
	
	/**
	 *  Stops a set of components, in order of dependencies.
	 *  
	 *  @param cids The component identifiers.
	 *  @return The id of the component and the results after the component has been killed.
	 */
	protected IIntermediateFuture>> killLocalComponents(IComponentIdentifier... cids)
	{
		if (cids == null || cids.length == 0)
			return new IntermediateFuture>>(new IllegalArgumentException("Component identifiers must not be null or empty."));
		
		try
		{
			debug	= debug | Arrays.asList(cids).stream().anyMatch(id ->
				SComponentManagementService.internalGetComponentDescription(id)!=null
				&& PlatformComponent._BROKEN.contains(SComponentManagementService.internalGetComponentDescription(id).getModelName()));
			
			if(debug)
			{
				component.getLogger().severe("killLocalComponents00: "+component+", "+SUtil.arrayToString(cids));			
			}
		}
		catch(Throwable e)
		{
			debug	= true;
			component.getLogger().severe("killLocalComponents00a: "+component+", "+SUtil.arrayToString(cids)+"\n"+SUtil.getExceptionStacktrace(e));			
		}
		
		final IntermediateFuture>> ret = new IntermediateFuture<>(); 
		
		final List sysinfos = new ArrayList<>();
		final List userinfos = new ArrayList<>();
		
		for (int i = 0; i < cids.length; ++i)
		{
			IComponentDescription	desc	= SComponentManagementService.getDescription(cids[i]);
			if(desc!=null && desc.isSystemComponent())
			{
				sysinfos.add(cids[i]);
			}
			else if(desc!=null)
			{
				userinfos.add(cids[i]);
			}
			// else ignore when component already terminated
		}
		
		if (userinfos.size() > 0)
		{
			if(debug)
			{
				component.getLogger().severe("killLocalComponents0 user " + component+ ", " + userinfos);						
			}
			
			doKillComponents(userinfos).addResultListener(new IntermediateDefaultResultListener>>()
			{
				public void intermediateResultAvailable(Tuple2> result)
				{
					ret.addIntermediateResult(result);
				}
				
				public void exceptionOccurred(Exception exception)
				{
					if(debug)
					{
						component.getLogger().severe("User kill failed: "+component+"\n"+SUtil.getExceptionStacktrace(exception));
					}
					ret.setException(exception);
				}
				
				public void finished()
				{
					if(debug)
					{
						component.getLogger().severe("User kill done, killing sysagents..." + sysinfos.size());						
					}
					if (!ret.isDone())
					{
						if (sysinfos.size() > 0)
							doKillComponents(sysinfos).addResultListener(new IntermediateDelegationResultListener<>(ret));
						else
							ret.setFinished();
					}
				}
			});
		}
		else
		{
			if (sysinfos.size() > 0)
				doKillComponents(sysinfos).addResultListener(new IntermediateDelegationResultListener<>(ret));
			else
				ret.setFinished();
		}
		
		return ret;
	}
	
	protected IIntermediateFuture>> doKillComponents(List cids)
	{
		final IntermediateFuture>> ret = new IntermediateFuture<>();
		
		final MultiCollection instances = new MultiCollection<>();
		
		getShutdownLevels(instances, cids).addResultListener(new IResultListener>>()
		{
			public void resultAvailable(List> levels)
			{
				int[] levelnum = new int[1];
				levelnum[0] = -1;
				
				IResultListener levelrl = new IResultListener()
				{
					public void exceptionOccurred(Exception exception)
					{
						ret.setExceptionIfUndone(exception);
					}
					
					public void resultAvailable(Void result)
					{
						++levelnum[0];

						final List exceptions = new ArrayList<>();
						if (levelnum[0] < levels.size())
						{
							FutureBarrier> levelbar = new FutureBarrier<>();
							Set level = levels.get(levelnum[0]);
							for (String mname : level)
							{
								
								Collection insts = instances.get(mname);
								if (insts != null)
								{
									for (IComponentIdentifier inst : insts)
									{
										IFuture> killfut = null;
										IExternalAccess tmpexta = null;
										try
										{
											tmpexta = SComponentManagementService.getExternalAccess(inst, component);
										}
										catch (Exception e)
										{
											exceptions.add(e);
											continue;
										}
										final IExternalAccess exta = tmpexta;
										if (exta != null)
										{
											if(debug)
											{
												component.getLogger().severe("doKillComponents2: start kill: " + inst+", "+IComponentIdentifier.LOCAL.get());
											}
											
											try
											{
												killfut = exta.killComponent();
											}
											catch(ComponentTerminatedException e)
											{
												// ignore
												if(debug)
												{
													component.getLogger().severe("doKillComponents2a: kill failed: " + inst+"\n"+SUtil.getExceptionStacktrace(e));
												}
											}
										}
										
										if(killfut!=null)
										{
											// Copy future to filter out ComponentTerminatedException
											Future> killfut2 = new Future>();
											levelbar.addFuture(killfut2);
											
											killfut.addResultListener(new IResultListener>()
											{
												public void exceptionOccurred(Exception exception)
												{
													// Ignore if already killed from outside during parent shutdown in progress
													if(exception instanceof ComponentTerminatedException)
													{
														killfut2.setResult(null);
													}
													else
													{
														if(debug)
														{
															component.getLogger().severe("doKillComponents3: kill failed: " + inst+"\n"+SUtil.getExceptionStacktrace(exception));
														}
														exceptions.add(exception);
														killfut2.setException(exception);
													}
												}
												
												public void resultAvailable(Map result)
												{
													killfut2.setResult(result);
													if(debug)
													{
														component.getLogger().severe("doKillComponents4: kill succeedeed: " + inst);
													}
													ret.addIntermediateResultIfUndone(new Tuple2>(inst, result));
												};
											});
										}
									}
								}
							}
							levelbar.waitFor().addResultListener(this);
						}
						else
						{
							if (!ret.isDone())
							{
								if (exceptions.size() > 0)
									ret.setException(new MultiException(exceptions));
								else
									ret.setFinished();
							}
						}
					}
				};
				levelrl.resultAvailable(null);
			}
			public void exceptionOccurred(Exception exception)
			{
				ret.setExceptionIfUndone(exception);
			}
		});
		
		return ret;
	}
	
	/**
	 *  Gets the ordered shutdown levels for a number of components.
	 *  
	 *  @param instances Empty lookup map type->instance (will be filled by the method.
	 *  @param cids The component identifiers.
	 *  @return Levels containing types defining shutdown order.
	 */
	protected IFuture>> getShutdownLevels(final MultiCollection instances, List cids)
	{
		try		{
			
		if(debug)
		{
			component.getLogger().severe("getShutdownLevels0: "+instances+", "+cids);
		}
		
		if (cids == null || cids.size() == 0)
			return new Future>>(new IllegalArgumentException("Component identifiers must not be null or empty."));
		
		final Future>> ret = new Future<>();
		
		FutureBarrier modelbar = new FutureBarrier<>();
		
		final Map> modelmap = new HashMap<>();
		for (int i = 0; i < cids.size(); ++i)
		{
			if(debug)
			{
				component.getLogger().severe("getShutdownLevels1: getModelAsync0 "+component+", "+i);
			}
			try
			{
				IExternalAccess exta = component.getExternalAccess(cids.get(i));
				IFuture fut = exta.getModelAsync();
				modelmap.put(i, fut);
				modelbar.addFuture(fut);
				if(debug)
				{
					component.getLogger().severe("getShutdownLevels1: getModelAsync1 "+component+", "+exta);
				}
			}
			catch(Exception e)
			{
				// Ignore when component killed itself in mean time.
				if(debug)
				{
					component.getLogger().severe("getShutdownLevels1a: getModelAsync1 failed "+component+"\n"+SUtil.getExceptionStacktrace(e));
				}
			}
		}
		
		modelbar.waitFor().addResultListener(new ExceptionDelegationResultListener>>(ret)
		{
			public void customResultAvailable(Void result)
			{
				if(debug)
				{
					component.getLogger().severe("getShutdownLevels2: getModelAsync done "+component);
				}
//				boolean lineardeps = true;
//				for (Map.Entry> entry : modelmap.entrySet())
//				{
//					IModelInfo model = entry.getValue().get();
//					if (!SUtil.arrayEmptyOrNull(model.getPredecessors()) ||
//						!SUtil.arrayEmptyOrNull(model.getSuccessors()))
//					{
//						lineardeps = false;
//						break;
//					}
//				}
				boolean lineardeps = false;
				
				DependencyResolver dr = new DependencyResolver<>();
				
				IModelInfo prev = null;
				for (Map.Entry> entry : modelmap.entrySet())
				{
					String[] prevdep = lineardeps && prev != null ? new String[] { prev.getFullName() } : null;
					try
					{
						addComponentToLevels(dr, cids.get(entry.getKey()), entry.getValue().get(), instances, prevdep);
					}
					catch (Exception e)
					{
						ret.setException(e);
						return;
					}
					prev = entry.getValue().get();
				}
				
				List> levels = dr.resolveDependenciesWithLevel();
				Collections.reverse(levels);
				ret.setResult(levels);
			}
		});
		return ret;
		
		}
		catch(Throwable t)
		{
//			if(debug)
			{
				component.getLogger().severe("getShutdownLevelsO: failed "+component+"\n"+SUtil.getExceptionStacktrace(t));
			}
			throw SUtil.throwUnchecked(t);
		}
	}
	
	/**
	 *  Create the initial subcomponents.
	 */
	protected IFuture> createInitialComponents(final ComponentInstanceInfo[] components)
	{
//		System.out.println("create subcompos: ");
//		for(ComponentInstanceInfo cii: components)
//		{
//			System.out.println(cii.getName()+" "+cii.getTypeName());
//		}
		
		final Future res = new Future();
		final List cinfos = new ArrayList();
//		IComponentManagementService cms = getComponent().getFeature(IRequiredServicesFeature.class).getLocalService(new ServiceQuery<>(IComponentManagementService.class));
		// NOTE: in current implementation application waits for subcomponents
		// to be finished and cms implements a hack to get the external
		// access of an uninited parent.
		
		// (NOTE1: parent cannot wait for subcomponents to be all created
		// before setting itself inited=true, because subcomponents need
		// the parent external access.)
		
		// (NOTE2: subcomponents must be created one by one as they
		// might depend on each other (e.g. bdi factory must be there for jcc)).
		
//		createInitialComponent(components, component.getModel(), 0, res, cids);
		createInitialCreationInfos(components, component.getModel(), 0, res, cinfos);
		
		final Future> ret = new Future>();
		res.addResultListener(new ExceptionDelegationResultListener>(ret)
		{
			public void customResultAvailable(Void result)
			{
				if (cinfos != null && !cinfos.isEmpty())
				{
					createComponents(cinfos.toArray(new CreationInfo[cinfos.size()])).addResultListener(new ExceptionDelegationResultListener, List>(ret)
					{
						public void customResultAvailable(Collection result)
						{
							List cids = new ArrayList<>();
							for (IExternalAccess exta : SUtil.notNull(result))
								cids.add(exta.getId());
							ret.setResult(cids);
						}
					});
				}
				else
				{
					ret.setResult(null);
				}
				
			}
		});
		
		return ret;
	}
	
	/**
	 * Search for components matching the given description.
	 * @return An array of matching component descriptions.
	 */
	public IFuture searchComponents(IComponentDescription adesc, ISearchConstraints con)
	{
		return getComponent().searchComponents(adesc, con);
	}
	
	/**
	 *  Create a subcomponent.
	 *  @param component The instance info.
	 */
//	public IFuture createChild(final ComponentInstanceInfo component)
//	{
//		final Future ret = new Future();
//		createComponents(new ComponentInstanceInfo[]{component}).addResultListener(createResultListener(
//			new ExceptionDelegationResultListener, IComponentIdentifier>(ret)
//			{
//				public void customResultAvailable(List cids)
//				{
//					ret.setResult(cids.get(0));
//				}
//			}));
//		return ret;
//	}
	
	/**
	 *  Create initial subcomponents.
	 */
	protected void	createInitialCreationInfos(final ComponentInstanceInfo[] components, final IModelInfo model, final int i, final Future fut, final List cinfos)
	{
		if(i0)
//				System.out.println("create comp: "+components[i].getName());
			
			IResultListener crl = new CollectionResultListener(num, false, 
				component.getFeature(IExecutionFeature.class).createResultListener(new ExceptionDelegationResultListener, Void>(fut)
			{
				public void customResultAvailable(Collection result)
				{
//					if(num>0)
//						System.out.println("created comp: "+components[i].getName());
					cinfos.addAll(result);
					createInitialCreationInfos(components, model, i+1, fut, cinfos);
				}
			}));
			for(int j=0; j()
//					{
//						public void resultAvailable(IExternalAccess result) 
//						{
//							crl.resultAvailable(result.getId());
//						}
//						
//						public void exceptionOccurred(Exception exception)
//						{
//							crl.exceptionOccurred(exception);
//						}
//					});
//					cms.createComponent(getName(components[i], model, j+1), getFilename(components[i], model),
//						new CreationInfo(components[i].getConfiguration(), getArguments(components[i], model), component.getId(),
//						suspend, master, daemon, autoshutdown, synchronous, persistable, monitoring, model.getAllImports(), bindings, null),
//						null).addResultListener(crl);
				}
				else
				{
					crl.exceptionOccurred(new RuntimeException("No such component type: "+components[i].getTypeName()));
				}
			}
		}
		else
		{
			fut.setResult(null);
		}
	}
	
	/**
	 *  Get the number of components to start.
	 *  Allows filename to be dynamically evaluated.
	 *  @return The number.
	 */
	protected String getFilename(ComponentInstanceInfo component, IModelInfo model)
	{
		String ret = null;
		SubcomponentTypeInfo si = component.getType(model);
		
		ret = (String)SJavaParser.evaluateExpressionPotentially(si.getFilename(), model.getAllImports(), this.component.getFetcher(), this.component.getClassLoader());
		
//		if(si.getFilename()!=null && si.getFilename().startsWith("%{"))
//		{
//			try
//			{
//				ret = (String)SJavaParser.evaluateExpression(si.getFilename().substring(2, si.getFilename().length()-1), model.getAllImports(), this.component.getFetcher(), this.component.getClassLoader());
//			}
//			catch(Exception e)
//			{
//				ret = si.getFilename();
//			}
//		}
//		else
//		{
//			ret	= si.getFilename();
//		}
		return ret;
	}
	
	/**
	 *  Get the number of components to start.
	 *  @return The number.
	 */
	protected int getNumber(ComponentInstanceInfo component, IModelInfo model)
	{
		Object ret = component.getNumber()!=null? SJavaParser.evaluateExpression(component.getNumber(), model.getAllImports(), this.component.getFetcher(), this.component.getClassLoader()): null;
		return ret instanceof Integer? ((Integer)ret).intValue(): 1;
	}
	
	/**
	 *  Get the name of components to start.
	 *  @return The name.
	 */
	protected String getName(ComponentInstanceInfo component, IModelInfo model, int cnt)
	{
		String ret = component.getName();
		if(ret!=null)
		{
			SimpleValueFetcher fetcher = new SimpleValueFetcher(this.component.getFetcher());
			fetcher.setValue("$n", Integer.valueOf(cnt));
			try
			{
				if(SJavaParser.isExpressionString(component.getName()))
					ret = (String)SJavaParser.evaluateExpressionPotentially(component.getName(), model.getAllImports(), fetcher, this.component.getClassLoader());
				else
					ret = (String)SJavaParser.evaluateExpression(component.getName(), model.getAllImports(), fetcher, this.component.getClassLoader());
				if(ret==null)
					ret = component.getName();
			}
			catch(RuntimeException e)
			{
			}
		}
		return ret;
	}

	/**
	 *  Get the arguments.
	 *  @return The arguments as a map of name-value pairs.
	 */
	protected Map getArguments(ComponentInstanceInfo component, IModelInfo model)
	{
		Map ret = null;		
		UnparsedExpression[] arguments = component.getArguments();
		UnparsedExpression argumentsexp = component.getArgumentsExpression();
		
		if(arguments.length>0)
		{
			ret = new HashMap();

			for(int i=0; i0)
				{
					Object val = SJavaParser.evaluateExpression(arguments[i].getValue(), model.getAllImports(), this.component.getFetcher(), this.component.getClassLoader());
					ret.put(arguments[i].getName(), val);
				}
			}
		}
		else if(argumentsexp!=null && argumentsexp.getValue()!=null && argumentsexp.getValue().length()>0)
		{
			// todo: language
			ret = (Map)SJavaParser.evaluateExpression(argumentsexp.getValue(), model.getAllImports(), this.component.getFetcher(), this.component.getClassLoader());
		}
		
		return ret;
	}
	
	//-------- IInternalSubcomponentsFeature interface -------
	
	/**
	 *  Called, when a subcomponent has been created.
	 */
	public IFuture componentCreated(final IComponentDescription desc)
	{
		// Throw component events for extensions (envsupport)
		final IMonitoringComponentFeature	mon	= getComponent().getFeature0(IMonitoringComponentFeature.class);
		if(mon!=null)
		{
			return getComponent().getFeature(IExecutionFeature.class).scheduleStep(new ImmediateComponentStep()
			{
				public IFuture execute(IInternalAccess ia)
				{
					Future	ret	= new Future();
					if(mon.hasEventTargets(PublishTarget.TOALL, PublishEventLevel.COARSE))
					{
						// desc.getCause()
						MonitoringEvent me = new MonitoringEvent(desc.getName(), desc.getCreationTime(), 
							MonitoringEvent.TYPE_COMPONENT_CREATED, desc.getCreationTime(), PublishEventLevel.COARSE);
						me.setProperty("details", desc);
						// for extensions only
						mon.publishEvent(me, PublishTarget.TOALL) .addResultListener(new DelegationResultListener(ret));
					}
					else
					{
						ret.setResult(null);
					}
					return ret;
				}
			});
		}
		else
		{
			return IFuture.DONE;
		}
	}
	
	/**
	 *  Called, when a subcomponent has been removed.
	 */
	public IFuture componentRemoved(final IComponentDescription desc)
	{
		// Throw component events for extensions (envsupport)
		final IMonitoringComponentFeature	mon	= getComponent().getFeature0(IMonitoringComponentFeature.class);
		if(mon!=null)
		{
			return getComponent().getFeature(IExecutionFeature.class).scheduleStep(new ImmediateComponentStep()
			{
				public IFuture execute(IInternalAccess ia)
				{
					Future	ret	= new Future();
					if(mon.hasEventTargets(PublishTarget.TOALL, PublishEventLevel.COARSE))
					{
//						desc.getCause()
						long time = getComponent().getFeature(IRequiredServicesFeature.class).getLocalService(new ServiceQuery<>(IClockService.class)).getTime();
						MonitoringEvent me = new MonitoringEvent(desc.getName(), desc.getCreationTime(), 
							MonitoringEvent.TYPE_COMPONENT_DISPOSED, time, PublishEventLevel.COARSE);
						me.setProperty("details", desc);
						// for extensions only
						mon.publishEvent(me, PublishTarget.TOALL) .addResultListener(new DelegationResultListener(ret));
					}
					else
					{
						ret.setResult(null);
					}
					return ret;
				}
			});
		}
		else
		{
			return IFuture.DONE;
		}
	}
	
	/**
	 *  Create a result listener that is executed on the
	 *  component thread.
	 */
	public  IResultListener createResultListener(IResultListener listener)
	{
		return getComponent().getFeature(IExecutionFeature.class).createResultListener(listener);
	}
	
	/**
	 *  Test if the current thread is an external thread.
	 */
	protected boolean isExternalThread()
	{
		return !getComponent().getFeature(IExecutionFeature.class).isComponentThread();
	}

	/**
	 *  Get the childcount.
	 *  @return the childcount.
	 */
	public int getChildcount()
	{
		return ((CMSComponentDescription)getComponent().getDescription()).getChildren().length;
//		return childcount;
	}

//	/**
//	 *  Set the child count.
//	 *  @param childcount the childcount to set.
//	 */
//	public void setChildcount(int childcount)
//	{
//		this.childcount = childcount;
//	}
	
//	/**
//	 *  Inc the child count.
//	 */
//	public int incChildcount()
//	{
//		return ++this.childcount;
//	}
//	
//	/**
//	 *  Dec the child count.
//	 */
//	public int decChildcount()
//	{
//		return childcount>0? --childcount: childcount;
//	}
	
	/**
	 *  Get the children (if any) component identifiers.
	 *  @param type The local child type.
	 *  @param parent The parent (null for this).
	 *  @return The children component identifiers.
	 */
	public IFuture getChildren(String type, IComponentIdentifier parent)
	{
		return getComponent().getChildren(type, parent);
	}
	
	/**
	 *  Get the local type name of this component as defined in the parent.
	 *  @return The type of this component type.
	 */
	public IFuture getLocalTypeAsync()
	{
		return new Future(getLocalType());
	}
	
	/**
	 *  Add a components to the dependency resolver to build start levels.
	 *  Components of the same level can be started in parallel.
	 */
	protected  void addComponentToLevels(DependencyResolver dr, T instanceinfo, IModelInfo minfo, MultiCollection instances, String... addpredecessors)
	{
		try
		{
			String cname = minfo.getFullName();
			
			dr.addNode(cname);
			String[] pres = minfo.getPredecessors();
			if(pres!=null)
			{
				for(String pre: pres)
					dr.addDependency(cname, (String)pre);
			}
			
			if (addpredecessors != null)
			{
				for (String addpredecessor : addpredecessors)
					dr.addDependency(cname, addpredecessor);
			}
			
			Object[] sucs = minfo.getSuccessors();
			if(sucs!=null)
			{
				for(Object suc: sucs)
					dr.addDependency((String)suc, cname);
			}
		
			// no predecessors
			if(debug && (pres==null || pres.length==0))
				System.err.println("NO PREDECESSORS: " + cname + " " + (pres == null ? "null" : Arrays.toString(pres)));
			
			instances.add(cname, instanceinfo);
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy