package org.distributeme.core; import net.anotheria.anoprise.metafactory.*; import net.anotheria.moskito.core.dynamic.ProxyUtils; import org.distributeme.core.conventions.SharedNamingUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A utility for convenient lookup of implementations for interfaces. This utility helps to reduce amount of code to instantiate a service if you * follow the naming patterns. * * @author lrosenberg * @version $Id: $Id */ public class ServiceLocator { /** * Log. */ private static Logger log = LoggerFactory.getLogger(ServiceLocator.class); /** * Returns a remote instance of a service aka stub. This is only useful for interface annotated with @DistributeMe and generated by the apt processor. * * @param pattern a {@link java.lang.Class} object. * @return a T object. */ public static <T extends Service> T getAsynchRemote(Class<T> pattern){ try{ return MetaFactory.get(pattern, Extension.ASYNCH); }catch(MetaFactoryException e){ //NOPMD } //try to lookup an instance by name String className = SharedNamingUtils.getAsynchFactoryFullClassName(pattern); try{ @SuppressWarnings("unchecked")Class<ServiceFactory<T>> factoryClazz = (Class<ServiceFactory<T>>)Class.forName(className); MetaFactory.addFactoryClass(pattern, Extension.ASYNCH, factoryClazz); }catch(ClassNotFoundException ignored){ ignored.printStackTrace(); } try{ return MetaFactory.get(pattern, Extension.ASYNCH); }catch(MetaFactoryException e){ log.error("getAsynchRemote("+pattern+")", e); throw new RuntimeException("No asynch impl for "+pattern.getName()+" known (tried MetaFactory.get("+pattern.getName()+" and "+className+")"); } } /** * Returns a remote instance of a service aka stub. This is only useful for interface annotated with @DistributeMe and generated by the apt processor. * * @param pattern a {@link java.lang.Class} object. * @return a T object. */ public static <T extends Service> T getRemote(Class<T> pattern){ try{ return MetaFactory.get(pattern, Extension.REMOTE); }catch(MetaFactoryException e){ //NOPMD } //try to lookup an instance by name String className = SharedNamingUtils.getStubFactoryFullClassName(pattern); try{ @SuppressWarnings("unchecked")Class<ServiceFactory<T>> factoryClazz = (Class<ServiceFactory<T>>)Class.forName(className); MetaFactory.addFactoryClass(pattern, Extension.REMOTE, factoryClazz); }catch(ClassNotFoundException ignored){ ignored.printStackTrace(); } try{ return MetaFactory.get(pattern, Extension.REMOTE); }catch(MetaFactoryException e){ log.error("getRemote("+pattern+")", e); throw new RuntimeException("No remote impl for "+pattern.getName()+" known (tried MetaFactory.get("+pattern.getName()+" and "+className+")"); } } /** * Returns a local instance of T. First this method tries to lookup T in the MetaFactory. If this fails it tries to * lookup a factory for T or a direct implementation of T. In success case it will register a factory for T in the MetaFactory and create an instance. * * @param pattern class of T. * @return a T object. */ public static <T extends Service> T getLocal(Class<T> pattern){ try{ return MetaFactory.get(pattern, Extension.LOCAL); }catch(MetaFactoryException e){ //NOPMD //ignore } //ok, we don't have a registered copy yet, lets check if we can find one. String patternName = pattern.getName(); final String factoryName = patternName+"Factory"; final String implName = patternName + "Impl"; try{ log.debug("looking up factory "+factoryName+" for service "+patternName); Class<ServiceFactory<T>> factoryClazz = (Class<ServiceFactory<T>>)Class.forName(factoryName); MetaFactory.addFactoryClass(pattern, Extension.LOCAL, factoryClazz); }catch(ClassNotFoundException factoryNotFound){ try{ // Even more convinient - try to instantiate the implementation directly log.debug("looking up impl "+implName+" for service "+patternName); Class<? extends T> implClazz = (Class<? extends T>)Class.forName(implName); MetaFactory.createOnTheFlyFactory(pattern, Extension.LOCAL, implClazz.newInstance()); }catch(ClassNotFoundException implNotFound){ log.warn("Giving up trying to find an impl instance, tried "+implName+" and "+factoryName); } catch (InstantiationException e) { log.warn("Found implementation "+implName+" but failed to instantiate, ", e); } catch (IllegalAccessException e) { log.warn("Found implementation "+implName+" but failed to instantiate due", e); } } //...outer catch try{ return MetaFactory.get(pattern, Extension.LOCAL); }catch(MetaFactoryException e){ throw new IllegalArgumentException(pattern + " doesn't seem to be dynamically resolveable, its missing "+implName+" or "+factoryName); } } /** * Returns a moskito-monitored local instance of the requested interface. * * @param pattern a {@link java.lang.Class} object. * @param monitorableInterfaces - additional interfaces the impl may implement. Since the returned instance will be proxied, the proxies should know of all interfaces * that you are going to use to call the returned instance. Therefor they all have to be submitted. However, in most cases you can just omit this parameter. * @return a T object. */ public static <T extends Service> T getMonitoredLocal(Class<T> pattern, Class<?> ... monitorableInterfaces){ T serviceInstance = getLocal(pattern); return ProxyUtils.createServiceInstance(serviceInstance, "default", pattern, monitorableInterfaces); } }