jadex.platform.service.cms.PlatformComponent Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jadex-platform Show documentation
Show all versions of jadex-platform Show documentation
The Jadex platform package contains implementations of platform services as well as the platform component itself.
package jadex.platform.service.cms;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.ConsoleHandler;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import jadex.base.Starter;
import jadex.bridge.IComponentIdentifier;
import jadex.bridge.IComponentStep;
import jadex.bridge.IExternalAccess;
import jadex.bridge.IInternalAccess;
import jadex.bridge.ImmediateComponentStep;
import jadex.bridge.component.ComponentCreationInfo;
import jadex.bridge.component.FeatureNotAvailableException;
import jadex.bridge.component.IArgumentsResultsFeature;
import jadex.bridge.component.IComponentFeature;
import jadex.bridge.component.IComponentFeatureFactory;
import jadex.bridge.component.IExecutionFeature;
import jadex.bridge.component.IMonitoringComponentFeature;
import jadex.bridge.component.IPropertiesFeature;
import jadex.bridge.component.impl.IInternalExecutionFeature;
import jadex.bridge.modelinfo.IModelInfo;
import jadex.bridge.modelinfo.ModelInfo;
import jadex.bridge.modelinfo.SubcomponentTypeInfo;
import jadex.bridge.service.RequiredServiceInfo;
import jadex.bridge.service.annotation.Timeout;
import jadex.bridge.service.component.IRequiredServicesFeature;
import jadex.bridge.service.search.SServiceProvider;
import jadex.bridge.service.types.cms.IComponentDescription;
import jadex.bridge.service.types.cms.IComponentManagementService;
import jadex.bridge.service.types.factory.IPlatformComponentAccess;
import jadex.bridge.service.types.monitoring.IMonitoringEvent;
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.IParameterGuesser;
import jadex.commons.IValueFetcher;
import jadex.commons.SReflect;
import jadex.commons.concurrent.TimeoutException;
import jadex.commons.future.CollectionResultListener;
import jadex.commons.future.CounterResultListener;
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.ExternalAccess;
/**
* Standalone platform component implementation.
*/
public class PlatformComponent implements IPlatformComponentAccess, IInternalAccess
{
//-------- constants --------
/** Property name for timeout after which component long running cleanup is forcefully aborted. */
public static final String PROPERTY_TERMINATION_TIMEOUT = "termination_timeout";
//-------- attributes --------
/** The creation info. */
protected ComponentCreationInfo info;
/** The features. */
protected Map, IComponentFeature> features;
/** The feature instances as list (for reverse execution, cached for speed). */
protected List lfeatures;
/** The inited feature instances as list (for shutdown after failed init). */
protected List ifeatures;
/** The logger. */
protected Logger logger;
/** The failure reason (if any). */
protected Exception exception;
/** The combined value fetcher (cached for speed). */
protected IValueFetcher fetcher;
/** The shutdown flag (set on start of shutdown). */
protected boolean shutdown;
//-------- IPlatformComponentAccess interface --------
/**
* Create the component, i.e. instantiate its features.
* This is the first method that is called by the platform.
*
* @param info The component creation info.
* @param platformdata The shared objects for all components of the same platform (registry etc.). See starter for available data.
* @param facs The factories for component features to be instantiated for this component.
*/
public void create(ComponentCreationInfo info, Collection facs)
{
// state = ComponentLifecycleState.CREATE;
this.info = info;
this.features = new LinkedHashMap, IComponentFeature>();
this.lfeatures = new ArrayList();
for(IComponentFeatureFactory fac: facs)
{
// System.out.println("feature: "+fac);
IComponentFeature instance = fac.createInstance(getInternalAccess(), info);
features.put((Class>)fac.getType(), instance);
for(Class> ltype: fac.getLookupTypes())
features.put(ltype, instance);
lfeatures.add(instance);
}
}
/**
* Perform the initialization of the component.
* Tries to switch to a separate thread for the component as soon as possible.
*
* @return A future to indicate when the initialization is done.
*/
public IFuture init()
{
// state = ComponentLifecycleState.INIT;
// Run init on component thread (hack!!! requires that execution feature works before its init)
IExecutionFeature exe = getComponentFeature(IExecutionFeature.class);
return exe.scheduleStep(new ImmediateComponentStep()
{
public IFuture execute(IInternalAccess ia)
{
ifeatures = new ArrayList();
return executeInitOnFeatures(lfeatures.iterator());
}
});
}
/**
* Perform the main execution of the component (if any).
*
* @return A future to indicate when the body is done.
*/
public IFuture body()
{
// state = ComponentLifecycleState.BODY;
IExecutionFeature exe = getComponentFeature(IExecutionFeature.class);
return exe.scheduleStep(new IComponentStep()
{
public IFuture execute(IInternalAccess ia)
{
return executeBodyOnFeatures(lfeatures.iterator());
}
});
}
/**
* Perform the shutdown of the component (if any).
*
* @return A future to indicate when the shutdown is done.
*/
public IFuture shutdown()
{
shutdown = true;
// state = ComponentLifecycleState.END;
// System.out.println("shutdown component features start: "+getComponentIdentifier());
IExecutionFeature exe = getComponentFeature(IExecutionFeature.class);
return exe.scheduleStep(new ImmediateComponentStep()
{
public IFuture execute(IInternalAccess ia)
{
final Future ret = new Future();
// if(getComponentIdentifier().getName().indexOf("Leaker")!=-1)
// System.out.println("shutdown component features start: "+getComponentIdentifier()+", "+ifeatures +", "+ lfeatures);
executeShutdownOnFeatures(ifeatures!=null ? ifeatures : lfeatures)
.addResultListener(new IResultListener()
{
public void resultAvailable(Void result)
{
proceed(null);
}
public void exceptionOccurred(Exception exception)
{
proceed(exception);
}
public void proceed(final Exception ex)
{
// if(getComponentIdentifier().getName().indexOf("Leaker")!=-1)
// System.out.println("shutdown component features end: "+getComponentIdentifier()+", "+ex);
if(getComponentFeature0(IMonitoringComponentFeature.class)!=null
&& getComponentFeature(IMonitoringComponentFeature.class).hasEventTargets(PublishTarget.TOALL, PublishEventLevel.COARSE))
{
// if(getComponentIdentifier().getName().indexOf("Feature")!=-1)
// System.out.println("shutdown component features end1: "+getComponentIdentifier()+", "+ex);
MonitoringEvent event = new MonitoringEvent(getComponentDescription().getName(), getComponentDescription().getCreationTime(),
IMonitoringEvent.TYPE_COMPONENT_DISPOSED, getComponentDescription().getCause(), System.currentTimeMillis(), PublishEventLevel.COARSE);
event.setProperty("details", getComponentDescription());
getComponentFeature(IMonitoringComponentFeature.class).publishEvent(event, PublishTarget.TOALL).addResultListener(new IResultListener()
{
public void resultAvailable(Void result)
{
// if(getComponentIdentifier().getName().indexOf("Feature")!=-1)
// System.out.println("shutdown component features end2: "+getComponentIdentifier()+", "+ex);
if(ex!=null)
ret.setExceptionIfUndone(ex);
else
ret.setResultIfUndone(null);
}
public void exceptionOccurred(Exception exception)
{
// if(getComponentIdentifier().getName().indexOf("Feature")!=-1)
// System.out.println("shutdown component features end3: "+getComponentIdentifier()+", "+ex);
ret.setExceptionIfUndone(exception);
}
});
}
else
{
// if(getComponentIdentifier().getName().indexOf("Feature")!=-1)
// System.out.println("shutdown component features end4: "+getComponentIdentifier()+", "+ex);
if(ex!=null)
ret.setExceptionIfUndone(ex);
else
ret.setResultIfUndone(null);
}
}
});
// Add timeout in case cleanup takes too long.
final Number timeout = (Number)getModel().getProperty(PROPERTY_TERMINATION_TIMEOUT, getClassLoader());
if(timeout==null || timeout.longValue()!=Timeout.NONE)
{
if(getComponentFeature0(IExecutionFeature.class)!=null)
{
getComponentFeature(IExecutionFeature.class).waitForDelay(timeout!=null ? timeout.longValue() : Starter.getLocalDefaultTimeout(getComponentIdentifier()), true)
.addResultListener(new IResultListener()
{
@Override
public void resultAvailable(Void result)
{
// System.out.println("shutdown component features timeout: "+getComponentIdentifier());
executeKillOnFeatures(ifeatures!=null ? ifeatures : lfeatures);
ret.setExceptionIfUndone(new TimeoutException("Timeout during component cleanup: "+timeout));
}
@Override
public void exceptionOccurred(Exception exception)
{
// ignore (e.g. ComponentTerminatedException when cleanup successful)
}
});
}
else
{
System.err.println("No execution feature for timeout: "+getComponentIdentifier());
}
}
return ret;
}
});
}
/**
* Recursively init the features.
*/
protected IFuture executeInitOnFeatures(final Iterator features)
{
// Try synchronous init.
IFuture ret = IFuture.DONE;
while(ret.isDone() && ret.getException()==null && features.hasNext())
{
IComponentFeature cf = features.next();
// if(getComponentIdentifier().getName().indexOf("Custom")!=-1)
// System.out.println("Initing "+cf+" of "+getComponentIdentifier());
ifeatures.add(cf);
ret = cf.init();
}
// Wait for future but also check features, as future might have become done since check in loop.
if(!ret.isDone() || features.hasNext())
{
// Recurse for asynchronous feature.
final Future fut = new Future();
ret.addResultListener(getComponentFeature(IExecutionFeature.class).createResultListener(new DelegationResultListener(fut)
{
public void customResultAvailable(Void result)
{
executeInitOnFeatures(features).addResultListener(new DelegationResultListener(fut));
}
}));
ret = fut;
}
// Init complete
else
{
if(ret.getException()!=null)
{
// System.out.println("Initing of "+getComponentIdentifier()+" failed due to "+fut.getException());
// Init failed: remove failed feature.
IComponentFeature feature = ifeatures.remove(ifeatures.size()-1);
feature.kill(); // Kill failed feature. Other features will be shutdowned.
}
else
{
// System.out.println("Initing of "+getComponentIdentifier()+" done.");
// Init succeeded: list no longer needed.
ifeatures = null;
}
}
return ret;
}
/**
* Execute feature bodies in parallel.
*/
protected IFuture executeBodyOnFeatures(final Iterator features)
{
List> undones = new ArrayList>();
IFuture ret = IFuture.DONE;
while(!shutdown && ret.getException()==null && features.hasNext())
{
final IComponentFeature cf = features.next();
// if(getComponentIdentifier().getName().indexOf("Custom")!=-1)
// System.out.println("Body "+cf+" of "+getComponentIdentifier());
// Execute user body on separate step to allow blocking get() and still execute the other bodies.
if(cf.hasUserBody())
{
ret = getComponentFeature(IExecutionFeature.class).scheduleStep(new IComponentStep()
{
@Override
public IFuture execute(IInternalAccess ia)
{
return cf.body();
}
});
}
else
{
ret = cf.body();
}
if(!ret.isDone())
{
undones.add(ret);
}
}
// Check if need to kill due to no keepalive.
if(!shutdown && ret.getException()==null)
{
// Body already finished -> kill if not keep alive
if(undones.isEmpty())
{
Boolean keepalive = getModel().getKeepalive(getConfiguration());
if(keepalive!=null && !keepalive.booleanValue())
{
killComponent();
}
}
// Wait for body and then kill.
else
{
final Future fut = new Future();
IResultListener crl = new CounterResultListener(undones.size(), new DelegationResultListener(fut)
{
public void customResultAvailable(Void result)
{
Boolean keepalive = getModel().getKeepalive(getConfiguration());
if(keepalive!=null && !keepalive.booleanValue())
{
killComponent();
}
fut.setResult(null);
}
});
for(IFuture undone: undones)
{
undone.addResultListener(crl);
}
ret = fut;
}
}
// else body failed -> return fut.
return ret;
}
/**
* Recursively shutdown the features in inverse order.
*/
protected IFuture executeShutdownOnFeatures(final List features)
{
// Try synchronous shutdown.
IFuture fut = IFuture.DONE;
boolean sync = true;
while(sync && !features.isEmpty())
{
// On exception -> print but continue shutdown with next feature
if(fut.getException()!=null)
{
StringWriter sw = new StringWriter();
fut.getException().printStackTrace(new PrintWriter(sw));
getLogger().warning("Exception during component cleanup of "+getComponentIdentifier()+": "+fut.getException());
getLogger().info(sw.toString());
}
// if(getComponentIdentifier().getName().indexOf("Leaker")!=-1)
// System.out.println("feature shutdown start: "+getComponentIdentifier()+" "+features);
fut = features.get(features.size()-1).shutdown();
sync = fut.isDone();
if(sync)
{
features.remove(features.size()-1);
}
}
// Recurse once for current async feature
if(!sync)
{
final Future ret = new Future();
fut.addResultListener(new IResultListener()
{
public void resultAvailable(Void result)
{
proceed();
}
public void exceptionOccurred(Exception exception)
{
StringWriter sw = new StringWriter();
exception.printStackTrace(new PrintWriter(sw));
getLogger().warning("Exception during component cleanup of "+getComponentIdentifier()+": "+exception);
getLogger().info(sw.toString());
proceed();
}
protected void proceed()
{
if(!features.isEmpty()) // Happens, when killed due to termination timeput
{
features.remove(features.size()-1);
executeShutdownOnFeatures(features).addResultListener(new DelegationResultListener(ret));
}
}
});
return ret;
}
else
{
return IFuture.DONE;
}
}
/**
* Kill the features in inverse order.
* Kill is invoked, when shutdown does not return due to timeout.
*/
protected void executeKillOnFeatures(List features)
{
while(!features.isEmpty())
{
features.remove(features.size()-1).kill();
}
}
/**
* Get the user view of this platform component.
*
* @return An internal access exposing user operations of the component.
*/
public IInternalAccess getInternalAccess()
{
return this;
}
/**
* Get the exception, if any.
* @return The failure reason for use during cleanup, if any.
*/
public Exception getException()
{
return exception;
}
// /**
// * Get the shared platform data.
// *
// * @return The objects shared by all components of the same platform (registry etc.). See starter for available data.
// */
// public Map getPlatformData()
// {
// return platformdata;
// }
//-------- IInternalAccess interface --------
/**
* @deprecated From version 3.0 - replaced with internal access.
* Get the service provider.
* @return The service provider.
*/
public IInternalAccess getServiceContainer()
{
return this;
}
/**
* @deprecated From 3.0. Use getComponentFeature(IArgumentsResultsFeature.class).getArguments()
* Get an argument value per name.
* @param name The argument name.
* @return The argument value.
*/
public Object getArgument(String name)
{
return getComponentFeature(IArgumentsResultsFeature.class).getArguments().get(name);
}
/**
* @deprecated From 3.0. Use internal access.
* @return The interpreter.
*/
public IInternalAccess getInterpreter()
{
return this;
}
/**
* @deprecated From version 3.0 - replaced with internal access.
* Get the service provider.
* @return The service provider.
*/
public IInternalAccess getServiceProvider()
{
return this;
}
/**
* @deprecated From version 3.0 - Use getComponentFeature(IRequiredServicesFeatures.class).getRequiredService()
* Get a required service of a given name.
* @param name The service name.
* @return The service.
*/
public IFuture getRequiredService(String name)
{
return getComponentFeature(IRequiredServicesFeature.class).getRequiredService(name);
}
/**
* @deprecated From version 3.0 - replaced with getComponentFeature(IExecutionFeature.class).scheduleStep()
* Execute a component step.
*/
public IFuture scheduleStep(IComponentStep step)
{
return getComponentFeature(IExecutionFeature.class).scheduleStep(step);
}
/**
* @deprecated From version 3.0 - replaced with getComponentFeature(IExecutionFeature.class).waitForDelay()
* Wait for some time and execute a component step afterwards.
*/
public IFuture waitForDelay(long delay, IComponentStep step)
{
return getComponentFeature(IExecutionFeature.class).waitForDelay(delay, step);
}
/**
* Get the model of the component.
* @return The model.
*/
public IModelInfo getModel()
{
return info.getModel();
}
/**
* Get the start configuration or the default configuration if any.
* @return The configuration.
*/
public String getConfiguration()
{
String ret = info.getConfiguration();
// if(ret==null)
// {
// ConfigurationInfo[] configs = getModel().getConfigurations();
// if(configs.length>0)
// {
// ret = configs[0].getName();
// }
// }
return ret;
}
/**
* Get the id of the component.
* @return The component id.
*/
public IComponentIdentifier getComponentIdentifier()
{
return info.getComponentDescription().getName();
}
/**
* Get the component description.
* @return The component description.
*/
// Todo: hack??? should be internal to CMS!?
public IComponentDescription getComponentDescription()
{
return info.getComponentDescription();
}
/**
* Get a feature of the component.
* @param feature The type of the feature.
* @return The feature instance.
*/
public T getComponentFeature(Class extends T> type)
{
if(!features.containsKey(type))
{
throw new FeatureNotAvailableException("No such feature: "+type);
}
else
{
return type.cast(features.get(type));
}
}
/**
* Get a feature of the component.
* @param feature The type of the feature.
* @return The feature instance.
*/
public T getComponentFeature0(Class extends T> type)
{
return type.cast(features.get(type));
}
/**
* Kill the component.
*/
public IFuture