Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorshuyangzhou2017-05-18 20:58:10 +0000
committerRaymond Auge2018-01-22 15:45:43 +0000
commit5951364be6642087127fd0ea77b39a70017223b9 (patch)
tree6104bd38c33617daca9933ce2c4394e41d8d5f31
parentda22ae61807be63939ff24057ee2b609c2cc0226 (diff)
downloadrt.equinox.bundles-5951364be6642087127fd0ea77b39a70017223b9.tar.gz
rt.equinox.bundles-5951364be6642087127fd0ea77b39a70017223b9.tar.xz
rt.equinox.bundles-5951364be6642087127fd0ea77b39a70017223b9.zip
Bug 530063 - [http] CNFE when session replication is used with equinox.http.servlet in bridge mode
Signed-off-by: Raymond Auge <raymond.auge@liferay.com> Signed-off-by: shuyangzhou <shuyang.zhou@liferay.com> Change-Id: I43a34e344c77bfae15d80bbcdb8fc73dd5b56734
-rw-r--r--bundles/org.eclipse.equinox.http.servlet.tests/META-INF/MANIFEST.MF3
-rw-r--r--bundles/org.eclipse.equinox.http.servlet.tests/pom.xml2
-rw-r--r--bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java130
-rw-r--r--bundles/org.eclipse.equinox.http.servlet/META-INF/MANIFEST.MF3
-rw-r--r--bundles/org.eclipse.equinox.http.servlet/pom.xml2
-rw-r--r--bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/Activator.java3
-rw-r--r--bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceRuntimeImpl.java22
-rw-r--r--bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ContextController.java33
-rw-r--r--bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletRequestWrapperImpl.java23
-rw-r--r--bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionAdaptor.java227
-rw-r--r--bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionTracker.java159
-rw-r--r--bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/session/HttpSessionInvalidator.java40
12 files changed, 459 insertions, 188 deletions
diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.http.servlet.tests/META-INF/MANIFEST.MF
index 2205f8b17..30d52b5d6 100644
--- a/bundles/org.eclipse.equinox.http.servlet.tests/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.http.servlet.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: org.eclipse.equinox.http.servlet.tests
Bundle-SymbolicName: org.eclipse.equinox.http.servlet.tests
-Bundle-Version: 1.4.100.qualifier
+Bundle-Version: 1.5.0.qualifier
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Eclipse-BundleShape: dir
Bundle-Activator: org.eclipse.equinox.http.servlet.tests.bundle.Activator
@@ -14,6 +14,7 @@ Import-Package: javax.servlet;version="2.6.0",
org.apache.commons.fileupload.servlet;version="1.2.2",
org.eclipse.equinox.http.servlet;version="1.1.0",
org.eclipse.equinox.http.servlet.context;version="1.0.0",
+ org.eclipse.equinox.http.servlet.session;version="1.0.0",
org.eclipse.osgi.service.urlconversion;version="1.0.0",
org.osgi.framework;version="1.6.0",
org.osgi.framework.hooks.service;version="1.1.0",
diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/pom.xml b/bundles/org.eclipse.equinox.http.servlet.tests/pom.xml
index 9d8701621..7810450a7 100644
--- a/bundles/org.eclipse.equinox.http.servlet.tests/pom.xml
+++ b/bundles/org.eclipse.equinox.http.servlet.tests/pom.xml
@@ -19,7 +19,7 @@
</parent>
<groupId>org.eclipse.equinox</groupId>
<artifactId>org.eclipse.equinox.http.servlet.tests</artifactId>
- <version>1.4.100-SNAPSHOT</version>
+ <version>1.5.0-SNAPSHOT</version>
<packaging>eclipse-test-plugin</packaging>
<build>
diff --git a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java
index 11ee568b5..e1d3cef73 100644
--- a/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java
+++ b/bundles/org.eclipse.equinox.http.servlet.tests/src/org/eclipse/equinox/http/servlet/tests/ServletTest.java
@@ -77,6 +77,7 @@ import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.eclipse.equinox.http.servlet.ExtendedHttpService;
import org.eclipse.equinox.http.servlet.context.ContextPathCustomizer;
+import org.eclipse.equinox.http.servlet.session.HttpSessionInvalidator;
import org.eclipse.equinox.http.servlet.testbase.BaseTest;
import org.eclipse.equinox.http.servlet.tests.util.BaseAsyncServlet;
import org.eclipse.equinox.http.servlet.tests.util.BaseChangeSessionIdServlet;
@@ -109,6 +110,7 @@ import org.osgi.service.http.runtime.dto.RuntimeDTO;
import org.osgi.service.http.runtime.dto.ServletContextDTO;
import org.osgi.service.http.runtime.dto.ServletDTO;
import org.osgi.service.http.whiteboard.HttpWhiteboardConstants;
+import org.osgi.util.tracker.ServiceTracker;
public class ServletTest extends BaseTest {
@Rule
@@ -1578,6 +1580,130 @@ public class ServletTest extends BaseTest {
}
@Test
+ public void test_Sessions03_HttpSessionInvalidator() throws Exception {
+ ServiceTracker<HttpSessionInvalidator, HttpSessionInvalidator> sessionInvalidatorTracker =
+ new ServiceTracker<>(getBundleContext(), HttpSessionInvalidator.class, null);
+ sessionInvalidatorTracker.open();
+ HttpSessionInvalidator invalidator = sessionInvalidatorTracker.waitForService(100);
+
+ final AtomicBoolean valueBound = new AtomicBoolean(false);
+ final AtomicBoolean valueUnbound = new AtomicBoolean(false);
+ final HttpSessionBindingListener bindingListener = new HttpSessionBindingListener() {
+
+ @Override
+ public void valueUnbound(HttpSessionBindingEvent event) {
+ valueUnbound.set(true);
+ }
+
+ @Override
+ public void valueBound(HttpSessionBindingEvent event) {
+ valueBound.set(true);
+ }
+ };
+ final AtomicBoolean sessionCreated = new AtomicBoolean(false);
+ final AtomicBoolean sessionDestroyed = new AtomicBoolean(false);
+ final AtomicReference<String> sessionId = new AtomicReference<String>();
+ HttpSessionListener sessionListener = new HttpSessionListener() {
+
+ @Override
+ public void sessionDestroyed(HttpSessionEvent se) {
+ sessionDestroyed.set(true);
+ }
+
+ @Override
+ public void sessionCreated(HttpSessionEvent se) {
+ sessionCreated.set(true);
+ }
+ };
+ HttpServlet sessionServlet = new HttpServlet() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException,
+ IOException {
+ HttpSession session = request.getSession();
+ if (session.getAttribute("test.attribute") == null) {
+ session.setAttribute("test.attribute", bindingListener);
+ sessionId.set(session.getId());
+ response.getWriter().print("created");
+ } else {
+ session.invalidate();
+ response.getWriter().print("invalidated");
+ }
+ }
+
+ };
+ ServiceRegistration<Servlet> servletReg = null;
+ ServiceRegistration<HttpSessionListener> sessionListenerReg = null;
+ Dictionary<String, Object> servletProps = new Hashtable<String, Object>();
+ servletProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN, "/sessions");
+ String actual = null;
+ CookieHandler previous = CookieHandler.getDefault();
+ CookieHandler.setDefault(new CookieManager( null, CookiePolicy.ACCEPT_ALL ) );
+ try {
+ servletReg = getBundleContext().registerService(Servlet.class, sessionServlet, servletProps);
+ Dictionary<String, String> listenerProps = new Hashtable<String, String>();
+ listenerProps.put(HttpWhiteboardConstants.HTTP_WHITEBOARD_LISTENER, "true");
+ sessionListenerReg = getBundleContext().registerService(HttpSessionListener.class, sessionListener, listenerProps);
+
+ sessionCreated.set(false);
+ valueBound.set(false);
+ sessionDestroyed.set(false);
+ valueUnbound.set(false);
+
+ // first call will create the session
+ actual = requestAdvisor.request("sessions");
+ assertEquals("Wrong result", "created", actual);
+ assertTrue("No sessionCreated called", sessionCreated.get());
+ assertTrue("No valueBound called", valueBound.get());
+ assertFalse("sessionDestroyed was called", sessionDestroyed.get());
+ assertFalse("valueUnbound was called", valueUnbound.get());
+
+ sessionCreated.set(false);
+ valueBound.set(false);
+ sessionDestroyed.set(false);
+ valueUnbound.set(false);
+
+ assertNotNull(sessionId.get());
+
+ // invalidate using the invalidator
+ invalidator.invalidate(sessionId.get(), true);
+
+ // second call should find the session invalidated, and create a new one
+ actual = requestAdvisor.request("sessions");
+ assertEquals("Wrong result", "created", actual);
+ assertTrue("No sessionCreated was called", sessionCreated.get());
+ assertTrue("No valueBound was called", valueBound.get());
+ assertTrue("No sessionDestroyed called", sessionDestroyed.get());
+ assertTrue("No valueUnbound called", valueUnbound.get());
+
+ sessionCreated.set(false);
+ sessionDestroyed.set(false);
+ valueBound.set(false);
+ valueUnbound.set(false);
+
+ // calling again should invalidate the session again
+ actual = requestAdvisor.request("sessions");
+ assertEquals("Wrong result", "invalidated", actual);
+ assertFalse("sessionCreated called", sessionCreated.get());
+ assertFalse("valueBound called", valueBound.get());
+ assertTrue("No sessionDestroyed called", sessionDestroyed.get());
+ assertTrue("No valueUnbound called", valueUnbound.get());
+ } catch (Exception e) {
+ fail("Unexpected exception: " + e);
+ } finally {
+ if (servletReg != null) {
+ servletReg.unregister();
+ }
+ if (sessionListenerReg != null) {
+ sessionListenerReg.unregister();
+ }
+ CookieHandler.setDefault(previous);
+ sessionInvalidatorTracker.close();
+ }
+ }
+
+ @Test
public void test_Resource1() throws Exception {
String expected = "a";
String actual;
@@ -3160,11 +3286,11 @@ public class ServletTest extends BaseTest {
final AtomicReference<HttpSession> sessionReference = new AtomicReference<HttpSession>();
ServletContextListener scl = new ServletContextListener() {
-
+
@Override
public void contextInitialized(ServletContextEvent arg0) {
}
-
+
@Override
public void contextDestroyed(ServletContextEvent arg0) {
listenerBalance.decrementAndGet();
diff --git a/bundles/org.eclipse.equinox.http.servlet/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.http.servlet/META-INF/MANIFEST.MF
index 015997743..8802c72f9 100644
--- a/bundles/org.eclipse.equinox.http.servlet/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.http.servlet/META-INF/MANIFEST.MF
@@ -3,12 +3,13 @@ Bundle-ManifestVersion: 2
Bundle-Name: %bundleName
Bundle-Vendor: %providerName
Bundle-SymbolicName: org.eclipse.equinox.http.servlet
-Bundle-Version: 1.4.100.qualifier
+Bundle-Version: 1.5.0.qualifier
Bundle-Activator: org.eclipse.equinox.http.servlet.internal.Activator
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Export-Package: org.eclipse.equinox.http.servlet;version="1.2.0",
org.eclipse.equinox.http.servlet.context;version="1.0.0";x-internal:=true,
+ org.eclipse.equinox.http.servlet.session;version="1.0.0";x-internal:=true,
org.eclipse.equinox.http.servlet.dto;version="1.0.0";x-internal:=true
Import-Package: org.apache.commons.fileupload;version="[1.2.2, 2.0.0)";resolution:=optional,
org.apache.commons.fileupload.disk;version="[1.2.2, 2.0.0)";resolution:=optional,
diff --git a/bundles/org.eclipse.equinox.http.servlet/pom.xml b/bundles/org.eclipse.equinox.http.servlet/pom.xml
index 8446a6712..1462163d0 100644
--- a/bundles/org.eclipse.equinox.http.servlet/pom.xml
+++ b/bundles/org.eclipse.equinox.http.servlet/pom.xml
@@ -20,6 +20,6 @@
</parent>
<groupId>org.eclipse.equinox</groupId>
<artifactId>org.eclipse.equinox.http.servlet</artifactId>
- <version>1.4.100-SNAPSHOT</version>
+ <version>1.5.0-SNAPSHOT</version>
<packaging>eclipse-plugin</packaging>
</project>
diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/Activator.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/Activator.java
index 8781c901f..301b1fe0f 100644
--- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/Activator.java
+++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/Activator.java
@@ -163,8 +163,7 @@ public class Activator
boolean useSystemContext = Boolean.valueOf(context.getProperty(PROP_GLOBAL_WHITEBOARD));
BundleContext trackingContext = useSystemContext ? context.getBundle(Constants.SYSTEM_BUNDLE_LOCATION).getBundleContext() : context;
HttpServiceRuntimeImpl httpServiceRuntime = new HttpServiceRuntimeImpl(
- trackingContext, context, servletContext,
- new UMDictionaryMap<String, Object>(serviceProperties));
+ trackingContext, context, servletContext, serviceProperties);
proxyServlet.setHttpServiceRuntimeImpl(httpServiceRuntime);
diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceRuntimeImpl.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceRuntimeImpl.java
index 62474bcef..c25aa85eb 100644
--- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceRuntimeImpl.java
+++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/HttpServiceRuntimeImpl.java
@@ -25,8 +25,10 @@ import org.eclipse.equinox.http.servlet.context.ContextPathCustomizer;
import org.eclipse.equinox.http.servlet.dto.ExtendedFailedServletDTO;
import org.eclipse.equinox.http.servlet.internal.context.*;
import org.eclipse.equinox.http.servlet.internal.error.*;
+import org.eclipse.equinox.http.servlet.internal.servlet.HttpSessionTracker;
import org.eclipse.equinox.http.servlet.internal.servlet.Match;
import org.eclipse.equinox.http.servlet.internal.util.*;
+import org.eclipse.equinox.http.servlet.session.HttpSessionInvalidator;
import org.osgi.framework.*;
import org.osgi.framework.dto.ServiceReferenceDTO;
import org.osgi.service.http.HttpContext;
@@ -49,7 +51,7 @@ public class HttpServiceRuntimeImpl
public HttpServiceRuntimeImpl(
BundleContext trackingContext, BundleContext consumingContext,
- ServletContext parentServletContext, Map<String, Object> attributes) {
+ ServletContext parentServletContext, Dictionary<String, Object> attributes) {
this.trackingContext = trackingContext;
this.consumingContext = consumingContext;
@@ -60,8 +62,10 @@ public class HttpServiceRuntimeImpl
this.listenerServiceFilter = createListenerFilter(consumingContext, parentServletContext);
this.parentServletContext = parentServletContext;
- this.attributes = attributes;
- this.targetFilter = "(" + Activator.UNIQUE_SERVICE_ID + "=" + attributes.get(Activator.UNIQUE_SERVICE_ID) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ this.attributes = new UMDictionaryMap<String, Object>(attributes);
+ this.targetFilter = "(" + Activator.UNIQUE_SERVICE_ID + "=" + this.attributes.get(Activator.UNIQUE_SERVICE_ID) + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ this.httpSessionTracker = new HttpSessionTracker(this);
+ this.invalidatorReg = trackingContext.registerService(HttpSessionInvalidator.class, this.httpSessionTracker, attributes);
contextServiceTracker =
new ServiceTracker<ServletContextHelper, AtomicReference<ContextController>>(
@@ -111,7 +115,7 @@ public class HttpServiceRuntimeImpl
ContextController contextController = new ContextController(
trackingContext, consumingContext, serviceReference, new ProxyContext(parentServletContext),
- this, contextName, contextPath);
+ this, contextName, contextPath, httpSessionTracker);
controllerMap.put(serviceReference, contextController);
@@ -174,6 +178,7 @@ public class HttpServiceRuntimeImpl
}
public void destroy() {
+ invalidatorReg.unregister();
defaultContextReg.unregister();
contextServiceTracker.close();
@@ -188,6 +193,9 @@ public class HttpServiceRuntimeImpl
failedServletContextDTOs.clear();
failedServletDTOs.clear();
+ httpSessionTracker.clear();
+
+ httpSessionTracker = null;
attributes = null;
trackingContext = null;
consumingContext = null;
@@ -276,6 +284,10 @@ public class HttpServiceRuntimeImpl
return null;
}
+ public void log(String message) {
+ parentServletContext.log(message);
+ }
+
public void log(String message, Throwable t) {
parentServletContext.log(message, t);
}
@@ -1104,6 +1116,8 @@ public class HttpServiceRuntimeImpl
private ServiceTracker<ServletContextHelper, AtomicReference<ContextController>> contextServiceTracker;
private ServiceTracker<ContextPathCustomizer, ContextPathCustomizer> contextPathAdaptorTracker;
private ContextPathCustomizerHolder contextPathCustomizerHolder;
+ private HttpSessionTracker httpSessionTracker;
+ private final ServiceRegistration<HttpSessionInvalidator> invalidatorReg;
static class DefaultServletContextHelperFactory implements ServiceFactory<ServletContextHelper> {
@Override
diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ContextController.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ContextController.java
index 019c6a3fb..90f50d520 100644
--- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ContextController.java
+++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/context/ContextController.java
@@ -110,7 +110,7 @@ public class ContextController {
BundleContext trackingContextParam, BundleContext consumingContext,
ServiceReference<ServletContextHelper> servletContextHelperRef,
ProxyContext proxyContext, HttpServiceRuntimeImpl httpServiceRuntime,
- String contextName, String contextPath) {
+ String contextName, String contextPath, HttpSessionTracker httpSessionTracker) {
validate(contextName, contextPath);
@@ -141,6 +141,7 @@ public class ContextController {
this.trackingContext = trackingContextParam;
this.consumingContext = consumingContext;
+ this.httpSessionTracker = httpSessionTracker;
listenerServiceTracker = new ServiceTracker<EventListener, AtomicReference<ListenerRegistration>>(
trackingContext, httpServiceRuntime.getListenerFilter(),
@@ -452,7 +453,7 @@ public class ContextController {
} finally {
if (registration == null) {
// Always attempt to release here; even though destroy() may have been called
- // on the registration while failing to add. There are cases where no
+ // on the registration while failing to add. There are cases where no
// ServletRegistration may have even been created at all to call destory() on.
// Also, addedRegisteredObject may be false which means we never call doAddServletRegistration
servletHolder.release();
@@ -1208,7 +1209,15 @@ public class ContextController {
}
public void removeActiveSession(HttpSession session) {
- activeSessions.remove(session.getId());
+ removeActiveSession(session.getId());
+ }
+
+ public void removeActiveSession(String sessionId) {
+ HttpSessionAdaptor httpSessionAdaptor = activeSessions.remove(sessionId);
+
+ if (httpSessionAdaptor != null) {
+ httpSessionTracker.removeHttpSessionAdaptor(sessionId, httpSessionAdaptor);
+ }
}
public void fireSessionIdChanged(String oldSessionId) {
@@ -1246,7 +1255,7 @@ public class ContextController {
session, servletContext, this);
HttpSessionAdaptor previousHttpSessionAdaptor =
- activeSessions.putIfAbsent(sessionId, httpSessionAdaptor);
+ addSessionAdaptor(sessionId, httpSessionAdaptor);
if (previousHttpSessionAdaptor != null) {
return previousHttpSessionAdaptor;
@@ -1268,6 +1277,21 @@ public class ContextController {
return httpSessionAdaptor;
}
+ public HttpSessionAdaptor addSessionAdaptor(
+ String sessionId, HttpSessionAdaptor httpSessionAdaptor) {
+
+ HttpSessionAdaptor previousHttpSessionAdaptor =
+ activeSessions.putIfAbsent(sessionId, httpSessionAdaptor);
+
+ if (previousHttpSessionAdaptor != null) {
+ return previousHttpSessionAdaptor;
+ }
+
+ httpSessionTracker.addHttpSessionAdaptor(sessionId, httpSessionAdaptor);
+
+ return null;
+ }
+
private void validate(String preValidationContextName, String preValidationContextPath) {
if (!contextNamePattern.matcher(preValidationContextName).matches()) {
throw new IllegalContextNameException(
@@ -1305,6 +1329,7 @@ public class ContextController {
private final ConcurrentMap<String, HttpSessionAdaptor> activeSessions = new ConcurrentHashMap<String, HttpSessionAdaptor>();
private final HttpServiceRuntimeImpl httpServiceRuntime;
+ private final HttpSessionTracker httpSessionTracker;
private final Set<ListenerRegistration> listenerRegistrations = new HashSet<ListenerRegistration>();
private final ProxyContext proxyContext;
private final ServiceReference<ServletContextHelper> servletContextHelperRef;
diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletRequestWrapperImpl.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletRequestWrapperImpl.java
index e7c05f197..dd8bb5524 100644
--- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletRequestWrapperImpl.java
+++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpServletRequestWrapperImpl.java
@@ -73,6 +73,25 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper {
this.request = request;
}
+ @Override
+ public String changeSessionId() {
+ HttpSessionAdaptor httpSessionAdaptor = (HttpSessionAdaptor)getSession(false);
+
+ if (httpSessionAdaptor == null) {
+ throw new IllegalStateException("No session"); //$NON-NLS-1$
+ }
+
+ DispatchTargets currentDispatchTarget = dispatchTargets.peek();
+
+ String oldSessionId = httpSessionAdaptor.getId();
+ String newSessionId = super.changeSessionId();
+
+ currentDispatchTarget.getContextController().removeActiveSession(oldSessionId);
+ currentDispatchTarget.getContextController().addSessionAdaptor(newSessionId, httpSessionAdaptor);
+
+ return newSessionId;
+ }
+
public String getAuthType() {
String authType = (String) this.getAttribute(HttpContext.AUTHENTICATION_TYPE);
if (authType != null)
@@ -172,7 +191,7 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper {
if ((dispatcherType == DispatcherType.ASYNC) ||
(dispatcherType == DispatcherType.REQUEST) ||
- !attributeName.startsWith("javax.servlet.")) {
+ !attributeName.startsWith("javax.servlet.")) { //$NON-NLS-1$
return request.getAttribute(attributeName);
}
@@ -239,7 +258,7 @@ public class HttpServletRequestWrapperImpl extends HttpServletRequestWrapper {
}
}
else if (dispatcherType == DispatcherType.FORWARD) {
- if (hasServletName && attributeName.startsWith("javax.servlet.forward")) {
+ if (hasServletName && attributeName.startsWith("javax.servlet.forward")) { //$NON-NLS-1$
return null;
}
diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionAdaptor.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionAdaptor.java
index c53578bfc..eb6112f40 100644
--- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionAdaptor.java
+++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionAdaptor.java
@@ -14,166 +14,14 @@ package org.eclipse.equinox.http.servlet.internal.servlet;
import java.io.Serializable;
import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.ServletContext;
import javax.servlet.http.*;
import org.eclipse.equinox.http.servlet.internal.context.ContextController;
-import org.eclipse.equinox.http.servlet.internal.util.EventListeners;
// This class adapts HttpSessions in order to return the right ServletContext and attributes
public class HttpSessionAdaptor implements HttpSession, Serializable {
private static final long serialVersionUID = 3418610936889860782L;
- static class ParentSessionListener implements HttpSessionBindingListener, Serializable {
- private static final long serialVersionUID = 4626167646903550760L;
-
- private static final String PARENT_SESSION_LISTENER_KEY = "org.eclipse.equinox.http.parent.session.listener"; //$NON-NLS-1$
- transient final Set<HttpSessionAdaptor> innerSessions = Collections.newSetFromMap(new ConcurrentHashMap<HttpSessionAdaptor, Boolean>());
- @Override
- public void valueBound(HttpSessionBindingEvent event) {
- // do nothing
- }
-
- @Override
- public void valueUnbound(HttpSessionBindingEvent event) {
- // Here we assume the unbound event is signifying the session is being invalidated.
- // Must invalidate the inner sessions
- Iterator<HttpSessionAdaptor> iterator = innerSessions.iterator();
-
- while (iterator.hasNext()) {
- HttpSessionAdaptor innerSession = iterator.next();
-
- iterator.remove();
-
- ContextController contextController =
- innerSession.getController();
-
- EventListeners eventListeners =
- contextController.getEventListeners();
-
- List<HttpSessionListener> httpSessionListeners =
- eventListeners.get(HttpSessionListener.class);
-
- if (!httpSessionListeners.isEmpty()) {
- HttpSessionEvent httpSessionEvent = new HttpSessionEvent(
- innerSession);
-
- for (HttpSessionListener listener : httpSessionListeners) {
- try {
- listener.sessionDestroyed(httpSessionEvent);
- }
- catch (IllegalStateException ise) {
- // outer session is already invalidated
- }
- }
- }
-
- contextController.removeActiveSession(
- innerSession.getSession());
- }
- }
-
- static void addHttpSessionAdaptor(HttpSessionAdaptor innerSession) {
- HttpSession httpSession = innerSession.getSession();
-
- ParentSessionListener parentListener;
- // need to have a global lock here because we must ensure that this is added only once
- synchronized (httpSession) {
- parentListener = (ParentSessionListener) httpSession.getAttribute(PARENT_SESSION_LISTENER_KEY);
- if (parentListener == null) {
- parentListener = new ParentSessionListener();
- httpSession.setAttribute(PARENT_SESSION_LISTENER_KEY, parentListener);
- }
- }
-
- parentListener.innerSessions.add(innerSession);
- }
-
- static void removeHttpSessionAdaptor(HttpSessionAdaptor innerSession) {
- HttpSession httpSession = innerSession.getSession();
-
- ParentSessionListener parentListener = (ParentSessionListener) httpSession.getAttribute(PARENT_SESSION_LISTENER_KEY);
-
- if (parentListener != null) {
- parentListener.innerSessions.remove(innerSession);
- }
- }
- }
-
- class HttpSessionAttributeWrapper implements HttpSessionBindingListener, HttpSessionActivationListener, Serializable {
- private static final long serialVersionUID = 7945998375225990980L;
-
- final String name;
- final Object value;
- final boolean added;
- final HttpSessionAdaptor innerSession;
-
- public HttpSessionAttributeWrapper(HttpSessionAdaptor innerSession, String name, Object value, boolean added) {
- this.innerSession = innerSession;
- this.name = name;
- this.value = value;
- this.added = added;
- }
-
- @Override
- public void valueBound(HttpSessionBindingEvent event) {
- List<HttpSessionAttributeListener> listeners = getEventListeners().get(
- HttpSessionAttributeListener.class);
-
- for (HttpSessionAttributeListener listener : listeners) {
- if (added) {
- listener.attributeAdded(event);
- }
- else {
- listener.attributeReplaced(event);
- }
- }
-
- if (value instanceof HttpSessionBindingListener) {
- ((HttpSessionBindingListener) value).valueBound(new HttpSessionBindingEvent(innerSession, name, value));
- }
- }
-
- @Override
- public void valueUnbound(HttpSessionBindingEvent event) {
- if (!added) {
- List<HttpSessionAttributeListener> listeners = getEventListeners().get(
- HttpSessionAttributeListener.class);
-
- for (HttpSessionAttributeListener listener : listeners) {
- listener.attributeRemoved(event);
- }
- }
-
- if (value instanceof HttpSessionBindingListener) {
- ((HttpSessionBindingListener) value).valueUnbound(new HttpSessionBindingEvent(innerSession, name, value));
- }
- }
-
- @Override
- public void sessionWillPassivate(HttpSessionEvent se) {
- if (value instanceof HttpSessionActivationListener) {
- ((HttpSessionActivationListener) value).sessionWillPassivate(new HttpSessionEvent(innerSession));
- }
- }
-
- @Override
- public void sessionDidActivate(HttpSessionEvent se) {
- if (value instanceof HttpSessionActivationListener) {
- ((HttpSessionActivationListener) value).sessionDidActivate(new HttpSessionEvent(innerSession));
- }
- }
-
- private EventListeners getEventListeners() {
- return innerSession.getController().getEventListeners();
- }
-
- @Override
- public String toString() {
- return String.valueOf(value);
- }
- }
-
private transient final ContextController controller;
private transient final HttpSession session;
private transient final ServletContext servletContext;
@@ -182,9 +30,7 @@ public class HttpSessionAdaptor implements HttpSession, Serializable {
static public HttpSessionAdaptor createHttpSessionAdaptor(
HttpSession session, ServletContext servletContext, ContextController controller) {
- HttpSessionAdaptor sessionAdaptor = new HttpSessionAdaptor(session, servletContext, controller);
- ParentSessionListener.addHttpSessionAdaptor(sessionAdaptor);
- return sessionAdaptor;
+ return new HttpSessionAdaptor(session, servletContext, controller);
}
private HttpSessionAdaptor(
@@ -209,11 +55,7 @@ public class HttpSessionAdaptor implements HttpSession, Serializable {
}
public Object getAttribute(String arg0) {
- Object result = session.getAttribute(attributePrefix + arg0);
- if (result instanceof HttpSessionAttributeWrapper) {
- result = ((HttpSessionAttributeWrapper) result).value;
- }
- return result;
+ return session.getAttribute(attributePrefix.concat(arg0));
}
public Enumeration<String> getAttributeNames() {
@@ -264,14 +106,14 @@ public class HttpSessionAdaptor implements HttpSession, Serializable {
// outer session is already invalidated
}
+ controller.removeActiveSession(session);
+
try {
- ParentSessionListener.removeHttpSessionAdaptor(this);
+ this.getSession().invalidate();
}
catch (IllegalStateException ise) {
- // outer session is already invalidated
+ controller.getHttpServiceRuntime().log("Session already invalidated!", ise); //$NON-NLS-1$
}
-
- controller.removeActiveSession(session);
}
public void invokeSessionListeners (List<Class<? extends EventListener>> classes, EventListener listener) {
@@ -312,7 +154,30 @@ public class HttpSessionAdaptor implements HttpSession, Serializable {
}
public void removeAttribute(String arg0) {
- session.removeAttribute(attributePrefix + arg0);
+ String newName = attributePrefix.concat(arg0);
+
+ Object value = session.getAttribute(newName);
+
+ session.removeAttribute(newName);
+
+ if (value == null) {
+ return;
+ }
+
+ List<HttpSessionAttributeListener> listeners =
+ controller.getEventListeners().get(
+ HttpSessionAttributeListener.class);
+
+ if (listeners.isEmpty()) {
+ return;
+ }
+
+ HttpSessionBindingEvent httpSessionBindingEvent =
+ new HttpSessionBindingEvent(this, newName);
+
+ for (HttpSessionAttributeListener listener : listeners) {
+ listener.attributeRemoved(httpSessionBindingEvent);
+ }
}
/**@deprecated*/
@@ -321,13 +186,35 @@ public class HttpSessionAdaptor implements HttpSession, Serializable {
}
public void setAttribute(String name, Object value) {
- Object actualValue = null;
+ String newName = attributePrefix.concat(name);
+
+ if (value == null) {
+ session.setAttribute(newName, null);
+
+ return;
+ }
+
+ boolean added = session.getAttribute(newName) == null;
+
+ session.setAttribute(newName, value);
+
+ List<HttpSessionAttributeListener> listeners =
+ controller.getEventListeners().get(
+ HttpSessionAttributeListener.class);
+
+ if (!listeners.isEmpty()) {
+ HttpSessionBindingEvent httpSessionBindingEvent =
+ new HttpSessionBindingEvent(this, newName, value);
- if (value != null) {
- boolean added = (session.getAttribute(attributePrefix + name) == null);
- actualValue = new HttpSessionAttributeWrapper(this, name, value, added);
+ for (HttpSessionAttributeListener listener : listeners) {
+ if (added) {
+ listener.attributeAdded(httpSessionBindingEvent);
+ }
+ else {
+ listener.attributeReplaced(httpSessionBindingEvent);
+ }
+ }
}
- session.setAttribute(attributePrefix + name, actualValue);
}
public void setMaxInactiveInterval(int arg0) {
diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionTracker.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionTracker.java
new file mode 100644
index 000000000..e1c05f365
--- /dev/null
+++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/HttpSessionTracker.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Liferay, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Liferay, Inc. - Bug 530063 - CNFE when session replication
+ * is used with equinox.http.servlet in bridge mode
+ ******************************************************************************/
+
+package org.eclipse.equinox.http.servlet.internal.servlet;
+
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import javax.servlet.http.*;
+import org.eclipse.equinox.http.servlet.internal.HttpServiceRuntimeImpl;
+import org.eclipse.equinox.http.servlet.internal.context.ContextController;
+import org.eclipse.equinox.http.servlet.internal.util.EventListeners;
+import org.eclipse.equinox.http.servlet.session.HttpSessionInvalidator;
+
+/**
+ * @since 1.4
+ */
+public class HttpSessionTracker implements HttpSessionInvalidator {
+
+ public HttpSessionTracker(HttpServiceRuntimeImpl httpServiceRuntime) {
+ this.httpServiceRuntime = httpServiceRuntime;
+ }
+
+ @Override
+ public void invalidate(String sessionId, boolean invalidateParent) {
+ Set<HttpSessionAdaptor> httpSessionAdaptors =
+ httpSessionAdaptorsMap.remove(sessionId);
+
+ if (httpSessionAdaptors == null) {
+ return;
+ }
+
+ for (HttpSessionAdaptor httpSessionAdaptor : httpSessionAdaptors) {
+ ContextController contextController =
+ httpSessionAdaptor.getController();
+
+ EventListeners eventListeners =
+ contextController.getEventListeners();
+
+ List<HttpSessionListener> httpSessionListeners = eventListeners.get(
+ HttpSessionListener.class);
+
+ if (!httpSessionListeners.isEmpty()) {
+ HttpSessionEvent httpSessionEvent = new HttpSessionEvent(
+ httpSessionAdaptor);
+
+ for (HttpSessionListener listener : httpSessionListeners) {
+ try {
+ listener.sessionDestroyed(httpSessionEvent);
+ }
+ catch (IllegalStateException ise) {
+ // outer session is already invalidated
+ }
+ }
+ }
+
+ List<HttpSessionAttributeListener> httpSessionAttributeListeners =
+ eventListeners.get(HttpSessionAttributeListener.class);
+
+ if (!httpSessionListeners.isEmpty()) {
+ Enumeration<String> enumeration =
+ httpSessionAdaptor.getAttributeNames();
+
+ while (enumeration.hasMoreElements()) {
+ HttpSessionBindingEvent httpSessionBindingEvent =
+ new HttpSessionBindingEvent(
+ httpSessionAdaptor, enumeration.nextElement());
+
+ for (HttpSessionAttributeListener
+ httpSessionAttributeListener :
+ httpSessionAttributeListeners) {
+
+ httpSessionAttributeListener.attributeRemoved(
+ httpSessionBindingEvent);
+ }
+ }
+ }
+
+ contextController.removeActiveSession(
+ httpSessionAdaptor.getSession());
+
+ if (invalidateParent) {
+ try {
+ httpSessionAdaptor.getSession().invalidate();
+ }
+ catch (IllegalStateException ise) {
+ httpServiceRuntime.log(
+ "Session was already invalidated!", ise); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ public void addHttpSessionAdaptor(
+ String sessionId, HttpSessionAdaptor httpSessionAdaptor) {
+
+ Set<HttpSessionAdaptor> httpSessionAdaptors =
+ httpSessionAdaptorsMap.get(sessionId);
+
+ if (httpSessionAdaptors == null) {
+ httpSessionAdaptors = Collections.newSetFromMap(
+ new ConcurrentHashMap<HttpSessionAdaptor, Boolean>());
+
+ Set<HttpSessionAdaptor> previousHttpSessionAdaptors =
+ httpSessionAdaptorsMap.putIfAbsent(
+ sessionId, httpSessionAdaptors);
+
+ if (previousHttpSessionAdaptors != null) {
+ httpSessionAdaptors = previousHttpSessionAdaptors;
+ }
+ }
+
+ httpSessionAdaptors.add(httpSessionAdaptor);
+ }
+
+ public void clear() {
+ // At this point there should be no left over sessions. If
+ // there are we'll log it because there's some kind of leak.
+ if (!httpSessionAdaptorsMap.isEmpty()) {
+ httpServiceRuntime.log(
+ "There are HttpSessionAdaptors left over. There might be a context or session leak!"); //$NON-NLS-1$
+ }
+ }
+
+ public boolean removeHttpSessionAdaptor(
+ String sessionId, HttpSessionAdaptor httpSessionAdaptor) {
+
+ Set<HttpSessionAdaptor> httpSessionAdaptors =
+ httpSessionAdaptorsMap.get(sessionId);
+
+ if (httpSessionAdaptors == null) {
+ return false;
+ }
+
+ try {
+ return httpSessionAdaptors.remove(httpSessionAdaptor);
+ }
+ finally {
+ if (httpSessionAdaptors.isEmpty()) {
+ httpSessionAdaptorsMap.remove(sessionId, httpSessionAdaptors);
+ }
+ }
+ }
+
+ private final ConcurrentMap<String, Set<HttpSessionAdaptor>>
+ httpSessionAdaptorsMap =
+ new ConcurrentHashMap<String, Set<HttpSessionAdaptor>>();
+ private final HttpServiceRuntimeImpl httpServiceRuntime;
+
+} \ No newline at end of file
diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/session/HttpSessionInvalidator.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/session/HttpSessionInvalidator.java
new file mode 100644
index 000000000..06c46467b
--- /dev/null
+++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/session/HttpSessionInvalidator.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Liferay, Inc.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Liferay, Inc. - Bug 530063 - CNFE when session replication
+ * is used with equinox.http.servlet in bridge mode
+ ******************************************************************************/
+
+package org.eclipse.equinox.http.servlet.session;
+
+/**
+ * The Http Whiteboard runtime registers a service of this type to
+ * allow an external actor to invalidate a session. This requirement is typical of
+ * the bridge deployment scenario where the host may need to control session invalidation.
+ * <p>
+ * <b>Note:</b> This class is part of an interim SPI that is still under
+ * development and expected to change significantly before reaching stability.
+ * It is being made available at this stage to solicit feedback from pioneering
+ * adopters on the understanding that any code that uses this SPI will almost certainly
+ * be broken (repeatedly) as the SPI evolves.
+ * </p>
+ * @since 1.4
+ */
+public interface HttpSessionInvalidator {
+
+ /**
+ * Invalidate a session. If no session matching the id is found, nothing happens.
+ * Optionally attempt to invalidate the parent (container) session.
+ *
+ * @param sessionId the session id to invalidate
+ * @param invalidateParent if true, attempt to invalidate the parent
+ * (container) session
+ */
+ public void invalidate(String sessionId, boolean invalidateParent);
+
+}

Back to the top