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

jadex.nfproperty.impl.NFPropertyFeature Maven / Gradle / Ivy

There is a newer version: 5.0-alpha6
Show newest version
package jadex.nfproperty.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import jadex.collection.ILRUEntryCleaner;
import jadex.collection.LRU;
import jadex.common.MethodInfo;
import jadex.common.SUtil;
import jadex.common.Tuple2;
import jadex.common.UnparsedExpression;
import jadex.core.IComponent;
import jadex.core.IExternalAccess;
import jadex.core.IThrowingFunction;
import jadex.core.impl.Component;
import jadex.core.impl.ComponentManager;
import jadex.execution.impl.ILifecycle;
import jadex.future.DefaultResultListener;
import jadex.future.Future;
import jadex.future.FutureBarrier;
import jadex.future.IFuture;
import jadex.future.IResultListener;
import jadex.future.ITerminableIntermediateFuture;
import jadex.future.TerminableIntermediateDelegationFuture;
import jadex.micro.MicroAgent;
import jadex.model.IModelFeature;
import jadex.model.impl.AbstractModelLoader;
import jadex.model.modelinfo.ModelInfo;
import jadex.nfproperty.INFMixedPropertyProvider;
import jadex.nfproperty.INFProperty;
import jadex.nfproperty.INFPropertyFeature;
import jadex.nfproperty.INFPropertyMetaInfo;
import jadex.nfproperty.INFPropertyProvider;
import jadex.nfproperty.impl.modelinfo.NFPropertyInfo;
import jadex.nfproperty.impl.search.IRankingSearchTerminationDecider;
import jadex.nfproperty.impl.search.IServiceRanker;
import jadex.nfproperty.impl.search.ServiceRankingDelegationResultListener;
import jadex.nfproperty.impl.search.ServiceRankingDelegationResultListener2;
import jadex.nfproperty.sensor.service.TagProperty;
import jadex.providedservice.IProvidedServiceFeature;
import jadex.providedservice.IService;
import jadex.providedservice.IServiceIdentifier;
import jadex.providedservice.annotation.Tag;
import jadex.providedservice.annotation.Tags;

public class NFPropertyFeature implements ILifecycle, INFPropertyFeature  
{
	//-------- attributes --------
	
	protected Component self;
	
	/** The component property provider. */
	protected INFPropertyProvider compprovider;
	
	/** The nf property providers for required services. */
	protected Map proserprops;
	
	/** The nf property providers for required services. */
	protected Map reqserprops;
	
	/** The max number of preserved req service providers. */
	protected int maxreq;
	
	///** The parent provider. */
	//protected INFPropertyProvider parent;
	
	//-------- constructors --------
	
	protected NFPropertyFeature(Component self)
	{
		this.self = self;
	}
	
	public Component getComponent()
	{
		return self;
	}
	
	@Override
	public void	onStart()
	{
		ModelInfo model = (ModelInfo)self.getFeature(IModelFeature.class).getModel();
		NFPropertyModel mymodel = (NFPropertyModel)model.getFeatureModel(INFPropertyFeature.class);
		if(mymodel==null)
			mymodel = loadModel();
		
		if(mymodel!=null)
		{
			// Init nf component props
			FutureBarrier bar = new FutureBarrier();
			
			Collection nfprops = mymodel.getComponentProperties();
			for(NFPropertyInfo nfprop: nfprops)
			{
				try
				{
					Class clazz = nfprop.getClazz().getType(getComponent().getClassLoader(), model.getAllImports());
					INFProperty nfp = AbstractNFProperty.createProperty(clazz, getComponent(), null, null, nfprop.getParameters());
					bar.add(getComponentPropertyProvider().addNFProperty(nfp));
				}
				catch(Exception e)
				{
					System.out.println("Property creation problem: "+e);
				}
			}
			
			Collection names = mymodel.getProvidedServiceNames();
			IProvidedServiceFeature psf = self.getFeature(IProvidedServiceFeature.class);
			final NFPropertyModel fmymodel = mymodel;
			
			names.forEach(name -> 
			{
				IService ser = psf.getProvidedService(name);
				
				Map> nfps = fmymodel.getProvidedServiceMethodProperties(name);
				nfps.entrySet().forEach(entry ->
				{
					bar.add(addNFMethodProperties(entry.getValue(), ser, entry.getKey()));
				});
				
				List snfps = fmymodel.getProvidedServiceProperties(name);
				if(snfps!=null)
				{
					bar.add(addNFProperties(snfps, ser));
					
					// tags handled directly in provided service now
					// Hack?! must update tags in sid :-(
					/*IServiceIdentifier sid = ser.getServiceId();
					getProvidedServicePropertyProvider(sid).getNFPropertyValue(TagProperty.NAME).then(val ->
					{
						Collection coll = val == null ? new ArrayList() : new LinkedHashSet((Collection)val);
						Set tags = new LinkedHashSet(coll);
						((ServiceIdentifier)sid).setTags(tags);
						// Hack!!! re-index
						ServiceRegistry reg = (ServiceRegistry)ServiceRegistry.getRegistry();
						reg.updateService(sid);
					}).catchEx(ex -> System.out.println("not found tag"));*/
				}
			});
			
			bar.waitFor().get();
		}
	}
	
	/**
	 *  Called when the feature is shutdowned.
	 */
	public void	onEnd()
	{
		FutureBarrier bar = new FutureBarrier();
		
		if(compprovider!=null)
			bar.add(compprovider.shutdownNFPropertyProvider());
		if(proserprops!=null)
			proserprops.values().stream().forEach(p -> bar.add(p.shutdownNFPropertyProvider()));
		if(reqserprops!=null)
			reqserprops.values().stream().forEach(p -> bar.add(p.shutdownNFPropertyProvider()));

		bar.waitFor().get();
	}
	
	public NFPropertyModel loadModel()
	{
		ModelInfo model = (ModelInfo)self.getFeature(IModelFeature.class).getModel();

		NFPropertyModel mymodel = (NFPropertyModel)model.getFeatureModel(INFPropertyFeature.class);
		if(mymodel==null)
		{
			mymodel = (NFPropertyModel)NFPropertyLoader.readFeatureModel(model, ((MicroAgent)self).getPojo().getClass(), this.getClass().getClassLoader());
			final NFPropertyModel fmymodel = mymodel;
			AbstractModelLoader loader = AbstractModelLoader.getLoader((Class< ? extends Component>)self.getClass());
			loader.updateCachedModel(() ->
			{
				model.putFeatureModel(INFPropertyFeature.class, fmymodel);
			});
		}
		
		return mymodel;
	}
	
	/**
	 *  Get the component property provider.
	 */
	public INFPropertyProvider getComponentPropertyProvider()
	{
		if(compprovider==null)
			this.compprovider = new NFPropertyProvider(null, getComponent()); 
		
		return compprovider;
	}
	
	/**
	 *  Get the required service property provider for a service.
	 */
	public INFMixedPropertyProvider getRequiredServicePropertyProvider(IServiceIdentifier sid)
	{
		INFMixedPropertyProvider ret = null;
		if(reqserprops==null)
		{
			reqserprops = new LRU(maxreq, new ILRUEntryCleaner()
			{
				public void cleanupEldestEntry(Entry eldest)
				{
					eldest.getValue().shutdownNFPropertyProvider().addResultListener(new DefaultResultListener()
					{
						public void resultAvailable(Void result)
						{
						}
					});
				}
			}); 
		}
		ret = reqserprops.get(sid);
		if(ret==null)
		{
			ret = new NFMethodPropertyProvider(getComponent().getId(), getComponent()); 
			reqserprops.put(sid, ret);
//			System.out.println("created req ser provider: "+sid+" "+hashCode());
		}
		return ret;
	}
	
	/**
	 *  Has the service a property provider.
	 */
	public boolean hasRequiredServicePropertyProvider(IServiceIdentifier sid)
	{
		return reqserprops!=null? reqserprops.get(sid)!=null: false;
	}
	
	/**
	 *  Get the provided service property provider for a service.
	 */
	public INFMixedPropertyProvider getProvidedServicePropertyProvider(IServiceIdentifier sid)
	{
		INFMixedPropertyProvider ret = null;
		if(proserprops==null)
		{
			proserprops = new HashMap();
		}
		ret = proserprops.get(sid);
		if(ret==null)
		{
			ret = new NFMethodPropertyProvider(getComponent().getId(), getComponent()); 
			proserprops.put(sid, ret);
		}
		return ret;
	}
	
//		/**
//		 *  Get the provided service property provider for a service.
//		 */
//		public INFMixedPropertyProvider getProvidedServicePropertyProvider(Class iface)
//		{
//		}
	
	/**
	 *  Init the service and method nf properties. 
	 * /
	public IFuture initNFProperties(final IInternalService ser, Class impltype)
	{
		final Future ret = new Future();
		
		List> classes = new ArrayList>();
		Class superclazz = ser.getServiceId().getServiceType().getType(getComponent().getClassLoader());
		while(superclazz != null && !Object.class.equals(superclazz))
		{
			classes.add(superclazz);
			superclazz = superclazz.getSuperclass();
		}
		
		if(impltype!=null)
		{
			superclazz = impltype;
			while(superclazz != null && !BasicService.class.equals(superclazz) && !Object.class.equals(superclazz))
			{
				classes.add(superclazz);
				superclazz = superclazz.getSuperclass();
			}
		}
//			Collections.reverse(classes);
		
		int cnt = 0;
		
		LateCounterListener lis = new LateCounterListener(new DelegationResultListener(ret));
		
		Map meths = new HashMap();
		for(Class sclazz: classes)
		{
			if(sclazz.isAnnotationPresent(NFProperties.class))
			{
				addNFProperties(sclazz.getAnnotation(NFProperties.class), ser).addResultListener(lis);
				cnt++;
			}
			
			if(sclazz.isAnnotationPresent(Tags.class))
			{
				addTags(sclazz.getAnnotation(Tags.class), ser).addResultListener(lis);
				cnt++;
			}
			
			Method[] methods = sclazz.getMethods();
			for(Method m : methods)
			{
				if(m.isAnnotationPresent(NFProperties.class))
				{
					MethodInfo mis = new MethodInfo(m.getName(), m.getParameterTypes());
					if(!meths.containsKey(mis))
					{
						meths.put(mis, m);
					}
				}
			}
		}
		
		for(MethodInfo key: meths.keySet())
		{
			addNFMethodProperties(meths.get(key).getAnnotation(NFProperties.class), ser, key).addResultListener(lis);
			cnt++;
		}
		
		// Set the number of issued calls
		lis.setMax(cnt);

		return ret;
	}*/
	
	/**
	 *  Add nf properties from a type.
	 */
	public IFuture addNFProperties(List infos, IService ser)
	{
		FutureBarrier bar = new FutureBarrier<>();
		INFMixedPropertyProvider prov = getProvidedServicePropertyProvider(ser.getServiceId());
		
		for(NFPropertyInfo nfprop : infos)
		{
			Class clazz = nfprop.getClazz().getType(ComponentManager.get().getClassLoader());
			INFProperty prop = AbstractNFProperty.createProperty(clazz, getComponent(), ser, null, nfprop.getParameters());
			bar.add(prov.addNFProperty(prop));
		}
		return bar.waitFor();
	}
	
	/**
	 *  Add nf properties from a type.
	 */
	public IFuture addTags(Tags tags, IService ser)
	{
		INFMixedPropertyProvider prov = getProvidedServicePropertyProvider(ser.getServiceId());
		
		List params = new ArrayList<>();
		
//			if(tags.argumentname().length()>0)
//				params.add(new UnparsedExpression(TagProperty.ARGUMENT, "\""+tags.argumentname()+"\""));
		
		for(int i=0; i0)
			{
				try
				{
					IModelFeature mf = getComponent().getFeature(IModelFeature.class);
					Object val = SJavaParser.evaluateExpression(tag.include(), mf.getModel().getAllImports(), mf.getFetcher(), IComponentManager.get().getClassLoader());
					if(val instanceof Boolean && ((Boolean)val).booleanValue())
						params.add(new UnparsedExpression(TagProperty.NAME+"_"+i, tag.value()));
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}
			}
			else
			{*/
				params.add(new UnparsedExpression(TagProperty.NAME+"_"+i, tag.value()));
			//}
		}
		
		IFuture ret = IFuture.DONE;
		if(params.size()>0)
		{
			INFProperty prop = AbstractNFProperty.createProperty(TagProperty.class, getComponent(), ser, null, params);
			ret = prov.addNFProperty(prop);
		}
		return ret;
	}
	
	/**
	 *  Add nf properties from a type.
	 */
	public IFuture addNFMethodProperties(List nfprops, IService ser, MethodInfo mi)
	{
		INFMixedPropertyProvider prov = getProvidedServicePropertyProvider(ser.getServiceId());
		FutureBarrier bar = new FutureBarrier<>();
		
		for(NFPropertyInfo nfprop: nfprops)
		{
			Class clazz = nfprop.getClazz().getType(ComponentManager.get().getClassLoader());
			INFProperty prop = AbstractNFProperty.createProperty(clazz, getComponent(), ser, mi, nfprop.getParameters());
			bar.add(prov.addMethodNFProperty(mi, prop));
		}
		
		return bar.waitFor();
	}
	
	/**
	 *  Get external feature facade.
	 */
	public  T getExternalFacade(Object context)
	{
		T ret = null;
		if(context instanceof IService)
		{
//				IServiceIdentifier sid = (IServiceIdentifier)context;
			ret = (T)getProvidedServicePropertyProvider(((IService)context).getServiceId());
		}
		else 
		{
			ret = (T)getComponentPropertyProvider();
		}
		
		return ret;
	}
	
//		/**
//		 * 
//		 */
//		public  Class getExternalFacadeType(Object context)
//		{
//			Class ret = (Class)INFPropertyComponentFeature.class;
//			if(context instanceof IService)
//			{
//				ret = (Class)INFMixedPropertyProvider.class;
//			}
//			return ret;
//		}
	
	
	/**
	 *  Returns the declared names of all non-functional properties of this service.
	 *  @return The names of the non-functional properties of this service.
	 */
	public IFuture getNFPropertyNames()
	{
		return getComponentPropertyProvider().getNFPropertyNames();
	}
	
	/**
	 *  Returns the names of all non-functional properties of this service.
	 *  @return The names of the non-functional properties of this service.
	 */
	public IFuture getNFAllPropertyNames()
	{
		return getComponentPropertyProvider().getNFAllPropertyNames();
	}
	
	/**
	 *  Returns the meta information about a non-functional property of this service.
	 *  @param name Name of the property.
	 *  @return The meta information about a non-functional property of this service.
	 */
	public IFuture> getNFPropertyMetaInfos()
	{
		return getComponentPropertyProvider().getNFPropertyMetaInfos();
	}
	
	/**
	 *  Returns the meta information about a non-functional property of this service.
	 *  @param name Name of the property.
	 *  @return The meta information about a non-functional property of this service.
	 */
	public IFuture getNFPropertyMetaInfo(String name)
	{
		return getNFPropertyMetaInfo(name);
	}
	
	/**
	 *  Returns the current value of a non-functional property of this service.
	 *  @param name Name of the property.
	 *  @param type Type of the property value.
	 *  @return The current value of a non-functional property of this service.
	 */
	public  IFuture getNFPropertyValue(String name)
	{
		return getComponentPropertyProvider().getNFPropertyValue(name);
	}
	
	/**
	 *  Returns the current value of a non-functional property of this service, performs unit conversion.
	 *  @param name Name of the property.
	 *  @param type Type of the property value.
	 *  @param unit Unit of the property value.
	 *  @return The current value of a non-functional property of this service.
	 */
	public  IFuture getNFPropertyValue(String name, U unit)
	{
		return getComponentPropertyProvider().getNFPropertyValue(name, unit);
	}
	
	/**
	 *  Returns the current value of a non-functional property of this component.
	 *  @param name Name of the property.
	 *  @param type Type of the property value.
	 *  @return The current value of a non-functional property of this component as string.
	 */
	public IFuture getNFPropertyPrettyPrintValue(String name) 
	{
		return getComponentPropertyProvider().getNFPropertyPrettyPrintValue(name);
	}
	
	/**
	 *  Add a non-functional property.
	 *  @param nfprop The property.
	 */
	public IFuture addNFProperty(INFProperty nfprop)
	{
		return getComponentPropertyProvider().addNFProperty(nfprop);
	}
	
	/**
	 *  Remove a non-functional property.
	 *  @param The name.
	 */
	public IFuture removeNFProperty(String name)
	{
		return getComponentPropertyProvider().removeNFProperty(name);
	}
	
	/**
	 *  Shutdown the provider.
	 */
	public IFuture shutdownNFPropertyProvider()
	{
		return getComponentPropertyProvider().shutdownNFPropertyProvider();
	}
	
	//-------- service methods --------
	
	/**
	 *  Returns the declared names of all non-functional properties of this service.
	 *  @return The names of the non-functional properties of this service.
	 */
	public IFuture getNFPropertyNames(IServiceIdentifier sid)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			 return getProvidedServicePropertyProvider(sid).getNFPropertyNames();
		}
		else
		{
			final Future ret = new Future();

			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				//return nfp.getProvidedServicePropertyProvider(sid).getNFPropertyNames();
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).getNFPropertyNames(): new Future(SUtil.EMPTY_STRING_ARRAY);
			}).delegateTo(ret);
			
			/*component.getExternalAccessAsync(sid.getProviderId()).addResultListener(new ExceptionDelegationResultListener(ret)
			{
				public void customResultAvailable(IExternalAccess result)
				{
					result.scheduleStep(new IPriorityComponentStep()
					{
						@Classname("getNFPropertyNames9")
						public IFuture execute(IInternalAccess ia)
						{
							INFPropertyComponentFeature nfp = ia.getFeature(INFPropertyComponentFeature.class);
							return nfp.getProvidedServicePropertyProvider(sid).getNFPropertyNames();
						}
					}).addResultListener(new DelegationResultListener(ret));
				}
			});*/

			return ret;
		}
	}
	
	/**
	 *  Returns the names of all non-functional properties of this service.
	 *  @return The names of the non-functional properties of this service.
	 */
	public IFuture getNFAllPropertyNames(final IServiceIdentifier sid)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			 return getProvidedServicePropertyProvider(sid).getNFAllPropertyNames();
		}
		else
		{
			final Future ret = new Future();
			
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).getNFAllPropertyNames(): new Future(SUtil.EMPTY_STRING_ARRAY);
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	/**
	 *  Returns the meta information about a non-functional property of this service.
	 *  @param name Name of the property.
	 *  @return The meta information about a non-functional property of this service.
	 */
	public IFuture> getNFPropertyMetaInfos(IServiceIdentifier sid)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			INFMixedPropertyProvider prov = getProvidedServicePropertyProvider(sid);
			if(prov!=null)
			{
				IFuture> metainf = prov.getNFPropertyMetaInfos();
				if(metainf!=null)
				{
					return metainf;
				}
			}
			return new Future>(new HashMap());
		}
		else
		{
			final Future> ret = new Future>();
			
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				INFMixedPropertyProvider prov = nfp.getProvidedServicePropertyProvider(sid);
				if(prov!=null)
				{
					IFuture> metainf = prov.getNFPropertyMetaInfos();
					if(metainf!=null)
						return metainf;
				}
				return new Future>(new HashMap());				
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	/**
	 *  Returns the meta information about a non-functional property of this service.
	 *  @param name Name of the property.
	 *  @return The meta information about a non-functional property of this service.
	 */
	public IFuture getNFPropertyMetaInfo(final IServiceIdentifier sid, final String name)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).getNFPropertyMetaInfo(name);
		}
		else
		{
			final Future ret = new Future();
			
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).getNFPropertyMetaInfo(name): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	/**
	 *  Returns the current value of a non-functional property of this service.
	 *  @param name Name of the property.
	 *  @param type Type of the property value.
	 *  @return The current value of a non-functional property of this service.
	 */
	public  IFuture getNFPropertyValue(final IServiceIdentifier sid, final String name)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).getNFPropertyValue(name);
		}
		else
		{
			final Future ret = new Future();
			
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).getNFPropertyValue(name): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	/**
	 *  Returns the current value of a non-functional property of this service, performs unit conversion.
	 *  @param name Name of the property.
	 *  @param type Type of the property value.
	 *  @param unit Unit of the property value.
	 *  @return The current value of a non-functional property of this service.
	 */
	public  IFuture getNFPropertyValue(final IServiceIdentifier sid, final String name, final U unit)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).getNFPropertyValue(name, unit);
		}
		else
		{
			final Future ret = new Future();
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).getNFPropertyValue(name, unit): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	/**
	 *  Returns the current value of a non-functional property of this service, performs unit conversion.
	 *  @param name Name of the property.
	 *  @param type Type of the property value.
	 *  @param unit Unit of the property value.
	 *  @return The current value of a non-functional property of this service as string.
	 */
	public IFuture getNFPropertyPrettyPrintValue(IServiceIdentifier sid, String name) 
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).getNFPropertyPrettyPrintValue(name);
		}
		else
		{
			final Future ret = new Future();
			
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).getNFPropertyPrettyPrintValue(name): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	/**
	 *  Add a non-functional property.
	 *  @param nfprop The property.
	 */
	public IFuture addNFProperty(final IServiceIdentifier sid, final INFProperty nfprop)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).addNFProperty(nfprop);
		}
		else
		{
			final Future ret = new Future();
			
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).addNFProperty(nfprop): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	/**
	 *  Remove a non-functional property.
	 *  @param The name.
	 */
	public IFuture removeNFProperty(final IServiceIdentifier sid, final String name)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).removeNFProperty(name);
		}
		else
		{
			final Future ret = new Future();
			
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).removeNFProperty(name): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	/**
	 *  Shutdown the provider.
	 */
	public IFuture shutdownNFPropertyProvider(final IServiceIdentifier sid)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).shutdownNFPropertyProvider();
		}
		else
		{
			final Future ret = new Future();
			
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).shutdownNFPropertyProvider(): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	//-------- provided service methods --------
	
	/**
	 *  Returns meta information about a non-functional properties of all methods.
	 *  @return The meta information about a non-functional properties.
	 */
	public IFuture>> getMethodNFPropertyMetaInfos(final IServiceIdentifier sid)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).getMethodNFPropertyMetaInfos();
		}
		else
		{
			final Future>> ret = new Future>>();

			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>>>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).getMethodNFPropertyMetaInfos(): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	/**
	 *  Returns the names of all non-functional properties of the specified method.
	 *  @param method The method targeted by this operation.
	 *  @return The names of the non-functional properties of the specified method.
	 */
	public IFuture getMethodNFPropertyNames(final IServiceIdentifier sid, final MethodInfo method)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).getMethodNFPropertyNames(method);
		}
		else
		{
			final Future ret = new Future();
			
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).getMethodNFPropertyNames(method): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	/**
	 *  Returns the names of all non-functional properties of this method.
	 *  This includes the properties of all parent components.
	 *  @return The names of the non-functional properties of this method.
	 */
	public IFuture getMethodNFAllPropertyNames(final IServiceIdentifier sid, final MethodInfo method)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).getMethodNFPropertyNames(method);
		}
		else
		{
			final Future ret = new Future();
			
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).getMethodNFAllPropertyNames(method): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	/**
	 *  Returns meta information about a non-functional properties of a method.
	 *  @return The meta information about a non-functional properties.
	 */
	public IFuture> getMethodNFPropertyMetaInfos(final IServiceIdentifier sid, final MethodInfo method)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).getMethodNFPropertyMetaInfos(method);
		}
		else
		{
			final Future> ret = new Future>();
			
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).getMethodNFPropertyMetaInfos(method): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	/**
	 *  Returns the meta information about a non-functional property of the specified method.
	 *  @param method The method targeted by this operation.
	 *  @param name Name of the property.
	 *  @return The meta information about a non-functional property of the specified method.
	 */
	public IFuture getMethodNFPropertyMetaInfo(final IServiceIdentifier sid, final MethodInfo method, final String name)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).getMethodNFPropertyMetaInfo(method, name);
		}
		else
		{
			final Future ret = new Future();
			
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).getMethodNFPropertyMetaInfo(method, name): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	/**
	 *  Returns the current value of a non-functional property of the specified method.
	 *  @param method The method targeted by this operation.
	 *  @param name Name of the property.
	 *  @param type Type of the property value.
	 *  @return The current value of a non-functional property of the specified method.
	 */
	public  IFuture getMethodNFPropertyValue(final IServiceIdentifier sid, final MethodInfo method, final String name)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).getMethodNFPropertyValue(method, name);
		}
		else
		{
			final Future ret = new Future();
			
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).getMethodNFPropertyValue(method, name): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	/**
	 *  Returns the current value of a non-functional property of the specified method, performs unit conversion.
	 *  @param method The method targeted by this operation.
	 *  @param name Name of the property.
	 *  @param type Type of the property value.
	 *  @param unit Unit of the property value.
	 *  @return The current value of a non-functional property of the specified method.
	 */
//		public  IFuture getNFPropertyValue(Method method, String name, Class unit);
	public  IFuture getMethodNFPropertyValue(final IServiceIdentifier sid, final MethodInfo method, final String name, final U unit)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).getMethodNFPropertyValue(method, name, unit);
		}
		else
		{
			final Future ret = new Future();
			
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).getMethodNFPropertyValue(method, name, unit): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}
	

	public IFuture getMethodNFPropertyPrettyPrintValue(IServiceIdentifier sid, MethodInfo method, String name) 
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).getMethodNFPropertyPrettyPrintValue(method, name);
		}
		else
		{
			final Future ret = new Future();
			
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).getMethodNFPropertyPrettyPrintValue(method, name): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	/**
	 *  Add a non-functional property.
	 *  @param method The method targeted by this operation.
	 *  @param nfprop The property.
	 */
	public IFuture addMethodNFProperty(final IServiceIdentifier sid, final MethodInfo method, final INFProperty nfprop)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).addMethodNFProperty(method, nfprop);
		}
		else
		{
			final Future ret = new Future();
			
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).addMethodNFProperty(method, nfprop): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}
	
	/**
	 *  Remove a non-functional property.
	 *  @param method The method targeted by this operation.
	 *  @param The name.
	 */
	public IFuture removeMethodNFProperty(final IServiceIdentifier sid, final MethodInfo method, final String name)
	{
		if(sid.getProviderId().equals(getComponent().getId()))
		{
			return getProvidedServicePropertyProvider(sid).removeMethodNFProperty(method, name);
		}
		else
		{
			final Future ret = new Future();
			IExternalAccess ex = getComponent().getExternalAccess(sid.getProviderId());
			
			ex.scheduleAsyncStep((IThrowingFunction>)agent ->
			{
				INFPropertyFeature nfp = agent.getFeature(INFPropertyFeature.class);
				return nfp!=null? nfp.getProvidedServicePropertyProvider(sid).removeMethodNFProperty(method, name): new Future<>(new RuntimeException("No nf properties"));
			}).delegateTo(ret);
			
			return ret;
		}
	}

	//-------- required properties --------
	
	/**
	 *  Returns the declared names of all non-functional properties of this service.
	 *  @return The names of the non-functional properties of this service.
	 */
	public IFuture getRequiredNFPropertyNames(final IServiceIdentifier sid)
	{
		return getRequiredServicePropertyProvider(sid).getNFPropertyNames();
	}
	
	/**
	 *  Returns the names of all non-functional properties of this service.
	 *  @return The names of the non-functional properties of this service.
	 */
	public IFuture getRequiredNFAllPropertyNames(final IServiceIdentifier sid)
	{
		return getRequiredServicePropertyProvider(sid).getNFAllPropertyNames();
	}
	
	/**
	 *  Returns the meta information about a non-functional property of this service.
	 *  @param name Name of the property.
	 *  @return The meta information about a non-functional property of this service.
	 */
	public IFuture> getRequiredNFPropertyMetaInfos(final IServiceIdentifier sid)
	{
		return getRequiredServicePropertyProvider(sid).getNFPropertyMetaInfos();
	}
	
	/**
	 *  Returns the meta information about a non-functional property of this service.
	 *  @param name Name of the property.
	 *  @return The meta information about a non-functional property of this service.
	 */
	public IFuture getRequiredNFPropertyMetaInfo(final IServiceIdentifier sid, final String name)
	{
		return getRequiredServicePropertyProvider(sid).getNFPropertyMetaInfo(name);
	}
	
	/**
	 *  Returns the current value of a non-functional property of this service.
	 *  @param name Name of the property.
	 *  @param type Type of the property value.
	 *  @return The current value of a non-functional property of this service.
	 */
	public  IFuture getRequiredNFPropertyValue(final IServiceIdentifier sid, final String name)
	{
		return getRequiredServicePropertyProvider(sid).getNFPropertyValue(name);
	}
	
	/**
	 *  Returns the current value of a non-functional property of this service, performs unit conversion.
	 *  @param name Name of the property.
	 *  @param type Type of the property value.
	 *  @param unit Unit of the property value.
	 *  @return The current value of a non-functional property of this service.
	 */
//		public  IFuture getNFPropertyValue(String name, Class unit);
	public  IFuture getRequiredNFPropertyValue(final IServiceIdentifier sid, final String name, final U unit)
	{
		return getRequiredServicePropertyProvider(sid).getNFPropertyValue(name, unit);
	}
	
	/**
	 *  Returns the current value of a non-functional property of this service.
	 *  @param name Name of the property.
	 *  @param type Type of the property value.
	 *  @return The current value of a non-functional property of this service.
	 */
	public IFuture getRequiredNFPropertyPrettyPrintValue(IServiceIdentifier sid, String name) 
	{
		return getRequiredServicePropertyProvider(sid).getNFPropertyPrettyPrintValue(name);
	}
	
	/**
	 *  Add a non-functional property.
	 *  @param nfprop The property.
	 */
	public IFuture addRequiredNFProperty(final IServiceIdentifier sid, final INFProperty nfprop)
	{
		return getRequiredServicePropertyProvider(sid).addNFProperty(nfprop);
	}
	
	/**
	 *  Remove a non-functional property.
	 *  @param The name.
	 */
	public IFuture removeRequiredNFProperty(final IServiceIdentifier sid, final String name)
	{
		return getRequiredServicePropertyProvider(sid).removeNFProperty(name);
	}
	
	/**
	 *  Shutdown the provider.
	 */
	public IFuture shutdownRequiredNFPropertyProvider(final IServiceIdentifier sid)
	{
		return getRequiredServicePropertyProvider(sid).shutdownNFPropertyProvider();
	}
	
	/**
	 *  Returns meta information about a non-functional properties of all methods.
	 *  @return The meta information about a non-functional properties.
	 */
	public IFuture>> getRequiredMethodNFPropertyMetaInfos(final IServiceIdentifier sid)
	{
		return getRequiredServicePropertyProvider(sid).getMethodNFPropertyMetaInfos();
	}
	
	/**
	 *  Returns the names of all non-functional properties of the specified method.
	 *  @param method The method targeted by this operation.
	 *  @return The names of the non-functional properties of the specified method.
	 */
	public IFuture getRequiredMethodNFPropertyNames(final IServiceIdentifier sid, final MethodInfo method)
	{
		return getRequiredServicePropertyProvider(sid).getMethodNFPropertyNames(method);
	}
	
	/**
	 *  Returns the names of all non-functional properties of this method.
	 *  This includes the properties of all parent components.
	 *  @return The names of the non-functional properties of this method.
	 */
	public IFuture getRequiredMethodNFAllPropertyNames(final IServiceIdentifier sid, final MethodInfo method)
	{
		return getRequiredServicePropertyProvider(sid).getMethodNFAllPropertyNames(method);
	}
	
	/**
	 *  Returns meta information about a non-functional properties of a method.
	 *  @return The meta information about a non-functional properties.
	 */
	public IFuture> getRequiredMethodNFPropertyMetaInfos(final IServiceIdentifier sid, final MethodInfo method)
	{
		return getRequiredServicePropertyProvider(sid).getMethodNFPropertyMetaInfos(method);
	}
	
	/**
	 *  Returns the meta information about a non-functional property of the specified method.
	 *  @param method The method targeted by this operation.
	 *  @param name Name of the property.
	 *  @return The meta information about a non-functional property of the specified method.
	 */
	public IFuture getRequiredMethodNFPropertyMetaInfo(final IServiceIdentifier sid, final MethodInfo method, final String name)
	{
		return getRequiredServicePropertyProvider(sid).getMethodNFPropertyMetaInfo(method, name);
	}
	
	/**
	 *  Returns the current value of a non-functional property of the specified method.
	 *  @param method The method targeted by this operation.
	 *  @param name Name of the property.
	 *  @param type Type of the property value.
	 *  @return The current value of a non-functional property of the specified method.
	 */
	public  IFuture getRequiredMethodNFPropertyValue(final IServiceIdentifier sid, final MethodInfo method, final String name)
	{
		return getRequiredServicePropertyProvider(sid).getMethodNFPropertyValue(method, name);
	}
	
	/**
	 *  Returns the current value of a non-functional property of the specified method, performs unit conversion.
	 *  @param method The method targeted by this operation.
	 *  @param name Name of the property.
	 *  @param type Type of the property value.
	 *  @param unit Unit of the property value.
	 *  @return The current value of a non-functional property of the specified method.
	 */
//		public  IFuture getNFPropertyValue(Method method, String name, Class unit);
	public  IFuture getRequiredMethodNFPropertyValue(final IServiceIdentifier sid, final MethodInfo method, final String name, final U unit)
	{
		return getRequiredServicePropertyProvider(sid).getMethodNFPropertyValue(method, name, unit);
	}
	
	/**
	 *  Returns the current value of a non-functional property of the specified method, performs unit conversion.
	 *  @param method The method targeted by this operation.
	 *  @param name Name of the property.
	 *  @param type Type of the property value.
	 *  @param unit Unit of the property value.
	 *  @return The current value of a non-functional property of the specified method.
	 */
	public IFuture getRequiredMethodNFPropertyPrettyPrintValue(IServiceIdentifier sid, MethodInfo method, String name) 
	{
		return getRequiredServicePropertyProvider(sid).getMethodNFPropertyPrettyPrintValue(method, name);
	}
	
	/**
	 *  Add a non-functional property.
	 *  @param method The method targeted by this operation.
	 *  @param nfprop The property.
	 */
	public IFuture addRequiredMethodNFProperty(final IServiceIdentifier sid, final MethodInfo method, final INFProperty nfprop)
	{
		return getRequiredServicePropertyProvider(sid).addMethodNFProperty(method, nfprop);
	}
	
	/**
	 *  Remove a non-functional property.
	 *  @param method The method targeted by this operation.
	 *  @param The name.
	 */
	public IFuture removeRequiredMethodNFProperty(final IServiceIdentifier sid, final MethodInfo method, final String name)
	{
		return getRequiredServicePropertyProvider(sid).removeMethodNFProperty(method, name);
	}
	
	/**
	 *  Rank the services of a search with a specific ranker.
	 */
	public  ITerminableIntermediateFuture rankServices(ITerminableIntermediateFuture searchfut, 
		IServiceRanker ranker, IRankingSearchTerminationDecider decider)
	{
		TerminableIntermediateDelegationFuture ret = new TerminableIntermediateDelegationFuture();
		searchfut.addResultListener(new ServiceRankingDelegationResultListener(ret, searchfut, ranker, decider));
		return ret;
	}
	
	/**
	 *  Rank the services of a search with a specific ranker and emit the scores.
	 */
	public  ITerminableIntermediateFuture> rankServicesWithScores(ITerminableIntermediateFuture searchfut, 
		IServiceRanker ranker, IRankingSearchTerminationDecider decider)
	{
		TerminableIntermediateDelegationFuture> ret = new TerminableIntermediateDelegationFuture>();
		searchfut.addResultListener(new ServiceRankingDelegationResultListener2(ret, searchfut, ranker, decider));
		return ret;
	}	
	
	/**
	 *  Counter listener that allows to set the max after usage.
	 */
	public static class LateCounterListener implements IResultListener
	{
		IResultListener delegate;
		int max = -1;
		int cnt = 0;
		
		public LateCounterListener(IResultListener delegate)
		{
			this.delegate = delegate;
		}
		
		public void resultAvailable(T result)
		{
			cnt++;
			check();
		}
		
		public void exceptionOccurred(Exception exception)
		{
			cnt++;
			check();
		}
		
		protected void check()
		{
			if(max>-1 && max==cnt)
			{
				delegate.resultAvailable(null);
			}
		}
		
		public void setMax(int max)
		{
			this.max = max;
			check();
		}
	}
}