Author: dhanji
Date: Sat Jan  3 23:17:25 2009
New Revision: 796

Added:
    trunk/servlet/src/com/google/inject/servlet/InternalServletModule.java
     
trunk/servlet/test/com/google/inject/servlet/MultiModuleDispatchIntegrationTest.java
    
(contents, props changed)
       - copied, changed from r795,  
/trunk/servlet/test/com/google/inject/servlet/FilterDispatchIntegrationTest.java
Modified:
    trunk/servlet/src/com/google/inject/servlet/FiltersModuleBuilder.java
    trunk/servlet/src/com/google/inject/servlet/GuiceFilter.java
    trunk/servlet/src/com/google/inject/servlet/ManagedFilterPipeline.java
    trunk/servlet/src/com/google/inject/servlet/ManagedServletPipeline.java
    trunk/servlet/src/com/google/inject/servlet/ServletModule.java
    trunk/servlet/src/com/google/inject/servlet/ServletsModuleBuilder.java
    trunk/servlet/src/com/google/inject/servlet/UriPatternType.java
    trunk/servlet/test/com/google/inject/servlet/AllTests.java
     
trunk/servlet/test/com/google/inject/servlet/ServletPipelineRequestDispatcherTest.java
    trunk/src/com/google/inject/InheritingState.java
    trunk/src/com/google/inject/Injector.java

Log:
Multiple modules support. Also weakened exception in Stage.DEVELOPMENT for  
multiple injectors with their own pipelines. This allows tests to work in  
the same VM.

Modified:  
trunk/servlet/src/com/google/inject/servlet/FiltersModuleBuilder.java
==============================================================================
--- trunk/servlet/src/com/google/inject/servlet/FiltersModuleBuilder.java       
 
(original)
+++ trunk/servlet/src/com/google/inject/servlet/FiltersModuleBuilder.java       
 
Sat Jan  3 23:17:25 2009
@@ -18,9 +18,12 @@
  import com.google.common.collect.Lists;
  import com.google.inject.AbstractModule;
  import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
+import static com.google.inject.name.Names.named;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
+import java.util.UUID;
  import javax.servlet.Filter;

  /**
@@ -36,9 +39,10 @@
    //invoked on injector config
    @Override
    protected void configure() {
-    // Bind these filter definitions to a singleton dispatcher pipeline  
(overrides the
-    // DefaultFilterPipeline)
-    bind(FilterPipeline.class).toInstance(new  
ManagedFilterPipeline(filterDefinitions));
+    // Bind these filter definitions to a unique random key. Doesn't  
matter what it is,
+    // coz it's never used.
+    bind(Key.get(new TypeLiteral<List<FilterDefinition>>() {},  
named(UUID.randomUUID().toString())))
+        .toInstance(filterDefinitions);
    }

    public ServletModule.FilterKeyBindingBuilder filter(List<String>  
patterns) {

Modified: trunk/servlet/src/com/google/inject/servlet/GuiceFilter.java
==============================================================================
--- trunk/servlet/src/com/google/inject/servlet/GuiceFilter.java        
(original)
+++ trunk/servlet/src/com/google/inject/servlet/GuiceFilter.java        Sat Jan 
 3  
23:17:25 2009
@@ -18,8 +18,10 @@

  import com.google.inject.Inject;
  import com.google.inject.OutOfScopeException;
+import com.google.inject.Stage;
  import java.io.IOException;
  import java.lang.ref.WeakReference;
+import java.util.logging.Logger;
  import javax.servlet.Filter;
  import javax.servlet.FilterChain;
  import javax.servlet.FilterConfig;
@@ -62,20 +64,29 @@
    static volatile WeakReference<ServletContext> servletContext =
        new WeakReference<ServletContext>(null);

+  private static final String MULTIPLE_INJECTORS_ERROR =
+      "Multiple injectors detected. Please install only one"
+          + " ServletModule in your web application. While you may "
+          + "have more than one injector, you should only configure"
+          + " guice-servlet in one of them. (Hint: look for legacy "
+          + "ServetModules or multiple calls to Servlets.configure()).";
+
    //VisibleForTesting
    @Inject
-  static void setPipeline(FilterPipeline pipeline) {
+  static void setPipeline(FilterPipeline pipeline, Stage stage) {

-    // Multiple injectors with ServletModules?
+    // Multiple injectors with Servlet pipelines?!
+    // We don't throw an exception in DEVELOPMENT stage, to allow for  
legacy
+    // tests that don't have a tearDown that calls  
GuiceFilter#clearPipeline().
      if (GuiceFilter.pipeline instanceof ManagedFilterPipeline) {
-      throw new RuntimeException("Multiple injectors detected. Please  
install only one"
-          + " ServletModule in your web application. While you may "
-          + "have more than one injector, you should only configure"
-          + " guice-servlet in one of them. (Hint: look for legacy "
-          + "ServetModules or multiple calls to Servlets.configure()).");
+      if (Stage.PRODUCTION.equals(stage)) {
+        throw new RuntimeException(MULTIPLE_INJECTORS_ERROR);
+      } else {
+         
Logger.getLogger(GuiceFilter.class.getName()).warning(MULTIPLE_INJECTORS_ERROR);
+      }
      }

-    // We will only overwrite the default pipeline
+    // We overwrite the default pipeline
      GuiceFilter.pipeline = pipeline;
    }


Added:  
trunk/servlet/src/com/google/inject/servlet/InternalServletModule.java
==============================================================================
--- (empty file)
+++ trunk/servlet/src/com/google/inject/servlet/InternalServletModule.java      
 
Sat Jan  3 23:17:25 2009
@@ -0,0 +1,113 @@
+package com.google.inject.servlet;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Provider;
+import com.google.inject.TypeLiteral;
+import static com.google.inject.servlet.ServletScopes.REQUEST;
+import static com.google.inject.servlet.ServletScopes.SESSION;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.ServletContext;
+import java.util.Map;
+
+/**
+ * This is a left-factoring of all ServletModules installed in the system.
+ * In other words, this module contains the bindings common to all  
ServletModules,
+ * and is bound exactly once per injector.
+ *
+ * @author [email protected] (Dhanji R. Prasanna)
+ */
+final class InternalServletModule extends AbstractModule {
+
+  @Override
+  protected void configure() {
+    // Scopes.
+    bindScope(RequestScoped.class, REQUEST);
+    bindScope(SessionScoped.class, SESSION);
+
+    // Bind request.
+    Provider<HttpServletRequest> requestProvider =
+        new Provider<HttpServletRequest>() {
+          public HttpServletRequest get() {
+            return GuiceFilter.getRequest();
+          }
+
+          public String toString() {
+            return "RequestProvider";
+          }
+        };
+    bind(HttpServletRequest.class).toProvider(requestProvider);
+    bind(ServletRequest.class).toProvider(requestProvider);
+
+    // Bind response.
+    Provider<HttpServletResponse> responseProvider =
+        new Provider<HttpServletResponse>() {
+          public HttpServletResponse get() {
+            return GuiceFilter.getResponse();
+          }
+
+          public String toString() {
+            return "ResponseProvider";
+          }
+        };
+    bind(HttpServletResponse.class).toProvider(responseProvider);
+    bind(ServletResponse.class).toProvider(responseProvider);
+
+    // Bind session.
+    bind(HttpSession.class).toProvider(new Provider<HttpSession>() {
+      public HttpSession get() {
+        return GuiceFilter.getRequest().getSession();
+      }
+
+      public String toString() {
+        return "SessionProvider";
+      }
+    });
+
+    // Bind servlet context.
+    bind(ServletContext.class).toProvider(new Provider<ServletContext>() {
+      public ServletContext get() {
+        return GuiceFilter.getServletContext();
+      }
+
+      public String toString() {
+        return "ServletContextProvider";
+      }
+    });
+
+    // Bind request parameters.
+    bind(new TypeLiteral<Map<String, String[]>>() {})
+        .annotatedWith(RequestParameters.class)
+        .toProvider(new Provider<Map<String, String[]>>() {
+              @SuppressWarnings({"unchecked"})
+              public Map<String, String[]> get() {
+                return GuiceFilter.getRequest().getParameterMap();
+              }
+
+              public String toString() {
+                return "RequestParametersProvider";
+              }
+            });
+
+    // inject the pipeline into GuiceFilter so it can route requests  
correctly
+    // Unfortunate staticness... =(
+    requestStaticInjection(GuiceFilter.class);
+
+    bind(ManagedServletPipeline.class);
+     
bind(FilterPipeline.class).to(ManagedFilterPipeline.class).asEagerSingleton();
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    // Is only ever installed internally, so we don't need to check state.
+    return o instanceof InternalServletModule;
+  }
+
+  @Override
+  public int hashCode() {
+    return InternalServletModule.class.hashCode();
+  }
+}

Modified:  
trunk/servlet/src/com/google/inject/servlet/ManagedFilterPipeline.java
==============================================================================
--- trunk/servlet/src/com/google/inject/servlet/ManagedFilterPipeline.java      
 
(original)
+++ trunk/servlet/src/com/google/inject/servlet/ManagedFilterPipeline.java      
 
Sat Jan  3 23:17:25 2009
@@ -15,13 +15,18 @@
   */
  package com.google.inject.servlet;

+import com.google.common.collect.Lists;
+import com.google.inject.Binding;
  import com.google.inject.Inject;
  import com.google.inject.Injector;
+import com.google.inject.Key;
  import com.google.inject.Provider;
  import com.google.inject.Singleton;
+import com.google.inject.TypeLiteral;
  import java.io.IOException;
  import java.util.Collections;
  import java.util.List;
+import java.util.Map;
  import javax.servlet.FilterChain;
  import javax.servlet.RequestDispatcher;
  import javax.servlet.ServletContext;
@@ -40,22 +45,46 @@
  @Singleton
  class ManagedFilterPipeline implements FilterPipeline{
    private final List<FilterDefinition> filterDefinitions;
-
-  @Inject
-  private final ManagedServletPipeline servletPipeline = null;
-
-  @Inject
-  private final Provider<ServletContext> servletContext = null;
+  private final ManagedServletPipeline servletPipeline;
+  private final Provider<ServletContext> servletContext;

    //Unfortunately, we need the injector itself in order to create filters  
+ servlets
-  @Inject
-  private final Injector injector = null;
+  private final Injector injector;

    //Guards a DCL, so needs to be volatile
    private volatile boolean initialized = false;
+  private static final TypeLiteral<List<FilterDefinition>> FILTER_DEFS =
+      new TypeLiteral<List<FilterDefinition>>() { };
+
+  @Inject
+  public ManagedFilterPipeline(Injector injector, ManagedServletPipeline  
servletPipeline,
+      Provider<ServletContext> servletContext) {
+    this.injector = injector;
+    this.servletPipeline = servletPipeline;
+    this.servletContext = servletContext;
+
+    this.filterDefinitions =  
Collections.unmodifiableList(collectFilterDefinitions(injector));
+  }
+
+  /**
+   * Introspects the injector and collects all instances of bound {...@code  
List<FilterDefinition>}
+   * into a master list.
+   *
+   * We have a guarantee that {...@link  
com.google.inject.Injector#getBindings()} returns a map
+   * that preserves insertion order in entry-set iterators.
+   */
+  private List<FilterDefinition> collectFilterDefinitions(Injector  
injector) {
+    List<FilterDefinition> filterDefinitions = Lists.newArrayList();
+    for (Map.Entry<Key<?>, Binding<?>> entry :  
injector.getBindings().entrySet()) {
+      if (FILTER_DEFS.equals(entry.getKey().getTypeLiteral())) {
+
+        @SuppressWarnings("unchecked")
+        Key<List<FilterDefinition>> defsKey =  
(Key<List<FilterDefinition>>) entry.getKey();
+        filterDefinitions.addAll(injector.getInstance(defsKey));
+      }
+    }

-  public ManagedFilterPipeline(List<FilterDefinition> filterDefinitions) {
-    this.filterDefinitions =  
Collections.unmodifiableList(filterDefinitions);
+    return filterDefinitions;
    }

    public synchronized void initPipeline(ServletContext servletContext)

Modified:  
trunk/servlet/src/com/google/inject/servlet/ManagedServletPipeline.java
==============================================================================
--- trunk/servlet/src/com/google/inject/servlet/ManagedServletPipeline.java     
 
(original)
+++ trunk/servlet/src/com/google/inject/servlet/ManagedServletPipeline.java     
 
Sat Jan  3 23:17:25 2009
@@ -15,27 +15,59 @@
   */
  package com.google.inject.servlet;

+import com.google.common.collect.Lists;
+import com.google.inject.Binding;
+import com.google.inject.Inject;
  import com.google.inject.Injector;
+import com.google.inject.Key;
  import com.google.inject.Singleton;
-
-import javax.servlet.*;
+import com.google.inject.TypeLiteral;
  import java.io.IOException;
  import java.util.Collections;
  import java.util.List;
+import java.util.Map;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;

  /**
   * A wrapping dispatcher for servlets, in much the same way as {...@link  
ManagedFilterPipeline} is for
   * filters.
   *
   * @author [email protected] (Dhanji R. Prasanna)
- * @see ManagedFilterPipeline
   */
  @Singleton
  class ManagedServletPipeline {
    private final List<ServletDefinition> servletDefinitions;
+  private static final TypeLiteral<List<ServletDefinition>> SERVLET_DEFS =
+      new TypeLiteral<List<ServletDefinition>>() {};
+
+  @Inject
+  public ManagedServletPipeline(Injector injector) {
+    this.servletDefinitions =  
Collections.unmodifiableList(collectServletDefinitions(injector));
+  }
+
+  /**
+   * Introspects the injector and collects all instances of bound {...@code  
List<ServletDefinition>}
+   * into a master list.
+   *
+   * We have a guarantee that {...@link  
com.google.inject.Injector#getBindings()} returns a map
+   * that preserves insertion order in entry-set iterators.
+   */
+  private List<ServletDefinition> collectServletDefinitions(Injector  
injector) {
+    List<ServletDefinition> servletDefinitions = Lists.newArrayList();
+    for (Map.Entry<Key<?>, Binding<?>> entry :  
injector.getBindings().entrySet()) {
+      if (SERVLET_DEFS.equals(entry.getKey().getTypeLiteral())) {
+
+        @SuppressWarnings("unchecked")
+        Key<List<ServletDefinition>> defsKey =  
(Key<List<ServletDefinition>>) entry.getKey();
+        servletDefinitions.addAll(injector.getInstance(defsKey));
+      }
+    }

-  public ManagedServletPipeline(List<ServletDefinition>  
servletDefinitions) {
-    this.servletDefinitions =  
Collections.unmodifiableList(servletDefinitions);
+    return servletDefinitions;
    }

    public void init(ServletContext servletContext, Injector injector)  
throws ServletException {

Modified: trunk/servlet/src/com/google/inject/servlet/ServletModule.java
==============================================================================
--- trunk/servlet/src/com/google/inject/servlet/ServletModule.java       
(original)
+++ trunk/servlet/src/com/google/inject/servlet/ServletModule.java      Sat Jan 
  
3 23:17:25 2009
@@ -19,19 +19,9 @@
  import com.google.common.collect.Lists;
  import com.google.inject.AbstractModule;
  import com.google.inject.Key;
-import com.google.inject.Provider;
-import com.google.inject.TypeLiteral;
-import static com.google.inject.servlet.ServletScopes.REQUEST;
-import static com.google.inject.servlet.ServletScopes.SESSION;
  import java.util.Map;
  import javax.servlet.Filter;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
  import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;

  /**
   * Configures the servlet scopes and creates bindings for the servlet API
@@ -48,82 +38,13 @@

    @Override
    protected final void configure() {
-    // Install the filter and servlet bindings.
+    // Install common bindings (skipped if already installed).
+    install(new InternalServletModule());
+
+    // Install local filter and servlet bindings.
      configureServlets();
      install(filtersModuleBuilder);
      install(servletsModuleBuilder);
-
-    // Scopes.
-    bindScope(RequestScoped.class, REQUEST);
-    bindScope(SessionScoped.class, SESSION);
-
-    // Bind request.
-    Provider<HttpServletRequest> requestProvider =
-        new Provider<HttpServletRequest>() {
-          public HttpServletRequest get() {
-            return GuiceFilter.getRequest();
-          }
-
-          public String toString() {
-            return "RequestProvider";
-          }
-        };
-    bind(HttpServletRequest.class).toProvider(requestProvider);
-    bind(ServletRequest.class).toProvider(requestProvider);
-
-    // Bind response.
-    Provider<HttpServletResponse> responseProvider =
-        new Provider<HttpServletResponse>() {
-          public HttpServletResponse get() {
-            return GuiceFilter.getResponse();
-          }
-
-          public String toString() {
-            return "ResponseProvider";
-          }
-        };
-    bind(HttpServletResponse.class).toProvider(responseProvider);
-    bind(ServletResponse.class).toProvider(responseProvider);
-
-    // Bind session.
-    bind(HttpSession.class).toProvider(new Provider<HttpSession>() {
-      public HttpSession get() {
-        return GuiceFilter.getRequest().getSession();
-      }
-
-      public String toString() {
-        return "SessionProvider";
-      }
-    });
-
-    // Bind servlet context.
-    bind(ServletContext.class).toProvider(new Provider<ServletContext>() {
-      public ServletContext get() {
-        return GuiceFilter.getServletContext();
-      }
-
-      public String toString() {
-        return "ServletContextProvider";
-      }
-    });
-
-    // Bind request parameters.
-    bind(new TypeLiteral<Map<String, String[]>>() {})
-        .annotatedWith(RequestParameters.class)
-        .toProvider(new Provider<Map<String, String[]>>() {
-              @SuppressWarnings({"unchecked"})
-              public Map<String, String[]> get() {
-                return GuiceFilter.getRequest().getParameterMap();
-              }
-
-              public String toString() {
-                return "RequestParametersProvider";
-              }
-            });
-
-    // inject the pipeline into GuiceFilter so it can route requests  
correctly
-    // Unfortunate staticness... =(
-    requestStaticInjection(GuiceFilter.class);
    }

    /**
@@ -252,6 +173,41 @@
     * </pre>
     *
     * See {...@link com.google.inject.Binder} for more information on binding  
syntax.
+   *
+   * <p>
+   * <h3>Multiple Modules</h3>
+   *
+   * It is sometimes useful to capture servlet and filter mappings from  
multiple different
+   * modules. This is essential if you want to package and offer drop-in  
Guice plugins that
+   * provide servlet functionality.
+   *
+   * <p>
+   * Guice Servlet allows you to register several instances of {...@code  
ServletModule} to your
+   * injector. The order in which these modules are installed determines  
the dispatch order
+   * of filters and the precedence order of servlets. For example, if you  
had two servlet modules,
+   * {...@code RpcModule} and {...@code WebServiceModule} and they each  
contained a filter that mapped
+   * to the same URI pattern, {...@code "/*"}:
+   *
+   * <p>
+   * In {...@code RpcModule}:
+   * <pre>
+   *     filter("/*").through(RpcFilter.class);
+   * </pre>
+   *
+   * In {...@code WebServiceModule}:
+   * <pre>
+   *     filter("/*").through(WebServiceFilter.class);
+   * </pre>
+   *
+   * Then the order in which these filters are dispatched is determined by  
the order in which
+   * the modules are installed:
+   *
+   * <pre>
+   *   <b>install(new WebServiceModule());</b>
+   *   install(new RpcModule());
+   * </pre>
+   *
+   * In the case shown above {...@code WebServiceFilter} will run first.
     *
     * @since 2.0
     */

Modified:  
trunk/servlet/src/com/google/inject/servlet/ServletsModuleBuilder.java
==============================================================================
--- trunk/servlet/src/com/google/inject/servlet/ServletsModuleBuilder.java      
 
(original)
+++ trunk/servlet/src/com/google/inject/servlet/ServletsModuleBuilder.java      
 
Sat Jan  3 23:17:25 2009
@@ -18,9 +18,12 @@
  import com.google.common.collect.Lists;
  import com.google.inject.AbstractModule;
  import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
+import static com.google.inject.name.Names.named;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
+import java.util.UUID;
  import javax.servlet.http.HttpServlet;

  /**
@@ -36,8 +39,10 @@
    //invoked on injector config
    @Override
    protected void configure() {
-    // Bind these servlet definitions to a singleton pipeline
-    bind(ManagedServletPipeline.class).toInstance(new  
ManagedServletPipeline(servletDefinitions));
+    // Bind these servlet definitions to a unique random key. Doesn't  
matter what it is,
+    // coz it's never used.
+    bind(Key.get(new TypeLiteral<List<ServletDefinition>>() {},
+         
named(UUID.randomUUID().toString()))).toInstance(servletDefinitions);
    }

    //the first level of the EDSL--

Modified: trunk/servlet/src/com/google/inject/servlet/UriPatternType.java
==============================================================================
--- trunk/servlet/src/com/google/inject/servlet/UriPatternType.java      
(original)
+++ trunk/servlet/src/com/google/inject/servlet/UriPatternType.java     Sat  
Jan  3 23:17:25 2009
@@ -35,7 +35,7 @@
    }

    /**
-   * Matchers URIs using the pattern grammar of the Servlet API and  
web.xml.
+   * Matches URIs using the pattern grammar of the Servlet API and web.xml.
     *
     * @author [email protected] (Dhanji R. Prasanna)
     */

Modified: trunk/servlet/test/com/google/inject/servlet/AllTests.java
==============================================================================
--- trunk/servlet/test/com/google/inject/servlet/AllTests.java  (original)
+++ trunk/servlet/test/com/google/inject/servlet/AllTests.java  Sat Jan  3  
23:17:25 2009
@@ -44,6 +44,9 @@
      suite.addTestSuite(VarargsFilterDispatchIntegrationTest.class);
      suite.addTestSuite(VarargsServletDispatchIntegrationTest.class);

+    // Multiple modules tests.
+    suite.addTestSuite(MultiModuleDispatchIntegrationTest.class);
+
      return suite;
    }
  }

Copied:  
trunk/servlet/test/com/google/inject/servlet/MultiModuleDispatchIntegrationTest.java
  
(from r795,  
/trunk/servlet/test/com/google/inject/servlet/FilterDispatchIntegrationTest.java)
==============================================================================
---  
/trunk/servlet/test/com/google/inject/servlet/FilterDispatchIntegrationTest.java
         
(original)
+++  
trunk/servlet/test/com/google/inject/servlet/MultiModuleDispatchIntegrationTest.java
     
Sat Jan  3 23:17:25 2009
@@ -20,17 +20,16 @@
  import javax.servlet.http.HttpServletRequest;
  import junit.framework.TestCase;

-
  /**
   *
   * This tests that filter stage of the pipeline dispatches
- * correctly to guice-managed filters.
+ * correctly to guice-managed filters with multiple modules.
   *
   * WARNING(dhanji): Non-parallelizable test =(
   *
   * @author [email protected] (Dhanji R. Prasanna)
   */
-public class FilterDispatchIntegrationTest extends TestCase {
+public class MultiModuleDispatchIntegrationTest extends TestCase {
      private static int inits, doFilters, destroys;

    @Override
@@ -49,87 +48,22 @@
        @Override
        protected void configureServlets() {
          filter("/*").through(TestFilter.class);
-        filter("*.html").through(TestFilter.class);
-        filter("/*").through(Key.get(TestFilter.class));

          // These filters should never fire
-        filter("/index/*").through(Key.get(TestFilter.class));
          filter("*.jsp").through(Key.get(TestFilter.class));
        }
-    });
-
-    final FilterPipeline pipeline =  
injector.getInstance(FilterPipeline.class);
-    pipeline.initPipeline(null);

-    //create ourselves a mock request with test URI
-    HttpServletRequest requestMock = createMock(HttpServletRequest.class);
-
-    expect(requestMock.getServletPath())
-            .andReturn("/index.html")
-            .anyTimes();
-
-    //dispatch request
-    replay(requestMock);
-    pipeline.dispatch(requestMock, null, createMock(FilterChain.class));
-    pipeline.destroyPipeline();
-
-    verify(requestMock);
-
-    assert inits == 5 && doFilters == 3 && destroys == 5 : "lifecycle  
states did not"
-          + " fire correct number of times-- inits: " + inits + "; dos: "  
+ doFilters
-          + "; destroys: " + destroys;
-  }
-
-  public final void testDispatchThatNoFiltersFire() throws  
ServletException, IOException {
-    final Injector injector = Guice.createInjector(new ServletModule() {
+    }, new ServletModule() {

        @Override
        protected void configureServlets() {
-        filter("/public/*").through(TestFilter.class);
          filter("*.html").through(TestFilter.class);
-        filter("*.xml").through(Key.get(TestFilter.class));
+        filter("/*").through(Key.get(TestFilter.class));

          // These filters should never fire
          filter("/index/*").through(Key.get(TestFilter.class));
-        filter("*.jsp").through(Key.get(TestFilter.class));
        }
-    });

-    final FilterPipeline pipeline =  
injector.getInstance(FilterPipeline.class);
-    pipeline.initPipeline(null);
-
-    //create ourselves a mock request with test URI
-    HttpServletRequest requestMock = createMock(HttpServletRequest.class);
-
-    expect(requestMock.getServletPath())
-            .andReturn("/index.xhtml")
-            .anyTimes();
-
-    //dispatch request
-    replay(requestMock);
-    pipeline.dispatch(requestMock, null, createMock(FilterChain.class));
-    pipeline.destroyPipeline();
-
-    verify(requestMock);
-
-    assert inits == 5 && doFilters == 0 && destroys == 5 : "lifecycle  
states did not "
-          + "fire correct number of times-- inits: " + inits + "; dos: " +  
doFilters
-          + "; destroys: " + destroys;
-  }
-
-  public final void testDispatchFilterPipelineWithRegexMatching() throws  
ServletException,
-      IOException {
-
-    final Injector injector = Guice.createInjector(new ServletModule() {
-
-      @Override
-      protected void configureServlets() {
-        filterRegex("/[A-Za-z]*").through(TestFilter.class);
-        filterRegex("/index").through(TestFilter.class);
-
-        //these filters should never fire
-        filterRegex("\\w").through(Key.get(TestFilter.class));
-      }
      });

      final FilterPipeline pipeline =  
injector.getInstance(FilterPipeline.class);
@@ -139,7 +73,7 @@
      HttpServletRequest requestMock = createMock(HttpServletRequest.class);

      expect(requestMock.getServletPath())
-            .andReturn("/index")
+            .andReturn("/index.html")
              .anyTimes();

      //dispatch request
@@ -149,9 +83,9 @@

      verify(requestMock);

-    assert inits == 3 && doFilters == 2 && destroys == 3 : "lifecycle  
states did not fire "
-        + "correct number of times-- inits: " + inits + "; dos: " +  
doFilters
-        + "; destroys: " + destroys;
+    assert inits == 5 && doFilters == 3 && destroys == 5 : "lifecycle  
states did not"
+          + " fire correct number of times-- inits: " + inits + "; dos: "  
+ doFilters
+          + "; destroys: " + destroys;
    }

    @Singleton
@@ -170,4 +104,4 @@
        destroys++;
      }
    }
-}
+}
\ No newline at end of file

Modified:  
trunk/servlet/test/com/google/inject/servlet/ServletPipelineRequestDispatcherTest.java
==============================================================================
---  
trunk/servlet/test/com/google/inject/servlet/ServletPipelineRequestDispatcherTest.java
   
(original)
+++  
trunk/servlet/test/com/google/inject/servlet/ServletPipelineRequestDispatcherTest.java
   
Sat Jan  3 23:17:25 2009
@@ -16,12 +16,15 @@

  package com.google.inject.servlet;

+import com.google.common.collect.ImmutableList;
+import com.google.inject.Binding;
  import com.google.inject.Injector;
  import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
  import java.io.IOException;
-import java.util.Arrays;
  import java.util.Date;
  import java.util.HashMap;
+import java.util.List;
  import java.util.UUID;
  import javax.servlet.RequestDispatcher;
  import javax.servlet.ServletException;
@@ -73,13 +76,24 @@
      expect(injector.getInstance(HTTP_SERLVET_KEY))
          .andReturn(mockServlet);

+    final Key<List<ServletDefinition>> servetDefsKey = Key
+        .get(new TypeLiteral<List<ServletDefinition>>() {});
+    expect(injector.getBindings())
+        .andReturn(new HashMap<Key<?>, Binding<?>>() {{
+
+          put(servetDefsKey, createMock(Binding.class));
+        }});
+
+    expect(injector.getInstance(servetDefsKey))
+        .andReturn(ImmutableList.of(servletDefinition));
+
      replay(injector, mockRequest);

      // Have to init the Servlet before we can dispatch to it.
      servletDefinition.init(null, injector);

      final RequestDispatcher dispatcher = new ManagedServletPipeline(
-        Arrays.asList(servletDefinition))
+        injector)
          .getRequestDispatcher(pattern);

      assertNotNull(dispatcher);
@@ -123,13 +137,23 @@
      expect(injector.getInstance(HTTP_SERLVET_KEY))
          .andReturn(mockServlet);

+    final Key<List<ServletDefinition>> servetDefsKey = Key
+        .get(new TypeLiteral<List<ServletDefinition>>() {});
+    expect(injector.getBindings())
+        .andReturn(new HashMap<Key<?>, Binding<?>>() {{
+
+          put(servetDefsKey, createMock(Binding.class));
+        }});
+
+    expect(injector.getInstance(servetDefsKey))
+        .andReturn(ImmutableList.of(servletDefinition));
+
      replay(injector, mockRequest, mockResponse);

      // Have to init the Servlet before we can dispatch to it.
      servletDefinition.init(null, injector);

-    final RequestDispatcher dispatcher = new ManagedServletPipeline(
-        Arrays.asList(servletDefinition))
+    final RequestDispatcher dispatcher = new  
ManagedServletPipeline(injector)
          .getRequestDispatcher(pattern);

      assertNotNull(dispatcher);
@@ -179,13 +203,24 @@
      expect(injector.getInstance(Key.get(HttpServlet.class)))
          .andReturn(mockServlet);

+
+    final Key<List<ServletDefinition>> servetDefsKey = Key
+        .get(new TypeLiteral<List<ServletDefinition>>() {});
+    expect(injector.getBindings())
+        .andReturn(new HashMap<Key<?>, Binding<?>>() {{
+
+          put(servetDefsKey, createMock(Binding.class));
+        }});
+
+    expect(injector.getInstance(servetDefsKey))
+        .andReturn(ImmutableList.of(servletDefinition));
+
      replay(injector, mockRequest, mockResponse);

      // Have to init the Servlet before we can dispatch to it.
      servletDefinition.init(null, injector);

-    final RequestDispatcher dispatcher = new ManagedServletPipeline(
-        Arrays.asList(servletDefinition))
+    final RequestDispatcher dispatcher = new  
ManagedServletPipeline(injector)
          .getRequestDispatcher(pattern);

      assertNotNull(dispatcher);

Modified: trunk/src/com/google/inject/InheritingState.java
==============================================================================
--- trunk/src/com/google/inject/InheritingState.java    (original)
+++ trunk/src/com/google/inject/InheritingState.java    Sat Jan  3 23:17:25  
2009
@@ -33,7 +33,9 @@
  class InheritingState implements State {

    private final State parent;
-  private final Map<Key<?>, Binding<?>> explicitBindingsMutable =  
Maps.newHashMap();
+
+  // Must be a linked hashmap in order to preserve order of bindings in  
Modules.
+  private final Map<Key<?>, Binding<?>> explicitBindingsMutable =  
Maps.newLinkedHashMap();
    private final Map<Key<?>, Binding<?>> explicitBindings
        = Collections.unmodifiableMap(explicitBindingsMutable);
    private final Map<Class<? extends Annotation>, Scope> scopes =  
Maps.newHashMap();

Modified: trunk/src/com/google/inject/Injector.java
==============================================================================
--- trunk/src/com/google/inject/Injector.java   (original)
+++ trunk/src/com/google/inject/Injector.java   Sat Jan  3 23:17:25 2009
@@ -64,9 +64,12 @@
     * Returns all explicit bindings.
     *
     * <p>The returned map does not include bindings inherited from a {...@link 
 
#getParent() parent
-   * injector}, should one exist.
+   * injector}, should one exist. The returned map is guaranteed to  
iterate (for example, with
+   * its {...@link java.util.Map#entrySet()} iterator) in the order of  
insertion. In other words,
+   * the order in which bindings appear in user Modules.
     *
     * <p>This method is part of the Guice SPI and is intended for use by  
tools and extensions.
+   *
     */
    Map<Key<?>, Binding<?>> getBindings();


--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---

Reply via email to