Bug 460720 - [http whiteboard] add support for Servlet 3.1 javax.servlet.http.HttpSessionIdListener as suggested by the draft spec

Signed-off-by: Raymond Auge <raymond.auge@liferay.com>
diff --git a/bundles/org.eclipse.equinox.http.jetty9/src/org/eclipse/equinox/http/jetty/internal/HttpServerManager.java b/bundles/org.eclipse.equinox.http.jetty9/src/org/eclipse/equinox/http/jetty/internal/HttpServerManager.java
index 19b0800..542d2ef 100644
--- a/bundles/org.eclipse.equinox.http.jetty9/src/org/eclipse/equinox/http/jetty/internal/HttpServerManager.java
+++ b/bundles/org.eclipse.equinox.http.jetty9/src/org/eclipse/equinox/http/jetty/internal/HttpServerManager.java
@@ -14,8 +14,12 @@
 
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.*;
 import javax.servlet.*;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionIdListener;
 import org.eclipse.equinox.http.jetty.JettyConstants;
 import org.eclipse.equinox.http.jetty.JettyCustomizer;
 import org.eclipse.equinox.http.servlet.HttpServiceServlet;
@@ -128,6 +132,13 @@
 		httpContext.addServlet(holder, "/*"); //$NON-NLS-1$
 		server.setHandler(httpContext);
 
+		SessionManager sessionManager = httpContext.getSessionHandler().getSessionManager();
+		try {
+			sessionManager.addEventListener((HttpSessionIdListener) holder.getServlet());
+		} catch (ServletException e) {
+			throw new ConfigurationException(pid, e.getMessage(), e);
+		}
+
 		try {
 			server.start();
 		} catch (Exception e) {
@@ -298,15 +309,23 @@
 		}
 	}
 
-	public static class InternalHttpServiceServlet implements Servlet {
+	public static class InternalHttpServiceServlet implements HttpSessionIdListener, Servlet {
 		//		private static final long serialVersionUID = 7477982882399972088L;
 		private Servlet httpServiceServlet = new HttpServiceServlet();
 		private ClassLoader contextLoader;
+		private Method method;
 
 		public void init(ServletConfig config) throws ServletException {
 			ServletContext context = config.getServletContext();
 			contextLoader = (ClassLoader) context.getAttribute(INTERNAL_CONTEXT_CLASSLOADER);
 
+			Class<?> clazz = httpServiceServlet.getClass();
+			try {
+				method = clazz.getMethod("sessionIdChanged", new Class<?>[] {String.class});
+			} catch (Exception e) {
+				throw new ServletException(e);
+			}
+
 			Thread thread = Thread.currentThread();
 			ClassLoader current = thread.getContextClassLoader();
 			thread.setContextClassLoader(contextLoader);
@@ -347,6 +366,23 @@
 		public String getServletInfo() {
 			return httpServiceServlet.getServletInfo();
 		}
+
+		public void sessionIdChanged(HttpSessionEvent event, String oldSessionId) {
+			Thread thread = Thread.currentThread();
+			ClassLoader current = thread.getContextClassLoader();
+			thread.setContextClassLoader(contextLoader);
+			try {
+				method.invoke(httpServiceServlet, oldSessionId);
+			} catch (IllegalAccessException e) {
+				// not likely
+			} catch (IllegalArgumentException e) {
+				// not likely
+			} catch (InvocationTargetException e) {
+				throw new RuntimeException(e.getCause());
+			} finally {
+				thread.setContextClassLoader(current);
+			}
+		}
 	}
 
 	// deleteDirectory is a convenience method to recursively delete a directory
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 3fb46fd..05bbc0c 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
@@ -54,7 +54,7 @@
 		this.servletServiceFilter = createServletFilter(consumingContext);
 		this.resourceServiceFilter = createResourceFilter(consumingContext);
 		this.filterServiceFilter = createFilterFilter(consumingContext);
-		this.listenerServiceFilter = createListenerFilter(consumingContext);
+		this.listenerServiceFilter = createListenerFilter(consumingContext, parentServletContext);
 
 		this.parentServletContext = parentServletContext;
 		this.attributes = Collections.unmodifiableMap(attributes);
@@ -954,7 +954,7 @@
 		}
 	}
 
-	private static org.osgi.framework.Filter createListenerFilter(BundleContext context) {
+	private static org.osgi.framework.Filter createListenerFilter(BundleContext context, ServletContext servletContext) {
 		StringBuilder sb = new StringBuilder();
 
 		sb.append("(&"); //$NON-NLS-1$
@@ -966,6 +966,11 @@
 		sb.append("(objectClass=").append(ServletRequestAttributeListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
 		sb.append("(objectClass=").append(HttpSessionListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
 		sb.append("(objectClass=").append(HttpSessionAttributeListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
+
+		if ((servletContext.getMajorVersion() >= 3) && (servletContext.getMinorVersion() > 0)) {
+			sb.append("(objectClass=").append(javax.servlet.http.HttpSessionIdListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
+		}
+
 		sb.append(")"); //$NON-NLS-1$
 		sb.append(")"); //$NON-NLS-1$
 
@@ -1082,6 +1087,12 @@
 		failedServletDTOs.remove(serviceReference);
 	}
 
+	public void fireSessionIdChanged(String oldSessionId) {
+		for (ContextController contextController : controllerMap.values()) {
+			contextController.fireSessionIdChanged(oldSessionId);
+		}
+	}
+
 	private Map<String, Object> attributes;
 	private final String targetFilter;
 	private final ServiceRegistration<ServletContextHelper> defaultContextReg;
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 bd10125..b706e46 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
@@ -1010,6 +1010,13 @@
 			classes.add(HttpSessionAttributeListener.class);
 		}
 
+		ServletContext servletContext = proxyContext.getServletContext();
+		if ((servletContext.getMajorVersion() >= 3) && (servletContext.getMinorVersion() > 0)) {
+			if (objectClassList.contains(javax.servlet.http.HttpSessionIdListener.class.getName())) {
+				classes.add(javax.servlet.http.HttpSessionIdListener.class);
+			}
+		}
+
 		return classes;
 	}
 
@@ -1056,6 +1063,30 @@
 		}
 	}
 
+	public void fireSessionIdChanged(String oldSessionId) {
+		ServletContext servletContext = proxyContext.getServletContext();
+		if ((servletContext.getMajorVersion() <= 3) && (servletContext.getMinorVersion() < 1)) {
+			return;
+		}
+
+		List<javax.servlet.http.HttpSessionIdListener> listeners = eventListeners.get(javax.servlet.http.HttpSessionIdListener.class);
+
+		if (listeners.isEmpty()) {
+			return;
+		}
+
+		Collection<HttpSessionAdaptor> currentActiveSessions;
+		synchronized (activeSessions) {
+			currentActiveSessions = new ArrayList<HttpSessionAdaptor>(activeSessions.values());
+		}
+		for (HttpSessionAdaptor httpSessionAdaptor : currentActiveSessions) {
+			HttpSessionEvent httpSessionEvent = new HttpSessionEvent(httpSessionAdaptor);
+			for (javax.servlet.http.HttpSessionIdListener listener : listeners) {
+				listener.sessionIdChanged(httpSessionEvent, oldSessionId);
+			}
+		}
+	}
+
 	public HttpSessionAdaptor getSessionAdaptor(
 		HttpSession session, ServletContext servletContext) {
 		boolean created = false;
diff --git a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ProxyServlet.java b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ProxyServlet.java
index cd68ca8..a21a040 100644
--- a/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ProxyServlet.java
+++ b/bundles/org.eclipse.equinox.http.servlet/src/org/eclipse/equinox/http/servlet/internal/servlet/ProxyServlet.java
@@ -48,6 +48,10 @@
 		this.httpServiceRuntimeImpl = httpServiceRuntimeImpl;
 	}
 
+	public void sessionIdChanged(String oldSessionId) {
+		httpServiceRuntimeImpl.fireSessionIdChanged(oldSessionId);
+	}
+
 	/**
 	 * @see HttpServlet#service(ServletRequest, ServletResponse)
 	 */