Revision: 1074 Author: dhanji Date: Sat Sep 5 23:22:08 2009 Log: Lifecycle now supports parallel execution. Need to add support for parallel startup and autostart next.
TODO added to check servlet spec compliance in GS2 request dispatcher. http://code.google.com/p/google-guice/source/detail?r=1074 Added: /trunk/lifecycle/test/com/google/inject/lifecycle/ParallelizedBroadcastTest.java Modified: /trunk/lifecycle/src/com/google/inject/lifecycle/BroadcastingLifecycle.java /trunk/lifecycle/src/com/google/inject/lifecycle/Lifecycle.java /trunk/lifecycle/src/com/google/inject/lifecycle/ListOfMatchers.java /trunk/lifecycle/src/com/google/inject/lifecycle/Startable.java /trunk/lifecycle/test/com/google/inject/lifecycle/ArbitraryBroadcastTest.java /trunk/lifecycle/test/com/google/inject/lifecycle/MultipleStartableTest.java /trunk/lifecycle/test/com/google/inject/lifecycle/StartableTest.java /trunk/servlet/src/com/google/inject/servlet/ManagedServletPipeline.java ======================================= --- /dev/null +++ /trunk/lifecycle/test/com/google/inject/lifecycle/ParallelizedBroadcastTest.java Sat Sep 5 23:22:08 2009 @@ -0,0 +1,55 @@ +package com.google.inject.lifecycle; + +import com.google.inject.Guice; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import junit.framework.TestCase; + +/** @author [email protected] (Dhanji R. Prasanna) */ +public class ParallelizedBroadcastTest extends TestCase { + private static final AtomicInteger called = new AtomicInteger(); + + public final void testCallable() throws InterruptedException { + called.set(0); + Lifecycle lifecycle = Guice.createInjector(new LifecycleModule() { + + @Override + protected void configureLifecycle() { + bind(Runnable.class).to(AClass.class); + + // Does not get called because the key does not expose the callable. + bind(Object.class).to(AClass.class); + + bind(BaseClass.class).to(AClass.class); + + callable(Runnable.class); + } + + }).getInstance(Lifecycle.class); + + final ExecutorService executorService = Executors.newFixedThreadPool(3); + lifecycle + .broadcast(Runnable.class, executorService) + .run(); + + executorService.shutdown(); + executorService.awaitTermination(5L, TimeUnit.SECONDS); + + assertEquals(2, called.get()); + } + + public static class BaseClass implements Runnable { + + public void run() { + called.incrementAndGet(); + } + } + + public static class AClass extends BaseClass implements Runnable { + public void run() { + super.run(); + } + } +} ======================================= --- /trunk/lifecycle/src/com/google/inject/lifecycle/BroadcastingLifecycle.java Fri Sep 4 02:08:15 2009 +++ /trunk/lifecycle/src/com/google/inject/lifecycle/BroadcastingLifecycle.java Sat Sep 5 23:22:08 2009 @@ -14,11 +14,16 @@ import java.lang.reflect.Method; import java.util.List; import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; import net.sf.cglib.proxy.InvocationHandler; import net.sf.cglib.proxy.Proxy; -/** @author [email protected] (Dhanji R. Prasanna) */ -...@singleton class BroadcastingLifecycle implements Lifecycle { +/** + * @author [email protected] (Dhanji R. Prasanna) + */ +...@singleton +class BroadcastingLifecycle implements Lifecycle { private final Injector injector; private final List<Class<?>> callableClasses; @@ -103,6 +108,26 @@ } public <T> T broadcast(Class<T> clazz, Matcher<? super T> matcher) { + final List<T> ts = instantiateForBroadcast(clazz, matcher); + + @SuppressWarnings("unchecked") T caster = (T) Proxy + .newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, new InvocationHandler() { + public Object invoke(Object o, Method method, Object[] objects) throws Throwable { + + // propagate the method call with the same arg list to all instances. + for (T t : ts) { + method.invoke(t, objects); + } + + // We can't return from multiple instances, so just return null. + return null; + } + }); + + return caster; + } + + private <T> List<T> instantiateForBroadcast(Class<T> clazz, Matcher<? super T> matcher) { final List<T> ts = Lists.newArrayList(); for (Key<?> key : callableKeys.get(clazz)) { // Should this get instancing happen during method call? @@ -113,14 +138,31 @@ ts.add(t); } } + return ts; + } + + public <T> T broadcast(Class<T> clazz, final ExecutorService executorService) { + return broadcast(clazz, executorService, any()); + } + + public <T> T broadcast(Class<T> clazz, final ExecutorService executorService, + Matcher<? super T> matcher) { + final List<T> ts = instantiateForBroadcast(clazz, matcher); @SuppressWarnings("unchecked") T caster = (T) Proxy .newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, new InvocationHandler() { - public Object invoke(Object o, Method method, Object[] objects) throws Throwable { + public Object invoke(Object o, final Method method, final Object[] objects) + throws Throwable { // propagate the method call with the same arg list to all instances. - for (T t : ts) { - method.invoke(t, objects); + for (final T t : ts) { + // Submit via executor service. TODO See if this can be parallelized by + // yet another dimension, i.e. inParallel(N) + executorService.submit(new Callable() { + public Object call() throws Exception { + return method.invoke(t, objects); + } + }); } // We can't return from multiple instances, so just return null. ======================================= --- /trunk/lifecycle/src/com/google/inject/lifecycle/Lifecycle.java Fri Sep 4 02:08:15 2009 +++ /trunk/lifecycle/src/com/google/inject/lifecycle/Lifecycle.java Sat Sep 5 23:22:08 2009 @@ -2,9 +2,10 @@ import com.google.inject.ImplementedBy; import com.google.inject.matcher.Matcher; +import java.util.concurrent.ExecutorService; /** - * @author [email protected] (Dhanji R. Prasanna) + * @author [email protected] (Dhanji R. Prasanna) */ @ImplementedBy(BroadcastingLifecycle.class) public interface Lifecycle { @@ -14,4 +15,8 @@ <T> T broadcast(Class<T> clazz); <T> T broadcast(Class<T> clazz, Matcher<? super T> matcher); -} + + <T> T broadcast(Class<T> clazz, ExecutorService executorService); + + <T> T broadcast(Class<T> clazz, ExecutorService executorService, Matcher<? super T> matcher); +} ======================================= --- /trunk/lifecycle/src/com/google/inject/lifecycle/ListOfMatchers.java Fri Sep 4 02:08:15 2009 +++ /trunk/lifecycle/src/com/google/inject/lifecycle/ListOfMatchers.java Sat Sep 5 23:22:08 2009 @@ -4,7 +4,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -/** @author [email protected] (Dhanji R. Prasanna) */ +/** @author [email protected] (Dhanji R. Prasanna) */ @Retention(RetentionPolicy.RUNTIME) @BindingAnnotation @interface ListOfMatchers { ======================================= --- /trunk/lifecycle/src/com/google/inject/lifecycle/Startable.java Fri Sep 4 02:08:15 2009 +++ /trunk/lifecycle/src/com/google/inject/lifecycle/Startable.java Sat Sep 5 23:22:08 2009 @@ -10,7 +10,7 @@ * All instances that wish to use startable *must* be bound as * singletons. * - * @author [email protected] (Dhanji R. Prasanna) + * @author [email protected] (Dhanji R. Prasanna) */ public interface Startable { /** ======================================= --- /trunk/lifecycle/test/com/google/inject/lifecycle/ArbitraryBroadcastTest.java Fri Sep 4 02:08:15 2009 +++ /trunk/lifecycle/test/com/google/inject/lifecycle/ArbitraryBroadcastTest.java Sat Sep 5 23:22:08 2009 @@ -4,7 +4,7 @@ import com.google.inject.Singleton; import junit.framework.TestCase; -/** @author [email protected] (Dhanji R. Prasanna) */ +/** @author [email protected] (Dhanji R. Prasanna) */ public class ArbitraryBroadcastTest extends TestCase { private static int called; ======================================= --- /trunk/lifecycle/test/com/google/inject/lifecycle/MultipleStartableTest.java Fri Sep 4 02:08:15 2009 +++ /trunk/lifecycle/test/com/google/inject/lifecycle/MultipleStartableTest.java Sat Sep 5 23:22:08 2009 @@ -4,7 +4,7 @@ import com.google.inject.Singleton; import junit.framework.TestCase; -/** @author [email protected] (Dhanji R. Prasanna) */ +/** @author [email protected] (Dhanji R. Prasanna) */ public class MultipleStartableTest extends TestCase { private static int started; ======================================= --- /trunk/lifecycle/test/com/google/inject/lifecycle/StartableTest.java Fri Sep 4 02:08:15 2009 +++ /trunk/lifecycle/test/com/google/inject/lifecycle/StartableTest.java Sat Sep 5 23:22:08 2009 @@ -4,7 +4,7 @@ import com.google.inject.Singleton; import junit.framework.TestCase; -/** @author [email protected] (Dhanji R. Prasanna) */ +/** @author [email protected] (Dhanji R. Prasanna) */ public class StartableTest extends TestCase { private static boolean started; ======================================= --- /trunk/servlet/src/com/google/inject/servlet/ManagedServletPipeline.java Tue Jun 16 11:47:41 2009 +++ /trunk/servlet/src/com/google/inject/servlet/ManagedServletPipeline.java Sat Sep 5 23:22:08 2009 @@ -115,6 +115,10 @@ */ RequestDispatcher getRequestDispatcher(String path) { final String newRequestUri = path; + + // TODO(dhanji): check servlet spec to see if the following is legal or not. + // Need to strip query string if requested... + for (final ServletDefinition servletDefinition : servletDefinitions) { if (servletDefinition.shouldServe(path)) { return new RequestDispatcher() { --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "google-guice-dev" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [email protected] For more options, visit this group at http://groups.google.com/group/google-guice-dev?hl=en -~----------~----~----~----~------~----~------~--~---
