package org.argeo.cms.equinox.http.jetty; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionIdListener; import javax.servlet.http.HttpSessionListener; import org.argeo.cms.jetty.CmsJettyServer; import org.eclipse.equinox.http.servlet.HttpServiceServlet; import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.osgi.framework.Constants; /** A {@link CmsJettyServer} integrating with Equinox HTTP framework. */ public class EquinoxJettyServer extends CmsJettyServer { private static final String INTERNAL_CONTEXT_CLASSLOADER = "org.eclipse.equinox.http.jetty.internal.ContextClassLoader"; @Override protected void addServlets(ServletContextHandler rootContextHandler) throws ServletException { ServletHolder holder = new ServletHolder(new InternalHttpServiceServlet()); holder.setInitOrder(0); holder.setInitParameter(Constants.SERVICE_VENDOR, "Eclipse.org"); //$NON-NLS-1$ holder.setInitParameter(Constants.SERVICE_DESCRIPTION, "Equinox Jetty-based Http Service"); //$NON-NLS-1$ rootContextHandler.addServlet(holder, "/*"); // post-start SessionHandler sessionManager = rootContextHandler.getSessionHandler(); sessionManager.addEventListener((HttpSessionIdListener) holder.getServlet()); } public static class InternalHttpServiceServlet implements HttpSessionListener, HttpSessionIdListener, Servlet { private final Servlet httpServiceServlet = new HttpServiceServlet(); private ClassLoader contextLoader; private final Method sessionDestroyed; private final Method sessionIdChanged; public InternalHttpServiceServlet() { Class clazz = httpServiceServlet.getClass(); try { sessionDestroyed = clazz.getMethod("sessionDestroyed", new Class[] { String.class }); //$NON-NLS-1$ } catch (Exception e) { throw new IllegalStateException(e); } try { sessionIdChanged = clazz.getMethod("sessionIdChanged", new Class[] { String.class }); //$NON-NLS-1$ } catch (Exception e) { throw new IllegalStateException(e); } } @Override public void init(ServletConfig config) throws ServletException { ServletContext context = config.getServletContext(); contextLoader = (ClassLoader) context.getAttribute(INTERNAL_CONTEXT_CLASSLOADER); Thread thread = Thread.currentThread(); ClassLoader current = thread.getContextClassLoader(); thread.setContextClassLoader(contextLoader); try { httpServiceServlet.init(config); } finally { thread.setContextClassLoader(current); } } @Override public void destroy() { Thread thread = Thread.currentThread(); ClassLoader current = thread.getContextClassLoader(); thread.setContextClassLoader(contextLoader); try { httpServiceServlet.destroy(); } finally { thread.setContextClassLoader(current); } contextLoader = null; } @Override public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { Thread thread = Thread.currentThread(); ClassLoader current = thread.getContextClassLoader(); thread.setContextClassLoader(contextLoader); try { httpServiceServlet.service(req, res); } finally { thread.setContextClassLoader(current); } } @Override public ServletConfig getServletConfig() { return httpServiceServlet.getServletConfig(); } @Override public String getServletInfo() { return httpServiceServlet.getServletInfo(); } @Override public void sessionCreated(HttpSessionEvent event) { // Nothing to do. } @Override public void sessionDestroyed(HttpSessionEvent event) { Thread thread = Thread.currentThread(); ClassLoader current = thread.getContextClassLoader(); thread.setContextClassLoader(contextLoader); try { sessionDestroyed.invoke(httpServiceServlet, event.getSession().getId()); } catch (IllegalAccessException | IllegalArgumentException e) { // not likely } catch (InvocationTargetException e) { throw new RuntimeException(e.getCause()); } finally { thread.setContextClassLoader(current); } } @Override public void sessionIdChanged(HttpSessionEvent event, String oldSessionId) { Thread thread = Thread.currentThread(); ClassLoader current = thread.getContextClassLoader(); thread.setContextClassLoader(contextLoader); try { sessionIdChanged.invoke(httpServiceServlet, oldSessionId); } catch (IllegalAccessException | IllegalArgumentException e) { // not likely } catch (InvocationTargetException e) { throw new RuntimeException(e.getCause()); } finally { thread.setContextClassLoader(current); } } } }