diff --git a/build.gradle b/build.gradle index 0ed645e1..75116a0a 100644 --- a/build.gradle +++ b/build.gradle @@ -68,6 +68,7 @@ subprojects { ext.slf4jApiVer = '1.7.21' ext.log4jVer = '1.2.17' ext.guavaVer = '19.0' + ext.guiceVer = '4.1.0' ext.okhttpVer = '2.6.0' // TODO Upgrade to 3.2.x @@ -108,6 +109,7 @@ subprojects { ext.kafkaClientsVer = '0.9.0.0' // ''0.8.2.2' ext.shiroVer = '1.2.4' + ext.javaxInjectVer = '1' configurations.all { resolutionStrategy { diff --git a/comsat-actors-undertow/build.gradle b/comsat-actors-undertow/build.gradle new file mode 100644 index 00000000..b690e4da --- /dev/null +++ b/comsat-actors-undertow/build.gradle @@ -0,0 +1,6 @@ +dependencies { + compile "javax.inject:javax.inject:$javaxInjectVer" + testCompile "com.google.inject:guice:$guiceVer" + testCompile "org.springframework:spring-core:$springVer" + testCompile "org.springframework:spring-context:$springVer" +} \ No newline at end of file diff --git a/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/AutoActorContext.java b/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/AutoActorContext.java new file mode 100644 index 00000000..436e7515 --- /dev/null +++ b/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/AutoActorContext.java @@ -0,0 +1,141 @@ +package co.paralleluniverse.comsat.webactors.undertow; + +import co.paralleluniverse.actors.Actor; +import co.paralleluniverse.actors.ActorImpl; +import co.paralleluniverse.actors.ActorRef; +import co.paralleluniverse.actors.ActorSpec; +import co.paralleluniverse.common.reflection.AnnotationUtil; +import co.paralleluniverse.common.reflection.ClassLoaderUtil; +import co.paralleluniverse.common.util.Pair; +import co.paralleluniverse.comsat.webactors.WebActor; +import co.paralleluniverse.comsat.webactors.WebMessage; +import io.undertow.UndertowLogger; +import io.undertow.server.HttpServerExchange; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.*; + +class AutoActorContext extends WebActorHandler.DefaultContextImpl { + + private static final List> actorClasses = new ArrayList<>(4); + private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; + + private String id; + + private final List packagePrefixes; + private final Map, Object[]> actorParams; + private final ClassLoader userClassLoader; + private Class> actorClass; + private ActorRef actorRef; + + public AutoActorContext(HttpServerExchange xch, List packagePrefixes, Map, Object[]> actorParams, ClassLoader userClassLoader) { + this.packagePrefixes = packagePrefixes; + this.actorParams = actorParams; + this.userClassLoader = userClassLoader; + } + + private void fillActor(HttpServerExchange xch) { + final Pair, Class>> p = autoCreateActor(xch); + if (p != null) { + actorRef = p.getFirst(); + actorClass = p.getSecond(); + } + } + + @Override + public final String getId() { + return id != null ? id : (id = UUID.randomUUID().toString()); + } + + @Override + public final void restart(HttpServerExchange xch) { + renewed = new Date().getTime(); + fillActor(xch); + } + + @Override + public final ActorRef getWebActor() { + return actorRef; + } + + @Override + public final boolean handlesWithWebSocket(String uri) { + return WebActorHandler.handlesWithWebSocket(uri, actorClass); + } + + @Override + public final boolean handlesWithHttp(String uri) { + return WebActorHandler.handlesWithHttp(uri, actorClass); + } + + @Override + public WatchPolicy watch() { + return WatchPolicy.DIE_IF_EXCEPTION_ELSE_RESTART; + } + + @SuppressWarnings("unchecked") + private Pair, Class>> autoCreateActor(HttpServerExchange xch) { + registerActorClasses(); + final String uri = xch.getRequestURI(); + for (final Class c : actorClasses) { + if (WebActorHandler.handlesWithHttp(uri, c) || WebActorHandler.handlesWithWebSocket(uri, c)) + return new Pair, Class>>( + spawnActor(c), (Class>) c + ); + } + + return null; + } + + @SuppressWarnings("unchecked") + protected ActorRef spawnActor(Class c) { + return Actor.newActor(new ActorSpec(c, actorParams != null ? actorParams.get(c) : EMPTY_OBJECT_ARRAY)).spawn(); + } + + private synchronized void registerActorClasses() { + if (actorClasses.isEmpty()) { + try { + final ClassLoader classLoader = userClassLoader != null ? userClassLoader : this.getClass().getClassLoader(); + ClassLoaderUtil.accept((URLClassLoader) classLoader, new ClassLoaderUtil.Visitor() { + @Override + public final void visit(String resource, URL url, ClassLoader cl) { + if (packagePrefixes != null) { + boolean found = false; + for (final String packagePrefix : packagePrefixes) { + if (packagePrefix != null && resource.startsWith(packagePrefix.replace('.', '/'))) { + found = true; + break; + } + } + if (!found) + return; + } + if (!ClassLoaderUtil.isClassFile(resource)) + return; + final String className = ClassLoaderUtil.resourceToClass(resource); + try (final InputStream is = cl.getResourceAsStream(resource)) { + if (AnnotationUtil.hasClassAnnotation(WebActor.class, is)) + registerWebActor(cl.loadClass(className)); + } catch (final IOException | ClassNotFoundException e) { + UndertowLogger.ROOT_LOGGER.error("Exception while scanning class " + className + " for WebActor annotation", e); + throw new RuntimeException(e); + } + } + + private void registerWebActor(Class c) { + actorClasses.add(c); + } + }); + } catch (final IOException e) { + UndertowLogger.ROOT_LOGGER.error("IOException while scanning classes for WebActor annotation", e); + } + } + } + + public void init(HttpServerExchange xch) { + fillActor(xch); + } +} \ No newline at end of file diff --git a/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/AutoContextProvider.java b/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/AutoContextProvider.java new file mode 100644 index 00000000..f8e8f179 --- /dev/null +++ b/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/AutoContextProvider.java @@ -0,0 +1,70 @@ +package co.paralleluniverse.comsat.webactors.undertow; + +import io.undertow.server.HttpServerExchange; +import io.undertow.server.session.Session; +import io.undertow.util.Sessions; + +import java.util.List; +import java.util.Map; + +import static co.paralleluniverse.comsat.webactors.undertow.WebActorHandler.ACTOR_KEY; + +class AutoContextProvider implements WebActorHandler.ContextProvider { + private final ClassLoader userClassLoader; + private final Map, Object[]> actorParams; + private final Long defaultContextValidityMS; + private final List packagePrefixes; + + public AutoContextProvider(ClassLoader userClassLoader, List packagePrefixes, Map, Object[]> actorParams) { + this(userClassLoader, packagePrefixes, actorParams, null); + } + + public AutoContextProvider(ClassLoader userClassLoader, List packagePrefixes, Map, Object[]> actorParams, Long defaultContextValidityMS) { + this.userClassLoader = userClassLoader; + this.packagePrefixes = packagePrefixes; + this.actorParams = actorParams; + this.defaultContextValidityMS = defaultContextValidityMS; + } + + @Override + public final WebActorHandler.Context get(final HttpServerExchange xch) { + WebActorHandler.Context actorContext; + Session session = null; + try { + session = Sessions.getOrCreateSession(xch); + } catch (final IllegalStateException ignored) { + } // No session handler + + if (session != null) { + actorContext = (WebActorHandler.Context) session.getAttribute(ACTOR_KEY); + if (actorContext == null || !actorContext.renew()) { + actorContext = newContext(xch); + session.setAttribute(ACTOR_KEY, actorContext); + } + } else { + actorContext = newContext(xch); + } + + return actorContext; + } + + private WebActorHandler.Context newContext(final HttpServerExchange xch) { + final AutoActorContext c = createContext(xch); + c.init(xch); + if (defaultContextValidityMS != null) + c.setValidityMS(defaultContextValidityMS); + return c; + } + + protected AutoActorContext createContext(HttpServerExchange xch) { + return new AutoActorContext(xch, packagePrefixes, actorParams, userClassLoader); + } + + public ClassLoader getUserClassLoader() { + return userClassLoader; + } + + public List getPackagePrefixes() { + return packagePrefixes; + } +} diff --git a/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/AutoWebActorHandler.java b/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/AutoWebActorHandler.java index 40a9af68..f378b1a9 100644 --- a/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/AutoWebActorHandler.java +++ b/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/AutoWebActorHandler.java @@ -13,30 +13,17 @@ */ package co.paralleluniverse.comsat.webactors.undertow; -import co.paralleluniverse.actors.*; -import co.paralleluniverse.common.reflection.AnnotationUtil; -import co.paralleluniverse.common.reflection.ClassLoaderUtil; -import co.paralleluniverse.common.util.Pair; -import co.paralleluniverse.comsat.webactors.WebActor; -import co.paralleluniverse.comsat.webactors.WebMessage; - -import io.undertow.UndertowLogger; -import io.undertow.server.HttpServerExchange; -import io.undertow.server.session.Session; -import io.undertow.util.Sessions; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.*; +import java.util.List; +import java.util.Map; /** * @author circlespainter */ -public final class AutoWebActorHandler extends WebActorHandler { - private static final List> actorClasses = new ArrayList<>(4); - private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; +public class AutoWebActorHandler extends WebActorHandler { + + private ClassLoader classLoader; + private List packagePrefixes; + private Map, Object[]> actorParams; public AutoWebActorHandler() { this(null, null, null); @@ -56,184 +43,16 @@ public AutoWebActorHandler(List packagePrefixes, Map, Object[]> public AutoWebActorHandler(ClassLoader userClassLoader, List packagePrefixes, Map, Object[]> actorParams) { super(null); - super.contextProvider = newContextProvider(userClassLoader != null ? userClassLoader : ClassLoader.getSystemClassLoader(), packagePrefixes, actorParams); - } - - public AutoWebActorHandler(AutoContextProvider prov) { - super(prov); - } - - protected AutoContextProvider newContextProvider(ClassLoader userClassLoader, List packagePrefixes, Map, Object[]> actorParams) { - return new AutoContextProvider(userClassLoader, packagePrefixes, actorParams); + this.classLoader = userClassLoader; + this.packagePrefixes = packagePrefixes; + this.actorParams = actorParams; } - private static class AutoContextProvider implements ContextProvider { - private final ClassLoader userClassLoader; - private final Map, Object[]> actorParams; - private final Long defaultContextValidityMS; - private final List packagePrefixes; - - public AutoContextProvider(ClassLoader userClassLoader, List packagePrefixes, Map, Object[]> actorParams) { - this(userClassLoader, packagePrefixes, actorParams, null); - } - - public AutoContextProvider(ClassLoader userClassLoader, List packagePrefixes, Map, Object[]> actorParams, Long defaultContextValidityMS) { - this.userClassLoader = userClassLoader; - this.packagePrefixes = packagePrefixes; - this.actorParams = actorParams; - this.defaultContextValidityMS = defaultContextValidityMS; - } - - @Override - public final Context get(final HttpServerExchange xch) { - Session session = null; - Context actorContext = newContext(xch); - if (actorContext != null) { - try { - session = Sessions.getOrCreateSession(xch); - } catch (final IllegalStateException ignored) { - } // No session handler - - if (session != null) { - Context sessionContext = (Context) session.getAttribute(ACTOR_KEY); - if (sessionContext == null || !sessionContext.renew()) - session.setAttribute(ACTOR_KEY, actorContext); - else - actorContext = sessionContext; - } - } - - return actorContext; - } - - private Context newContext(final HttpServerExchange xch) { - final AutoActorContext c = new AutoActorContext(packagePrefixes, actorParams, userClassLoader); - boolean valid = c.fillActor(xch); - if (!valid) - return null; - - if (defaultContextValidityMS != null) - c.setValidityMS(defaultContextValidityMS); - return c; - } + protected void initContextProvider() { + super.contextProvider = new AutoContextProvider(classLoader != null ? classLoader : ClassLoader.getSystemClassLoader(), packagePrefixes, actorParams); } - private static final class AutoActorContext extends DefaultContextImpl { - private String id; - - private final List packagePrefixes; - private final Map, Object[]> actorParams; - private final ClassLoader userClassLoader; - private Class> actorClass; - private ActorRef actorRef; - - public AutoActorContext(List packagePrefixes, Map, Object[]> actorParams, ClassLoader userClassLoader) { - this.packagePrefixes = packagePrefixes; - this.actorParams = actorParams; - this.userClassLoader = userClassLoader; - } - - /** - * Associates a {@link WebActor} annotated class to an {@link HttpServerExchange} - * @param xch The exchange - * @return Whether or not an actor has been associated - */ - private boolean fillActor(HttpServerExchange xch) { - final Pair, Class>> p = autoCreateActor(xch); - if (p != null) { - actorRef = p.getFirst(); - actorClass = p.getSecond(); - return true; - } - return false; - } - - @Override - public final String getId() { - return id != null ? id : (id = UUID.randomUUID().toString()); - } - - @Override - public final void restart(HttpServerExchange xch) { - renewed = new Date().getTime(); - fillActor(xch); - } - - @Override - public final ActorRef getWebActor() { - return actorRef; - } - - @Override - public final boolean handlesWithWebSocket(String uri) { - return WebActorHandler.handlesWithWebSocket(uri, actorClass); - } - - @Override - public final boolean handlesWithHttp(String uri) { - return WebActorHandler.handlesWithHttp(uri, actorClass); - } - - @Override - public WatchPolicy watch() { - return WatchPolicy.DIE_IF_EXCEPTION_ELSE_RESTART; - } - - @SuppressWarnings("unchecked") - private Pair, Class>> autoCreateActor(HttpServerExchange xch) { - registerActorClasses(); - final String uri = xch.getRequestURI(); - for (final Class c : actorClasses) { - if (WebActorHandler.handlesWithHttp(uri, c) || WebActorHandler.handlesWithWebSocket(uri, c)) - return new Pair, Class>> ( - Actor.newActor ( - new ActorSpec(c, actorParams != null ? actorParams.get(c) : EMPTY_OBJECT_ARRAY) - ).spawn(), - (Class>) c - ); - } - - return null; - } - - private synchronized void registerActorClasses() { - if (actorClasses.isEmpty()) { - try { - final ClassLoader classLoader = userClassLoader != null ? userClassLoader : this.getClass().getClassLoader(); - ClassLoaderUtil.accept((URLClassLoader) classLoader, new ClassLoaderUtil.Visitor() { - @Override - public final void visit(String resource, URL url, ClassLoader cl) { - if (packagePrefixes != null) { - boolean found = false; - for (final String packagePrefix : packagePrefixes) { - if (packagePrefix != null && resource.startsWith(packagePrefix.replace('.', '/'))) { - found = true; - break; - } - } - if (!found) - return; - } - if (!ClassLoaderUtil.isClassFile(resource)) - return; - final String className = ClassLoaderUtil.resourceToClass(resource); - try (final InputStream is = cl.getResourceAsStream(resource)) { - if (AnnotationUtil.hasClassAnnotation(WebActor.class, is)) - registerWebActor(cl.loadClass(className)); - } catch (final IOException | ClassNotFoundException e) { - UndertowLogger.ROOT_LOGGER.error("Exception while scanning class " + className + " for WebActor annotation", e); - throw new RuntimeException(e); - } - } - - private void registerWebActor(Class c) { - actorClasses.add(c); - } - }); - } catch (final IOException e) { - UndertowLogger.ROOT_LOGGER.error("IOException while scanning classes for WebActor annotation", e); - } - } - } + public AutoWebActorHandler(AutoContextProvider prov) { + super(prov); } } diff --git a/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/InjectAutoActorContext.java b/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/InjectAutoActorContext.java new file mode 100644 index 00000000..e9f3e2fa --- /dev/null +++ b/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/InjectAutoActorContext.java @@ -0,0 +1,29 @@ +package co.paralleluniverse.comsat.webactors.undertow; + +import co.paralleluniverse.actors.ActorRef; +import co.paralleluniverse.actors.BasicActor; +import io.undertow.server.HttpServerExchange; + +import java.util.List; + +/** + * @author rodedb + */ +class InjectAutoActorContext extends AutoActorContext { + + private InjectAutoWebActorHandler.ProvidersWrapper providersWrapper; + + public InjectAutoActorContext(HttpServerExchange xch, + List packagePrefixes, + ClassLoader userClassLoader, + InjectAutoWebActorHandler.ProvidersWrapper providersWrapper) { + super(xch, packagePrefixes, null, userClassLoader); + this.providersWrapper = providersWrapper; + } + + @Override + protected ActorRef spawnActor(Class c) { + BasicActor actor = (BasicActor) providersWrapper.getProvider(c).get(); + return actor.spawn(); + } +} diff --git a/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/InjectAutoContextProvider.java b/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/InjectAutoContextProvider.java new file mode 100644 index 00000000..3403662f --- /dev/null +++ b/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/InjectAutoContextProvider.java @@ -0,0 +1,25 @@ +package co.paralleluniverse.comsat.webactors.undertow; + +import io.undertow.server.HttpServerExchange; + +import java.util.List; + +/** + * @author rodedb + */ +class InjectAutoContextProvider extends AutoContextProvider { + + private InjectAutoWebActorHandler.ProvidersWrapper providersWrapper; + + public InjectAutoContextProvider(ClassLoader userClassLoader, List packagePrefixes, InjectAutoWebActorHandler.ProvidersWrapper providersWrapper) { + super(userClassLoader, packagePrefixes, null); + this.providersWrapper = providersWrapper; + } + + @Override + protected AutoActorContext createContext(HttpServerExchange xch) { + if (providersWrapper == null) + throw new IllegalArgumentException("ProvidersWrapper not set"); + return new InjectAutoActorContext(xch, getPackagePrefixes(), getUserClassLoader(), providersWrapper); + } +} diff --git a/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/InjectAutoWebActorHandler.java b/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/InjectAutoWebActorHandler.java new file mode 100644 index 00000000..734cf4ed --- /dev/null +++ b/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/InjectAutoWebActorHandler.java @@ -0,0 +1,102 @@ +package co.paralleluniverse.comsat.webactors.undertow; + +import javax.inject.Inject; +import javax.inject.Provider; +import javax.inject.Singleton; +import java.util.List; +import java.util.Map; + +/** + * @author rodedb + */ +@Singleton +public class InjectAutoWebActorHandler extends AutoWebActorHandler { + + private Settings settings; + + @Inject + public InjectAutoWebActorHandler(Settings settings) { + this.settings = settings; + } + + @Override + protected void initContextProvider() { + this.contextProvider = + new InjectAutoContextProvider( + settings.getClassLoader(), + settings.getPackagePrefixes(), + settings.getProvidersWrapper()); + } + + /** + * Wrapper class used to provide all necessary settings to an {@link InjectAutoWebActorHandler} instance. + * Assuming a DI framework is used to inject the {@link InjectAutoWebActorHandler} instance, its {@link Settings} + * instance should be configured for injection as well. + *

+ * See {@link AutoWebActorHandler} for details regarding the setting properties. + */ + public static class Settings { + + public Settings(ProvidersWrapper providersWrapper) { + this(providersWrapper, null, null); + } + + public Settings(ProvidersWrapper providersWrapper, List packagePrefixes) { + this(providersWrapper, null, packagePrefixes); + } + + public Settings(ProvidersWrapper providersWrapper, ClassLoader classLoader, List packagePrefixes) { + if (providersWrapper == null) + throw new IllegalArgumentException("InjectAutoWebActorHandler requires a ProvidersWrapper"); + this.providersWrapper = providersWrapper; + this.classLoader = classLoader; + this.packagePrefixes = packagePrefixes; + } + + private ClassLoader classLoader = null; + private List packagePrefixes = null; + private ProvidersWrapper providersWrapper; + + public ClassLoader getClassLoader() { + return classLoader; + } + + public void setClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + public List getPackagePrefixes() { + return packagePrefixes; + } + + public void setPackagePrefixes(List packagePrefixes) { + this.packagePrefixes = packagePrefixes; + } + + public ProvidersWrapper getProvidersWrapper() { + return providersWrapper; + } + + public void setProvidersWrapper(ProvidersWrapper providersWrapper) { + this.providersWrapper = providersWrapper; + } + } + + /** + * Part of the {@link InjectAutoWebActorHandler.Settings} object which wraps actor {@link Provider}s for access by their + * class. {@link InjectAutoActorContext} will use the appropriate {@link Provider} to instantiate the actor class + * via the DI framework. + */ + public static class ProvidersWrapper { + + public ProvidersWrapper(Map, Provider> providers) { + this.providers = providers; + } + + private Map, Provider> providers; + + public Provider getProvider(Class clazz) { + return providers.get(clazz); + } + } +} diff --git a/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/WebActorHandler.java b/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/WebActorHandler.java index b6351294..f7165118 100644 --- a/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/WebActorHandler.java +++ b/comsat-actors-undertow/src/main/java/co/paralleluniverse/comsat/webactors/undertow/WebActorHandler.java @@ -159,6 +159,10 @@ public final void setFallbackHttpHandler(HttpHandler httpHandler) { @Override public final void handleRequest(final HttpServerExchange xch) throws Exception { + if (contextProvider == null) { + initContextProvider(); + } + final Context context = contextProvider.get(xch); if (context == null) { handlingComplete(xch); @@ -282,6 +286,9 @@ protected final void error(IOException e) { } } + protected void initContextProvider() { + } + private void handlingComplete(HttpServerExchange xch) throws Exception { if (fallbackHttpHandler != null) fallbackHttpHandler.handleRequest(xch); diff --git a/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/GuiceInjectedAutoWebActorHandlerModule.java b/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/GuiceInjectedAutoWebActorHandlerModule.java new file mode 100644 index 00000000..828ef6df --- /dev/null +++ b/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/GuiceInjectedAutoWebActorHandlerModule.java @@ -0,0 +1,29 @@ +package co.paralleluniverse.comsat.webactors.undertow; + +import com.google.common.collect.Maps; +import com.google.inject.AbstractModule; +import com.google.inject.name.Names; + +import javax.inject.Provider; +import java.util.Map; + +/** + * A Guice module which prepares bindings for {@link InjectAutoWebActorHandler}. + * + * @author rodedb + */ +public class GuiceInjectedAutoWebActorHandlerModule extends AbstractModule { + + private static final Object INJECTED_VALUE = new Object(); + + @Override + protected void configure() { + Map, Provider> providers = Maps.newHashMap(); + providers.put(UndertowWebActor.class, getProvider(UndertowWebActorInjected.class)); + InjectAutoWebActorHandler.ProvidersWrapper providersWrapper = new InjectAutoWebActorHandler.ProvidersWrapper(providers); + InjectAutoWebActorHandler.Settings settings = new InjectAutoWebActorHandler.Settings(providersWrapper); + bind(InjectAutoWebActorHandler.Settings.class).toInstance(settings); + bind(WebActorHandler.class).to(InjectAutoWebActorHandler.class); + bind(Object.class).annotatedWith(Names.named("webActorInjectedValue")).toInstance(INJECTED_VALUE); + } +} diff --git a/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/SpringInjectedAutoWebActorHandlerConfig.java b/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/SpringInjectedAutoWebActorHandlerConfig.java new file mode 100644 index 00000000..23ce432a --- /dev/null +++ b/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/SpringInjectedAutoWebActorHandlerConfig.java @@ -0,0 +1,49 @@ +package co.paralleluniverse.comsat.webactors.undertow; + +import com.google.common.collect.Maps; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +import javax.inject.Inject; +import javax.inject.Provider; +import java.util.Map; + +/** + * A Spring configuration which prepares bindings for {@link InjectAutoWebActorHandler}. + * + * @author rodedb + */ +@Configuration +public class SpringInjectedAutoWebActorHandlerConfig { + + private static final Object INJECTED_VALUE = new Object(); + + @Inject + private Provider undertowWebActorProvider; + + @Bean(name = "webActorInjectedValue") + public Object webActorInjectedBean() { + return INJECTED_VALUE; + } + + @Bean + @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) + public UndertowWebActor undertowWebActor() { + return new UndertowWebActorInjected(); + } + + @Bean + public WebActorHandler webActor(InjectAutoWebActorHandler.Settings settings) { + return new InjectAutoWebActorHandler(settings); + } + + @Bean + public InjectAutoWebActorHandler.Settings injectedAutoWebActorHandlerSettings() throws Exception { + Map, Provider> providers = Maps.newHashMap(); + providers.put(UndertowWebActor.class, undertowWebActorProvider); + InjectAutoWebActorHandler.ProvidersWrapper providersWrapper = new InjectAutoWebActorHandler.ProvidersWrapper(providers); + return new InjectAutoWebActorHandler.Settings(providersWrapper); + } +} \ No newline at end of file diff --git a/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/UndertowWebActor.java b/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/UndertowWebActor.java index 053bd471..a55166f1 100644 --- a/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/UndertowWebActor.java +++ b/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/UndertowWebActor.java @@ -20,4 +20,4 @@ * @author circlespainter */ @WebActor(httpUrlPatterns = {"/*"}, webSocketUrlPatterns = {"/ws"}) -public final class UndertowWebActor extends MyWebActor {} +public class UndertowWebActor extends MyWebActor {} diff --git a/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/UndertowWebActorInjected.java b/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/UndertowWebActorInjected.java new file mode 100644 index 00000000..f99caf0c --- /dev/null +++ b/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/UndertowWebActorInjected.java @@ -0,0 +1,39 @@ +/* + * COMSAT + * Copyright (C) 2015, Parallel Universe Software Co. All rights reserved. + * + * This program and the accompanying materials are dual-licensed under + * either the terms of the Eclipse Public License v1.0 as published by + * the Eclipse Foundation + * + * or (per the licensee's choosing) + * + * under the terms of the GNU Lesser General Public License version 3.0 + * as published by the Free Software Foundation. + */ +package co.paralleluniverse.comsat.webactors.undertow; + +import co.paralleluniverse.comsat.webactors.WebActor; + +import javax.inject.Inject; +import javax.inject.Named; + +/** + * Used to test injection into WebActors. + * + * @author rodedb + */ +@WebActor(httpUrlPatterns = {"/*"}, webSocketUrlPatterns = {"/ws"}) +public final class UndertowWebActorInjected extends UndertowWebActor { + + private Object injectedValue; + + @Inject + public void setInjectedValue(@Named("webActorInjectedValue") Object injectedValue) { + this.injectedValue = injectedValue; + } + + public Object getInjectedValue() { + return injectedValue; + } +} diff --git a/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/WebActorInjectionTest.java b/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/WebActorInjectionTest.java new file mode 100644 index 00000000..d19718f1 --- /dev/null +++ b/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/WebActorInjectionTest.java @@ -0,0 +1,41 @@ +package co.paralleluniverse.comsat.webactors.undertow; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.name.Names; +import org.junit.Test; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; + +import javax.inject.Provider; + +import static org.junit.Assert.assertSame; + +/** + * @author rodedb + */ +public class WebActorInjectionTest { + + @SuppressWarnings("unchecked") + @Test + public void guiceWebActorInjection() { + Injector injector = Guice.createInjector(new GuiceInjectedAutoWebActorHandlerModule()); + InjectAutoWebActorHandler.Settings settings = injector.getInstance(InjectAutoWebActorHandler.Settings.class); + Provider webActorProvider = settings.getProvidersWrapper().getProvider(UndertowWebActor.class); + UndertowWebActorInjected webActor = (UndertowWebActorInjected) webActorProvider.get(); + Object injectedValue = injector.getInstance(Key.get(Object.class, Names.named("webActorInjectedValue"))); + assertSame(webActor.getInjectedValue(), injectedValue); + } + + @SuppressWarnings("unchecked") + @Test + public void springWebActorInjection() { + ApplicationContext context = new AnnotationConfigApplicationContext(SpringInjectedAutoWebActorHandlerConfig.class); + InjectAutoWebActorHandler.Settings settings = context.getBean(InjectAutoWebActorHandler.Settings.class); + Provider webActorProvider = settings.getProvidersWrapper().getProvider(UndertowWebActor.class); + UndertowWebActorInjected webActor = (UndertowWebActorInjected) webActorProvider.get(); + Object injectedValue = context.getBean("webActorInjectedValue"); + assertSame(webActor.getInjectedValue(), injectedValue); + } +} \ No newline at end of file diff --git a/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/WebActorTest.java b/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/WebActorTest.java index 16e65ce5..adb37ce3 100644 --- a/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/WebActorTest.java +++ b/comsat-actors-undertow/src/test/java/co/paralleluniverse/comsat/webactors/undertow/WebActorTest.java @@ -18,6 +18,8 @@ import co.paralleluniverse.comsat.webactors.AbstractWebActorTest; import co.paralleluniverse.comsat.webactors.WebMessage; import co.paralleluniverse.embedded.containers.AbstractEmbeddedServer; +import com.google.inject.Guice; +import com.google.inject.Injector; import io.undertow.Undertow; import io.undertow.server.HttpServerExchange; import io.undertow.server.handlers.RequestDumpingHandler; @@ -31,6 +33,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; import java.io.IOException; import java.util.Arrays; @@ -105,11 +109,29 @@ public WebActorHandler call() throws Exception { } }; + private static final Callable autoGuiceInjectedWebActorHandlerCreator = new Callable() { + @Override + public WebActorHandler call() throws Exception { + Injector injector = Guice.createInjector(new GuiceInjectedAutoWebActorHandlerModule()); + return injector.getInstance(WebActorHandler.class); + } + }; + + private static final Callable autoSpringInjectedWebActorHandlerCreator = new Callable() { + @Override + public WebActorHandler call() throws Exception { + ApplicationContext context = new AnnotationConfigApplicationContext(SpringInjectedAutoWebActorHandlerConfig.class); + return context.getBean(WebActorHandler.class); + } + }; + @Parameterized.Parameters(name = "{0}") public static Collection data() { return Arrays.asList(new Object[][]{ {basicWebActorHandlerCreator}, - {autoWebActorHandlerCreator} + {autoWebActorHandlerCreator}, + {autoGuiceInjectedWebActorHandlerCreator}, + {autoSpringInjectedWebActorHandlerCreator} }); } @@ -143,7 +165,7 @@ public void setUp() throws Exception { @After public void tearDown() throws Exception { server.stop(); - + Thread.sleep(1000); // TODO (rodedb): temp System.out.println("Server is down"); }