various APIs being used.
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="org.argeo.cms.pkgServlet">
<implementation class="org.argeo.cms.servlet.internal.PkgServlet"/>
<service>
- <provide interface="javax.servlet.Servlet"/>
+ <provide interface="jakarta.servlet.Servlet"/>
</service>
<property name="osgi.http.whiteboard.servlet.pattern" type="String" value="/*"/>
<property name="osgi.http.whiteboard.context.select" type="String" value="(osgi.http.whiteboard.context.name=pkgServletContext)"/>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="org.argeo.cms.pkgServletContext">
<implementation class="org.argeo.cms.servlet.CmsServletContext"/>
<service>
- <provide interface="org.osgi.service.http.context.ServletContextHelper"/>
+ <provide interface="org.eclipse.rap.service.http.HttpContext"/>
</service>
<property name="osgi.http.whiteboard.context.name" type="String" value="pkgServletContext"/>
<property name="osgi.http.whiteboard.context.path" type="String" value="/pkg"/>
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
import org.argeo.api.cms.CmsAuth;
import org.argeo.api.cms.CmsLog;
import org.argeo.cms.auth.RemoteAuthResponse;
import org.argeo.cms.auth.RemoteAuthUtils;
import org.argeo.cms.servlet.internal.HttpUtils;
+import org.eclipse.rap.service.http.HttpContext;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.osgi.service.http.context.ServletContextHelper;
/**
return bundle.getResource(name);
}
+ @Override
+ public String getMimeType(String name) {
+ return null;
+ }
+
+
}
import java.util.SortedMap;
import java.util.TreeMap;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import org.argeo.cms.osgi.FilterRequirement;
import org.argeo.cms.osgi.PublishNamespace;
--- /dev/null
+package org.argeo.cms.servlet.javax;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Map;
+
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
+
+import org.argeo.api.cms.CmsAuth;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.auth.RemoteAuthCallbackHandler;
+import org.argeo.cms.auth.RemoteAuthRequest;
+import org.argeo.cms.auth.RemoteAuthResponse;
+import org.argeo.cms.auth.RemoteAuthUtils;
+import org.argeo.cms.servlet.internal.HttpUtils;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.service.http.context.ServletContextHelper;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Default servlet context degrading to anonymous if the the session is not
+ * pre-authenticated.
+ */
+public class JavaxServletContext extends ServletContextHelper {
+ private final static CmsLog log = CmsLog.getLog(JavaxServletContext.class);
+ // use CMS bundle for resources
+ private Bundle bundle = FrameworkUtil.getBundle(getClass());
+
+ private final String httpAuthRealm = "Argeo";
+ private final boolean forceBasic = false;
+
+ public void init(Map<String, String> properties) {
+
+ }
+
+ public void destroy() {
+
+ }
+
+ @Override
+ public boolean handleSecurity(HttpServletRequest request, HttpServletResponse response) throws IOException {
+// if (log.isTraceEnabled())
+// HttpUtils.logRequestHeaders(log, request);
+ RemoteAuthRequest remoteAuthRequest = new JavaxServletHttpRequest(request);
+ RemoteAuthResponse remoteAuthResponse = new JavaxServletHttpResponse(response);
+ ClassLoader currentThreadContextClassLoader = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(JavaxServletContext.class.getClassLoader());
+ LoginContext lc;
+ try {
+ lc = CmsAuth.USER.newLoginContext(new RemoteAuthCallbackHandler(remoteAuthRequest, remoteAuthResponse));
+ lc.login();
+ } catch (LoginException e) {
+ if (authIsRequired(remoteAuthRequest, remoteAuthResponse)) {
+ int statusCode = RemoteAuthUtils.askForWwwAuth(remoteAuthRequest,
+ remoteAuthResponse, httpAuthRealm,
+ forceBasic);
+ response.setStatus(statusCode);
+ return false;
+
+ } else {
+ lc = RemoteAuthUtils.anonymousLogin(remoteAuthRequest, remoteAuthResponse);
+ }
+ if (lc == null)
+ return false;
+ } finally {
+ Thread.currentThread().setContextClassLoader(currentThreadContextClassLoader);
+ }
+
+// Subject subject = lc.getSubject();
+// Subject.doAs(subject, new PrivilegedAction<Void>() {
+//
+// @Override
+// public Void run() {
+// // TODO also set login context in order to log out ?
+// RemoteAuthUtils.configureRequestSecurity(remoteAuthRequest);
+// return null;
+// }
+//
+// });
+ return true;
+ }
+
+// @Override
+// public void finishSecurity(HttpServletRequest request, HttpServletResponse response) {
+// RemoteAuthUtils.clearRequestSecurity(new ServletHttpRequest(request));
+// }
+
+ protected boolean authIsRequired(RemoteAuthRequest remoteAuthRequest, RemoteAuthResponse remoteAuthResponse) {
+ return false;
+ }
+
+// protected LoginContext processUnauthorized(HttpServletRequest request, HttpServletResponse response) {
+// // anonymous
+// ClassLoader currentContextClassLoader = Thread.currentThread().getContextClassLoader();
+// try {
+// Thread.currentThread().setContextClassLoader(CmsServletContext.class.getClassLoader());
+// LoginContext lc = CmsAuth.ANONYMOUS.newLoginContext(
+// new RemoteAuthCallbackHandler(new ServletHttpRequest(request), new ServletHttpResponse(response)));
+// lc.login();
+// return lc;
+// } catch (LoginException e1) {
+// if (log.isDebugEnabled())
+// log.error("Cannot log in as anonymous", e1);
+// return null;
+// } finally {
+// Thread.currentThread().setContextClassLoader(currentContextClassLoader);
+// }
+// }
+
+ @Override
+ public URL getResource(String name) {
+ // TODO make it more robust and versatile
+ // if used directly it can only load from within this bundle
+ return bundle.getResource(name);
+ }
+
+}
--- /dev/null
+package org.argeo.cms.servlet.javax;
+
+import java.util.Objects;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.argeo.cms.auth.RemoteAuthResponse;
+
+public class JavaxServletHttpResponse implements RemoteAuthResponse {
+ private final HttpServletResponse response;
+
+ public JavaxServletHttpResponse(HttpServletResponse response) {
+ Objects.requireNonNull(response);
+ this.response = response;
+ }
+
+ @Override
+ public void setHeader(String headerName, String value) {
+ response.setHeader(headerName, value);
+ }
+
+ @Override
+ public void addHeader(String headerName, String value) {
+ response.addHeader(headerName, value);
+ }
+
+}
--- /dev/null
+package org.argeo.cms.jetty;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import org.eclipse.jetty.server.handler.ContextHandler;
+
+import com.sun.net.httpserver.Authenticator;
+import com.sun.net.httpserver.Filter;
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+
+/**
+ * An @{HttpContext} implementation based on Jetty.
+ */
+public abstract class AbstractJettyHttpContext extends HttpContext {
+ private final JettyHttpServer httpServer;
+ private final String path;
+ private final List<Filter> filters = new ArrayList<>();
+
+ private HttpHandler handler;
+ private Authenticator authenticator;
+
+ public AbstractJettyHttpContext(JettyHttpServer httpServer, String path) {
+ this.httpServer = httpServer;
+ if (!path.endsWith("/"))
+ throw new IllegalArgumentException("Path " + path + " should end with a /");
+ this.path = path;
+ }
+
+ protected abstract ContextHandler getJettyHandler();
+
+ @Override
+ public HttpHandler getHandler() {
+ return handler;
+ }
+
+ @Override
+ public void setHandler(HttpHandler handler) {
+ if (this.handler != null)
+ throw new IllegalArgumentException("Handler is already set");
+ Objects.requireNonNull(handler);
+ this.handler = handler;
+ }
+
+ @Override
+ public String getPath() {
+ return path;
+ }
+
+ @Override
+ public HttpServer getServer() {
+ return getJettyHttpServer();
+ }
+
+ protected JettyHttpServer getJettyHttpServer() {
+ return httpServer;
+ }
+
+ @Override
+ public List<Filter> getFilters() {
+ return filters;
+ }
+
+ @Override
+ public Authenticator setAuthenticator(Authenticator auth) {
+ Authenticator previousAuthenticator = authenticator;
+ this.authenticator = auth;
+ return previousAuthenticator;
+ }
+
+ @Override
+ public Authenticator getAuthenticator() {
+ return authenticator;
+ }
+
+}
+++ /dev/null
-package org.argeo.cms.jetty;
-
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.concurrent.CompletableFuture;
-
-import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
-import org.eclipse.jetty.ee10.servlet.SessionHandler;
-import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer.Configurator;
-import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
-
-import jakarta.servlet.ServletContext;
-import jakarta.servlet.ServletException;
-import jakarta.websocket.DeploymentException;
-import jakarta.websocket.server.ServerContainer;
-
-/** A {@link JettyHttpServer} which is compatible with Equinox servlets. */
-public class CmsJettyServer extends JettyHttpServer {
- private static final String CONTEXT_TEMPDIR = "javax.servlet.context.tempdir";
- // Equinox compatibility
- private static final String INTERNAL_CONTEXT_CLASSLOADER = "org.eclipse.equinox.http.jetty.internal.ContextClassLoader";
- private Path tempDir;
-
- private CompletableFuture<ServerContainer> serverContainer = new CompletableFuture<>();
-
- protected void addServlets(ServletContextHandler servletContextHandler) throws ServletException {
- }
-
- @Override
- public void start() {
- try {
- tempDir = Files.createTempDirectory("jetty");
- } catch (IOException e) {
- throw new IllegalStateException("Cannot create temp dir", e);
- }
- super.start();
- }
-
- @Override
- protected ServletContextHandler createRootContextHandler() {
- ServletContextHandler servletContextHandler = new ServletContextHandler();
- servletContextHandler.setAttribute(INTERNAL_CONTEXT_CLASSLOADER,
- Thread.currentThread().getContextClassLoader());
- servletContextHandler.setClassLoader(this.getClass().getClassLoader());
- servletContextHandler.setContextPath("/");
-
- servletContextHandler.setAttribute(CONTEXT_TEMPDIR, tempDir.toAbsolutePath().toFile());
- SessionHandler handler = new SessionHandler();
- // FIXME deal with long running session
- // handler.setMaxInactiveInterval(-1);
- servletContextHandler.setSessionHandler(handler);
-
- JakartaWebSocketServletContainerInitializer.configure(servletContextHandler, new Configurator() {
-
- @Override
- public void accept(ServletContext servletContext, ServerContainer serverContainer)
- throws DeploymentException {
- CmsJettyServer.this.serverContainer.complete(serverContainer);
- }
- });
-
- return servletContextHandler;
- }
-
- @Override
- protected ServerContainer getRootServerContainer() {
- return serverContainer.join();
- }
-
- @Override
- protected void configureRootContextHandler(ServletContextHandler servletContextHandler) throws ServletException {
- addServlets(servletContextHandler);
- }
-
- /*
- * WEB SOCKET
- */
-
-}
* A {@link Map} implementation wrapping the attributes of a Jetty
* {@link ContextHandler}.
*/
-class ContextHandlerAttributes extends AbstractMap<String, Object> {
+public class ContextHandlerAttributes extends AbstractMap<String, Object> {
private ContextHandler contextHandler;
public ContextHandlerAttributes(ContextHandler contextHandler) {
+++ /dev/null
-package org.argeo.cms.jetty;
-
-import java.util.Map;
-
-import jakarta.servlet.ServletContext;
-import jakarta.websocket.DeploymentException;
-import jakarta.websocket.server.ServerContainer;
-
-import org.argeo.cms.servlet.httpserver.HttpContextServlet;
-import org.argeo.cms.websocket.server.WebsocketEndpoints;
-import org.eclipse.jetty.ee10.servlet.SessionHandler;
-import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
-import org.eclipse.jetty.ee10.servlet.ServletHolder;
-import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
-import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer.Configurator;
-
-import com.sun.net.httpserver.HttpHandler;
-
-/**
- * An @{HttpContext} implementation based on a Jetty
- * {@link ServletContextHandler}.
- */
-class ContextHandlerHttpContext extends JettyHttpContext {
- private final ServletContextHandler servletContextHandler;
- private final ContextHandlerAttributes attributes;
-
- public ContextHandlerHttpContext(JettyHttpServer httpServer, String path) {
- super(httpServer, path);
-
- // Jetty context handler
- this.servletContextHandler = new ServletContextHandler();
- servletContextHandler.setContextPath(path);
- HttpContextServlet servlet = new HttpContextServlet(this);
- servletContextHandler.addServlet(new ServletHolder(servlet), "/*");
- SessionHandler sessionHandler = new SessionHandler();
- // FIXME find a better default
- // FIXME find out how to have long-running sessions
- // sessionHandler.setMaxInactiveInterval(-1);
- servletContextHandler.setSessionHandler(sessionHandler);
-
- attributes = new ContextHandlerAttributes(servletContextHandler);
- }
-
- @Override
- public void setHandler(HttpHandler handler) {
- super.setHandler(handler);
-
- // web socket
- if (handler instanceof WebsocketEndpoints) {
- JakartaWebSocketServletContainerInitializer.configure(servletContextHandler, new Configurator() {
-
- @Override
- public void accept(ServletContext servletContext, ServerContainer serverContainer)
- throws DeploymentException {
- for (Class<?> clss : ((WebsocketEndpoints) handler).getEndPoints()) {
- serverContainer.addEndpoint(clss);
- }
- }
- });
- }
-
- if (getJettyHttpServer().isStarted())
- try {
- servletContextHandler.start();
- } catch (Exception e) {
- throw new IllegalStateException("Cannot start context handler", e);
- }
- }
-
- @Override
- public Map<String, Object> getAttributes() {
- return attributes;
- }
-
- @Override
- protected ServletContextHandler getServletContextHandler() {
- return servletContextHandler;
- }
-
-}
+++ /dev/null
-package org.argeo.cms.jetty;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-import org.argeo.cms.websocket.server.WebsocketEndpoints;
-import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
-
-import com.sun.net.httpserver.Authenticator;
-import com.sun.net.httpserver.Filter;
-import com.sun.net.httpserver.HttpContext;
-import com.sun.net.httpserver.HttpHandler;
-import com.sun.net.httpserver.HttpServer;
-
-/**
- * An @{HttpContext} implementation based on Jetty. It supports web sockets if
- * the handler implements {@link WebsocketEndpoints}.
- */
-abstract class JettyHttpContext extends HttpContext {
- private final JettyHttpServer httpServer;
- private final String path;
- private final List<Filter> filters = new ArrayList<>();
-
- private HttpHandler handler;
- private Authenticator authenticator;
-
- public JettyHttpContext(JettyHttpServer httpServer, String path) {
- this.httpServer = httpServer;
- if (!path.endsWith("/"))
- throw new IllegalArgumentException("Path " + path + " should end with a /");
- this.path = path;
- }
-
- protected abstract ServletContextHandler getServletContextHandler();
-
- @Override
- public HttpHandler getHandler() {
- return handler;
- }
-
- @Override
- public void setHandler(HttpHandler handler) {
- if (this.handler != null)
- throw new IllegalArgumentException("Handler is already set");
- Objects.requireNonNull(handler);
- this.handler = handler;
- }
-
- @Override
- public String getPath() {
- return path;
- }
-
- @Override
- public HttpServer getServer() {
- return getJettyHttpServer();
- }
-
- protected JettyHttpServer getJettyHttpServer() {
- return httpServer;
- }
-
- @Override
- public List<Filter> getFilters() {
- return filters;
- }
-
- @Override
- public Authenticator setAuthenticator(Authenticator auth) {
- Authenticator previousAuthenticator = authenticator;
- this.authenticator = auth;
- return previousAuthenticator;
- }
-
- @Override
- public Authenticator getAuthenticator() {
- return authenticator;
- }
-
-}
import java.util.concurrent.ThreadPoolExecutor;
import javax.net.ssl.SSLContext;
-import jakarta.servlet.ServletException;
-import jakarta.websocket.server.ServerContainer;
import org.argeo.api.cms.CmsLog;
import org.argeo.api.cms.CmsState;
import org.argeo.cms.CmsDeployProperty;
import org.argeo.cms.http.server.HttpServerUtils;
-import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
+import org.argeo.cms.jetty.ee10.ContextHandlerHttpContext;
+import org.argeo.cms.jetty.server.JettyHttpContext;
import org.eclipse.jetty.http.UriCompliance;
+import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsServer;
+import jakarta.websocket.server.ServerContainer;
+
/** An {@link HttpServer} implementation based on Jetty. */
public class JettyHttpServer extends HttpsServer {
private final static CmsLog log = CmsLog.getLog(JettyHttpServer.class);
private HttpsConfigurator httpsConfigurator;
- private final Map<String, JettyHttpContext> contexts = new TreeMap<>();
+ private final Map<String, AbstractJettyHttpContext> contexts = new TreeMap<>();
- private ServletContextHandler rootContextHandler;
+ private Handler rootContextHandler;
protected final ContextHandlerCollection contextHandlerCollection = new ContextHandlerCollection();
private boolean started;
if (contexts.containsKey(path))
throw new IllegalArgumentException("Context " + path + " already exists");
- JettyHttpContext httpContext = new ServletHttpContext(this, path);
+ AbstractJettyHttpContext httpContext = new JettyHttpContext(this, path);
contexts.put(path, httpContext);
- contextHandlerCollection.addHandler(httpContext.getServletContextHandler());
+ contextHandlerCollection.addHandler(httpContext.getJettyHandler());
return httpContext;
}
path = path + "/";
if (!contexts.containsKey(path))
throw new IllegalArgumentException("Context " + path + " does not exist");
- JettyHttpContext httpContext = contexts.remove(path);
+ AbstractJettyHttpContext httpContext = contexts.remove(path);
if (httpContext instanceof ContextHandlerHttpContext contextHandlerHttpContext) {
// TODO stop handler first?
// FIXME understand compatibility with Jetty 12
return httpsConnector.getLocalPort();
}
- protected ServletContextHandler createRootContextHandler() {
+ protected Handler createRootContextHandler() {
return null;
}
- protected void configureRootContextHandler(ServletContextHandler servletContextHandler) throws ServletException {
+ protected void configureRootContextHandler(Handler servletContextHandler) {
}
+ // TODO protect it?
+ public Handler getRootContextHandler() {
+ return rootContextHandler;
+ }
+
public void setCmsState(CmsState cmsState) {
this.cmsState = cmsState;
}
- boolean isStarted() {
+ public boolean isStarted() {
return started;
}
- ServletContextHandler getRootContextHandler() {
- return rootContextHandler;
- }
-
- ServerContainer getRootServerContainer() {
+ // TODO protect it?
+ public ServerContainer getRootServerContainer() {
throw new UnsupportedOperationException();
}
+++ /dev/null
-package org.argeo.cms.jetty;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-
-import jakarta.websocket.DeploymentException;
-import jakarta.websocket.server.ServerContainer;
-
-import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.servlet.httpserver.HttpContextServlet;
-import org.argeo.cms.websocket.server.WebsocketEndpoints;
-import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
-import org.eclipse.jetty.ee10.servlet.ServletHolder;
-
-import com.sun.net.httpserver.HttpHandler;
-
-/**
- * A {@link JettyHttpContext} based on registering a servlet to the root handler
- * of the {@link JettyHttpServer}, in order to integrate the sessions.
- */
-public class ServletHttpContext extends JettyHttpContext {
- private final static CmsLog log = CmsLog.getLog(ServletHttpContext.class);
-
- private Map<String, Object> attributes = Collections.synchronizedMap(new HashMap<>());
-
- public ServletHttpContext(JettyHttpServer httpServer, String path) {
- super(httpServer, path);
-
- ServletContextHandler rootContextHandler = httpServer.getRootContextHandler();
- HttpContextServlet servlet = new HttpContextServlet(this);
- rootContextHandler.addServlet(new ServletHolder(servlet), path + "*");
- }
-
- @Override
- public void setHandler(HttpHandler handler) {
- super.setHandler(handler);
-
- // web socket
- if (handler instanceof WebsocketEndpoints) {
- ServerContainer serverContainer = getJettyHttpServer().getRootServerContainer();
- for (Class<?> clss : ((WebsocketEndpoints) handler).getEndPoints()) {
- try {
- serverContainer.addEndpoint(clss);
- log.debug(() -> "Added web socket " + clss + " to " + getPath());
- } catch (DeploymentException e) {
- log.error("Cannot deploy Web Socket " + clss, e);
- }
- }
- }
- }
-
- @Override
- public Map<String, Object> getAttributes() {
- return attributes;
- }
-
- @Override
- protected ServletContextHandler getServletContextHandler() {
- return getJettyHttpServer().getRootContextHandler();
- }
-
-}
--- /dev/null
+package org.argeo.cms.jetty.ee10;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.CompletableFuture;
+
+import org.argeo.cms.jetty.JettyHttpServer;
+import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
+import org.eclipse.jetty.ee10.servlet.SessionHandler;
+import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
+import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer.Configurator;
+import org.eclipse.jetty.server.Handler;
+
+import jakarta.servlet.ServletContext;
+import jakarta.websocket.DeploymentException;
+import jakarta.websocket.server.ServerContainer;
+
+/** A {@link JettyHttpServer} which is compatible with Equinox servlets. */
+public class CmsJettyServer extends JettyHttpServer {
+ private static final String CONTEXT_TEMPDIR = "javax.servlet.context.tempdir";
+ // Equinox compatibility
+ private static final String INTERNAL_CONTEXT_CLASSLOADER = "org.eclipse.equinox.http.jetty.internal.ContextClassLoader";
+ private Path tempDir;
+
+ private CompletableFuture<ServerContainer> serverContainer = new CompletableFuture<>();
+
+ protected void addServlets(ServletContextHandler servletContextHandler) {
+ }
+
+ @Override
+ public void start() {
+ try {
+ tempDir = Files.createTempDirectory("jetty");
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot create temp dir", e);
+ }
+ super.start();
+ }
+
+ @Override
+ protected ServletContextHandler createRootContextHandler() {
+ ServletContextHandler servletContextHandler = new ServletContextHandler();
+ servletContextHandler.setAttribute(INTERNAL_CONTEXT_CLASSLOADER,
+ Thread.currentThread().getContextClassLoader());
+ servletContextHandler.setClassLoader(this.getClass().getClassLoader());
+ servletContextHandler.setContextPath("/");
+
+ servletContextHandler.setAttribute(CONTEXT_TEMPDIR, tempDir.toAbsolutePath().toFile());
+ SessionHandler handler = new SessionHandler();
+ // FIXME deal with long running session
+ // handler.setMaxInactiveInterval(-1);
+ servletContextHandler.setSessionHandler(handler);
+
+ JakartaWebSocketServletContainerInitializer.configure(servletContextHandler, new Configurator() {
+
+ @Override
+ public void accept(ServletContext servletContext, ServerContainer serverContainer)
+ throws DeploymentException {
+ CmsJettyServer.this.serverContainer.complete(serverContainer);
+ }
+ });
+
+ return servletContextHandler;
+ }
+
+ @Override
+ public ServerContainer getRootServerContainer() {
+ return serverContainer.join();
+ }
+
+ @Override
+ protected void configureRootContextHandler(Handler servletContextHandler) {
+ addServlets((ServletContextHandler) servletContextHandler);
+ }
+
+ /*
+ * WEB SOCKET
+ */
+
+}
--- /dev/null
+package org.argeo.cms.jetty.ee10;
+
+import java.util.Map;
+
+import jakarta.servlet.ServletContext;
+import jakarta.websocket.DeploymentException;
+import jakarta.websocket.server.ServerContainer;
+
+import org.argeo.cms.jetty.ContextHandlerAttributes;
+import org.argeo.cms.jetty.AbstractJettyHttpContext;
+import org.argeo.cms.jetty.JettyHttpServer;
+import org.argeo.cms.servlet.httpserver.HttpContextServlet;
+import org.argeo.cms.websocket.server.WebsocketEndpoints;
+import org.eclipse.jetty.ee10.servlet.SessionHandler;
+import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
+import org.eclipse.jetty.ee10.servlet.ServletHolder;
+import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
+import org.eclipse.jetty.ee10.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer.Configurator;
+
+import com.sun.net.httpserver.HttpHandler;
+
+/**
+ * An @{HttpContext} implementation based on a Jetty
+ * {@link ServletContextHandler}.
+ */
+@Deprecated
+public class ContextHandlerHttpContext extends AbstractJettyHttpContext {
+ private final ServletContextHandler servletContextHandler;
+ private final ContextHandlerAttributes attributes;
+
+ public ContextHandlerHttpContext(JettyHttpServer httpServer, String path) {
+ super(httpServer, path);
+
+ // Jetty context handler
+ this.servletContextHandler = new ServletContextHandler();
+ servletContextHandler.setContextPath(path);
+ HttpContextServlet servlet = new HttpContextServlet(this);
+ servletContextHandler.addServlet(new ServletHolder(servlet), "/*");
+ SessionHandler sessionHandler = new SessionHandler();
+ // FIXME find a better default
+ // FIXME find out how to have long-running sessions
+ // sessionHandler.setMaxInactiveInterval(-1);
+ servletContextHandler.setSessionHandler(sessionHandler);
+
+ attributes = new ContextHandlerAttributes(servletContextHandler);
+ }
+
+ @Override
+ public void setHandler(HttpHandler handler) {
+ super.setHandler(handler);
+
+ // web socket
+ if (handler instanceof WebsocketEndpoints) {
+ JakartaWebSocketServletContainerInitializer.configure(servletContextHandler, new Configurator() {
+
+ @Override
+ public void accept(ServletContext servletContext, ServerContainer serverContainer)
+ throws DeploymentException {
+ for (Class<?> clss : ((WebsocketEndpoints) handler).getEndPoints()) {
+ serverContainer.addEndpoint(clss);
+ }
+ }
+ });
+ }
+
+ if (getJettyHttpServer().isStarted())
+ try {
+ servletContextHandler.start();
+ } catch (Exception e) {
+ throw new IllegalStateException("Cannot start context handler", e);
+ }
+ }
+
+ @Override
+ public Map<String, Object> getAttributes() {
+ return attributes;
+ }
+
+ @Override
+ protected ServletContextHandler getJettyHandler() {
+ return servletContextHandler;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.jetty.ee10;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.argeo.api.cms.CmsLog;
+import org.argeo.cms.jetty.AbstractJettyHttpContext;
+import org.argeo.cms.jetty.JettyHttpServer;
+import org.argeo.cms.servlet.httpserver.HttpContextServlet;
+import org.argeo.cms.websocket.server.WebsocketEndpoints;
+import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
+import org.eclipse.jetty.ee10.servlet.ServletHolder;
+
+import com.sun.net.httpserver.HttpHandler;
+
+import jakarta.websocket.DeploymentException;
+import jakarta.websocket.server.ServerContainer;
+
+/**
+ * A {@link AbstractJettyHttpContext} based on registering a servlet to the root handler
+ * of the {@link JettyHttpServer}, in order to integrate the sessions. It
+ * supports web sockets if the handler implements {@link WebsocketEndpoints}.
+ */
+public class ServletHttpContext extends AbstractJettyHttpContext {
+ private final static CmsLog log = CmsLog.getLog(ServletHttpContext.class);
+
+ private Map<String, Object> attributes = Collections.synchronizedMap(new HashMap<>());
+
+ public ServletHttpContext(JettyHttpServer httpServer, String path) {
+ super(httpServer, path);
+
+ ServletContextHandler rootContextHandler = (ServletContextHandler) httpServer.getRootContextHandler();
+ HttpContextServlet servlet = new HttpContextServlet(this);
+ rootContextHandler.addServlet(new ServletHolder(servlet), path + "*");
+ }
+
+ @Override
+ public void setHandler(HttpHandler handler) {
+ super.setHandler(handler);
+
+ // web socket
+ if (handler instanceof WebsocketEndpoints) {
+ ServerContainer serverContainer = getJettyHttpServer().getRootServerContainer();
+ for (Class<?> clss : ((WebsocketEndpoints) handler).getEndPoints()) {
+ try {
+ serverContainer.addEndpoint(clss);
+ log.debug(() -> "Added web socket " + clss + " to " + getPath());
+ } catch (DeploymentException e) {
+ log.error("Cannot deploy Web Socket " + clss, e);
+ }
+ }
+ }
+ }
+
+ @Override
+ public Map<String, Object> getAttributes() {
+ return attributes;
+ }
+
+ @Override
+ protected ServletContextHandler getJettyHandler() {
+ return (ServletContextHandler) getJettyHttpServer().getRootContextHandler();
+ }
+
+}
--- /dev/null
+package org.argeo.cms.jetty.ee8;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.concurrent.CompletableFuture;
+
+import javax.servlet.ServletContext;
+import javax.websocket.DeploymentException;
+import javax.websocket.server.ServerContainer;
+
+import org.argeo.cms.jetty.JettyHttpServer;
+import org.eclipse.jetty.ee8.nested.SessionHandler;
+import org.eclipse.jetty.ee8.servlet.ServletContextHandler;
+import org.eclipse.jetty.ee8.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.ee8.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer.Configurator;
+import org.eclipse.jetty.server.Handler;
+
+/** A {@link JettyHttpServer} which is compatible with Equinox servlets. */
+public class CmsJavaxJettyServer extends JettyHttpServer {
+ private static final String CONTEXT_TEMPDIR = "javax.servlet.context.tempdir";
+ // Equinox compatibility
+ private static final String INTERNAL_CONTEXT_CLASSLOADER = "org.eclipse.equinox.http.jetty.internal.ContextClassLoader";
+ private Path tempDir;
+
+ private CompletableFuture<ServerContainer> serverContainer = new CompletableFuture<>();
+
+ // FIXME
+ private ServletContextHandler rootContextHandler;
+
+ protected void addServlets(ServletContextHandler servletContextHandler) {
+ }
+
+ @Override
+ public void start() {
+ try {
+ tempDir = Files.createTempDirectory("jetty");
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot create temp dir", e);
+ }
+ super.start();
+ }
+
+ @Override
+ protected Handler createRootContextHandler() {
+ ServletContextHandler servletContextHandler = new ServletContextHandler();
+ servletContextHandler.setAttribute(INTERNAL_CONTEXT_CLASSLOADER,
+ Thread.currentThread().getContextClassLoader());
+ servletContextHandler.setClassLoader(this.getClass().getClassLoader());
+ servletContextHandler.setContextPath("/");
+
+ servletContextHandler.setAttribute(CONTEXT_TEMPDIR, tempDir.toAbsolutePath().toFile());
+ SessionHandler handler = new SessionHandler();
+ // FIXME deal with long running session
+ // handler.setMaxInactiveInterval(-1);
+ servletContextHandler.setSessionHandler(handler);
+
+ JavaxWebSocketServletContainerInitializer.configure(servletContextHandler, new Configurator() {
+
+ @Override
+ public void accept(ServletContext servletContext, ServerContainer serverContainer)
+ throws DeploymentException {
+ CmsJavaxJettyServer.this.serverContainer.complete(serverContainer);
+ }
+ });
+
+ rootContextHandler = servletContextHandler;
+ return servletContextHandler.get();
+ }
+
+// @Override
+// protected ServerContainer getRootServerContainer() {
+// return serverContainer.join();
+// }
+
+ @Override
+ protected void configureRootContextHandler(Handler servletContextHandler) {
+ addServlets(rootContextHandler);
+ }
+
+ /*
+ * WEB SOCKET
+ */
+
+}
--- /dev/null
+package org.argeo.cms.jetty.server;
+
+import org.eclipse.jetty.server.handler.ContextHandler;
+
+import com.sun.net.httpserver.HttpContext;
+
+/** A Jetty {@link ContextHandler} based on an {@link HttpContext}. */
+class HttpContextJettyContextHandler extends ContextHandler {
+
+ public HttpContextJettyContextHandler(HttpContext httpContext) {
+ super(new HttpContextJettyHandler(httpContext), httpContext.getPath());
+ }
+
+}
--- /dev/null
+package org.argeo.cms.jetty.server;
+
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Handler.Abstract;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Response;
+import org.eclipse.jetty.util.Callback;
+
+import com.sun.net.httpserver.HttpContext;
+
+/** A jetty {@link Handler} based on an {@link HttpContext}. */
+class HttpContextJettyHandler extends Abstract {
+ private final HttpContext httpContext;
+
+ public HttpContextJettyHandler(HttpContext httpContext) {
+ this.httpContext = httpContext;
+ }
+
+ @Override
+ public boolean handle(Request request, Response response, Callback callback) throws Exception {
+ JettyHttpExchange httpExchange = new JettyHttpExchange(httpContext, request, response);
+ // FIXME deal with authentication
+ httpContext.getHandler().handle(httpExchange);
+ callback.succeeded();
+ return true;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.jetty.server;
+
+import java.util.Map;
+
+import org.argeo.cms.jetty.AbstractJettyHttpContext;
+import org.argeo.cms.jetty.ContextHandlerAttributes;
+import org.argeo.cms.jetty.JettyHttpServer;
+import org.eclipse.jetty.server.handler.ContextHandler;
+
+import com.sun.net.httpserver.HttpContext;
+
+/**
+ * A {@link HttpContext} based on pure Jetty server components (no dependency to
+ * the jakarta/javax servlet APIs).
+ */
+public class JettyHttpContext extends AbstractJettyHttpContext {
+ private final ContextHandler contextHandler;
+ private final ContextHandlerAttributes attributes;
+
+ public JettyHttpContext(JettyHttpServer httpServer, String path) {
+ super(httpServer, path);
+ contextHandler = new HttpContextJettyContextHandler(this);
+ attributes = new ContextHandlerAttributes(contextHandler);
+ }
+
+ @Override
+ protected ContextHandler getJettyHandler() {
+ return contextHandler;
+ }
+
+ @Override
+ public Map<String, Object> getAttributes() {
+ return attributes;
+ }
+
+}
--- /dev/null
+package org.argeo.cms.jetty.server;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.System.Logger;
+import java.net.InetSocketAddress;
+import java.net.URI;
+
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLSession;
+
+import org.eclipse.jetty.io.Content;
+import org.eclipse.jetty.io.EndPoint;
+import org.eclipse.jetty.io.ssl.SslConnection;
+import org.eclipse.jetty.io.ssl.SslConnection.SslEndPoint;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.server.Response;
+import org.eclipse.jetty.util.Fields;
+
+import com.sun.net.httpserver.Headers;
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpPrincipal;
+import com.sun.net.httpserver.HttpsExchange;
+
+/** Integrates {@link HttpsExchange} in a servlet container. */
+class JettyHttpExchange extends HttpsExchange {
+ private final static Logger logger = System.getLogger(JettyHttpExchange.class.getName());
+ // see
+ // https://github.com/jetty/jetty.project/blob/jetty-12.0.x/documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/migration/ServletToHandlerDocs.java
+ // for mapping between the Servelt and Jetty APIs.
+
+ private final HttpContext httpContext;
+ private final Request request;
+ private final Response response;
+
+ private final Headers requestHeaders;
+ private final Headers responseHeaders;
+
+ private InputStream filteredIn;
+ private OutputStream filteredOut;
+
+ private HttpPrincipal principal;
+
+ public JettyHttpExchange(HttpContext httpContext, Request jettyRequest, Response jettyResponse) {
+ this.httpContext = httpContext;
+ this.request = jettyRequest;
+ this.response = jettyResponse;
+
+ // request headers
+ requestHeaders = new Headers();
+
+ Fields allParameters = Request.extractQueryParameters(request);
+ for (Fields.Field parameter : allParameters) {
+ requestHeaders.put(parameter.getName(), parameter.getValues());
+ }
+
+ responseHeaders = new Headers();
+ }
+
+ @Override
+ public SSLSession getSSLSession() {
+ SSLSession sslSession = null;
+ EndPoint endPoint = request.getConnectionMetaData().getConnection().getEndPoint();
+ if (endPoint instanceof SslEndPoint sslEndPoint) {
+ SslConnection sslConnection = sslEndPoint.getSslConnection();
+ SSLEngine sslEngine = sslConnection.getSSLEngine();
+ sslSession = sslEngine.getSession();
+ }
+ if (sslSession == null)
+ throw new IllegalStateException("SSL session not found");
+ return sslSession;
+ }
+
+ @Override
+ public Headers getRequestHeaders() {
+ return requestHeaders;
+ }
+
+ @Override
+ public Headers getResponseHeaders() {
+ return responseHeaders;
+ }
+
+ @Override
+ public URI getRequestURI() {
+ return request.getHttpURI().toURI();
+ }
+
+ @Override
+ public String getRequestMethod() {
+ return request.getMethod();
+ }
+
+ @Override
+ public HttpContext getHttpContext() {
+ return httpContext;
+ }
+
+ @Override
+ public void close() {
+
+ try {
+ Content.Source.asInputStream(request).close();
+ } catch (IOException e) {
+ logger.log(System.Logger.Level.WARNING, "Cannot close stream of request " + request, e);
+ }
+ try {
+ Content.Sink.asOutputStream(response).close();
+ } catch (IOException e) {
+ logger.log(System.Logger.Level.WARNING, "Cannot close stream of response " + response, e);
+ }
+
+ }
+
+ @Override
+ public InputStream getRequestBody() {
+ if (filteredIn != null)
+ return filteredIn;
+ else
+ return Content.Source.asInputStream(request);
+ }
+
+ @Override
+ public OutputStream getResponseBody() {
+ if (filteredOut != null)
+ return filteredOut;
+ else
+ return Content.Sink.asOutputStream(response);
+ }
+
+ @Override
+ public void sendResponseHeaders(int rCode, long responseLength) throws IOException {
+ for (String headerName : responseHeaders.keySet()) {
+ for (String headerValue : responseHeaders.get(headerName)) {
+ response.getHeaders().put(headerName, headerValue);
+ }
+ }
+ // TODO deal with content length etc.
+ response.setStatus(rCode);
+ }
+
+ @Override
+ public InetSocketAddress getRemoteAddress() {
+ // TODO support non IP socket address? (e.g. UNIX sockets)
+ return (InetSocketAddress) request.getConnectionMetaData().getRemoteSocketAddress();
+ }
+
+ @Override
+ public int getResponseCode() {
+ return response.getStatus();
+ }
+
+ @Override
+ public InetSocketAddress getLocalAddress() {
+ // TODO support non IP socket address? (e.g. UNIX sockets)
+ return (InetSocketAddress) request.getConnectionMetaData().getLocalSocketAddress();
+ }
+
+ @Override
+ public String getProtocol() {
+ return request.getConnectionMetaData().getProtocol();
+ }
+
+ @Override
+ public Object getAttribute(String name) {
+ return request.getAttribute(name);
+ }
+
+ @Override
+ public void setAttribute(String name, Object value) {
+ request.setAttribute(name, value);
+ }
+
+ @Override
+ public void setStreams(InputStream i, OutputStream o) {
+ if (i != null)
+ filteredIn = i;
+ if (o != null)
+ filteredOut = o;
+
+ }
+
+ @Override
+ public HttpPrincipal getPrincipal() {
+ return principal;
+ }
+
+ void setPrincipal(HttpPrincipal principal) {
+ this.principal = principal;
+ }
+
+}
import jakarta.servlet.http.HttpSessionListener;
import org.argeo.api.cms.CmsLog;
-import org.argeo.cms.jetty.CmsJettyServer;
+import org.argeo.cms.jetty.ee10.CmsJettyServer;
import org.eclipse.rap.http.servlet.HttpServiceServlet;
import org.eclipse.jetty.ee10.servlet.SessionHandler;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
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());
+ protected void addServlets(ServletContextHandler rootContextHandler) {
+ try {
+ 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());
+ } catch (ServletException e) {
+ throw new RuntimeException("Cannot add servlets", e);
+ }
}
public static class InternalHttpServiceServlet implements HttpSessionListener, HttpSessionIdListener, Servlet {
--- /dev/null
+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.api.cms.CmsLog;
+import org.argeo.cms.jetty.ee10.CmsJettyServer;
+import org.argeo.cms.jetty.ee8.CmsJavaxJettyServer;
+import org.eclipse.equinox.http.servlet.HttpServiceServlet;
+import org.eclipse.jetty.ee8.nested.SessionHandler;
+import org.eclipse.jetty.ee8.servlet.ServletContextHandler;
+import org.eclipse.jetty.ee8.servlet.ServletHolder;
+import org.osgi.framework.Constants;
+
+/** A {@link CmsJettyServer} integrating with Equinox HTTP framework. */
+public class JavaxJettyServer extends CmsJavaxJettyServer {
+ private final static CmsLog log = CmsLog.getLog(EquinoxJettyServer.class);
+ private static final String INTERNAL_CONTEXT_CLASSLOADER = "org.eclipse.equinox.http.jetty.internal.ContextClassLoader";
+
+ @Override
+ protected void addServlets(ServletContextHandler rootContextHandler) {
+ try {
+ 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());
+ } catch (ServletException e) {
+ throw new RuntimeException("Cannot add servlets", e);
+ }
+ }
+
+ 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);
+ } catch (IllegalStateException e) {
+ // context is probably in shutdown
+ if (log.isTraceEnabled())
+ log.error("Cannot process request", e);
+ } 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);
+ }
+ }
+ }
+
+}