package com.sun.jersey.guice.spi.container; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Scope; import com.google.inject.Scopes; import com.google.inject.spi.BindingScopingVisitor; import com.sun.jersey.core.spi.component.ComponentContext; import com.sun.jersey.core.spi.component.ComponentScope; import com.sun.jersey.core.spi.component.ioc.IoCComponentProvider; import com.sun.jersey.core.spi.component.ioc.IoCComponentProviderFactory; import com.sun.jersey.core.spi.component.ioc.IoCInstantiatedComponentProvider; import com.sun.jersey.core.spi.component.ioc.IoCManagedComponentProvider; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; /** * The Guice-based {@link IoCComponentProviderFactory}. * * @author Gili Tzabari * @author Paul Sandoz */ public class GuiceComponentProviderFactory implements IoCComponentProviderFactory { private static final Logger LOGGER = Logger.getLogger(GuiceComponentProviderFactory.class.getName()); private final Map scopeMap = createScopeMap(); private final Injector injector; public GuiceComponentProviderFactory(Injector injector) { this.injector = injector; } public IoCComponentProvider getComponentProvider(Class c) { return getComponentProvider(null, c); } public IoCComponentProvider getComponentProvider(ComponentContext cc, Class clazz) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("getComponentProvider(" + clazz.getName() + ")"); } @SuppressWarnings("unchecked") Class c = (Class) clazz; if (!injector.getBindings().containsKey(Key.get(c))) { return null; } final Scope[] scope = new Scope[1]; injector.getBinding(c).acceptScopingVisitor(new BindingScopingVisitor() { public Void visitEagerSingleton() { scope[0] = Scopes.SINGLETON; return null; } public Void visitScope(Scope theScope) { scope[0] = theScope; return null; } public Void visitScopeAnnotation(Class scopeAnnotation) { // This method is not invoked for Injector bindings throw new UnsupportedOperationException(); } public Void visitNoScoping() { scope[0] = Scopes.NO_SCOPE; return null; } }); assert (scope[0] != null); LOGGER.info("Binding " + clazz.getName() + " to GuiceManagedComponentProvider(" + getComponentScope(scope[0]) + ")"); return new GuiceManagedComponentProvider(injector, getComponentScope(scope[0]), clazz); } /** * Converts a Guice scope to Jersey scope. * * @param scope the guice scope * @return the Jersey scope */ private ComponentScope getComponentScope(Scope scope) { ComponentScope cs = scopeMap.get(scope); return (cs != null) ? cs : ComponentScope.Undefined; } /** * Maps a Guice scope to a Jersey scope. * * @return the map */ private static Map createScopeMap() { Map result = new HashMap(); result.put(Scopes.SINGLETON, ComponentScope.Singleton); result.put(Scopes.NO_SCOPE, ComponentScope.PerRequest); return result; } /** * Guice injects instances while Jersey manages their scope. * * @author Gili Tzabari */ private static class GuiceInstantiatedComponentProvider implements IoCInstantiatedComponentProvider { private final Injector injector; private final Class clazz; /** * Creates a new GuiceManagedComponentProvider. * * @param injector the injector * @param clazz the class */ public GuiceInstantiatedComponentProvider(Injector injector, Class clazz) { this.injector = injector; this.clazz = clazz; } public Class getInjectableClass(Class c) { return c.getSuperclass(); } // IoCInstantiatedComponentProvider public Object getInjectableInstance(Object o) { return o; } public Object getInstance() { return injector.getInstance(clazz); } } /** * Guice injects instances and manages their scope. * * @author Gili Tzabari */ private static class GuiceManagedComponentProvider extends GuiceInstantiatedComponentProvider implements IoCManagedComponentProvider { private final ComponentScope scope; /** * Creates a new GuiceManagedComponentProvider. * * @param injector the injector * @param scope the Jersey scope * @param clazz the class */ public GuiceManagedComponentProvider(Injector injector, ComponentScope scope, Class clazz) { super(injector, clazz); this.scope = scope; } public ComponentScope getScope() { return scope; } } }