Author: dhanji
Date: Tue Dec 23 22:39:43 2008
New Revision: 738

Added:
     
trunk/servlet/test/com/google/inject/servlet/ServletDefinitionPathsTest.java
    trunk/servlet/test/com/google/inject/servlet/ServletDefinitionTest.java
     
trunk/servlet/test/com/google/inject/servlet/ServletDispatchIntegrationTest.java
     
trunk/servlet/test/com/google/inject/servlet/ServletPipelineRequestDispatcherTest.java
     
trunk/servlet/test/com/google/inject/servlet/VarargsFilterDispatchIntegrationTest.java
    
(contents, props changed)
       - copied, changed from r737,  
/trunk/servlet/test/com/google/inject/servlet/FilterDispatchIntegrationTest.java
     
trunk/servlet/test/com/google/inject/servlet/VarargsServletDispatchIntegrationTest.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/ManagedServletPipeline.java
    trunk/servlet/src/com/google/inject/servlet/ServletDefinition.java
    trunk/servlet/src/com/google/inject/servlet/ServletModule.java
    trunk/servlet/src/com/google/inject/servlet/ServletsModuleBuilder.java
    trunk/servlet/test/com/google/inject/servlet/AllTests.java

Log:
Added varargs mapping for filters and servlets. And added a bunch of tests  
that verify the dispatch pipeline, servlet spec compliance, and so forth.

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       
 
Tue Dec 23 22:39:43 2008
@@ -41,21 +41,21 @@
      bind(FilterPipeline.class).toInstance(new  
ManagedFilterPipeline(filterDefinitions));
    }

-  public ServletModule.FilterKeyBindingBuilder filter(String urlPattern) {
-    return new FilterKeyBindingBuilderImpl(urlPattern,  
UriPatternType.SERVLET);
+  public ServletModule.FilterKeyBindingBuilder filter(List<String>  
patterns) {
+    return new FilterKeyBindingBuilderImpl(patterns,  
UriPatternType.SERVLET);
    }

-  public ServletModule.FilterKeyBindingBuilder filterRegex(String regex) {
-    return new FilterKeyBindingBuilderImpl(regex, UriPatternType.REGEX);
+  public ServletModule.FilterKeyBindingBuilder filterRegex(List<String>  
regexes) {
+    return new FilterKeyBindingBuilderImpl(regexes, UriPatternType.REGEX);
    }

    //non-static inner class so it can access state of enclosing module class
    class FilterKeyBindingBuilderImpl implements  
ServletModule.FilterKeyBindingBuilder {
-    private final String uriPattern;
+    private final List<String> uriPatterns;
      private final UriPatternType uriPatternType;

-    private FilterKeyBindingBuilderImpl(String uriPattern, UriPatternType  
uriPatternType) {
-      this.uriPattern = uriPattern;
+    private FilterKeyBindingBuilderImpl(List<String> uriPatterns,  
UriPatternType uriPatternType) {
+      this.uriPatterns = uriPatterns;
        this.uriPatternType = uriPatternType;
      }

@@ -76,9 +76,11 @@
      public void through(Key<? extends Filter> filterKey,
          Map<String, String> contextParams) {

-      filterDefinitions.add(
-          new FilterDefinition(uriPattern, filterKey,  
UriPatternType.get(uriPatternType),
-              contextParams));
+      for (String pattern : uriPatterns) {
+        filterDefinitions.add(
+            new FilterDefinition(pattern, filterKey,  
UriPatternType.get(uriPatternType),
+                contextParams));
+      }
      }
    }
  }

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        Tue Dec 
23  
22:39:43 2008
@@ -56,8 +56,7 @@
   */
  public class GuiceFilter implements Filter {
    static final ThreadLocal<Context> localContext = new  
ThreadLocal<Context>();
-  static volatile WeakReference<FilterPipeline> pipeline =
-      new WeakReference<FilterPipeline>(new DefaultFilterPipeline());
+  static volatile FilterPipeline pipeline = new DefaultFilterPipeline();

    /** Used to inject the servlets configured via {...@link ServletModule} */
    static volatile WeakReference<ServletContext> servletContext =
@@ -68,7 +67,7 @@
    static void setPipeline(FilterPipeline pipeline) {

      // Multiple injectors with ServletModules?
-    if (GuiceFilter.pipeline.get() instanceof ManagedFilterPipeline) {
+    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"
@@ -77,12 +76,12 @@
      }

      // We will only overwrite the default pipeline
-    GuiceFilter.pipeline = new WeakReference<FilterPipeline>(pipeline);
+    GuiceFilter.pipeline = pipeline;
    }

    //VisibleForTesting
    static void clearPipeline() {
-    pipeline = new WeakReference<FilterPipeline>(null);
+    pipeline = null;
    }

    public void doFilter(ServletRequest servletRequest,
@@ -90,7 +89,7 @@
        throws IOException, ServletException {

      Context previous = localContext.get();
-    FilterPipeline filterPipeline = pipeline.get();
+    FilterPipeline filterPipeline = pipeline;

      try {
        localContext.set(new Context((HttpServletRequest) servletRequest,
@@ -155,17 +154,17 @@
      // In the default pipeline, this is a noop. However, if replaced
      // by a managed pipeline, a lazy init will be triggered the first time
      // dispatch occurs.
-    GuiceFilter.pipeline.get().initPipeline(servletContext);
+    GuiceFilter.pipeline.initPipeline(servletContext);
    }

    public void destroy() {

      try {
        // Destroy all registered filters & servlets in that order
-      pipeline.get().destroyPipeline();
+      pipeline.destroyPipeline();

      } finally {
-      pipeline.clear();
+      clearPipeline();
        servletContext.clear();
      }
    }

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     
 
Tue Dec 23 22:39:43 2008
@@ -77,17 +77,17 @@
                    + "flush buffers)");
              }

-            //clear buffer before forwarding
+            // clear buffer before forwarding
              servletResponse.resetBuffer();

-            //now dispatch to the servlet
+            // now dispatch to the servlet
              servletDefinition.doService(servletRequest, servletResponse);
            }

            public void include(ServletRequest servletRequest,  
ServletResponse servletResponse)
                throws ServletException, IOException {

-            //route to the target servlet
+            // route to the target servlet
              servletDefinition.doService(servletRequest, servletResponse);
            }
          };

Modified: trunk/servlet/src/com/google/inject/servlet/ServletDefinition.java
==============================================================================
--- trunk/servlet/src/com/google/inject/servlet/ServletDefinition.java   
(original)
+++ trunk/servlet/src/com/google/inject/servlet/ServletDefinition.java  Tue  
Dec 23 22:39:43 2008
@@ -153,8 +153,8 @@
            pathInfo =  
getRequestURI().substring(getContextPath().length()).replaceAll("[/]{2,}", "/")
                .substring(servletPathLength);

-          //corner case: when servlet path and request path match exactly  
(without trailing '/'),
-          //pathinfo is null
+          // Corner case: when servlet path and request path match exactly  
(without trailing '/'),
+          // then pathinfo is null
            if ("".equals(pathInfo) && servletPathLength != 0) {
              pathInfo = null;
            }
@@ -177,7 +177,7 @@
          return (null == info) ? null : getRealPath(info);
        }

-      //memoizer pattern
+      // Memoizer pattern.
        private String computePath() {
          if (!pathComputed) {
            path = patternMatcher.extractPath(pattern);

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      Tue Dec 
 
23 22:39:43 2008
@@ -16,14 +16,13 @@

  package com.google.inject.servlet;

-import static com.google.inject.servlet.ServletScopes.REQUEST;
-import static com.google.inject.servlet.ServletScopes.SESSION;
-
+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;
@@ -154,7 +153,13 @@
     *       <b>serve("/my/*").with(MyServlet.class)</b>
     * </pre>
     *
-   * You are free to register as many servlets and filters as you like  
this way:
+   * Every servlet is required to be a singleton and will implicitly be  
bound as one if it isn't
+   * already. Mapping a servlet that is bound under any other scope is an  
error.
+   *
+   * <p>
+   * <h4>Dispatch Order</h4>
+   * You are free to register as many servlets and filters as you like  
this way. They will
+   * be compared and dispatched in the order in which the filter methods  
are called:
     *
     * <pre>
     *
@@ -162,17 +167,41 @@
     *
     *     {...@literal @}Override
     *     protected void configureServlets() {
-   *       filter("/*").through(MyFilter.class)
-   *       filter("*.css").through(MyCssFilter.class)
+   *       filter("/*").through(MyFilter.class);
+   *       filter("*.css").through(MyCssFilter.class);
     *       // etc..
     *
-   *       serve("*.html").with(MyServlet.class)
-   *       serve("/my/*").with(MyServlet.class)
+   *       serve("*.html").with(MyServlet.class);
+   *       serve("/my/*").with(MyServlet.class);
     *       // etc..
     *      }
     *    }
     * </pre>
+   * This will traverse down the list of rules in lexical order. For  
example, a url
+   *  "{...@code /my/file.js}" (after it runs through the matching filters)  
will first
+   *  be compared against the servlet mapping:
+   *
+   * <pre>
+   *       serve("*.html").with(MyServlet.class);
+   * </pre>
+   * And failing that, it will descend to the next servlet mapping:
     *
+   * <pre>
+   *       serve("/my/*").with(MyServlet.class);
+   * </pre>
+   *
+   * Since this rule matches, Guice Servlet will dispatch to {...@code  
MyServlet}. These
+   * two mapping rules can also be written in more compact form using  
varargs syntax:
+   *
+   * <pre>
+   *       serve(<b>"*.html", "/my/*"</b>).with(MyServlet.class);
+   * </pre>
+   *
+   * This way you can map several URI patterns to the same servlet. A  
similar syntax is
+   * also available for filter mappings.
+   *
+   * <p>
+   * <h4>Regular Expressions</h4>
     * You can also map servlets (or filters) to URIs using regular  
expressions:
     * <pre>
     *    <b>serveRegex("(.)*ajax(.)*").with(MyAjaxServlet.class)</b>
@@ -203,15 +232,14 @@
     *      serve("/*").with(MyServlet.class, <b>params</b>)
     * </pre>
     *
-   *
+   * <p>
     * <h3>Binding Keys</h3>
     *
-   * <p> You can also bind keys rather than classes. This lets you hide
+   * You can also bind keys rather than classes. This lets you hide
     * implementations with package-local visbility and expose them using
     * only a Guice module and an annotation:
     *
     * <pre>
-   *
     *  ...
     *      filter("/*").through(<b>Key.get(Filter.class, Fave.class)</b>);
     * </pre>
@@ -224,7 +252,7 @@
     *    
bind(Filter.class)<b>.annotatedWith(Fave.class)</b>.to(MyFilterImpl.class);
     * </pre>
     *
-   * See Guice documentation for more information on binding annotations.
+   * See {...@link com.google.inject.Binder} for more information on binding  
syntax.
     */
    protected void configureServlets() {
    }
@@ -236,29 +264,29 @@
    /**
     * @param urlPattern Any Servlet-style pattern. examples: /*, /html/*,  
*.html, etc.
     */
-  protected final FilterKeyBindingBuilder filter(String urlPattern) {
-    return filtersModuleBuilder.filter(urlPattern);
+  protected final FilterKeyBindingBuilder filter(String urlPattern,  
String... morePatterns) {
+    return filtersModuleBuilder.filter(Lists.asList(urlPattern,  
morePatterns));
    }

    /**
     * @param regex Any Java-style regular expression.
     */
-  protected final FilterKeyBindingBuilder filterRegex(String regex) {
-    return filtersModuleBuilder.filterRegex(regex);
+  protected final FilterKeyBindingBuilder filterRegex(String regex,  
String... regexes) {
+    return filtersModuleBuilder.filterRegex(Lists.asList(regex, regexes));
    }

    /**
     * @param urlPattern Any Servlet-style pattern. examples: /*, /html/*,  
*.html, etc.
     */
-  protected final ServletKeyBindingBuilder serve(String urlPattern) {
-    return servletsModuleBuilder.serve(urlPattern);
+  protected final ServletKeyBindingBuilder serve(String urlPattern,  
String... morePatterns) {
+    return servletsModuleBuilder.serve(Lists.asList(urlPattern,  
morePatterns));
    }

    /**
     * @param regex Any Java-style regular expression.
     */
-  protected final ServletKeyBindingBuilder serveRegex(String regex) {
-    return servletsModuleBuilder.serveRegex(regex);
+  protected final ServletKeyBindingBuilder serveRegex(String regex,  
String... regexes) {
+    return servletsModuleBuilder.serveRegex(Lists.asList(regex, regexes));
    }

    public static interface FilterKeyBindingBuilder {

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      
 
Tue Dec 23 22:39:43 2008
@@ -41,21 +41,21 @@
    }

    //the first level of the EDSL--
-  public ServletModule.ServletKeyBindingBuilder serve(String urlPattern) {
-    return new ServletKeyBindingBuilderImpl(urlPattern,  
UriPatternType.SERVLET);
+  public ServletModule.ServletKeyBindingBuilder serve(List<String>  
urlPatterns) {
+    return new ServletKeyBindingBuilderImpl(urlPatterns,  
UriPatternType.SERVLET);
    }

-  public ServletModule.ServletKeyBindingBuilder serveRegex(String regex) {
-    return new ServletKeyBindingBuilderImpl(regex, UriPatternType.REGEX);
+  public ServletModule.ServletKeyBindingBuilder serveRegex(List<String>  
regexes) {
+    return new ServletKeyBindingBuilderImpl(regexes, UriPatternType.REGEX);
    }

    //non-static inner class so it can access state of enclosing module class
    class ServletKeyBindingBuilderImpl implements  
ServletModule.ServletKeyBindingBuilder {
-    private final String uriPattern;
+    private final List<String> uriPatterns;
      private final UriPatternType uriPatternType;

-    private ServletKeyBindingBuilderImpl(String uriPattern, UriPatternType  
uriPatternType) {
-      this.uriPattern = uriPattern;
+    private ServletKeyBindingBuilderImpl(List<String> uriPatterns,  
UriPatternType uriPatternType) {
+      this.uriPatterns = uriPatterns;
        this.uriPatternType = uriPatternType;
      }

@@ -74,9 +74,12 @@

      public void with(Key<? extends HttpServlet> servletKey,
          Map<String, String> contextParams) {
-      servletDefinitions.add(
-          new ServletDefinition(uriPattern, servletKey,  
UriPatternType.get(uriPatternType),
-              contextParams));
+
+      for (String pattern : uriPatterns) {
+        servletDefinitions.add(
+            new ServletDefinition(pattern, servletKey,  
UriPatternType.get(uriPatternType),
+                contextParams));
+      }
      }
    }
  }

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  Tue Dec 23  
22:39:43 2008
@@ -27,12 +27,22 @@
    public static Test suite() {
      TestSuite suite = new TestSuite();

-    // Servlet tests.
+    // Filter tests.
      suite.addTestSuite(EdslTest.class);
      suite.addTestSuite(FilterDefinitionTest.class);
      suite.addTestSuite(FilterDispatchIntegrationTest.class);
      suite.addTestSuite(FilterPipelineTest.class);
+
+    // Servlet + integration tests.
      suite.addTestSuite(ServletTest.class);
+    suite.addTestSuite(ServletDefinitionTest.class);
+    suite.addTestSuite(ServletDefinitionPathsTest.class);
+    suite.addTestSuite(ServletPipelineRequestDispatcherTest.class);
+    suite.addTestSuite(ServletDispatchIntegrationTest.class);
+
+    // Varargs URL mapping tests.
+    suite.addTestSuite(VarargsFilterDispatchIntegrationTest.class);
+    suite.addTestSuite(VarargsServletDispatchIntegrationTest.class);

      return suite;
    }

Added:  
trunk/servlet/test/com/google/inject/servlet/ServletDefinitionPathsTest.java
==============================================================================
--- (empty file)
+++  
trunk/servlet/test/com/google/inject/servlet/ServletDefinitionPathsTest.java    
 
Tue Dec 23 22:39:43 2008
@@ -0,0 +1,260 @@
+/**
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.inject.servlet;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+
+import com.google.inject.Injector;
+import com.google.inject.Key;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.util.HashMap;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Ensures servlet spec compliance for CGI-style variables and general
+ *  path/pattern matching.
+ *
+ * @author Dhanji R. Prasanna (dha...@gmail com)
+ */
+public class ServletDefinitionPathsTest extends TestCase {
+
+  // Data-driven test.
+  public final void testServletPathMatching() throws IOException,  
ServletException {
+    servletPath("/index.html", "*.html", "/index.html");
+     
servletPath("/somewhere/index.html", "*.html", "/somewhere/index.html");
+    servletPath("/somewhere/index.html", "/*", "");
+    servletPath("/index.html", "/*", "");
+    servletPath("/", "/*", "");
+    servletPath("//", "/*", "");
+    servletPath("/////", "/*", "");
+    servletPath("", "/*", "");
+    servletPath("/thing/index.html", "/thing/*", "/thing");
+    servletPath("/thing/wing/index.html", "/thing/*", "/thing");
+  }
+
+  private void servletPath(final String requestPath, String mapping,
+      final String expectedServletPath) throws IOException,  
ServletException {
+
+    Injector injector = createMock(Injector.class);
+    HttpServletRequest request = createMock(HttpServletRequest.class);
+    HttpServletResponse response = createMock(HttpServletResponse.class);
+
+    final boolean[] run = new boolean[1];
+
+    //get an instance of this servlet
+    expect(injector.getInstance(Key.get(HttpServlet.class)))
+        .andReturn(new HttpServlet() {
+
+          @Override
+          protected void service(HttpServletRequest servletRequest,
+              HttpServletResponse httpServletResponse) throws  
ServletException, IOException {
+
+            final String path = servletRequest.getServletPath();
+            assertEquals(String.format("expected [%s] but was [%s]",  
expectedServletPath, path),
+                expectedServletPath, path);
+            run[0] = true;
+          }
+        });
+
+    expect(request.getServletPath())
+        .andReturn(requestPath);
+
+    replay(injector, request);
+
+    ServletDefinition servletDefinition = new ServletDefinition(mapping,  
Key.get(HttpServlet.class),
+        UriPatternType.get(UriPatternType.SERVLET), new HashMap<String,  
String>());
+
+    servletDefinition.init(null, injector);
+    servletDefinition.doService(request, response);
+
+    assertTrue("Servlet did not run!", run[0]);
+
+  }
+
+  // Data-driven test.
+  public final void testPathInfoWithServletStyleMatching() throws  
IOException, ServletException {
+     
pathInfoWithServletStyleMatching("/path/index.html", "/path", "/*", 
"/index.html", "");
+     
pathInfoWithServletStyleMatching("/path//hulaboo///index.html", "/path", "/*",
+        "/hulaboo/index.html", "");
+    pathInfoWithServletStyleMatching("/path/", "/path", "/*", "/", "");
+     
pathInfoWithServletStyleMatching("/path////////", "/path", "/*", "/", "");
+
+    // a servlet mapping of /thing/*
+     
pathInfoWithServletStyleMatching("/path/thing////////", "/path", "/thing/*", 
"/", "/thing");
+     
pathInfoWithServletStyleMatching("/path/thing/stuff", "/path", "/thing/*", 
"/stuff", "/thing");
+     
pathInfoWithServletStyleMatching("/path/thing/stuff.html", "/path", "/thing/*", 
"/stuff.html",
+        "/thing");
+    pathInfoWithServletStyleMatching("/path/thing", "/path", "/thing/*",  
null, "/thing");
+
+    // *.xx style mapping
+     
pathInfoWithServletStyleMatching("/path/thing.thing", "/path", "*.thing",  
null, "/thing.thing");
+     
pathInfoWithServletStyleMatching("/path///h.thing", "/path", "*.thing",  
null, "/h.thing");
+     
pathInfoWithServletStyleMatching("/path///...//h.thing", "/path", "*.thing",  
null,
+        "/.../h.thing");
+     
pathInfoWithServletStyleMatching("/path/my/h.thing", "/path", "*.thing",  
null, "/my/h.thing");
+
+  }
+
+  private void pathInfoWithServletStyleMatching(final String requestUri,  
final String contextPath,
+      String mapping, final String expectedPathInfo, final String  
servletPath)
+      throws IOException, ServletException {
+
+    Injector injector = createMock(Injector.class);
+    HttpServletRequest request = createMock(HttpServletRequest.class);
+    HttpServletResponse response = createMock(HttpServletResponse.class);
+
+    final boolean[] run = new boolean[1];
+
+    //get an instance of this servlet
+    expect(injector.getInstance(Key.get(HttpServlet.class)))
+        .andReturn(new HttpServlet() {
+
+          @Override
+          protected void service(HttpServletRequest servletRequest,
+              HttpServletResponse httpServletResponse) throws  
ServletException, IOException {
+
+            final String path = servletRequest.getPathInfo();
+
+            if (null == expectedPathInfo) {
+              assertNull(String.format("expected [%s] but was [%s]",  
expectedPathInfo, path),
+                  path);
+            }
+            else {
+              assertEquals(String.format("expected [%s] but was [%s]",  
expectedPathInfo, path),
+                  expectedPathInfo, path);
+            }
+
+            //assert memoizer
+            //noinspection StringEquality
+            assertSame("memo field did not work", path,  
servletRequest.getPathInfo());
+
+            run[0] = true;
+          }
+        });
+
+    expect(request.getRequestURI())
+        .andReturn(requestUri);
+
+    expect(request.getServletPath())
+        .andReturn(servletPath)
+        .anyTimes();
+
+    expect(request.getContextPath())
+        .andReturn(contextPath);
+
+    replay(injector, request);
+
+    ServletDefinition servletDefinition = new ServletDefinition(mapping,  
Key.get(HttpServlet.class),
+        UriPatternType.get(UriPatternType.SERVLET), new HashMap<String,  
String>());
+
+    servletDefinition.init(null, injector);
+    servletDefinition.doService(request, response);
+
+    assertTrue("Servlet did not run!", run[0]);
+
+  }
+
+  // Data-driven test.
+  public final void testPathInfoWithRegexMatching() throws IOException,  
ServletException {
+    // first a mapping of /*
+     
pathInfoWithRegexMatching("/path/index.html", "/path", "/(.)*", "/index.html", 
"");
+     
pathInfoWithRegexMatching("/path//hulaboo///index.html", "/path", "/(.)*",
+        "/hulaboo/index.html", "");
+    pathInfoWithRegexMatching("/path/", "/path", "/(.)*", "/", "");
+    pathInfoWithRegexMatching("/path////////", "/path", "/(.)*", "/", "");
+
+    // a servlet mapping of /thing/*
+     
pathInfoWithRegexMatching("/path/thing////////", "/path", "/thing/(.)*", "/", 
"/thing");
+     
pathInfoWithRegexMatching("/path/thing/stuff", "/path", "/thing/(.)*", 
"/stuff", "/thing");
+     
pathInfoWithRegexMatching("/path/thing/stuff.html", "/path", "/thing/(.)*", 
"/stuff.html",
+        "/thing");
+    pathInfoWithRegexMatching("/path/thing", "/path", "/thing/(.)*",  
null, "/thing");
+
+    // *.xx style mapping
+     
pathInfoWithRegexMatching("/path/thing.thing", "/path", "(.)*\\.thing",  
null, "/thing.thing");
+    pathInfoWithRegexMatching("/path///h.thing", "/path", "(.)*\\.thing",  
null, "/h.thing");
+     
pathInfoWithRegexMatching("/path///...//h.thing", "/path", "(.)*\\.thing",  
null,
+        "/.../h.thing");
+    pathInfoWithRegexMatching("/path/my/h.thing", "/path", "(.)*\\.thing",  
null, "/my/h.thing");
+  }
+
+  public final void pathInfoWithRegexMatching(final String requestUri,  
final String contextPath,
+      String mapping, final String expectedPathInfo, final String  
servletPath)
+      throws IOException, ServletException {
+
+    Injector injector = createMock(Injector.class);
+    HttpServletRequest request = createMock(HttpServletRequest.class);
+    HttpServletResponse response = createMock(HttpServletResponse.class);
+
+    final boolean[] run = new boolean[1];
+
+    //get an instance of this servlet
+    expect(injector.getInstance(Key.get(HttpServlet.class)))
+        .andReturn(new HttpServlet() {
+
+          @Override
+          protected void service(HttpServletRequest servletRequest,
+              HttpServletResponse httpServletResponse) throws  
ServletException, IOException {
+
+            final String path = servletRequest.getPathInfo();
+
+            if (null == expectedPathInfo) {
+              assertNull(String.format("expected [%s] but was [%s]",  
expectedPathInfo, path),
+                  path);
+            }
+            else {
+              assertEquals(String.format("expected [%s] but was [%s]",  
expectedPathInfo, path),
+                  expectedPathInfo, path);
+            }
+
+            //assert memoizer
+            //noinspection StringEquality
+            assertSame("memo field did not work", path,  
servletRequest.getPathInfo());
+
+            run[0] = true;
+          }
+        });
+
+    expect(request.getRequestURI())
+        .andReturn(requestUri);
+
+    expect(request.getServletPath())
+        .andReturn(servletPath)
+        .anyTimes();
+
+    expect(request.getContextPath())
+        .andReturn(contextPath);
+
+    replay(injector, request);
+
+    ServletDefinition servletDefinition = new ServletDefinition(mapping,  
Key.get(HttpServlet.class),
+        UriPatternType.get(UriPatternType.REGEX), new HashMap<String,  
String>());
+
+    servletDefinition.init(null, injector);
+    servletDefinition.doService(request, response);
+
+    assertTrue("Servlet did not run!", run[0]);
+  }
+}

Added:  
trunk/servlet/test/com/google/inject/servlet/ServletDefinitionTest.java
==============================================================================
--- (empty file)
+++ trunk/servlet/test/com/google/inject/servlet/ServletDefinitionTest.java     
 
Tue Dec 23 22:39:43 2008
@@ -0,0 +1,90 @@
+/**
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.inject.servlet;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import junit.framework.TestCase;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+
+/**
+ * Basic unit test for lifecycle of a ServletDefinition (wrapper).
+ *
+ * @author Dhanji R. Prasanna (dha...@gmail com)
+ */
+public class ServletDefinitionTest extends TestCase {
+
+  public final void testServletInitAndConfig() throws ServletException {
+    Injector injector = createMock(Injector.class);
+
+    final HttpServlet mockServlet = new HttpServlet() {
+    };
+    expect(injector.getInstance(Key.get(HttpServlet.class)))
+        .andReturn(mockServlet)
+        .anyTimes();
+
+    replay(injector);
+
+    //some init params
+    //noinspection SSBasedInspection
+    final Map<String, String> initParams = new HashMap<String, String>() {
+      {
+        put("ahsd", "asdas24dok");
+        put("ahssd", "asdasd124ok");
+        put("ahfsasd", "asda124sdok");
+        put("ahsasgd", "a124sdasdok");
+        put("ahsd124124", "as124124124dasdok");
+      }
+    };
+
+    final ServletDefinition servletDefinition = new ServletDefinition("/*",
+        Key.get(HttpServlet.class),  
UriPatternType.get(UriPatternType.SERVLET), initParams);
+
+    ServletContext servletContext = createMock(ServletContext.class);
+    final String contextName = "thing__!@@44__SRV" + getClass();
+    expect(servletContext.getServletContextName())
+        .andReturn(contextName);
+
+    replay(servletContext);
+
+    servletDefinition.init(servletContext, injector);
+
+    assertNotNull(mockServlet.getServletContext());
+    assertEquals(contextName,  
mockServlet.getServletContext().getServletContextName());
+    assertEquals(Key.get(HttpServlet.class).toString(),  
mockServlet.getServletName());
+
+    final ServletConfig servletConfig = mockServlet.getServletConfig();
+    final Enumeration names = servletConfig.getInitParameterNames();
+    while (names.hasMoreElements()) {
+      String name = (String) names.nextElement();
+
+      assertTrue(initParams.containsKey(name));
+      assertEquals(initParams.get(name),  
servletConfig.getInitParameter(name));
+    }
+  }
+}

Added:  
trunk/servlet/test/com/google/inject/servlet/ServletDispatchIntegrationTest.java
==============================================================================
--- (empty file)
+++  
trunk/servlet/test/com/google/inject/servlet/ServletDispatchIntegrationTest.java
         
Tue Dec 23 22:39:43 2008
@@ -0,0 +1,191 @@
+/**
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.inject.servlet;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Singleton;
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import junit.framework.TestCase;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * Tests the FilterPipeline that dispatches to guice-managed servlets,
+ * is a full integration test, with a real injector.
+ *
+ * @author Dhanji R. Prasanna (dhanji gmail com)
+ */
+public class ServletDispatchIntegrationTest extends TestCase {
+  private static int inits, services, destroys, doFilters;
+
+  @Override
+  public void setUp() {
+    inits = 0;
+    services = 0;
+    destroys = 0;
+    doFilters = 0;
+
+    GuiceFilter.clearPipeline();
+  }
+
+  public final void testDispatchRequestToManagedPipelineServlets()
+      throws ServletException, IOException {
+    final Injector injector = Guice.createInjector(new ServletModule() {
+
+      @Override
+      protected void configureServlets() {
+        serve("/*").with(TestServlet.class);
+
+        // These servets should never fire... (ordering test)
+        serve("*.html").with(NeverServlet.class);
+        serve("/*").with(Key.get(NeverServlet.class));
+        serve("/index/*").with(Key.get(NeverServlet.class));
+        serve("*.jsp").with(Key.get(NeverServlet.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")
+        .times(1);
+
+    //dispatch request
+    replay(requestMock);
+
+    pipeline.dispatch(requestMock, null, createMock(FilterChain.class));
+
+    pipeline.destroyPipeline();
+
+    verify(requestMock);
+
+    assertTrue("lifecycle states did not fire correct number of times--  
inits: " + inits + "; dos: "
+            + services + "; destroys: " + destroys,
+        inits == 5 && services == 1 && destroys == 5);
+  }
+
+  public final void testDispatchRequestToManagedPipelineWithFilter()
+      throws ServletException, IOException {
+    final Injector injector = Guice.createInjector(new ServletModule() {
+
+      @Override
+      protected void configureServlets() {
+        filter("/*").through(TestFilter.class);
+
+        serve("/*").with(TestServlet.class);
+
+        // These servets should never fire...
+        serve("*.html").with(NeverServlet.class);
+        serve("/*").with(Key.get(NeverServlet.class));
+        serve("/index/*").with(Key.get(NeverServlet.class));
+        serve("*.jsp").with(Key.get(NeverServlet.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")
+        .times(2);
+
+    //dispatch request
+    replay(requestMock);
+
+    pipeline.dispatch(requestMock, null, createMock(FilterChain.class));
+
+    pipeline.destroyPipeline();
+
+    verify(requestMock);
+
+    assertTrue("lifecycle states did not fire correct number of times--  
inits: " + inits + "; dos: "
+            + services + "; destroys: " + destroys,
+        inits == 6 && services == 1 && destroys == 6 && doFilters == 1);
+  }
+
+  @Singleton
+  public static class TestServlet extends HttpServlet {
+    public void init(ServletConfig filterConfig) throws ServletException {
+      inits++;
+    }
+
+    public void service(ServletRequest servletRequest, ServletResponse  
servletResponse)
+        throws IOException, ServletException {
+      services++;
+    }
+
+    public void destroy() {
+      destroys++;
+    }
+  }
+
+  @Singleton
+  public static class NeverServlet extends HttpServlet {
+    public void init(ServletConfig filterConfig) throws ServletException {
+      inits++;
+    }
+
+    public void service(ServletRequest servletRequest, ServletResponse  
servletResponse)
+        throws IOException, ServletException {
+      assertTrue("NeverServlet was fired, when it should not have been.",  
false);
+    }
+
+    public void destroy() {
+      destroys++;
+    }
+  }
+
+  @Singleton
+  public static class TestFilter implements Filter {
+    public void init(FilterConfig filterConfig) throws ServletException {
+      inits++;
+    }
+
+    public void doFilter(ServletRequest servletRequest, ServletResponse  
servletResponse,
+        FilterChain filterChain) throws IOException, ServletException {
+      doFilters++;
+      filterChain.doFilter(servletRequest, servletResponse);
+    }
+
+    public void destroy() {
+      destroys++;
+    }
+  }
+}
\ No newline at end of file

Added:  
trunk/servlet/test/com/google/inject/servlet/ServletPipelineRequestDispatcherTest.java
==============================================================================
--- (empty file)
+++  
trunk/servlet/test/com/google/inject/servlet/ServletPipelineRequestDispatcherTest.java
   
Tue Dec 23 22:39:43 2008
@@ -0,0 +1,198 @@
+/**
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.inject.servlet;
+
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.UUID;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import junit.framework.TestCase;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * Tests forwarding and inclusion (RequestDispatcher actions from the
+ * servlet spec).
+ *
+ * @author Dhanji R. Prasanna (dha...@gmail com)
+ */
+public class ServletPipelineRequestDispatcherTest extends TestCase {
+  private static final Key<HttpServlet> HTTP_SERLVET_KEY =  
Key.get(HttpServlet.class);
+  private static final String A_KEY = "thinglyDEgintly" + new Date() +  
UUID.randomUUID();
+  private static final String A_VALUE =  
ServletPipelineRequestDispatcherTest.class.toString()
+      + new Date() + UUID.randomUUID();
+
+  public final void testIncludeManagedServlet() throws IOException,  
ServletException {
+    final ServletDefinition servletDefinition = new  
ServletDefinition("blah.html",
+        Key.get(HttpServlet.class),  
UriPatternType.get(UriPatternType.SERVLET),
+        new HashMap<String, String>());
+
+    final Injector injector = createMock(Injector.class);
+    final HttpServletRequest mockRequest =  
createMock(HttpServletRequest.class);
+
+    expect(mockRequest.getAttribute(A_KEY))
+        .andReturn(A_VALUE);
+
+    final boolean[] run = new boolean[1];
+    final HttpServlet mockServlet = new HttpServlet() {
+      protected void service(HttpServletRequest request,  
HttpServletResponse httpServletResponse)
+          throws ServletException, IOException {
+        run[0] = true;
+
+        final Object o = request.getAttribute(A_KEY);
+        assertEquals("Wrong attrib returned - " + o, A_VALUE, o);
+      }
+    };
+
+    expect(injector.getInstance(HTTP_SERLVET_KEY))
+        .andReturn(mockServlet);
+
+    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))
+        .getRequestDispatcher("blah.html");
+
+    assertNotNull(dispatcher);
+    dispatcher.include(mockRequest, createMock(HttpServletResponse.class));
+
+    assertTrue("Include did not dispatch to our servlet!", run[0]);
+
+    verify(injector, mockRequest);
+  }
+
+  public final void testForwardToManagedServlet() throws IOException,  
ServletException {
+    final ServletDefinition servletDefinition = new  
ServletDefinition("blah.html",
+        Key.get(HttpServlet.class),  
UriPatternType.get(UriPatternType.SERVLET),
+        new HashMap<String, String>());
+
+    final Injector injector = createMock(Injector.class);
+    final HttpServletRequest mockRequest =  
createMock(HttpServletRequest.class);
+    final HttpServletResponse mockResponse =  
createMock(HttpServletResponse.class);
+
+    expect(mockRequest.getAttribute(A_KEY))
+        .andReturn(A_VALUE);
+
+    expect(mockResponse.isCommitted())
+        .andReturn(false);
+
+    mockResponse.resetBuffer();
+    expectLastCall().once();
+
+    final boolean[] run = new boolean[1];
+    final HttpServlet mockServlet = new HttpServlet() {
+      protected void service(HttpServletRequest request,  
HttpServletResponse httpServletResponse)
+          throws ServletException, IOException {
+        run[0] = true;
+
+        final Object o = request.getAttribute(A_KEY);
+        assertEquals("Wrong attrib returned - " + o, A_VALUE, o);
+      }
+    };
+
+    expect(injector.getInstance(HTTP_SERLVET_KEY))
+        .andReturn(mockServlet);
+
+    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))
+        .getRequestDispatcher("blah.html");
+
+    assertNotNull(dispatcher);
+    dispatcher.forward(mockRequest, mockResponse);
+
+    assertTrue("Include did not dispatch to our servlet!", run[0]);
+
+    verify(injector, mockRequest, mockResponse);
+  }
+
+  public final void testForwardToManagedServletFailureOnCommittedBuffer()
+      throws IOException, ServletException {
+    IllegalStateException expected = null;
+    try {
+      forwardToManagedServletFailureOnCommittedBuffer();
+    }
+    catch (IllegalStateException ise) {
+      expected = ise;
+    } finally {
+      assertNotNull("Expected IllegalStateException was not thrown",  
expected);
+    }
+  }
+
+  public final void forwardToManagedServletFailureOnCommittedBuffer()
+      throws IOException, ServletException {
+    final ServletDefinition servletDefinition = new  
ServletDefinition("blah.html",
+        Key.get(HttpServlet.class),  
UriPatternType.get(UriPatternType.SERVLET),
+        new HashMap<String, String>());
+
+    final Injector injector = createMock(Injector.class);
+    final HttpServletRequest mockRequest =  
createMock(HttpServletRequest.class);
+    final HttpServletResponse mockResponse =  
createMock(HttpServletResponse.class);
+
+    expect(mockResponse.isCommitted())
+        .andReturn(true);
+
+    final HttpServlet mockServlet = new HttpServlet() {
+      protected void service(HttpServletRequest request,  
HttpServletResponse httpServletResponse)
+          throws ServletException, IOException {
+
+        final Object o = request.getAttribute(A_KEY);
+        assertEquals("Wrong attrib returned - " + o, A_VALUE, o);
+      }
+    };
+
+    expect(injector.getInstance(Key.get(HttpServlet.class)))
+        .andReturn(mockServlet);
+
+    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))
+        .getRequestDispatcher("blah.html");
+
+    assertNotNull(dispatcher);
+
+    try {
+      dispatcher.forward(mockRequest, mockResponse);
+    }
+    finally {
+      verify(injector, mockRequest, mockResponse);
+    }
+
+  }
+}

Copied:  
trunk/servlet/test/com/google/inject/servlet/VarargsFilterDispatchIntegrationTest.java
  
(from r737,  
/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/VarargsFilterDispatchIntegrationTest.java
   
Tue Dec 23 22:39:43 2008
@@ -20,7 +20,6 @@
  import javax.servlet.http.HttpServletRequest;
  import junit.framework.TestCase;

-
  /**
   *
   * This tests that filter stage of the pipeline dispatches
@@ -30,7 +29,7 @@
   *
   * @author [email protected] (Dhanji R. Prasanna)
   */
-public class FilterDispatchIntegrationTest extends TestCase {
+public class VarargsFilterDispatchIntegrationTest extends TestCase {
      private static int inits, doFilters, destroys;

    @Override
@@ -48,9 +47,8 @@

        @Override
        protected void configureServlets() {
-        filter("/*").through(TestFilter.class);
-        filter("*.html").through(TestFilter.class);
-        filter("/*").through(Key.get(TestFilter.class));
+        // This is actually a double match for "/*"
+        filter("/*", "*.html", "/*").through(Key.get(TestFilter.class));

          // These filters should never fire
          filter("/index/*").through(Key.get(TestFilter.class));
@@ -85,9 +83,7 @@

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

          // These filters should never fire
          filter("/index/*").through(Key.get(TestFilter.class));
@@ -124,8 +120,7 @@

        @Override
        protected void configureServlets() {
-        filterRegex("/[A-Za-z]*").through(TestFilter.class);
-        filterRegex("/index").through(TestFilter.class);
+        filterRegex("/[A-Za-z]*", "/index").through(TestFilter.class);

          //these filters should never fire
          filterRegex("\\w").through(Key.get(TestFilter.class));
@@ -170,4 +165,4 @@
        destroys++;
      }
    }
-}
+}
\ No newline at end of file

Added:  
trunk/servlet/test/com/google/inject/servlet/VarargsServletDispatchIntegrationTest.java
==============================================================================
--- (empty file)
+++  
trunk/servlet/test/com/google/inject/servlet/VarargsServletDispatchIntegrationTest.java
  
Tue Dec 23 22:39:43 2008
@@ -0,0 +1,221 @@
+/**
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.inject.servlet;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Singleton;
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import junit.framework.TestCase;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+/**
+ * Tests the FilterPipeline that dispatches to guice-managed servlets,
+ * is a full integration test, with a real injector.
+ *
+ * @author Dhanji R. Prasanna (dhanji gmail com)
+ */
+public class VarargsServletDispatchIntegrationTest extends TestCase {
+  private static int inits, services, destroys, doFilters;
+
+  @Override
+  public void setUp() {
+    inits = 0;
+    services = 0;
+    destroys = 0;
+    doFilters = 0;
+
+    GuiceFilter.clearPipeline();
+  }
+
+  public final void testDispatchRequestToManagedPipelineServlets()
+      throws ServletException, IOException {
+    final Injector injector = Guice.createInjector(new ServletModule() {
+
+      @Override
+      protected void configureServlets() {
+        serve("/*", "/index.html").with(TestServlet.class);
+
+        // These servets should never fire... (ordering test)
+         
serve("*.html", "/*", "/index/*", "*.jsp").with(Key.get(NeverServlet.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")
+        .times(1);
+
+    //dispatch request
+    replay(requestMock);
+
+    pipeline.dispatch(requestMock, null, createMock(FilterChain.class));
+    pipeline.destroyPipeline();
+
+    verify(requestMock);
+
+    assertTrue("lifecycle states did not fire correct number of times--  
inits: " + inits + "; dos: "
+            + services + "; destroys: " + destroys,
+        inits == 6 && services == 1 && destroys == 6);
+  }
+
+  public final void  
testVarargsSkipDispatchRequestToManagedPipelineServlets()
+      throws ServletException, IOException {
+    final Injector injector = Guice.createInjector(new ServletModule() {
+
+      @Override
+      protected void configureServlets() {
+        serve("/notindex", "/&*", "/index.html").with(TestServlet.class);
+
+        // These servets should never fire... (ordering test)
+         
serve("*.html", "/*", "/index/*", "*.jsp").with(Key.get(NeverServlet.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")
+        .times(3);
+
+    //dispatch request
+    replay(requestMock);
+
+    pipeline.dispatch(requestMock, null, createMock(FilterChain.class));
+    pipeline.destroyPipeline();
+
+    verify(requestMock);
+
+    assertTrue("lifecycle states did not fire correct number of times--  
inits: " + inits + "; dos: "
+            + services + "; destroys: " + destroys,
+        inits == 7 && services == 1 && destroys == 7);
+  }
+
+  public final void testDispatchRequestToManagedPipelineWithFilter()
+      throws ServletException, IOException {
+    final Injector injector = Guice.createInjector(new ServletModule() {
+
+      @Override
+      protected void configureServlets() {
+        filter("/*").through(TestFilter.class);
+
+        serve("/*").with(TestServlet.class);
+
+        // These servets should never fire...
+         
serve("*.html", "/*", "/index/*", "*.jsp").with(Key.get(NeverServlet.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")
+        .times(2);
+
+    //dispatch request
+    replay(requestMock);
+
+    pipeline.dispatch(requestMock, null, createMock(FilterChain.class));
+
+    pipeline.destroyPipeline();
+
+    verify(requestMock);
+
+    assertTrue("lifecycle states did not fire correct number of times--  
inits: " + inits + "; dos: "
+            + services + "; destroys: " + destroys,
+        inits == 6 && services == 1 && destroys == 6 && doFilters == 1);
+  }
+
+  @Singleton
+  public static class TestServlet extends HttpServlet {
+    public void init(ServletConfig filterConfig) throws ServletException {
+      inits++;
+    }
+
+    public void service(ServletRequest servletRequest, ServletResponse  
servletResponse)
+        throws IOException, ServletException {
+      services++;
+    }
+
+    public void destroy() {
+      destroys++;
+    }
+  }
+
+  @Singleton
+  public static class NeverServlet extends HttpServlet {
+    public void init(ServletConfig filterConfig) throws ServletException {
+      inits++;
+    }
+
+    public void service(ServletRequest servletRequest, ServletResponse  
servletResponse)
+        throws IOException, ServletException {
+      assertTrue("NeverServlet was fired, when it should not have been.",  
false);
+    }
+
+    public void destroy() {
+      destroys++;
+    }
+  }
+
+  @Singleton
+  public static class TestFilter implements Filter {
+    public void init(FilterConfig filterConfig) throws ServletException {
+      inits++;
+    }
+
+    public void doFilter(ServletRequest servletRequest, ServletResponse  
servletResponse,
+        FilterChain filterChain) throws IOException, ServletException {
+      doFilters++;
+      filterChain.doFilter(servletRequest, servletResponse);
+    }
+
+    public void destroy() {
+      destroys++;
+    }
+  }
+}
\ No newline at end of file

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