Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
jadex.bridge.service.BasicService 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.
package jadex.bridge.service;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
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.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import jadex.bridge.ClassInfo;
import jadex.bridge.IComponentIdentifier;
import jadex.bridge.IInternalAccess;
import jadex.bridge.IResourceIdentifier;
import jadex.bridge.SFuture;
import jadex.bridge.component.IExecutionFeature;
import jadex.bridge.component.INFPropertyComponentFeature;
import jadex.bridge.component.impl.NFPropertyComponentFeature;
import jadex.bridge.sensor.service.TagProperty;
import jadex.bridge.service.annotation.GuiClass;
import jadex.bridge.service.annotation.GuiClassName;
import jadex.bridge.service.annotation.GuiClassNames;
import jadex.bridge.service.annotation.Security;
import jadex.bridge.service.annotation.Service;
import jadex.bridge.service.annotation.Timeout;
import jadex.bridge.service.component.BasicServiceInvocationHandler;
import jadex.bridge.service.component.IProvidedServicesFeature;
import jadex.bridge.service.search.ServiceRegistry;
import jadex.commons.MethodInfo;
import jadex.commons.SReflect;
import jadex.commons.SUtil;
import jadex.commons.future.ExceptionDelegationResultListener;
import jadex.commons.future.Future;
import jadex.commons.future.IFuture;
import jadex.commons.future.IResultListener;
/**
* Basic service provide a simple default isValid() implementation
* that returns true after start service and false afterwards.
*/
public class BasicService implements IInternalService //extends NFMethodPropertyProvider implements IInternalService
{
//-------- constants --------
// /** Constant for timeout name in non-functional properties. */
// public static final String TIMEOUT = "timeout";
//-------- attributes --------
/** The id counter. */
protected static long idcnt;
/** Internal access to its component. */
protected IInternalAccess internalaccess;
/** The started state. */
protected volatile boolean started;
/** The shutdowned state. */
protected volatile boolean shutdowned;
/** The service id. */
protected IServiceIdentifier sid;
/** The service properties. */
private Map properties;
/** The provider id. */
protected IComponentIdentifier providerid;
protected Class> type;
protected Class> impltype;
//-------- constructors --------
/**
* Create a new service.
*/
// todo: remove type!!!
public BasicService(IComponentIdentifier providerid, Class> type, Map properties)
{
this(providerid, type, null, properties);
}
/**
* Create a new service.
*/
// todo: remove type!!!
public BasicService(IComponentIdentifier providerid, Class> type, Class> impltype, Map properties)
{
// super(null);
// if(properties!=null && properties.size()>0)
// System.out.println("sdyf");
// if(!SReflect.isSupertype(type, getClass()))
// throw new RuntimeException("Service must implement provided interface: "+getClass().getName()+", "+type.getName());
this.providerid = providerid;
// this.type = type;
// this.implclazz = implclazz;
this.properties = properties;
this.type = type;
this.impltype = impltype;
// todo: move to be able to use the constant
// jadex.base.gui.componentviewer.IAbstractViewerPanel.PROPERTY_VIEWERCLASS
Object guiclazz = properties!=null? properties.get("componentviewer.viewerclass"): null;
if(guiclazz==null && type.isAnnotationPresent(GuiClass.class))
{
GuiClass gui = (GuiClass)type.getAnnotation(GuiClass.class);
guiclazz = gui.value();
if(this.properties==null)
this.properties = new HashMap();
this.properties.put("componentviewer.viewerclass", guiclazz);
// System.out.println("found: "+guiclazz);
}
else if(guiclazz==null && type.isAnnotationPresent(GuiClassName.class))
{
GuiClassName gui = (GuiClassName)type.getAnnotation(GuiClassName.class);
guiclazz = gui.value();
if(this.properties==null)
this.properties = new HashMap();
this.properties.put("componentviewer.viewerclass", guiclazz);
// System.out.println("found: "+guiclazz);
}
else if(guiclazz==null && type.isAnnotationPresent(GuiClassNames.class))
{
GuiClassNames anno = type.getAnnotation(GuiClassNames.class);
GuiClassName[] guis = anno.value();
String[] guiClasses = new String[guis.length];
for (int i = 0; i < guis.length; i++) {
guiClasses[i] = guis[i].value();
}
if(this.properties==null)
this.properties = new HashMap();
this.properties.put("componentviewer.viewerclass", guiClasses);
}
// if(type.isAnnotationPresent(TargetResolver.class))
// {
// TargetResolver tr = type.getAnnotation(TargetResolver.class);
// if(this.properties==null)
// this.properties = new HashMap();
// this.properties.put(TargetResolver.TARGETRESOLVER, tr.value());
// }
//
// if(type.isAnnotationPresent(NFProperties.class))
// {
// if(nfproperties==null)
// nfproperties = new HashMap>();
// addNFProperties(type.getAnnotation(NFProperties.class), nfproperties, null);
// }
//
// Method[] methods = type.getMethods();
// for(Method m : methods)
// {
// if(m.isAnnotationPresent(NFProperties.class))
// {
// if(methodnfproperties==null)
// methodnfproperties = new HashMap>>();
// Map> nfmap = methodnfproperties.get(m);
// if (nfmap == null)
// {
// nfmap = new HashMap>();
// methodnfproperties.put(m, nfmap);
// }
// addNFProperties(m.getAnnotation(NFProperties.class), nfmap, new MethodInfo(m));
// }
// }
}
// /**
// *
// */
// public void initNFProperties()
// {
// IService ser = (IService)internalaccess.getComponentFeature(IProvidedServicesFeature.class).getProvidedService(type);
//
// List> classes = new ArrayList>();
// Class> superclazz = type;
// while(superclazz != null && !Object.class.equals(superclazz))
// {
// classes.add(superclazz);
// superclazz = superclazz.getSuperclass();
// }
// superclazz = impltype!=null? impltype: this.getClass();
// while(superclazz != null && !BasicService.class.equals(superclazz) && !Object.class.equals(superclazz))
// {
// classes.add(superclazz);
// superclazz = superclazz.getSuperclass();
// }
// Collections.reverse(classes);
//
// for(Class> sclazz: classes)
// {
// if(sclazz.isAnnotationPresent(NFProperties.class))
// {
// if(nfproperties==null)
// nfproperties = new HashMap>();
// addNFProperties(sclazz.getAnnotation(NFProperties.class), nfproperties, ser, null);
// }
//
// Method[] methods = sclazz.getMethods();
// for(Method m : methods)
// {
// if(m.isAnnotationPresent(NFProperties.class))
// {
// if(methodnfproperties==null)
// methodnfproperties = new HashMap>>();
//
// Map> nfmap = methodnfproperties.get(new MethodInfo(m));
// if(nfmap == null)
// {
// nfmap = new HashMap>();
// methodnfproperties.put(new MethodInfo(m), nfmap);
// }
// }
// }
// }
//
// if(methodnfproperties!=null)
// {
// for(MethodInfo key: methodnfproperties.keySet())
// {
// Map> nfmap = methodnfproperties.get(key);
// addNFProperties(key.getMethod(internalaccess.getClassLoader()).getAnnotation(NFProperties.class), nfmap, ser, key);
// }
// }
// }
// /**
// * Add nf properties from a type.
// */
// public void addNFProperties(NFProperties nfprops, Map> nfps, IService ser, MethodInfo mi)
// {
// for(NFProperty nfprop : nfprops.value())
// {
// Class> clazz = nfprop.value();
// INFProperty, ?> prop = AbstractNFProperty.createProperty(clazz, internalaccess, ser, mi);
// nfps.put(prop.getName(), prop);
// }
// }
//-------- methods --------
/**
* Test if the service is valid.
* @return True, if service can be used.
*
*/
public IFuture isValid()
{
// if(getId().getServiceName().indexOf("Decoupled")!=-1)
// System.out.println("isValid: "+getId()+": "+(started && !shutdowned));
return started && !shutdowned ? IFuture.TRUE : IFuture.FALSE;
}
/**
* Set the service identifier.
*/
public void setServiceIdentifier(IServiceIdentifier sid)
{
this.sid = sid;
}
/**
* Get the service id.
* @return The service id.
*/
public IServiceIdentifier getServiceId()
{
if(sid==null)
throw new RuntimeException("No service identifier: "+this);
// sid = createServiceIdentifier(providerid, name, type, implclazz==null ? getClass() : implclazz);
return sid;
}
/**
* Invoke a method reflectively.
* @param methodname The method name.
* @param argtypes The argument types (can be null if method exists only once).
* @param args The arguments.
* @return The result.
*/
public IFuture invokeMethod(String methodname, ClassInfo[] argtypes, Object[] args, ClassInfo rettype)
{
Future ret = (Future)SFuture.getNoTimeoutFuture(rettype.getType(internalaccess.getClassLoader()), internalaccess);
Method m = getInvokeMethod(this.getClass(), internalaccess.getClassLoader(), methodname, argtypes);
if(m!=null)
{
try
{
ret = (Future)m.invoke(this, args);
}
catch(Exception e)
{
ret.setException(e);
}
}
else
{
ret.setException(new RuntimeException("Method not found: "+methodname));
}
return ret;
}
/**
* Get reflective info about the service methods, args, return types.
* @return The method infos.
*/
public IFuture getMethodInfos()
{
Class> iface = sid.getServiceType().getType(internalaccess.getClassLoader());
Set ms = new HashSet<>();
Set> todo = new HashSet<>();
todo.add(iface);
todo.add(IService.class);
while(todo.size()>0)
{
Class> cur = todo.iterator().next();
todo.remove(cur);
ms.addAll(SUtil.arrayToList(cur.getMethods()));
cur = cur.getSuperclass();
while(cur!=null && cur.getAnnotation(Service.class)==null)
cur = cur.getSuperclass();
if(cur!=null)
todo.add(cur);
}
MethodInfo[] ret = new MethodInfo[ms.size()];
Iterator it = ms.iterator();
for(int i=0; i(ret);
}
/**
* Get method that should be invoked on target object.
*/
public static Method getInvokeMethod(Class> target, ClassLoader cl, String methodname, ClassInfo[] argtypes)
{
Method m = null;
if(argtypes==null)
{
Method[] methods = SReflect.getMethods(target, methodname);
if(methods.length!=1)
{
throw new IllegalArgumentException("Multiple methods with name: "+methodname);
}
else
{
m = methods[0];
}
}
else
{
Class>[] ats = new Class[argtypes.length];
for(int i=0; i setComponentAccess(IInternalAccess access)
{
internalaccess = access;
// setParent(internalaccess.getExternalAccess());
//
// // init properties when access is available
return initNFProperties();
// return IFuture.DONE;
}
/**
* Init the non-functional properties (todo: move to other location?)
*/
protected IFuture initNFProperties()
{
final Future ret = new Future();
if(getInternalAccess().getFeature0(INFPropertyComponentFeature.class)!=null)
{
final INFPropertyComponentFeature nfcf = getInternalAccess().getFeature(INFPropertyComponentFeature.class);
IProvidedServicesFeature psf = getInternalAccess().getFeature(IProvidedServicesFeature.class);
IInternalService ser = (IInternalService)getInternalAccess().getFeature(IProvidedServicesFeature.class).getProvidedService(type);
Class> impltype = psf.getProvidedServiceRawImpl(ser.getServiceId())!=null? psf.getProvidedServiceRawImpl(ser.getServiceId()).getClass(): null;
// todo: make internal interface for initProperties
// if(type!=null && type.getName().indexOf("ITest")!=-1)
// System.out.println("sdfsdf");
((NFPropertyComponentFeature)nfcf).initNFProperties(ser, impltype)
.addResultListener(getInternalAccess().getFeature(IExecutionFeature.class) // TODO: why wrong thread (start 2x autoterminate on 6-core)
.createResultListener(new ExceptionDelegationResultListener(ret)
{
public void customResultAvailable(Void result) throws Exception
{
nfcf.getProvidedServicePropertyProvider(sid).getNFPropertyValue(TagProperty.NAME).addResultListener(new IResultListener()
{
public void resultAvailable(Object result)
{
// System.out.println("Starting serviceINIT: "+getId()+" "+getInternalAccess().getComponentFeature(IExecutionFeature.class).isComponentThread());
Collection coll = result == null ? new ArrayList() : new LinkedHashSet((Collection)result);
// Is now done using addTagsProerties()
// IValueFetcher vf = (IValueFetcher) internalaccess.getFetcher();
// Class>[] sertypes = new Class>[] { type, BasicService.this.impltype };
// for(int si = 0; si < sertypes.length; ++si)
// {
// if(sertypes[si] != null && sertypes[si].isAnnotationPresent(Tags.class))
// {
// Tags anntags = (Tags)sertypes[si].getAnnotation(Tags.class);
// String[] tags = anntags != null ? anntags.value() : null;
// if(tags != null && tags.length > 0)
// {
// for(int i = 0; i < tags.length; ++i)
// {
// Object tagval = SJavaParser.evaluateExpression(tags[i], null, vf, internalaccess.getClassLoader());
// if(tagval instanceof String)
// coll.add((String) tagval);
// else
// internalaccess.getLogger().warning("Invalid tag value, ignored: " + tagval + " " + tags[i]);
// }
// }
// }
// }
if(coll!=null && coll.size()>0)
{
if(properties==null)
properties = new HashMap();
Set tags = new LinkedHashSet(coll);
// Hack!!! save props in service identifier
// properties.put(TagProperty.SERVICE_PROPERTY_NAME, tags);
((ServiceIdentifier)sid).setTags(tags);
// Hack!!! re-index
ServiceRegistry reg = (ServiceRegistry)ServiceRegistry.getRegistry(sid.getProviderId());
reg.updateService(sid);
}
ret.setResult(null);
}
public void exceptionOccurred(Exception exception)
{
// exception.printStackTrace();
// System.out.println("Starting serviceINITEX: "+getId()+" "+getInternalAccess().getComponentFeature(IExecutionFeature.class).isComponentThread());
// ret.setResult(null);
resultAvailable(null);
}
});
}
}));
}
else
{
ret.setResult(null);
}
return ret;
}
/**
* Get a service property.
* @return The service property (if any).
*/
public Map getPropertyMap()
{
Map ret;
if(properties!=null)
{
ret = properties;
}
else
{
ret = Collections.emptyMap();
}
return ret;
}
/**
* Set the properties.
* @param properties The properties to set.
*/
public void setPropertyMap(Map properties)
{
this.properties = properties;
}
// /**
// * Get the hosting component of the service.
// * @return The component.
// */
// public IFuture getComponent()
// {
// }
/**
* Start the service.
* @return A future that is done when the service has completed starting.
*/
public IFuture startService()
{
// System.out.println("start: "+this);
Future ret = new Future();
boolean ex = false;
if(started)
{
ex = true;
// System.out.println("setting started true ex: "+this);
}
else
{
started = true;
// System.out.println("setting started true: "+this);
}
if(ex)
{
ret.setException(new RuntimeException("Already running: "+System.identityHashCode(this)));
}
else
{
ret.setResult(null);
// ret.setResult(getId());
}
return ret;
}
/**
* Shutdown the service.
* @return A future that is done when the service has completed its shutdown.
*/
public IFuture shutdownService()
{
// if(getClass().getName().toLowerCase().indexOf("super")!=-1)
// System.out.println("shutdown service: "+getServiceId());
// Deregister pojo->sid mapping in shutdown.
if(sid!=null) // sid is null for shared/wrapped service impls.
BasicServiceInvocationHandler.removePojoServiceProxy(sid);
final Future ret = new Future();
isValid().addResultListener(new ExceptionDelegationResultListener(ret)
{
public void customResultAvailable(Boolean result)
{
// if(getClass().getName().indexOf("ContextSer")!=-1)
// System.out.println("shutdowned service: "+getId());
if(!result.booleanValue())
{
ret.setException(new RuntimeException("Not running."));
}
else
{
shutdowned = true;
ret.setResult(null);
// System.out.println("shutdowned service: "+getId());
}
}
});
return ret;
}
/**
* Generate a unique name.
* @param The calling service class.
*/
public static String generateServiceName(Class> service)
{
synchronized(BasicService.class)
{
return SReflect.getInnerClassName(service)+"_#"+idcnt++;
}
}
/**
* Create a new service identifier for the own component.
*/
public static IServiceIdentifier createServiceIdentifier(IInternalAccess provider, String servicename,
Class> servicetype, Class> serviceimpl, IResourceIdentifier rid, ProvidedServiceInfo info)
{
// if(servicetype.getName().indexOf("IServicePool")!=-1)
// System.out.println("sdjhvkl");
Security security = getSecurityLevel(provider, info, serviceimpl, servicetype, null, null);
Set roles = ServiceIdentifier.getRoles(security, provider);
ServiceScope scope = info!=null ? info.getScope() : null;
return new ServiceIdentifier(provider, servicetype, servicename!=null? servicename: generateServiceName(servicetype), rid, scope,
roles!=null && roles.contains(Security.UNRESTRICTED));
}
/**
* Create a new service identifier for a potentially remote component.
*/
public static ServiceIdentifier createServiceIdentifier(IComponentIdentifier providerid, ClassInfo type, ClassInfo[] supertypes, String servicename, IResourceIdentifier rid, ServiceScope scope, Set networknames, boolean unrestricted)
{
return new ServiceIdentifier(providerid, type, supertypes, servicename, rid, scope, networknames, unrestricted);
}
/**
* Get the internal access.
*/
public IInternalAccess getInternalAccess()
{
return internalaccess;
}
/**
* Check if the service is valid.
* /
public IFuture checkValid()
{
Future ret = new Future();
if(!isValid())
ret.setException(new RuntimeException("Service invalid: "+getId()));
else
ret.setResult(null);
return ret;
}*/
/**
* Check if the service is equal. The service is considered equal if the service identifiers match.
*
* @param obj Object of comparison.
* @return True, if the object is a service with a matching service identifier.
*/
public boolean equals(Object obj)
{
if(obj instanceof IService)
{
return getServiceId().equals(((IService) obj).getServiceId());
}
return false;
}
/**
* Get the hashcode.
*/
public int hashCode()
{
return 31 + getServiceId().hashCode();
}
/**
* Get a string representation.
*/
public String toString()
{
return SReflect.getUnqualifiedClassName(getClass())+"("+sid+")";
}
//-------- helper methods --------
/**
* Get the default timeout for a method.
*/
public static long getMethodTimeout(Class>[] interfaces, Method method, boolean remote)
{
long ret = Timeout.UNSET;
Class>[] allinterfaces = SReflect.getSuperInterfaces(interfaces);
long deftimeout = Timeout.UNSET;
for(int i=0; deftimeout==Timeout.UNSET && i> getImplementationType()
// {
// return new Future>(impltype!=null? impltype: getClass());
// }
/**
* Get the interface type.
* @return The interface type.
*/
public Class> getInterfaceType()
{
return type;
}
/**
* todo: move to some security class
* Check if a service method is unrestricted.
* Schedules on component to check this.
* @param sid The service id.
* @param component The internal access.
* @param mi The method info.
* @return True, if is unrestricted.
*/
public static IFuture isUnrestricted(IServiceIdentifier sid, IInternalAccess component, Method method)
{
IComponentIdentifier cid = sid.getProviderId();
return component.getExternalAccess(cid).scheduleStep((IInternalAccess access) ->
{
Security sec = getSecurityLevel(access, null, null, null, method, sid);
Set roles = ServiceIdentifier.getRoles(sec, access);
return new Future(roles!=null && roles.contains(Security.UNRESTRICTED));
});
}
/**
* Find the most specific security setting.
*/
public static Security getSecurityLevel(IInternalAccess access, ProvidedServiceInfo info, Class> implclass, Class> type, Method method, IServiceIdentifier sid)
{
Security level = null;
// at runtime: have to refetch info from model
if(info==null && sid!=null)
{
ProvidedServiceInfo found = null;
for(ProvidedServiceInfo psi: access.getModel().getProvidedServices())
{
if(psi.getType().equals(sid.getServiceType()))
{
// Match when type and name are equal
if(sid.getServiceName().equals(psi.getName()))
{
found = psi;
break;
}
// Potential match when type is equal and no other service with same type
else if(found==null)
{
found = psi;
}
// Two services with same type -> fail if settings differ because we don't know which to use
else if(Arrays.equals(psi.getSecurity().roles(), found.getSecurity().roles()))
{
throw new RuntimeException("Use specific names for security settings on provided services with same type: "+psi.getType());
}
}
}
info = found;
}
// Instance level -> check for instance settings in provided service description
if(info!=null && info.getSecurity()!=null && info.getSecurity().roles().length>0)
{
level = info.getSecurity();
}
// at runtime: fetch implclass from service
if(level==null && implclass==null && sid!=null)
{
Object impl = access.getFeature(IProvidedServicesFeature.class).getProvidedServiceRawImpl(sid);
implclass = impl!=null ? impl.getClass() : null;
}
// For service call -> look for annotation in impl class hierarchy
// Precedence: hierarchy before specificity (e.g. class annotation in subclass wins over method annotation in superclass)
while(level==null && implclass!=null)
{
// Specificity: method before class
if(method!=null)
{
Method declmeth = SReflect.getDeclaredMethod0(implclass, method.getName(), method.getParameterTypes());
if(declmeth != null)
{
level = declmeth.getAnnotation(Security.class);
}
}
if(level==null)
{
level = implclass.getAnnotation(Security.class);
}
implclass = implclass.getSuperclass();
}
// at runtime: fetch interface from sid
if(level==null && type==null && sid!=null)
{
type = sid.getServiceType().getType(access.getClassLoader());
}
// For service call -> look for annotation in interface hierarchy
// Precedence: hierarchy before specificity (e.g. class annotation in subclass wins over method annotation in superclass)
if(level==null && type!=null)
{
List> types = new LinkedList>();
types.add(type);
while(level==null && !types.isEmpty())
{
type = types.remove(0);
// Only consider interfaces that contain or inherit the method (if any)
if(method==null || SReflect.getMethod(type, method.getName(), method.getParameterTypes())!=null)
{
// Specificity: method before class
if(method!=null)
{
Method declmeth = SReflect.getDeclaredMethod0(type, method.getName(), method.getParameterTypes());
if(declmeth != null)
{
level = declmeth.getAnnotation(Security.class);
}
}
if(level==null)
{
level = type.getAnnotation(Security.class);
}
// prepend -> depth first search
types.addAll(0, Arrays.asList(type.getInterfaces()));
}
}
}
// Default: e.g. remote invocation on non-service methods?
if(level==null && method!=null)
{
level = method.getAnnotation(Security.class);
}
// // Default to interface if not specified in impl.
// if(level==null)
// {
// level = method.getAnnotation(Security.class);
// Class> type = sid.getServiceType().getType(access.getClassLoader());
//
// if(level==null && type != null)
// {
// type = SReflect.getDeclaringInterface(type, method.getName(), method.getParameterTypes());
//
// if(type != null)
// {
// Method declmeth = null;
// try
// {
// declmeth = type.getDeclaredMethod(method.getName(), method.getParameterTypes());
// }
// catch (Exception e)
// {
// // Should not happen, we know the method is there...
// }
// level = declmeth.getAnnotation(Security.class);
// if (level == null)
// level = type.getAnnotation(Security.class);
// }
// }
if(level==null && access.getDescription().isSystemComponent())
{
level = DEFAULT_SYSTEM_SECURITY;
}
// level==null -> disallow direct access to components (overridden by TRUSTED platform)
return level;
}
public static final Security DEFAULT_SYSTEM_SECURITY = new Security()
{
public Class extends Annotation> annotationType()
{
return Security.class;
}
public String[] roles()
{
return new String[] { Security.ADMIN };
}
};
// /**
// *
// */
// public Class> getFeatureClass(Class> type)
// {
// IComponentFeature feat = (IComponentFeature)getInternalAccess().getComponentFeature(type);
// return feat.getExternalFacadeType(this);
// }
}