Author: dhanji
Date: Sat Feb 14 02:28:08 2009
New Revision: 846
Modified:
trunk/servlet/src/com/google/inject/servlet/FilterDefinition.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/ServletDefinition.java
trunk/servlet/test/com/google/inject/servlet/FilterDefinitionTest.java
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/VarargsServletDispatchIntegrationTest.java
Log:
Critical bug fix for issue:
http://code.google.com/p/google-guice/issues/detail?id=335
Modified: trunk/servlet/src/com/google/inject/servlet/FilterDefinition.java
==============================================================================
--- trunk/servlet/src/com/google/inject/servlet/FilterDefinition.java
(original)
+++ trunk/servlet/src/com/google/inject/servlet/FilterDefinition.java Sat
Feb 14 02:28:08 2009
@@ -24,6 +24,7 @@
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
@@ -58,7 +59,9 @@
return patternMatcher.matches(uri);
}
- public void init(final ServletContext servletContext, Injector injector)
throws ServletException {
+ public void init(final ServletContext servletContext, Injector injector,
+ Set<Filter> initializedSoFar) throws ServletException {
+
// This absolutely must be a singleton, and so is only initialized
once.
if (!isSingletonBinding(injector.getBinding(filterKey))) {
throw new ServletException("Filters must be bound as singletons. "
@@ -68,6 +71,12 @@
Filter filter = injector.getInstance(filterKey);
this.filter.set(filter);
+ // Only fire init() if this Singleton filter has not already appeared
earlier
+ // in the filter chain.
+ if (initializedSoFar.contains(filter)) {
+ return;
+ }
+
//initialize our filter with the configured context params and servlet
context
filter.init(new FilterConfig() {
public String getFilterName() {
@@ -86,19 +95,28 @@
return Iterators.asEnumeration(initParams.keySet().iterator());
}
});
+
+ initializedSoFar.add(filter);
}
- public void destroy() {
+ public void destroy(Set<Filter> destroyedSoFar) {
// filters are always singletons
Filter reference = filter.get();
// Do nothing if this Filter was invalid (usually due to not being
scoped
- // properly). According to Servlet Spec: it is "out of service", and
does not
- // need to be destroyed.
- if (null == reference) {
+ // properly), or was already destroyed. According to Servlet Spec: it
is
+ // "out of service", and does not need to be destroyed.
+ // Also prevent duplicate destroys to the same singleton that may
appear
+ // more than once on the filter chain.
+ if (null == reference || destroyedSoFar.contains(reference)) {
return;
}
- reference.destroy();
+
+ try {
+ reference.destroy();
+ } finally {
+ destroyedSoFar.add(reference);
+ }
}
public void doFilter(ServletRequest servletRequest,
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 Feb 14 02:28:08 2009
@@ -15,7 +15,9 @@
*/
package com.google.inject.servlet;
+import com.google.common.base.ReferenceType;
import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import com.google.inject.Binding;
import com.google.inject.Inject;
import com.google.inject.Injector;
@@ -26,6 +28,8 @@
import java.io.IOException;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
+import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
@@ -91,8 +95,11 @@
if (initialized)
return;
+ // Used to prevent duplicate initialization.
+ Set<Filter> initializedSoFar =
Sets.newIdentityHashSet(ReferenceType.STRONG);
+
for (FilterDefinition filterDefinition : filterDefinitions) {
- filterDefinition.init(servletContext, injector);
+ filterDefinition.init(servletContext, injector, initializedSoFar);
}
//next, initialize servlets...
@@ -151,9 +158,9 @@
servletPipeline.destroy();
//go down chain and destroy all our filters
- //TODO check servlet spec if we should continue destroying even if
exceptions are thrown
+ Set<Filter> destroyedSoFar =
Sets.newIdentityHashSet(ReferenceType.STRONG);
for (FilterDefinition filterDefinition : filterDefinitions) {
- filterDefinition.destroy();
+ filterDefinition.destroy(destroyedSoFar);
}
}
}
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 Feb 14 02:28:08 2009
@@ -15,7 +15,10 @@
*/
package com.google.inject.servlet;
+import com.google.common.base.Preconditions;
+import com.google.common.base.ReferenceType;
import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import com.google.inject.Binding;
import com.google.inject.Inject;
import com.google.inject.Injector;
@@ -25,11 +28,13 @@
import java.io.IOException;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServlet;
/**
* A wrapping dispatcher for servlets, in much the same way as {...@link
ManagedFilterPipeline} is for
@@ -68,8 +73,10 @@
}
public void init(ServletContext servletContext, Injector injector)
throws ServletException {
+ Set<HttpServlet> initializedSoFar =
Sets.newIdentityHashSet(ReferenceType.STRONG);
+
for (ServletDefinition servletDefinition : servletDefinitions) {
- servletDefinition.init(servletContext, injector);
+ servletDefinition.init(servletContext, injector, initializedSoFar);
}
}
@@ -88,8 +95,9 @@
}
public void destroy() {
+ Set<HttpServlet> destroyedSoFar =
Sets.newIdentityHashSet(ReferenceType.STRONG);
for (ServletDefinition servletDefinition : servletDefinitions) {
- servletDefinition.destroy();
+ servletDefinition.destroy(destroyedSoFar);
}
}
@@ -105,11 +113,9 @@
public void forward(ServletRequest servletRequest,
ServletResponse servletResponse)
throws ServletException, IOException {
- if (servletResponse.isCommitted()) {
- throw new IllegalStateException("Response has been
committed--you can "
- + "only call forward before committing the response
(hint: don't "
- + "flush buffers)");
- }
+ Preconditions.checkState(!servletResponse.isCommitted(),
+ "Response has been committed--you can only call forward
before"
+ + " committing the response (hint: don't flush buffers)");
// clear buffer before forwarding
servletResponse.resetBuffer();
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 Sat
Feb 14 02:28:08 2009
@@ -24,6 +24,7 @@
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
@@ -61,7 +62,9 @@
return patternMatcher.matches(uri);
}
- public void init(final ServletContext servletContext, Injector injector)
throws ServletException {
+ public void init(final ServletContext servletContext, Injector injector,
+ Set<HttpServlet> initializedSoFar) throws ServletException {
+
// This absolutely must be a singleton, and so is only initialized
once.
if (!isSingletonBinding(injector.getBinding(servletKey))) {
throw new ServletException("Servlets must be bound as singletons. "
@@ -71,6 +74,11 @@
HttpServlet httpServlet = injector.getInstance(servletKey);
this.httpServlet.set(httpServlet);
+ // Only fire init() if we have not appeared before in the filter chain.
+ if (initializedSoFar.contains(httpServlet)) {
+ return;
+ }
+
//initialize our servlet with the configured context params and
servlet context
httpServlet.init(new ServletConfig() {
public String getServletName() {
@@ -89,18 +97,28 @@
return Iterators.asEnumeration(initParams.keySet().iterator());
}
});
+
+ // Mark as initialized.
+ initializedSoFar.add(httpServlet);
}
- public void destroy() {
+ public void destroy(Set<HttpServlet> destroyedSoFar) {
HttpServlet reference = httpServlet.get();
// Do nothing if this Servlet was invalid (usually due to not being
scoped
// properly). According to Servlet Spec: it is "out of service", and
does not
// need to be destroyed.
- if (null == reference) {
+ // Also prevent duplicate destroys to the same singleton that may
appear
+ // more than once on the filter chain.
+ if (null == reference || destroyedSoFar.contains(reference)) {
return;
}
- reference.destroy();
+
+ try {
+ reference.destroy();
+ } finally {
+ destroyedSoFar.add(reference);
+ }
}
/**
Modified:
trunk/servlet/test/com/google/inject/servlet/FilterDefinitionTest.java
==============================================================================
--- trunk/servlet/test/com/google/inject/servlet/FilterDefinitionTest.java
(original)
+++ trunk/servlet/test/com/google/inject/servlet/FilterDefinitionTest.java
Sat Feb 14 02:28:08 2009
@@ -1,5 +1,7 @@
package com.google.inject.servlet;
+import com.google.common.base.ReferenceType;
+import com.google.common.collect.Sets;
import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.Key;
@@ -64,7 +66,7 @@
replay(servletContext);
- filterDef.init(servletContext, injector);
+ filterDef.init(servletContext, injector,
Sets.<Filter>newIdentityHashSet(ReferenceType.STRONG));
final FilterConfig filterConfig = mockFilter.getConfig();
assert null != filterConfig;
@@ -103,7 +105,8 @@
assert filterDef.getFilter() instanceof MockFilter;
//should fire on mockfilter now
- filterDef.init(createMock(ServletContext.class), injector);
+ filterDef.init(createMock(ServletContext.class), injector,
+ Sets.<Filter>newIdentityHashSet(ReferenceType.STRONG));
assert mockFilter.isInit() : "Init did not fire";
@@ -118,7 +121,7 @@
assertTrue("Filter did not proceed down chain", proceed[0]);
- filterDef.destroy();
+
filterDef.destroy(Sets.<Filter>newIdentityHashSet(ReferenceType.STRONG));
assertTrue("Destroy did not fire", mockFilter.isDestroy());
verify(injector, request);
@@ -157,7 +160,8 @@
assert filterDef.getFilter() instanceof MockFilter;
//should fire on mockfilter now
- filterDef.init(createMock(ServletContext.class), injector);
+ filterDef.init(createMock(ServletContext.class), injector,
+ Sets.<Filter>newIdentityHashSet(ReferenceType.STRONG));
assert mockFilter.isInit() : "Init did not fire";
@@ -171,7 +175,7 @@
assert !proceed[0] : "Filter did not suppress chain";
- filterDef.destroy();
+
filterDef.destroy(Sets.<Filter>newIdentityHashSet(ReferenceType.STRONG));
assert mockFilter.isDestroy() : "Destroy did not fire";
verify(injector, request);
Modified:
trunk/servlet/test/com/google/inject/servlet/ServletDefinitionPathsTest.java
==============================================================================
---
trunk/servlet/test/com/google/inject/servlet/ServletDefinitionPathsTest.java
(original)
+++
trunk/servlet/test/com/google/inject/servlet/ServletDefinitionPathsTest.java
Sat Feb 14 02:28:08 2009
@@ -16,6 +16,8 @@
package com.google.inject.servlet;
+import com.google.common.base.ReferenceType;
+import com.google.common.collect.Sets;
import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.Key;
@@ -86,7 +88,7 @@
ServletDefinition servletDefinition = new ServletDefinition(mapping,
Key.get(HttpServlet.class),
UriPatternType.get(UriPatternType.SERVLET, mapping), new
HashMap<String, String>());
- servletDefinition.init(null, injector);
+ servletDefinition.init(null, injector,
Sets.<HttpServlet>newIdentityHashSet(ReferenceType.STRONG));
servletDefinition.doService(request, response);
assertTrue("Servlet did not run!", run[0]);
@@ -171,7 +173,7 @@
ServletDefinition servletDefinition = new ServletDefinition(mapping,
Key.get(HttpServlet.class),
UriPatternType.get(UriPatternType.SERVLET, mapping), new
HashMap<String, String>());
- servletDefinition.init(null, injector);
+ servletDefinition.init(null, injector,
Sets.<HttpServlet>newIdentityHashSet(ReferenceType.STRONG));
servletDefinition.doService(request, response);
assertTrue("Servlet did not run!", run[0]);
@@ -256,7 +258,7 @@
ServletDefinition servletDefinition = new ServletDefinition(mapping,
Key.get(HttpServlet.class),
UriPatternType.get(UriPatternType.REGEX, mapping), new
HashMap<String, String>());
- servletDefinition.init(null, injector);
+ servletDefinition.init(null, injector,
Sets.<HttpServlet>newIdentityHashSet(ReferenceType.STRONG));
servletDefinition.doService(request, response);
assertTrue("Servlet did not run!", run[0]);
Modified:
trunk/servlet/test/com/google/inject/servlet/ServletDefinitionTest.java
==============================================================================
--- trunk/servlet/test/com/google/inject/servlet/ServletDefinitionTest.java
(original)
+++ trunk/servlet/test/com/google/inject/servlet/ServletDefinitionTest.java
Sat Feb 14 02:28:08 2009
@@ -16,15 +16,11 @@
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.common.base.ReferenceType;
+import com.google.common.collect.Sets;
+import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.Key;
-import com.google.inject.Binding;
-import junit.framework.TestCase;
-
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
@@ -32,6 +28,10 @@
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
+import junit.framework.TestCase;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
/**
* Basic unit test for lifecycle of a ServletDefinition (wrapper).
@@ -76,7 +76,7 @@
replay(servletContext);
- servletDefinition.init(servletContext, injector);
+ servletDefinition.init(servletContext, injector,
Sets.<HttpServlet>newIdentityHashSet(ReferenceType.STRONG));
assertNotNull(mockServlet.getServletContext());
assertEquals(contextName,
mockServlet.getServletContext().getServletContextName());
Modified:
trunk/servlet/test/com/google/inject/servlet/ServletDispatchIntegrationTest.java
==============================================================================
---
trunk/servlet/test/com/google/inject/servlet/ServletDispatchIntegrationTest.java
(original)
+++
trunk/servlet/test/com/google/inject/servlet/ServletDispatchIntegrationTest.java
Sat Feb 14 02:28:08 2009
@@ -93,7 +93,7 @@
assertTrue("lifecycle states did not fire correct number of times--
inits: " + inits + "; dos: "
+ services + "; destroys: " + destroys,
- inits == 5 && services == 1 && destroys == 5);
+ inits == 2 && services == 1 && destroys == 2);
}
public final void testDispatchRequestToManagedPipelineWithFilter()
@@ -136,8 +136,8 @@
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);
+ + services + "; destroys: " + destroys + "; doFilters: " +
doFilters,
+ inits == 3 && services == 1 && destroys == 3 && doFilters == 1);
}
@Singleton
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 Feb 14 02:28:08 2009
@@ -16,7 +16,9 @@
package com.google.inject.servlet;
+import com.google.common.base.ReferenceType;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Sets;
import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.Key;
@@ -94,7 +96,7 @@
replay(injector, mockRequest, mockBinding);
// Have to init the Servlet before we can dispatch to it.
- servletDefinition.init(null, injector);
+ servletDefinition.init(null, injector,
Sets.<HttpServlet>newIdentityHashSet(ReferenceType.STRONG));
final RequestDispatcher dispatcher = new ManagedServletPipeline(
injector)
@@ -158,7 +160,7 @@
replay(injector, mockRequest, mockResponse, mockBinding);
// Have to init the Servlet before we can dispatch to it.
- servletDefinition.init(null, injector);
+ servletDefinition.init(null, injector,
Sets.<HttpServlet>newIdentityHashSet(ReferenceType.STRONG));
final RequestDispatcher dispatcher = new
ManagedServletPipeline(injector)
.getRequestDispatcher(pattern);
@@ -228,7 +230,7 @@
replay(injector, mockRequest, mockResponse, mockBinding);
// Have to init the Servlet before we can dispatch to it.
- servletDefinition.init(null, injector);
+ servletDefinition.init(null, injector,
Sets.<HttpServlet>newIdentityHashSet(ReferenceType.STRONG));
final RequestDispatcher dispatcher = new
ManagedServletPipeline(injector)
.getRequestDispatcher(pattern);
Modified:
trunk/servlet/test/com/google/inject/servlet/VarargsServletDispatchIntegrationTest.java
==============================================================================
---
trunk/servlet/test/com/google/inject/servlet/VarargsServletDispatchIntegrationTest.java
(original)
+++
trunk/servlet/test/com/google/inject/servlet/VarargsServletDispatchIntegrationTest.java
Sat Feb 14 02:28:08 2009
@@ -89,7 +89,7 @@
assertTrue("lifecycle states did not fire correct number of times--
inits: " + inits + "; dos: "
+ services + "; destroys: " + destroys,
- inits == 6 && services == 1 && destroys == 6);
+ inits == 2 && services == 1 && destroys == 2);
}
public final void
testVarargsSkipDispatchRequestToManagedPipelineServlets()
@@ -126,7 +126,7 @@
assertTrue("lifecycle states did not fire correct number of times--
inits: " + inits + "; dos: "
+ services + "; destroys: " + destroys,
- inits == 7 && services == 1 && destroys == 7);
+ inits == 2 && services == 1 && destroys == 2);
}
public final void testDispatchRequestToManagedPipelineWithFilter()
@@ -167,7 +167,7 @@
assertTrue("lifecycle states did not fire correct number of times--
inits: " + inits + "; dos: "
+ services + "; destroys: " + destroys,
- inits == 6 && services == 1 && destroys == 6 && doFilters == 1);
+ inits == 3 && services == 1 && destroys == 3 && doFilters == 1);
}
@Singleton
--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---