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

jadex.bridge.service.component.ProvidedServicesComponentFeature 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.service.component;

import java.lang.reflect.Array;
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.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

import jadex.base.IPlatformConfiguration;
import jadex.base.Starter;
import jadex.bridge.IExternalAccess;
import jadex.bridge.IInternalAccess;
import jadex.bridge.ProxyFactory;
import jadex.bridge.component.ComponentCreationInfo;
import jadex.bridge.component.IExecutionFeature;
import jadex.bridge.component.impl.AbstractComponentFeature;
import jadex.bridge.modelinfo.ConfigurationInfo;
import jadex.bridge.modelinfo.UnparsedExpression;
import jadex.bridge.sensor.service.IMethodInvocationListener;
import jadex.bridge.service.BasicService;
import jadex.bridge.service.IInternalService;
import jadex.bridge.service.IService;
import jadex.bridge.service.IServiceIdentifier;
import jadex.bridge.service.ProvidedServiceImplementation;
import jadex.bridge.service.ProvidedServiceInfo;
import jadex.bridge.service.PublishInfo;
import jadex.bridge.service.RequiredServiceInfo;
import jadex.bridge.service.ServiceIdentifier;
import jadex.bridge.service.ServiceScope;
import jadex.bridge.service.annotation.Service;
import jadex.bridge.service.search.IServiceRegistry;
import jadex.bridge.service.search.ServiceNotFoundException;
import jadex.bridge.service.search.ServiceQuery;
import jadex.bridge.service.search.ServiceRegistry;
import jadex.bridge.service.types.library.ILibraryService;
import jadex.bridge.service.types.monitoring.IMonitoringService.PublishEventLevel;
import jadex.bridge.service.types.publish.IPublishService;
import jadex.commons.IValueFetcher;
import jadex.commons.MethodInfo;
import jadex.commons.SReflect;
import jadex.commons.SUtil;
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.IResultListener;
import jadex.commons.future.IntermediateEmptyResultListener;
import jadex.javaparser.SJavaParser;

/**
 *  Feature for provided services.
 */
public class ProvidedServicesComponentFeature extends AbstractComponentFeature implements IProvidedServicesFeature
{
	//-------- attributes --------
	
	/** The map of platform services. */
	protected Map, Collection> services;
	
	/** The map of provided service infos. (sid -> method listener) */
	protected Map servicelisteners;
	
	/** The map of provided service infos. (sid -> provided service info) */
	protected Map serviceinfos;
	
	//-------- constructors --------
	
	/**
	 *  Factory method constructor for instance level.
	 */
	public ProvidedServicesComponentFeature(IInternalAccess component, ComponentCreationInfo cinfo)
	{
		super(component, cinfo);
	}
	
	//-------- IComponentFeature interface / instance level --------
	
	/**
	 *  Initialize the feature.
	 */
	public IFuture	init()
	{
		final Future ret = new Future();
		
		// Collect provided services from model (name or type -> provided service info)
		ProvidedServiceInfo[] ps = component.getModel().getProvidedServices();
		Map sermap = new LinkedHashMap();
		for(int i=0; i args = getComponent().getInternalAccess().getArguments();
		Boolean extaarg = (Boolean)args.get("externalaccess");
		Boolean extaplatarg = (Boolean)((Map)Starter.getPlatformValue(getComponent().getId(), IPlatformConfiguration.PLATFORMARGS)).get("externalaccess");
		boolean on = extaarg!=null? extaarg.booleanValue(): extaplatarg!=null? extaplatarg.booleanValue(): true;
//			System.out.println("on: "+on+" "+extaarg+" "+extaplatarg);
		if(on)
		{
			ProvidedServiceImplementation impl = new ProvidedServiceImplementation();
			impl.setValue("$component.getExternalAccess()");
			// platform external access service will be published network wide, all others only on platform
			ProvidedServiceInfo psi= new ProvidedServiceInfo("externalaccessservice", IExternalAccess.class, impl, 
				getComponent().getId().equals(getComponent().getId().getRoot())? ServiceScope.NETWORK: ServiceScope.PLATFORM, null, null, null, null);
			sermap.put("externalaccessservice", psi);
		}
		
		FutureBarrier bar = new FutureBarrier<>();
		
		// Instantiate service objects
		for(ProvidedServiceInfo info: sermap.values())
		{
			// Evaluate and replace scope expression, if any.
			ServiceScope scope = info.getScope();
			if(ServiceScope.EXPRESSION.equals(scope))
			{
				scope = (ServiceScope)SJavaParser.getParsedValue(info.getScopeExpression(), component.getModel().getAllImports(), component.getFetcher(), component.getClassLoader());
				info = new ProvidedServiceInfo(info.getName(), info.getType(), info.getImplementation(), scope, info.getScopeExpression(), info.getSecurity(), info.getPublish(), info.getProperties(), info.isSystemService());
//				System.out.println("expression scope '"
//					+ (info.getScopeExpression()!=null ? info.getScopeExpression().getValue() : "")
//					+ "': "+scope);
			}
				
			final Future fut = new Future<>();
			bar.addFuture(fut);
			
			final ProvidedServiceImplementation	impl = info.getImplementation();
			// Virtual service (e.g. promoted)
			if(impl!=null && impl.getBinding()!=null)
			{
				RequiredServiceInfo rsi = new RequiredServiceInfo(BasicService.generateServiceName(info.getType().getType( 
					component.getClassLoader(), component.getModel().getAllImports()))+":virtual", info.getType().getType(component.getClassLoader(), component.getModel().getAllImports()));
				IServiceIdentifier sid = BasicService.createServiceIdentifier(component, 
					rsi.getName(), rsi.getType().getType(component.getClassLoader(), component.getModel().getAllImports()),
					BasicServiceInvocationHandler.class, component.getModel().getResourceIdentifier(), info);
				final IInternalService service = BasicServiceInvocationHandler.createDelegationProvidedServiceProxy(
					component, sid, rsi, impl.getBinding(), component.getClassLoader(), Starter.isRealtimeTimeout(component.getId(), true));
				
				addService(service, info);
				fut.setResult(null);
			}
			else
			{
				final ProvidedServiceInfo finfo = info;
				createServiceImplementation(info, getComponent().getFetcher())
					.then(ser ->
				{
					// Implementation may null to disable service in some configurations.
					if(ser!=null)
					{
						UnparsedExpression[] ins = finfo.getImplementation().getInterceptors();
						IServiceInvocationInterceptor[] ics = null;
						if(ins!=null)
						{
							ics = new IServiceInvocationInterceptor[ins.length];
							for(int i=0; i0)
								{
									ics[i] = (IServiceInvocationInterceptor)SJavaParser.evaluateExpression(ins[i].getValue(), component.getModel().getAllImports(), component.getFetcher(), component.getClassLoader());
								}
								else
								{
									try
									{
										ics[i] = (IServiceInvocationInterceptor)ins[i].getClazz().getType(component.getClassLoader(), component.getModel().getAllImports()).newInstance();
									}
									catch(Exception e)
									{
										e.printStackTrace();
									}
								}
							}
						}
						
						final Class type = finfo.getType().getType(component.getClassLoader(), component.getModel().getAllImports());
						PublishEventLevel elm = component.getDescription().getMonitoring()!=null? component.getDescription().getMonitoring(): null;
//						 todo: remove this? currently the level cannot be turned on due to missing interceptor
						boolean moni = elm!=null? !PublishEventLevel.OFF.equals(elm.getLevel()): false; 
						final IInternalService proxy = BasicServiceInvocationHandler.createProvidedServiceProxy(
							component, ser, finfo.getName(), type, ics,
							moni, finfo);
						
						addService(proxy, finfo);
					}
					fut.setResult(null);
					
				}).catchEx(e -> {e.printStackTrace(); fut.setResult(null);});
			}
		}
		
		bar.waitFor().then(v ->
		{
			// Start the services.
			Collection allservices = getAllServices();
			if(!allservices.isEmpty())
			{
				initServices(allservices.iterator()).addResultListener(new DelegationResultListener(ret));
			}
			else
			{
				ret.setResult(null);
			}
		}).catchEx(ret);
		
		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;
	}
	
	/**
	 *  Called when the feature is shutdowned.
	 */
	public IFuture shutdown()
	{
		Future ret = new Future();
		
		// Shutdown the services.
		Collection allservices = getAllServices();
		if(!allservices.isEmpty())
		{
			LinkedList list = new LinkedList(allservices);
			shutdownServices(list.descendingIterator()).addResultListener(new DelegationResultListener(ret));
		}
		else
		{
			ret.setResult(null);
		}
		
		return ret;
	}
	
	/**
	 *  Add a service.
	 *  @param service	The service object.
	 *  @param info	 The service info.
	 */
	protected void addService(IInternalService service, ProvidedServiceInfo info)
	{
		if(serviceinfos==null)
			serviceinfos = new HashMap();
		serviceinfos.put(service.getServiceId(), info);
		
		// Find service types
//		Class	type	= info.getType().getType(component.getClassLoader(), component.getModel().getAllImports());
		Class	type	= service.getServiceId().getServiceType().getType(component.getClassLoader(), component.getModel().getAllImports());
		Set> types = new LinkedHashSet>();
		types.add(type);
		for(Class sin: SReflect.getSuperInterfaces(new Class[]{type}))
		{
			if(sin.isAnnotationPresent(Service.class))
			{
				types.add(sin);
			}
		}

		if(services==null)
			services = Collections.synchronizedMap(new LinkedHashMap, Collection>());
		
//		return ServiceRegistry.getRegistry(component.getComponentIdentifier()).addService(service);
		
//		FutureBarrier bar = new FutureBarrier();
		
		for(Class servicetype: types)
		{
			Collection tmp = services.get(servicetype);
			if(tmp==null)
			{
				tmp = Collections.synchronizedList(new ArrayList());
				services.put(servicetype, tmp);
			}
			tmp.add(service);
			
			// Make service available immediately, even before start (hack???).
//			bar.addFuture(SynchronizedServiceRegistry.getRegistry(component.getComponentIdentifier()).addService(new ClassInfo(servicetype), service));
		}
		
		ServiceRegistry.getRegistry(component.getId()).addLocalService(service);
		//System.out.println("added service: "+component.getId()+" "+service.getServiceId());
//		return bar.waitFor();
	}
	
	/**
	 *  Get the provided service info for a service.
	 *  @param sid The service identifier.
	 *  @return The provided service info.
	 */
	protected ProvidedServiceInfo getProvidedServiceInfo(IServiceIdentifier sid)
	{
		return serviceinfos.get(sid);
	}
	
	/**
	 *  Remove a service.
	 *  @param service	The service object.
	 *  @param info	 The service info.
	 */
	protected void	removeService(IInternalService service)
	{
		IServiceRegistry	registry	= ServiceRegistry.getRegistry(component.getId());
		
		if(registry!=null) // Maybe null on rescue thread (todo: why remove() on rescue thread?)
		{
			registry.removeService(service.getServiceId());
		}
	}
	
	/**
	 *  Create a service implementation from description.
	 */
	public IFuture createServiceImplementation(ProvidedServiceInfo info, IValueFetcher fetcher) 
	{
		final Future ret = new Future<>();
		
		Object	ser	= null;
		ProvidedServiceImplementation impl = info.getImplementation();
		if(impl!=null && impl.getValue()!=null)
		{
			// todo: other Class imports, how can be found out?
			try
			{
//				SimpleValueFetcher fetcher = new SimpleValueFetcher(component.getFetcher());
//				fetcher.setValue("$servicename", info.getName());
//				fetcher.setValue("$servicetype", info.getType().getType(component.getClassLoader(), component.getModel().getAllImports()));
//				System.out.println("sertype: "+fetcher.fetchValue("$servicetype")+" "+info.getName());
				ser = SJavaParser.getParsedValue(impl, component.getModel().getAllImports(), fetcher, component.getClassLoader());
//				System.out.println("added: "+ser+" "+model.getName());
				ret.setResult(ser);
			}
			catch(RuntimeException e)
			{
//				e.printStackTrace();
				ret.setException(new RuntimeException("Service creation error: "+info, e));
			}
		}
		else if(impl!=null && impl.getClazz()!=null)
		{
			if(impl.getClazz().getType(component.getClassLoader(), component.getModel().getAllImports())!=null)
			{
				try
				{
					ser = impl.getClazz().getType(component.getClassLoader(), component.getModel().getAllImports()).newInstance();
					ret.setResult(ser);
				}
				catch(Exception e)
				{
					ret.setException(e);
				}
			}
			else
			{
				try
				{
					Class c = Class.forName("jadex.extension.rs.publish.JettyRestPublishService", false, component.getClassLoader());
					System.out.println("foundd: "+c);
				}
				catch(Exception e)
				{
					e.printStackTrace();
				}
				ret.setException(new RuntimeException("Could not load service implementation class: "+impl.getClazz()+" "+component.getClassLoader()));
			}
		}
		else
		{
			ret.setResult(null);
		}
//		else if(IExternalAccess.class.equals(info.getType().getType(getComponent().getClassLoader())))
//		{
//			ser = getComponent().getExternalAccess();
//		}
		
		return ret;
	}
	
	/**
	 *  Get all services in a single collection.
	 */
	protected Collection	getAllServices()
	{
		Collection allservices;
		if(services!=null && services.size()>0)
		{
			allservices = new LinkedHashSet();
			for(Iterator> it=services.values().iterator(); it.hasNext(); )
			{
				// Service may occur at different positions if added with more than one interface
				Collection col = it.next();
				for(IInternalService ser: col)
				{
					if(!allservices.contains(ser))
					{
						allservices.add(ser);
					}
				}
			}
		}
		else
		{
			allservices	= Collections.emptySet();
		}
		
		return allservices;
	}
	
	/**
	 *  Init the services one by one.
	 */
	protected IFuture initServices(final Iterator services)
	{
		final Future ret = new Future();
		if(services.hasNext())
		{
			final IInternalService	is	= services.next();
			initService(is).addResultListener(new DelegationResultListener(ret)
			{
				public void customResultAvailable(Void result)
				{
					initServices(services).addResultListener(new DelegationResultListener(ret));
				}
			});
//			component.getLogger().info("Starting service: "+is.getId());
//			is.setComponentAccess(component).addResultListener(new DelegationResultListener(ret)
//			{
//				public void customResultAvailable(Void result)
//				{
//					is.startService().addResultListener(new IResultListener()
//					{
//						public void resultAvailable(Void result)
//						{
//							component.getLogger().info("Started service: "+is.getId());
//							
//							
//						}
//						
//						public void exceptionOccurred(Exception exception)
//						{
//							ret.setException(exception);
//						}
//					});
//				}
//			});
		}
		else
		{
			ret.setResult(null);
		}
		return ret;
	}
	
	/**
	 *  Init a service, i.e. set the component (internal access) and call startService.
	 */
	protected IFuture initService(final IInternalService is)
	{
		final Future ret = new Future();
		component.getLogger().info("Starting service: "+is.getServiceId()+" "+component.getFeature(IExecutionFeature.class).isComponentThread());
		is.setComponentAccess(component).addResultListener(new DelegationResultListener(ret)
		{
			public void customResultAvailable(Void result)
			{
//				System.out.println("Starting service: "+is.getServiceId()+" "+component.getFeature(IExecutionFeature.class).isComponentThread());
				is.startService().addResultListener(new DelegationResultListener(ret)
				{
					public void customResultAvailable(Void result)
					{
						component.getLogger().info("Started service: "+is.getServiceId());
						serviceStarted(is).addResultListener(new DelegationResultListener(ret));
					}
				});
			}
		});
		return ret;
	}
	
	/**
	 *  Called after a service has been started.
	 */
	public IFuture serviceStarted(final IInternalService service)
	{
		final Future ret = new Future();
		ProvidedServiceInfo info = getProvidedServiceInfo(service.getServiceId());
		PublishInfo pit = info==null? null: info.getPublish();
		if(pit!=null)
		{
			// Hack?! evaluate the publish id string 
			// Must clone info to not change the model
			final PublishInfo pi = new PublishInfo(pit);
			try
			{
				String pid = (String)SJavaParser.evaluateExpression(pi.getPublishId(), getComponent().getModel().getAllImports(), getComponent().getFetcher(), getComponent().getClassLoader());
				pi.setPublishId(pid);
//				System.out.println("pid is now: "+pid);
			}
			catch(Exception e)
			{
//				e.printStackTrace();
			}
			
			if (pi.isMulti())
			{
				getComponent().getFeature(IRequiredServicesFeature.class)
					.searchServices(new ServiceQuery<>(IPublishService.class, pi.getPublishScope()))
					.addResultListener(new IntermediateEmptyResultListener()
				{
					/** Flag if published at least once. */
					protected boolean published = false;
					
					/** Flag if finished. */
					protected boolean finished = false;
					
					public void exceptionOccurred(Exception exception)
					{
						exception.printStackTrace();
					}

					public void intermediateResultAvailable(final IPublishService result)
					{
						result.publishService(service.getServiceId(), pi).addResultListener(new IResultListener()
						{
							public void resultAvailable(Void vresult)
							{
								if (!published)
								{
									ret.setResult(null);
									published = true;
								}
							}
							
							public void exceptionOccurred(Exception exception)
							{
								if (finished && !published)
								{
									getComponent().getLogger().severe("Could not publish: "+service.getServiceId());
									ret.setException(exception);
								}
							}
						});
					}

					public void finished()
					{
						finished = true;
					}
				});
//				SServiceProvider.getServices(getComponent(), IPublishService.class, pi.getPublishScope()).addResultListener(new IResultListener>()
//				{
//					public void exceptionOccurred(Exception exception)
//					{
//						getComponent().getLogger().severe("Could not publish: "+service.getId()+" "+exception.getMessage());
//						ret.setResult(null);
//					}
//					
//					public void resultAvailable(Collection result)
//					{
//						for (final IPublishService pubserv : result)
//						{
//							pubserv.publishService(service.getId(), pi).addResultListener(new IResultListener()
//							{
//								public void resultAvailable(Void result)
//								{
//								}
//								
//								public void exceptionOccurred(Exception exception)
//								{
//									getComponent().getLogger().severe("Could not publish to " + pubserv + ": "+service.getId()+" "+exception.getMessage());
//								}
//							});
//						}
//					}
//				});
			}
			else
			{
				getPublishService(getInternalAccess(), pi.getPublishType(), pi.getPublishScope(), (Iterator)null)
					.addResultListener(getComponent().getFeature(IExecutionFeature.class)
					.createResultListener(new ExceptionDelegationResultListener(ret)
				{
					public void customResultAvailable(IPublishService ps)
					{
						//System.out.println("Got publish service " + ps);
						ps.publishService(service.getServiceId(), pi)
							.addResultListener(getComponent().getFeature(IExecutionFeature.class).createResultListener(new DelegationResultListener(ret)));
					}
					public void exceptionOccurred(Exception exception)
					{
	//					exception.printStackTrace();
						getComponent().getLogger().severe("Could not publish: "+service.getServiceId()+" "+exception.getMessage());
						ret.setResult(null);
					}
				}));
			}
		}
		else
		{
			ret.setResult(null);
		}
		return ret;
	}
	
	/**
	 *  Called after a service has been shutdowned.
	 */
	public IFuture serviceShutdowned(final IInternalService service)
	{
		final Future ret = new Future();
//		adapter.invokeLater(new Runnable()
//		{
//			public void run()
//			{
				ProvidedServiceInfo info = getProvidedServiceInfo(service.getServiceId());
				final PublishInfo pi = info==null? null: info.getPublish();
//				System.out.println("shutdown ser: "+service.getId());
				if(pi!=null)
				{
					final IServiceIdentifier sid = service.getServiceId();
//					getPublishService(instance, pi.getPublishType(), null).addResultListener(instance.createResultListener(new IResultListener()
					getPublishService(getInternalAccess(), pi.getPublishType(), pi.getPublishScope(), null).addResultListener(new IResultListener()
					{
						public void resultAvailable(IPublishService ps)
						{
							ps.unpublishService(sid).addResultListener(new DelegationResultListener(ret));
						}
						
						public void exceptionOccurred(Exception exception)
						{
			//				instance.getLogger().severe("Could not unpublish: "+sid+" "+exception.getMessage());
							
							// ignore, if no publish info
							ret.setResult(null);
							// todo: what if publish info but no publish service?
						}
					});
				}
				else
				{
					ret.setResult(null);
				}				
//			}
//		});
		return ret;
	}
	
	/**
	 *  Get the publish service for a publish type (e.g. web service).
	 *  @param type The type.
	 *  @param services The iterator of publish services (can be null).
	 *  @return The publish service.
	 */
	public static IFuture getPublishService(final IInternalAccess instance, final String type, final ServiceScope scope, final Iterator services)
	{
		final Future ret = new Future();
		
		if(services==null)
		{
			IFuture> fut = instance.getFeature(IRequiredServicesFeature.class).searchServices(new ServiceQuery<>(IPublishService.class, scope));
			fut.addResultListener(instance.getFeature(IExecutionFeature.class).createResultListener(new ExceptionDelegationResultListener, IPublishService>(ret)
			{
				@Override
				public void exceptionOccurred(Exception exception) {
					// TODO Auto-generated method stub
					super.exceptionOccurred(exception);
					exception.printStackTrace();
				}
				public void customResultAvailable(Collection result)
				{
					getPublishService(instance, type, scope, result.iterator()).addResultListener(new DelegationResultListener(ret));
				}
			}));
		}
		else
		{
			if(services.hasNext())
			{
				final IPublishService ps = (IPublishService)services.next();
				ps.isSupported(type).addResultListener(instance.getFeature(IExecutionFeature.class).createResultListener(new ExceptionDelegationResultListener(ret)
				{
					public void customResultAvailable(Boolean supported)
					{
						if(supported.booleanValue())
						{
							ret.setResult(ps);
						}
						else
						{
							getPublishService(instance, type, scope, services).addResultListener(new DelegationResultListener(ret));
						}
					}
				}));
			}
			else
			{
//				ret.setResult(null);
				ret.setException(new ServiceNotFoundException("IPublishService not found."));
			}
		}
		
		return ret;
	}
	
	/**
	 *  Shutdown the services one by one.
	 */
	protected IFuture shutdownServices(final Iterator services)
	{
		final Future ret = new Future();
		if(services.hasNext())
		{
			final IInternalService	is	= services.next();
			// Remove service from registry before shutdown.
			removeService(is);
			
//			component.getLogger().info("Stopping service: "+is.getServiceId());
//			if(is instanceof IExternalAccess)
//				System.out.println("Stopping service: "+is.getServiceId());
			is.shutdownService().addResultListener(new DelegationResultListener(ret)
			{
				public void customResultAvailable(Void result)
				{
//					component.getLogger().info("Stopped service: "+is.getServiceId());
//					System.out.println("Stopped service: "+is.getServiceId());
					serviceShutdowned(is).addResultListener(new DelegationResultListener(ret)
					{
						public void customResultAvailable(Void result)
						{
							shutdownServices(services).addResultListener(new DelegationResultListener(ret));
						}
					});
				}
				
				@Override
				public void exceptionOccurred(Exception exception)
				{
					// On error -> print and continue shutdown process.
					component.getLogger().severe("Exception in service shutdown: "+is+"\n"+SUtil.getExceptionStacktrace(exception));
					customResultAvailable(null); 
				}
			});
		}
		else
		{
			ret.setResult(null);
		}
		return ret;
	}
	
	//-------- IProvidedServicesFeature interface --------

	/**
	 *  Get provided (declared) service.
	 *  @return The service.
	 */
	public IService getProvidedService(String name)
	{
		IService ret = null;
		if(services!=null)
		{
			for(Iterator> it=services.keySet().iterator(); it.hasNext() && ret==null; )
			{
				Collection sers = services.get(it.next());
				for(Iterator it2=sers.iterator(); it2.hasNext() && ret==null; )
				{
					IService ser = it2.next();
					if(ser.getServiceId().getServiceName().equals(name))
					{
						ret = ser;
					}
				}
			}
		}
		
		return ret;
	}
	
	/**
	 *  Get the raw implementation of the provided service.
	 *  @param clazz The class.
	 *  @return The raw object.
	 */
	public  T getProvidedServiceRawImpl(Class clazz)
	{
		T ret = null;
		
		T service = getProvidedService(clazz);
		if(service!=null)
		{
			BasicServiceInvocationHandler handler = (BasicServiceInvocationHandler)ProxyFactory.getInvocationHandler(service);
			ret = clazz.cast(handler.getDomainService());
		}
		
		return ret;
	}

	/**
	 *  Get the provided service implementation object by name.
	 *  
	 *  @param name The service name.
	 *  @return The service.
	 */
	public Object getProvidedServiceRawImpl(String name)
	{
		Object ret = null;
		
		Object service = getProvidedService(name);
		if(service!=null)
		{
			BasicServiceInvocationHandler handler = (BasicServiceInvocationHandler)ProxyFactory.getInvocationHandler(service);
			ret = handler.getDomainService();
		}
		
		return ret;	
	}
	
	/**
	 *  Get the provided service implementation object by id.
	 *  
	 *  @param name The service identifier.
	 *  @return The service.
	 */
	public Object getProvidedService(IServiceIdentifier sid)
	{
		Object ret = null;
		
		Object[] services = getProvidedServices(sid.getServiceType().getType(getComponent().getClassLoader()));
		if(services!=null)
		{
			for(Object ser: services)
			{
				// Special case for fake proxies, i.e. creating a service proxy for a known component (without knowing cid)
				if(sid.getServiceName().equals("NULL"))
				{
					((IService)ser).getServiceId().getServiceType().equals(sid.getServiceType());
					ret = (IService)ser;
					break;
				}
				else if(((IService)ser).getServiceId().equals(sid))
				{
					ret = (IService)ser;
					break;
				}
			}
		}
		
		return ret;	
	}
	
	/**
	 *  Get the provided service implementation object by id.
	 *  
	 *  @param name The service identifier.
	 *  @return The service.
	 */
	public Object getProvidedServiceRawImpl(IServiceIdentifier sid)
	{
		Object ret = null;
		
		Object[] services = getProvidedServices(sid.getServiceType().getType(getComponent().getClassLoader()));
		if(services!=null)
		{
			IService service = null;
			for(Object ser: services)
			{
				if(((IService)ser).getServiceId().equals(sid))
				{
					service = (IService)ser;
					break;
				}
			}
			if(service!=null)
			{
				if(ProxyFactory.isProxyClass(service.getClass()))
				{
					BasicServiceInvocationHandler handler = (BasicServiceInvocationHandler)ProxyFactory.getInvocationHandler(service);
					ret = handler.getDomainService();
				}
				else
				{
					ret = service;
				}
			}
		}
		
		return ret;	
	}
	
	/**
	 *  Get provided (declared) service.
	 *  @param clazz The interface.
	 *  @return The service.
	 */
	public  T[] getProvidedServices(Class clazz)
	{
		Collection coll	= null;
		if(services!=null)
		{
			if(clazz!=null)
			{
				coll = services.get(clazz);
			}
			else
			{
				coll = new HashSet();
				for(Class cl: services.keySet())
				{
					Collection sers = services.get(cl);
					coll.addAll(sers);
				}
			}			
		}
		
		T[] ret	= (T[])Array.newInstance(clazz==null? Object.class: clazz, coll!=null ? coll.size(): 0);
		return coll==null ? ret : coll.toArray(ret);
	}
	
	/**
	 *  Get provided (declared) service.
	 *  @param clazz The interface.
	 *  @return The service.
	 */
	public  T getProvidedService(Class clazz)
	{
		T[] ret = getProvidedServices(clazz);
		return ret.length>0? ret[0]: null;
	}

	/**
	 *  Get the services.
	 *  @return The services.
	 */
	public Map, Collection> getServices() 
	{
		return services;
	}

	/**
	 *  Add a service to the platform. 
	 *  If under the same name and type a service was contained,
	 *  the old one is removed and shutdowned.
	 *  @param type The public service interface.
	 *  @param service The service.
	 */
	public IFuture addService(String name, Class type, Object service)
	{
		return addService(name, type, null, service, null);
	}
	
	/**
	 *  Add a service to the platform.
	 *  If under the same name and type a service was contained,
	 *  the old one is removed and shutdowned.
	 *  @param type The public service interface.
	 *  @param service The service.
	 *  @param type The proxy type (@see{BasicServiceInvocationHandler}).
	 */
	public IFuture addService(String name, Class type, Object service, String proxytype)
	{
		ProvidedServiceImplementation	impl	= proxytype!=null ? new ProvidedServiceImplementation(null, null, proxytype, null, null) : null;
		ProvidedServiceInfo info = proxytype!=null ? new ProvidedServiceInfo(name, type, impl): null;
		return addService(name, type, null, service, info);
	}
	
	// todo:
//	/**
//	 *  Add a service to the platform. 
//	 *  If under the same name and type a service was contained,
//	 *  the old one is removed and shutdowned.
//	 *  @param type The public service interface.
//	 *  @param service The service.
//	 */
//	public void addService(String name, Class type, Object service, PublishInfo pi)
//	{
//		addService(name, type, BasicServiceInvocationHandler.PROXYTYPE_DECOUPLED, null, service, pi);
//	}
	
	/**
	 *  Add a service to the platform. 
	 *  If under the same name and type a service was contained,
	 *  the old one is removed and shutdowned.
	 *  @param type The public service interface.
	 *  @param service The service.
	 *  @param scope	The service scope.
	 */
	public IFuture addService(String name, Class type, Object service, PublishInfo pi, ServiceScope scope)
	{
		ProvidedServiceInfo psi = pi!=null || scope!=null ? new ProvidedServiceInfo(null, type, null, scope, null, null, pi, null): null;
		return addService(name, type, service, psi);
	}
	
	/**
	 *  Add a service to the platform. 
	 *  If under the same name and type a service was contained,
	 *  the old one is removed and shutdowned.
	 *  @param type The public service interface.
	 *  @param info The config settings.
	 */
	public IFuture addService(String name, Class type, Object service, ProvidedServiceInfo info)
	{
		return addService(name, type, null, service, info);
	}

	
	/**
	 *  Sets the tags of a service.
	 *  
	 *  @param sid The Service identifier.
	 *  @param tags The tags.
	 *  @return New service identifier.
	 */
	public IFuture setTags(IServiceIdentifier sid, String... tags)
	{
		Future ret = new Future<>();
		
		if(sid instanceof ServiceIdentifier)
		{
			ServiceIdentifier ssid = (ServiceIdentifier) sid;
			ssid.setTags(new HashSet(Arrays.asList(tags)));
			
			Collection coll = services.get(ssid.getServiceType().getType(component.getClassLoader()));
			if(coll != null)
			{
//				synchronized(coll)
//				{
					for(Iterator it = coll.iterator(); it.hasNext(); )
					{
						IInternalService ser = it.next();
						if(ser.getServiceId().equals(ssid))
						{
							ser.setServiceIdentifier(ssid);
							break;
						}
					}
//				}
			}
			
//			synchronized(servicelisteners)
//			{
			if (servicelisteners != null)
			{
				if (servicelisteners.containsKey(sid))
				{
					MethodListenerHandler hndlr = servicelisteners.get(sid);
					servicelisteners.put(ssid, hndlr);
				}
			}
//			}
			
//			synchronized(serviceinfos)
//			{
			if (serviceinfos != null)
			{
				if (serviceinfos.containsKey(sid))
				{
					ProvidedServiceInfo info = serviceinfos.get(sid);
					serviceinfos.put(ssid, info);
				}
			}
//			}
			
			ServiceRegistry.getRegistry(component.getId().getRoot()).updateService(ssid);
			
			ret.setResult(null);
		}
		else
		{
			ret.setException(new IllegalArgumentException("Unsupported service identifier type: " + sid));
		}
		
		return ret;
	}

	/**
	 *  Removes a service from the platform (shutdowns also the service).
	 *  @param service The service.
	 */
	public IFuture removeService(final IServiceIdentifier sid)
	{
		final Future ret = new Future();
		
		if(sid==null)
		{
			ret.setException(new IllegalArgumentException("Service identifier nulls."));
			return ret;
		}
			
		getServiceTypes(sid).addResultListener(new ExceptionDelegationResultListener>, Void>(ret)
		{
			public void customResultAvailable(final Collection> servicetypes)
			{
//				System.out.println("Removing service: " + servicetype);
				synchronized(this)
				{
					IInternalService service = null;
					
					for(Class servicetype: servicetypes)
					{
						Collection tmp = services!=null? services.get(servicetype): null;
						
						service = null;
						
						if(tmp!=null)
						{
							for(Iterator it=tmp.iterator(); it.hasNext() && service==null; )
							{
								final IInternalService tst = it.next();
								if(tst.getServiceId().equals(sid))
								{
									service = tst;
									tmp.remove(service);
								}
							}
							
							// Remove collection if last service
							if(tmp.isEmpty())
							{
								services.remove(servicetype);
							}
						}
						
						if(service==null)
						{
							ret.setException(new IllegalArgumentException("Service not found: "+sid));
							break;
						}
					}
					
					if(service!=null)
					{
						final IInternalService fservice = service;
						// Todo: fix started/terminated!? (i.e. addService() is ignored, when not started!?)
	//					if(!terminated)
	//					{
//							if(sid.toString().indexOf("Context")!=-1)
//									System.out.println("Terminating service: "+sid);
							getComponent().getLogger().info("Terminating service: "+sid);
							
							// Dispose nonfunc properties
							
							// todo: how to shutdown?
							
							ret.setResult(null);
							
//							service.shutdownNFPropertyProvider().addResultListener(new DelegationResultListener(ret)
//							{
//								public void customResultAvailable(Void result)
//								{
////									if(fservice.getId().toString().indexOf("ContextSer")!=-1)
////										System.out.println("hierda");
//									
//									fservice.shutdownService().addResultListener(new DelegationResultListener(ret)
//									{
//										public void customResultAvailable(Void result)
//										{
////											if(id.getParent()==null)// && sid.toString().indexOf("Async")!=-1)
////												System.out.println("Terminated service: "+sid);
//											getLogger().info("Terminated service: "+sid);
//											
//											for(Class key: servicetypes)
//											{
//												getServiceRegistry().removeService(new ClassInfo(key), fservice);
//											}
//											
//											serviceShutdowned(fservice).addResultListener(new DelegationResultListener(ret));
//										}
//										
//										public void exceptionOccurred(Exception exception)
//										{
//											exception.printStackTrace();
//											super.exceptionOccurred(exception);
//										}
//									});
//								}
//								
//								public void exceptionOccurred(Exception exception)
//								{
//									exception.printStackTrace();
//									super.exceptionOccurred(exception);
//								}
//							});							
	//					}
	//					else
	//					{
	//						ret.setResult(null);
	//					}
					}
				}
			}
		});
		
		return ret;
	}

	/**
	 * 
	 */
	public IFuture>> getServiceTypes(final IServiceIdentifier sid)
	{
		final Future>> ret = new Future>>();
		getServiceType(sid).addResultListener(new ExceptionDelegationResultListener, Collection>>(ret)
		{
			public void customResultAvailable(Class result)
			{
				// todo: cache results
				Set> res = new LinkedHashSet>();
				res.add(result);
				
				Class[] sins = SReflect.getSuperInterfaces(new Class[]{result});
				for(Class sin: sins)
				{
					if(sin.isAnnotationPresent(Service.class))
					{
						res.add(sin);
					}
				}
				
				ret.setResult(res);
			}
		});
		
		return ret;
	}
	
	/**
	 * 
	 */
	public IFuture> getServiceType(final IServiceIdentifier sid)
	{
		final Future> ret = new Future>();
		if(sid.getServiceType().getType(getComponent().getClassLoader(), getComponent().getModel().getAllImports())!=null)
		{
			ret.setResult(sid.getServiceType().getType(getComponent().getClassLoader(), getComponent().getModel().getAllImports())); // todo: only local? remote would cause nullpointer
		}
		else
		{
			ILibraryService ls = getComponent().getFeature(IRequiredServicesFeature.class).getLocalService(new ServiceQuery<>(ILibraryService.class));
			ls.getClassLoader(sid.getResourceIdentifier())
				.addResultListener(new ExceptionDelegationResultListener>(ret)
			{
				public void customResultAvailable(ClassLoader cl)
				{
					ret.setResult(sid.getServiceType().getType(cl));
				}
			});
		}
		return ret;
	}
	
	
	/**
	 *  Add a service to the component. 
	 *  @param type The service interface.
	 *  @param service The service.
	 *  @param proxytype The proxy type (@see{BasicServiceInvocationHandler}).
	 */
	public IFuture addService(final String name, final Class type, final IServiceInvocationInterceptor[] ics, final Object service, final ProvidedServiceInfo info)
	{
		final Future ret = new Future();
		
//		System.out.println("addS:"+service);

		PublishEventLevel elm = getComponent().getDescription().getMonitoring()!=null? getComponent().getDescription().getMonitoring(): null;
		// todo: remove this? currently the level cannot be turned on due to missing interceptor
//		boolean moni = elm!=null? !PublishEventLevel.OFF.equals(elm.getLevel()): false; 
		
		boolean moni = elm!=null && !PublishEventLevel.OFF.equals(elm); 
		final IInternalService proxy = BasicServiceInvocationHandler.createProvidedServiceProxy(
			getInternalAccess(), service, name, type, ics, moni, info); 
		// TODO: was this DEFAULT handling (commented out below) used somewhere?
//			info, ServiceScope.DEFAULT.equals(scope) && info!=null? info.getScope() : scope);
		
		addService(proxy, info);
		initService(proxy).addResultListener(new DelegationResultListener(ret));
				
		return ret;
	}
	
	/**
	 *  Add a method invocation handler.
	 */
	public void addMethodInvocationListener(IServiceIdentifier sid, MethodInfo mi, IMethodInvocationListener listener)
	{
//		System.out.println("added lis: "+sid+" "+mi+" "+hashCode());
		
		if(servicelisteners==null)
			servicelisteners = new HashMap();
		MethodListenerHandler handler = servicelisteners.get(sid);
		if(handler==null)
		{
			handler = new MethodListenerHandler();
			servicelisteners.put(sid, handler);
		}
		handler.addMethodListener(mi, listener);
	}
	
	/**
	 *  Remove a method invocation handler.
	 */
	public void removeMethodInvocationListener(IServiceIdentifier sid, MethodInfo mi, IMethodInvocationListener listener)
	{
		if(servicelisteners!=null)
		{
			MethodListenerHandler handler = servicelisteners.get(sid);
			if(handler!=null)
			{
				handler.removeMethodListener(mi, listener);
			}
		}
	}
	
	/**
	 *  Notify listeners that a service method has been called.
	 */
	public void notifyMethodListeners(IServiceIdentifier sid, boolean start, Object proxy, final Method method, final Object[] args, Object callid, ServiceInvocationContext context)
	{
		if(servicelisteners!=null)
		{
			MethodListenerHandler handler = servicelisteners.get(sid);
			if(handler!=null)
			{
//				MethodInfo mi = new MethodInfo(method);
				handler.notifyMethodListeners(start, proxy, method, args, callid, context);
			}
		}
	}
	
	/**
	 *  Test if service and method has listeners.
	 */
	public boolean hasMethodListeners(IServiceIdentifier sid, MethodInfo mi)
	{
		boolean ret = false;
		if(servicelisteners!=null)
		{
			MethodListenerHandler handler = servicelisteners.get(sid);
			if(handler!=null)
			{
				ret = handler.hasMethodListeners(sid, mi);
			}
		}
		
		return ret;
	}
	
	/**
	 *  Add a service interceptor.
	 *  @param interceptor The interceptor.
	 *  @param service The service.
	 *  @param pos The position (0=first, -1=last-1, i.e. one before method invocation).
	 */
	public void addInterceptor(IServiceInvocationInterceptor interceptor, Object service, int pos)
	{
		BasicServiceInvocationHandler handler = (BasicServiceInvocationHandler)ProxyFactory.getInvocationHandler(service);
		handler.addServiceInterceptor(interceptor, pos);
	}
	
	/**
	 *  Remove a service interceptor.
	 *  @param interceptor The interceptor.
	 *  @param service The service.
	 */
	public void removeInterceptor(IServiceInvocationInterceptor interceptor, Object service)
	{
		BasicServiceInvocationHandler handler = (BasicServiceInvocationHandler)ProxyFactory.getInvocationHandler(service);
		handler.removeServiceInterceptor(interceptor);
	}
	
	/**
	 *  Get the interceptors of a service.
	 *  @param service The service.
	 *  @return The interceptors.
	 */
	public IServiceInvocationInterceptor[] getInterceptors(Object service)
	{
		BasicServiceInvocationHandler handler = (BasicServiceInvocationHandler)ProxyFactory.getInvocationHandler(service);
		return handler.getInterceptors();
	}
}