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