Move Equinox specific code to the appropriate variant
authorMathieu Baudier <mbaudier@argeo.org>
Tue, 1 Nov 2022 08:06:48 +0000 (09:06 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Tue, 1 Nov 2022 08:06:48 +0000 (09:06 +0100)
25 files changed:
Makefile
org.argeo.cms.lib.equinox/.classpath [deleted file]
org.argeo.cms.lib.equinox/.gitignore [deleted file]
org.argeo.cms.lib.equinox/.project [deleted file]
org.argeo.cms.lib.equinox/META-INF/.gitignore [deleted file]
org.argeo.cms.lib.equinox/OSGI-INF/jettyServiceFactory.xml [deleted file]
org.argeo.cms.lib.equinox/bnd.bnd [deleted file]
org.argeo.cms.lib.equinox/build.properties [deleted file]
org.argeo.cms.lib.equinox/src/org/argeo/cms/equinox/http/jetty/EquinoxJettyServer.java [deleted file]
org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyConfig.java [deleted file]
org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyHttpConstants.java [deleted file]
org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/CmsJettyCustomizer.java [deleted file]
org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/package-info.java [deleted file]
osgi/equinox/org.argeo.cms.lib.equinox/.classpath [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/.gitignore [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/.project [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/META-INF/.gitignore [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/OSGI-INF/jettyServiceFactory.xml [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/bnd.bnd [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/build.properties [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/equinox/http/jetty/EquinoxJettyServer.java [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyConfig.java [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyHttpConstants.java [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/CmsJettyCustomizer.java [new file with mode: 0644]
osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/package-info.java [new file with mode: 0644]

index 57bb5b38c77489938b681f18b1256c28d2d79a31..3d881b870532d9081cac41e9c34b866d1914b823 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -17,9 +17,9 @@ org.argeo.cms \
 org.argeo.cms.ux \
 org.argeo.cms.ee \
 org.argeo.cms.lib.jetty \
-org.argeo.cms.lib.equinox \
 org.argeo.cms.lib.sshd \
 org.argeo.cms.cli \
+osgi/equinox/org.argeo.cms.lib.equinox \
 swt/org.argeo.swt.minidesktop \
 swt/org.argeo.cms.swt \
 swt/org.argeo.cms.e4 \
diff --git a/org.argeo.cms.lib.equinox/.classpath b/org.argeo.cms.lib.equinox/.classpath
deleted file mode 100644 (file)
index 81fe078..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
-       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
-       <classpathentry kind="src" path="src"/>
-       <classpathentry kind="output" path="bin"/>
-</classpath>
diff --git a/org.argeo.cms.lib.equinox/.gitignore b/org.argeo.cms.lib.equinox/.gitignore
deleted file mode 100644 (file)
index 09e3bc9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/bin/
-/target/
diff --git a/org.argeo.cms.lib.equinox/.project b/org.argeo.cms.lib.equinox/.project
deleted file mode 100644 (file)
index c551d5d..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-       <name>org.argeo.cms.lib.equinox</name>
-       <comment></comment>
-       <projects>
-       </projects>
-       <buildSpec>
-               <buildCommand>
-                       <name>org.eclipse.jdt.core.javabuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.ManifestBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.SchemaBuilder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-               <buildCommand>
-                       <name>org.eclipse.pde.ds.core.builder</name>
-                       <arguments>
-                       </arguments>
-               </buildCommand>
-       </buildSpec>
-       <natures>
-               <nature>org.eclipse.pde.PluginNature</nature>
-               <nature>org.eclipse.jdt.core.javanature</nature>
-       </natures>
-</projectDescription>
diff --git a/org.argeo.cms.lib.equinox/META-INF/.gitignore b/org.argeo.cms.lib.equinox/META-INF/.gitignore
deleted file mode 100644 (file)
index 4854a41..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/MANIFEST.MF
diff --git a/org.argeo.cms.lib.equinox/OSGI-INF/jettyServiceFactory.xml b/org.argeo.cms.lib.equinox/OSGI-INF/jettyServiceFactory.xml
deleted file mode 100644 (file)
index 6a13362..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" activate="start" deactivate="stop" name="Jetty Service Factory">
-   <implementation class="org.argeo.cms.equinox.http.jetty.EquinoxJettyServer"/>
-   <property name="service.pid" type="String" value="org.argeo.equinox.jetty.config"/>
-   <reference bind="setCmsState" cardinality="1..1" interface="org.argeo.api.cms.CmsState" name="CmsState" policy="static"/>
-   <service>
-      <provide interface="com.sun.net.httpserver.HttpServer"/>
-   </service>
-</scr:component>
diff --git a/org.argeo.cms.lib.equinox/bnd.bnd b/org.argeo.cms.lib.equinox/bnd.bnd
deleted file mode 100644 (file)
index 2c83158..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-Service-Component: \
-OSGI-INF/jettyServiceFactory.xml,\
diff --git a/org.argeo.cms.lib.equinox/build.properties b/org.argeo.cms.lib.equinox/build.properties
deleted file mode 100644 (file)
index 34d2e4d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-source.. = src/
-output.. = bin/
-bin.includes = META-INF/,\
-               .
diff --git a/org.argeo.cms.lib.equinox/src/org/argeo/cms/equinox/http/jetty/EquinoxJettyServer.java b/org.argeo.cms.lib.equinox/src/org/argeo/cms/equinox/http/jetty/EquinoxJettyServer.java
deleted file mode 100644 (file)
index e6595a0..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-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);
-                       }
-               }
-       }
-
-}
diff --git a/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyConfig.java b/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyConfig.java
deleted file mode 100644 (file)
index 50be8b7..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-package org.argeo.cms.servlet.internal.jetty;
-
-import java.io.File;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.Map;
-import java.util.concurrent.ForkJoinPool;
-
-import javax.websocket.DeploymentException;
-import javax.websocket.server.ServerContainer;
-import javax.websocket.server.ServerEndpointConfig;
-
-import org.argeo.api.cms.CmsConstants;
-import org.argeo.api.cms.CmsLog;
-import org.argeo.api.cms.CmsState;
-import org.argeo.cms.CmsDeployProperty;
-import org.argeo.cms.websocket.server.CmsWebSocketConfigurator;
-import org.argeo.cms.websocket.server.TestEndpoint;
-import org.argeo.util.LangUtils;
-import org.eclipse.equinox.http.jetty.JettyConfigurator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
-
-public class JettyConfig {
-       private final static CmsLog log = CmsLog.getLog(JettyConfig.class);
-
-       final static String CMS_JETTY_CUSTOMIZER_CLASS = "org.argeo.equinox.jetty.CmsJettyCustomizer";
-
-       private CmsState cmsState;
-
-       private final BundleContext bc = FrameworkUtil.getBundle(JettyConfig.class).getBundleContext();
-
-       // private static final String JETTY_PROPERTY_PREFIX =
-       // "org.eclipse.equinox.http.jetty.";
-
-       public void start() {
-               // We need to start asynchronously so that Jetty bundle get started by lazy init
-               // due to the non-configurable behaviour of its activator
-               ForkJoinPool.commonPool().execute(() -> {
-                       Dictionary<String, Object> properties = getHttpServerConfig();
-                       startServer(properties);
-               });
-
-               ServiceTracker<ServerContainer, ServerContainer> serverSt = new ServiceTracker<ServerContainer, ServerContainer>(
-                               bc, ServerContainer.class, null) {
-
-                       @Override
-                       public ServerContainer addingService(ServiceReference<ServerContainer> reference) {
-                               ServerContainer serverContainer = super.addingService(reference);
-
-                               BundleContext bc = reference.getBundle().getBundleContext();
-                               ServiceReference<ServerEndpointConfig.Configurator> srConfigurator = bc
-                                               .getServiceReference(ServerEndpointConfig.Configurator.class);
-                               ServerEndpointConfig.Configurator endpointConfigurator = bc.getService(srConfigurator);
-                               ServerEndpointConfig config = ServerEndpointConfig.Builder
-                                               .create(TestEndpoint.class, "/ws/test/events/").configurator(endpointConfigurator).build();
-                               try {
-                                       serverContainer.addEndpoint(config);
-                               } catch (DeploymentException e) {
-                                       throw new IllegalStateException("Cannot initalise the WebSocket server runtime.", e);
-                               }
-                               return serverContainer;
-                       }
-
-               };
-               serverSt.open();
-
-               // check initialisation
-//             ServiceTracker<?, ?> httpSt = new ServiceTracker<HttpService, HttpService>(bc, HttpService.class, null) {
-//
-//                     @Override
-//                     public HttpService addingService(ServiceReference<HttpService> sr) {
-//                             Object httpPort = sr.getProperty("http.port");
-//                             Object httpsPort = sr.getProperty("https.port");
-//                             log.info(httpPortsMsg(httpPort, httpsPort));
-//                             close();
-//                             return super.addingService(sr);
-//                     }
-//             };
-//             httpSt.open();
-       }
-
-       public void stop() {
-               try {
-                       JettyConfigurator.stopServer(CmsConstants.DEFAULT);
-               } catch (Exception e) {
-                       log.error("Cannot stop default Jetty server.", e);
-               }
-
-       }
-
-       public void startServer(Dictionary<String, Object> properties) {
-               // Explicitly configures Jetty so that the default server is not started by the
-               // activator of the Equinox Jetty bundle.
-               Map<String, String> config = LangUtils.dictToStringMap(properties);
-               if (!config.isEmpty()) {
-                       config.put("customizer.class", CMS_JETTY_CUSTOMIZER_CLASS);
-
-                       // TODO centralise with Jetty extender
-                       Object webSocketEnabled = config.get(CmsDeployProperty.WEBSOCKET_ENABLED.getProperty());
-                       if (webSocketEnabled != null && webSocketEnabled.toString().equals("true")) {
-                               bc.registerService(ServerEndpointConfig.Configurator.class, new CmsWebSocketConfigurator(), null);
-                               // config.put(WEBSOCKET_ENABLED, "true");
-                       }
-               }
-
-               properties.put(Constants.SERVICE_PID, "default");
-               File jettyWorkDir = new File(bc.getDataFile(""), "jettywork"); //$NON-NLS-1$
-               jettyWorkDir.mkdir();
-
-//             HttpServerManager serverManager = new HttpServerManager(jettyWorkDir);
-//             try {
-//                     serverManager.updated("default", properties);
-//             } catch (ConfigurationException e) {
-//                     // TODO Auto-generated catch block
-//                     e.printStackTrace();
-//             }
-               Object httpPort = config.get(JettyHttpConstants.HTTP_PORT);
-               Object httpsPort = config.get(JettyHttpConstants.HTTPS_PORT);
-               log.info(httpPortsMsg(httpPort, httpsPort));
-
-//             long begin = System.currentTimeMillis();
-//             int tryCount = 60;
-//             try {
-//                     while (tryCount > 0) {
-//                             try {
-//                                     // FIXME deal with multiple ids
-//                                     JettyConfigurator.startServer(CmsConstants.DEFAULT, new Hashtable<>(config));
-//
-//                                     Object httpPort = config.get(JettyHttpConstants.HTTP_PORT);
-//                                     Object httpsPort = config.get(JettyHttpConstants.HTTPS_PORT);
-//                                     log.info(httpPortsMsg(httpPort, httpsPort));
-//
-//                                     // Explicitly starts Jetty OSGi HTTP bundle, so that it gets triggered if OSGi
-//                                     // configuration is not cleaned
-//                                     FrameworkUtil.getBundle(JettyConfigurator.class).start();
-//                                     return;
-//                             } catch (IllegalStateException e) {
-//                                     // e.printStackTrace();
-//                                     // Jetty may not be ready
-//                                     try {
-//                                             Thread.sleep(1000);
-//                                     } catch (Exception e1) {
-//                                             // silent
-//                                     }
-//                                     tryCount--;
-//                             }
-//                     }
-//                     long duration = System.currentTimeMillis() - begin;
-//                     log.error("Gave up with starting Jetty server after " + (duration / 1000) + " s");
-//             } catch (Exception e) {
-//                     log.error("Cannot start default Jetty server with config " + properties, e);
-//             }
-
-       }
-
-       private String httpPortsMsg(Object httpPort, Object httpsPort) {
-               return (httpPort != null ? "HTTP " + httpPort + " " : " ") + (httpsPort != null ? "HTTPS " + httpsPort : "");
-       }
-
-       /** Override the provided config with the framework properties */
-       public Dictionary<String, Object> getHttpServerConfig() {
-               String httpPort = getFrameworkProp(CmsDeployProperty.HTTP_PORT);
-               String httpsPort = getFrameworkProp(CmsDeployProperty.HTTPS_PORT);
-               /// TODO make it more generic
-               String httpHost = getFrameworkProp(CmsDeployProperty.HOST);
-//             String httpsHost = getFrameworkProp(
-//                             JettyConfig.JETTY_PROPERTY_PREFIX + CmsHttpConstants.HTTPS_HOST);
-               String webSocketEnabled = getFrameworkProp(CmsDeployProperty.WEBSOCKET_ENABLED);
-
-               final Hashtable<String, Object> props = new Hashtable<String, Object>();
-               // try {
-               if (httpPort != null || httpsPort != null) {
-                       boolean httpEnabled = httpPort != null;
-                       props.put(JettyHttpConstants.HTTP_ENABLED, httpEnabled);
-                       boolean httpsEnabled = httpsPort != null;
-                       props.put(JettyHttpConstants.HTTPS_ENABLED, httpsEnabled);
-
-                       if (httpEnabled) {
-                               props.put(JettyHttpConstants.HTTP_PORT, httpPort);
-                               if (httpHost != null)
-                                       props.put(JettyHttpConstants.HTTP_HOST, httpHost);
-                       }
-
-                       if (httpsEnabled) {
-                               props.put(JettyHttpConstants.HTTPS_PORT, httpsPort);
-                               if (httpHost != null)
-                                       props.put(JettyHttpConstants.HTTPS_HOST, httpHost);
-
-                               // keystore
-                               props.put(JettyHttpConstants.SSL_KEYSTORETYPE, getFrameworkProp(CmsDeployProperty.SSL_KEYSTORETYPE));
-                               props.put(JettyHttpConstants.SSL_KEYSTORE, getFrameworkProp(CmsDeployProperty.SSL_KEYSTORE));
-                               props.put(JettyHttpConstants.SSL_PASSWORD, getFrameworkProp(CmsDeployProperty.SSL_PASSWORD));
-
-                               // truststore
-                               props.put(JettyHttpConstants.SSL_TRUSTSTORETYPE,
-                                               getFrameworkProp(CmsDeployProperty.SSL_TRUSTSTORETYPE));
-                               props.put(JettyHttpConstants.SSL_TRUSTSTORE, getFrameworkProp(CmsDeployProperty.SSL_TRUSTSTORE));
-                               props.put(JettyHttpConstants.SSL_TRUSTSTOREPASSWORD,
-                                               getFrameworkProp(CmsDeployProperty.SSL_TRUSTSTOREPASSWORD));
-
-                               // client certificate authentication
-                               String wantClientAuth = getFrameworkProp(CmsDeployProperty.SSL_WANTCLIENTAUTH);
-                               if (wantClientAuth != null)
-                                       props.put(JettyHttpConstants.SSL_WANTCLIENTAUTH, Boolean.parseBoolean(wantClientAuth));
-                               String needClientAuth = getFrameworkProp(CmsDeployProperty.SSL_NEEDCLIENTAUTH);
-                               if (needClientAuth != null)
-                                       props.put(JettyHttpConstants.SSL_NEEDCLIENTAUTH, Boolean.parseBoolean(needClientAuth));
-                       }
-
-                       // web socket
-                       if (webSocketEnabled != null && webSocketEnabled.equals("true"))
-                               props.put(CmsDeployProperty.WEBSOCKET_ENABLED.getProperty(), true);
-
-                       props.put(CmsConstants.CN, CmsConstants.DEFAULT);
-               }
-               return props;
-       }
-
-       private String getFrameworkProp(CmsDeployProperty deployProperty) {
-               return cmsState.getDeployProperty(deployProperty.getProperty());
-       }
-
-       public void setCmsState(CmsState cmsState) {
-               this.cmsState = cmsState;
-       }
-
-}
diff --git a/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyHttpConstants.java b/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyHttpConstants.java
deleted file mode 100644 (file)
index 8ceb358..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-package org.argeo.cms.servlet.internal.jetty;
-
-/** Compatible with Jetty. */
-interface JettyHttpConstants {
-       static final String HTTP_ENABLED = "http.enabled";
-       static final String HTTP_PORT = "http.port";
-       static final String HTTP_HOST = "http.host";
-       static final String HTTPS_ENABLED = "https.enabled";
-       static final String HTTPS_HOST = "https.host";
-       static final String HTTPS_PORT = "https.port";
-       static final String SSL_KEYSTORE = "ssl.keystore";
-       static final String SSL_PASSWORD = "ssl.password";
-       static final String SSL_KEYPASSWORD = "ssl.keypassword";
-       static final String SSL_NEEDCLIENTAUTH = "ssl.needclientauth";
-       static final String SSL_WANTCLIENTAUTH = "ssl.wantclientauth";
-       static final String SSL_PROTOCOL = "ssl.protocol";
-       static final String SSL_ALGORITHM = "ssl.algorithm";
-       static final String SSL_KEYSTORETYPE = "ssl.keystoretype";
-
-       // Argeo
-       static final String SSL_TRUSTSTORE = "ssl.truststore";
-       static final String SSL_TRUSTSTOREPASSWORD = "ssl.truststorepassword";
-       static final String SSL_TRUSTSTORETYPE = "ssl.truststoretype";
-
-}
diff --git a/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/CmsJettyCustomizer.java b/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/CmsJettyCustomizer.java
deleted file mode 100644 (file)
index 7be23fc..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-package org.argeo.equinox.jetty;
-
-import java.util.Dictionary;
-
-import javax.servlet.ServletContext;
-import javax.websocket.DeploymentException;
-import javax.websocket.server.ServerContainer;
-
-import org.eclipse.equinox.http.jetty.JettyCustomizer;
-import org.eclipse.jetty.server.ConnectionFactory;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.server.SslConnectionFactory;
-import org.eclipse.jetty.servlet.ServletContextHandler;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
-import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
-import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer.Configurator;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-
-/** Customises the Jetty HTTP server. */
-public class CmsJettyCustomizer extends JettyCustomizer {
-       static final String SSL_TRUSTSTORE = "ssl.truststore";
-       static final String SSL_TRUSTSTOREPASSWORD = "ssl.truststorepassword";
-       static final String SSL_TRUSTSTORETYPE = "ssl.truststoretype";
-
-       private BundleContext bc = FrameworkUtil.getBundle(CmsJettyCustomizer.class).getBundleContext();
-
-       public final static String WEBSOCKET_ENABLED = "argeo.websocket.enabled";
-
-       @Override
-       public Object customizeContext(Object context, Dictionary<String, ?> settings) {
-               // WebSocket
-               Object webSocketEnabled = settings.get(WEBSOCKET_ENABLED);
-               if (webSocketEnabled != null && webSocketEnabled.toString().equals("true")) {
-                       ServletContextHandler servletContextHandler = (ServletContextHandler) context;
-                       JavaxWebSocketServletContainerInitializer.configure(servletContextHandler, new Configurator() {
-
-                               @Override
-                               public void accept(ServletContext servletContext, ServerContainer serverContainer)
-                                               throws DeploymentException {
-                                       bc.registerService(javax.websocket.server.ServerContainer.class, serverContainer, null);
-                               }
-                       });
-               }
-               return super.customizeContext(context, settings);
-
-       }
-
-       @Override
-       public Object customizeHttpsConnector(Object connector, Dictionary<String, ?> settings) {
-               ServerConnector httpsConnector = (ServerConnector) connector;
-               if (httpsConnector != null)
-                       for (ConnectionFactory connectionFactory : httpsConnector.getConnectionFactories()) {
-                               if (connectionFactory instanceof SslConnectionFactory) {
-                                       SslContextFactory.Server sslContextFactory = ((SslConnectionFactory) connectionFactory)
-                                                       .getSslContextFactory();
-                                       sslContextFactory.setTrustStorePath((String) settings.get(SSL_TRUSTSTORE));
-                                       sslContextFactory.setTrustStoreType((String) settings.get(SSL_TRUSTSTORETYPE));
-                                       sslContextFactory.setTrustStorePassword((String) settings.get(SSL_TRUSTSTOREPASSWORD));
-                               }
-                       }
-               return super.customizeHttpsConnector(connector, settings);
-       }
-
-}
diff --git a/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/package-info.java b/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/package-info.java
deleted file mode 100644 (file)
index 41c8ce9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-/** Equinox Jetty extensions. */
-package org.argeo.equinox.jetty;
\ No newline at end of file
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/.classpath b/osgi/equinox/org.argeo.cms.lib.equinox/.classpath
new file mode 100644 (file)
index 0000000..81fe078
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/.gitignore b/osgi/equinox/org.argeo.cms.lib.equinox/.gitignore
new file mode 100644 (file)
index 0000000..09e3bc9
--- /dev/null
@@ -0,0 +1,2 @@
+/bin/
+/target/
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/.project b/osgi/equinox/org.argeo.cms.lib.equinox/.project
new file mode 100644 (file)
index 0000000..c551d5d
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>org.argeo.cms.lib.equinox</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ManifestBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.SchemaBuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.eclipse.pde.ds.core.builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.pde.PluginNature</nature>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/META-INF/.gitignore b/osgi/equinox/org.argeo.cms.lib.equinox/META-INF/.gitignore
new file mode 100644 (file)
index 0000000..4854a41
--- /dev/null
@@ -0,0 +1 @@
+/MANIFEST.MF
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/OSGI-INF/jettyServiceFactory.xml b/osgi/equinox/org.argeo.cms.lib.equinox/OSGI-INF/jettyServiceFactory.xml
new file mode 100644 (file)
index 0000000..6a13362
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" activate="start" deactivate="stop" name="Jetty Service Factory">
+   <implementation class="org.argeo.cms.equinox.http.jetty.EquinoxJettyServer"/>
+   <property name="service.pid" type="String" value="org.argeo.equinox.jetty.config"/>
+   <reference bind="setCmsState" cardinality="1..1" interface="org.argeo.api.cms.CmsState" name="CmsState" policy="static"/>
+   <service>
+      <provide interface="com.sun.net.httpserver.HttpServer"/>
+   </service>
+</scr:component>
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/bnd.bnd b/osgi/equinox/org.argeo.cms.lib.equinox/bnd.bnd
new file mode 100644 (file)
index 0000000..2c83158
--- /dev/null
@@ -0,0 +1,2 @@
+Service-Component: \
+OSGI-INF/jettyServiceFactory.xml,\
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/build.properties b/osgi/equinox/org.argeo.cms.lib.equinox/build.properties
new file mode 100644 (file)
index 0000000..34d2e4d
--- /dev/null
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/equinox/http/jetty/EquinoxJettyServer.java b/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/equinox/http/jetty/EquinoxJettyServer.java
new file mode 100644 (file)
index 0000000..e6595a0
--- /dev/null
@@ -0,0 +1,151 @@
+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);
+                       }
+               }
+       }
+
+}
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyConfig.java b/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyConfig.java
new file mode 100644 (file)
index 0000000..50be8b7
--- /dev/null
@@ -0,0 +1,231 @@
+package org.argeo.cms.servlet.internal.jetty;
+
+import java.io.File;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.concurrent.ForkJoinPool;
+
+import javax.websocket.DeploymentException;
+import javax.websocket.server.ServerContainer;
+import javax.websocket.server.ServerEndpointConfig;
+
+import org.argeo.api.cms.CmsConstants;
+import org.argeo.api.cms.CmsLog;
+import org.argeo.api.cms.CmsState;
+import org.argeo.cms.CmsDeployProperty;
+import org.argeo.cms.websocket.server.CmsWebSocketConfigurator;
+import org.argeo.cms.websocket.server.TestEndpoint;
+import org.argeo.util.LangUtils;
+import org.eclipse.equinox.http.jetty.JettyConfigurator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class JettyConfig {
+       private final static CmsLog log = CmsLog.getLog(JettyConfig.class);
+
+       final static String CMS_JETTY_CUSTOMIZER_CLASS = "org.argeo.equinox.jetty.CmsJettyCustomizer";
+
+       private CmsState cmsState;
+
+       private final BundleContext bc = FrameworkUtil.getBundle(JettyConfig.class).getBundleContext();
+
+       // private static final String JETTY_PROPERTY_PREFIX =
+       // "org.eclipse.equinox.http.jetty.";
+
+       public void start() {
+               // We need to start asynchronously so that Jetty bundle get started by lazy init
+               // due to the non-configurable behaviour of its activator
+               ForkJoinPool.commonPool().execute(() -> {
+                       Dictionary<String, Object> properties = getHttpServerConfig();
+                       startServer(properties);
+               });
+
+               ServiceTracker<ServerContainer, ServerContainer> serverSt = new ServiceTracker<ServerContainer, ServerContainer>(
+                               bc, ServerContainer.class, null) {
+
+                       @Override
+                       public ServerContainer addingService(ServiceReference<ServerContainer> reference) {
+                               ServerContainer serverContainer = super.addingService(reference);
+
+                               BundleContext bc = reference.getBundle().getBundleContext();
+                               ServiceReference<ServerEndpointConfig.Configurator> srConfigurator = bc
+                                               .getServiceReference(ServerEndpointConfig.Configurator.class);
+                               ServerEndpointConfig.Configurator endpointConfigurator = bc.getService(srConfigurator);
+                               ServerEndpointConfig config = ServerEndpointConfig.Builder
+                                               .create(TestEndpoint.class, "/ws/test/events/").configurator(endpointConfigurator).build();
+                               try {
+                                       serverContainer.addEndpoint(config);
+                               } catch (DeploymentException e) {
+                                       throw new IllegalStateException("Cannot initalise the WebSocket server runtime.", e);
+                               }
+                               return serverContainer;
+                       }
+
+               };
+               serverSt.open();
+
+               // check initialisation
+//             ServiceTracker<?, ?> httpSt = new ServiceTracker<HttpService, HttpService>(bc, HttpService.class, null) {
+//
+//                     @Override
+//                     public HttpService addingService(ServiceReference<HttpService> sr) {
+//                             Object httpPort = sr.getProperty("http.port");
+//                             Object httpsPort = sr.getProperty("https.port");
+//                             log.info(httpPortsMsg(httpPort, httpsPort));
+//                             close();
+//                             return super.addingService(sr);
+//                     }
+//             };
+//             httpSt.open();
+       }
+
+       public void stop() {
+               try {
+                       JettyConfigurator.stopServer(CmsConstants.DEFAULT);
+               } catch (Exception e) {
+                       log.error("Cannot stop default Jetty server.", e);
+               }
+
+       }
+
+       public void startServer(Dictionary<String, Object> properties) {
+               // Explicitly configures Jetty so that the default server is not started by the
+               // activator of the Equinox Jetty bundle.
+               Map<String, String> config = LangUtils.dictToStringMap(properties);
+               if (!config.isEmpty()) {
+                       config.put("customizer.class", CMS_JETTY_CUSTOMIZER_CLASS);
+
+                       // TODO centralise with Jetty extender
+                       Object webSocketEnabled = config.get(CmsDeployProperty.WEBSOCKET_ENABLED.getProperty());
+                       if (webSocketEnabled != null && webSocketEnabled.toString().equals("true")) {
+                               bc.registerService(ServerEndpointConfig.Configurator.class, new CmsWebSocketConfigurator(), null);
+                               // config.put(WEBSOCKET_ENABLED, "true");
+                       }
+               }
+
+               properties.put(Constants.SERVICE_PID, "default");
+               File jettyWorkDir = new File(bc.getDataFile(""), "jettywork"); //$NON-NLS-1$
+               jettyWorkDir.mkdir();
+
+//             HttpServerManager serverManager = new HttpServerManager(jettyWorkDir);
+//             try {
+//                     serverManager.updated("default", properties);
+//             } catch (ConfigurationException e) {
+//                     // TODO Auto-generated catch block
+//                     e.printStackTrace();
+//             }
+               Object httpPort = config.get(JettyHttpConstants.HTTP_PORT);
+               Object httpsPort = config.get(JettyHttpConstants.HTTPS_PORT);
+               log.info(httpPortsMsg(httpPort, httpsPort));
+
+//             long begin = System.currentTimeMillis();
+//             int tryCount = 60;
+//             try {
+//                     while (tryCount > 0) {
+//                             try {
+//                                     // FIXME deal with multiple ids
+//                                     JettyConfigurator.startServer(CmsConstants.DEFAULT, new Hashtable<>(config));
+//
+//                                     Object httpPort = config.get(JettyHttpConstants.HTTP_PORT);
+//                                     Object httpsPort = config.get(JettyHttpConstants.HTTPS_PORT);
+//                                     log.info(httpPortsMsg(httpPort, httpsPort));
+//
+//                                     // Explicitly starts Jetty OSGi HTTP bundle, so that it gets triggered if OSGi
+//                                     // configuration is not cleaned
+//                                     FrameworkUtil.getBundle(JettyConfigurator.class).start();
+//                                     return;
+//                             } catch (IllegalStateException e) {
+//                                     // e.printStackTrace();
+//                                     // Jetty may not be ready
+//                                     try {
+//                                             Thread.sleep(1000);
+//                                     } catch (Exception e1) {
+//                                             // silent
+//                                     }
+//                                     tryCount--;
+//                             }
+//                     }
+//                     long duration = System.currentTimeMillis() - begin;
+//                     log.error("Gave up with starting Jetty server after " + (duration / 1000) + " s");
+//             } catch (Exception e) {
+//                     log.error("Cannot start default Jetty server with config " + properties, e);
+//             }
+
+       }
+
+       private String httpPortsMsg(Object httpPort, Object httpsPort) {
+               return (httpPort != null ? "HTTP " + httpPort + " " : " ") + (httpsPort != null ? "HTTPS " + httpsPort : "");
+       }
+
+       /** Override the provided config with the framework properties */
+       public Dictionary<String, Object> getHttpServerConfig() {
+               String httpPort = getFrameworkProp(CmsDeployProperty.HTTP_PORT);
+               String httpsPort = getFrameworkProp(CmsDeployProperty.HTTPS_PORT);
+               /// TODO make it more generic
+               String httpHost = getFrameworkProp(CmsDeployProperty.HOST);
+//             String httpsHost = getFrameworkProp(
+//                             JettyConfig.JETTY_PROPERTY_PREFIX + CmsHttpConstants.HTTPS_HOST);
+               String webSocketEnabled = getFrameworkProp(CmsDeployProperty.WEBSOCKET_ENABLED);
+
+               final Hashtable<String, Object> props = new Hashtable<String, Object>();
+               // try {
+               if (httpPort != null || httpsPort != null) {
+                       boolean httpEnabled = httpPort != null;
+                       props.put(JettyHttpConstants.HTTP_ENABLED, httpEnabled);
+                       boolean httpsEnabled = httpsPort != null;
+                       props.put(JettyHttpConstants.HTTPS_ENABLED, httpsEnabled);
+
+                       if (httpEnabled) {
+                               props.put(JettyHttpConstants.HTTP_PORT, httpPort);
+                               if (httpHost != null)
+                                       props.put(JettyHttpConstants.HTTP_HOST, httpHost);
+                       }
+
+                       if (httpsEnabled) {
+                               props.put(JettyHttpConstants.HTTPS_PORT, httpsPort);
+                               if (httpHost != null)
+                                       props.put(JettyHttpConstants.HTTPS_HOST, httpHost);
+
+                               // keystore
+                               props.put(JettyHttpConstants.SSL_KEYSTORETYPE, getFrameworkProp(CmsDeployProperty.SSL_KEYSTORETYPE));
+                               props.put(JettyHttpConstants.SSL_KEYSTORE, getFrameworkProp(CmsDeployProperty.SSL_KEYSTORE));
+                               props.put(JettyHttpConstants.SSL_PASSWORD, getFrameworkProp(CmsDeployProperty.SSL_PASSWORD));
+
+                               // truststore
+                               props.put(JettyHttpConstants.SSL_TRUSTSTORETYPE,
+                                               getFrameworkProp(CmsDeployProperty.SSL_TRUSTSTORETYPE));
+                               props.put(JettyHttpConstants.SSL_TRUSTSTORE, getFrameworkProp(CmsDeployProperty.SSL_TRUSTSTORE));
+                               props.put(JettyHttpConstants.SSL_TRUSTSTOREPASSWORD,
+                                               getFrameworkProp(CmsDeployProperty.SSL_TRUSTSTOREPASSWORD));
+
+                               // client certificate authentication
+                               String wantClientAuth = getFrameworkProp(CmsDeployProperty.SSL_WANTCLIENTAUTH);
+                               if (wantClientAuth != null)
+                                       props.put(JettyHttpConstants.SSL_WANTCLIENTAUTH, Boolean.parseBoolean(wantClientAuth));
+                               String needClientAuth = getFrameworkProp(CmsDeployProperty.SSL_NEEDCLIENTAUTH);
+                               if (needClientAuth != null)
+                                       props.put(JettyHttpConstants.SSL_NEEDCLIENTAUTH, Boolean.parseBoolean(needClientAuth));
+                       }
+
+                       // web socket
+                       if (webSocketEnabled != null && webSocketEnabled.equals("true"))
+                               props.put(CmsDeployProperty.WEBSOCKET_ENABLED.getProperty(), true);
+
+                       props.put(CmsConstants.CN, CmsConstants.DEFAULT);
+               }
+               return props;
+       }
+
+       private String getFrameworkProp(CmsDeployProperty deployProperty) {
+               return cmsState.getDeployProperty(deployProperty.getProperty());
+       }
+
+       public void setCmsState(CmsState cmsState) {
+               this.cmsState = cmsState;
+       }
+
+}
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyHttpConstants.java b/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/cms/servlet/internal/jetty/JettyHttpConstants.java
new file mode 100644 (file)
index 0000000..8ceb358
--- /dev/null
@@ -0,0 +1,25 @@
+package org.argeo.cms.servlet.internal.jetty;
+
+/** Compatible with Jetty. */
+interface JettyHttpConstants {
+       static final String HTTP_ENABLED = "http.enabled";
+       static final String HTTP_PORT = "http.port";
+       static final String HTTP_HOST = "http.host";
+       static final String HTTPS_ENABLED = "https.enabled";
+       static final String HTTPS_HOST = "https.host";
+       static final String HTTPS_PORT = "https.port";
+       static final String SSL_KEYSTORE = "ssl.keystore";
+       static final String SSL_PASSWORD = "ssl.password";
+       static final String SSL_KEYPASSWORD = "ssl.keypassword";
+       static final String SSL_NEEDCLIENTAUTH = "ssl.needclientauth";
+       static final String SSL_WANTCLIENTAUTH = "ssl.wantclientauth";
+       static final String SSL_PROTOCOL = "ssl.protocol";
+       static final String SSL_ALGORITHM = "ssl.algorithm";
+       static final String SSL_KEYSTORETYPE = "ssl.keystoretype";
+
+       // Argeo
+       static final String SSL_TRUSTSTORE = "ssl.truststore";
+       static final String SSL_TRUSTSTOREPASSWORD = "ssl.truststorepassword";
+       static final String SSL_TRUSTSTORETYPE = "ssl.truststoretype";
+
+}
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/CmsJettyCustomizer.java b/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/CmsJettyCustomizer.java
new file mode 100644 (file)
index 0000000..7be23fc
--- /dev/null
@@ -0,0 +1,65 @@
+package org.argeo.equinox.jetty;
+
+import java.util.Dictionary;
+
+import javax.servlet.ServletContext;
+import javax.websocket.DeploymentException;
+import javax.websocket.server.ServerContainer;
+
+import org.eclipse.equinox.http.jetty.JettyCustomizer;
+import org.eclipse.jetty.server.ConnectionFactory;
+import org.eclipse.jetty.server.ServerConnector;
+import org.eclipse.jetty.server.SslConnectionFactory;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.util.ssl.SslContextFactory;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
+import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer.Configurator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+
+/** Customises the Jetty HTTP server. */
+public class CmsJettyCustomizer extends JettyCustomizer {
+       static final String SSL_TRUSTSTORE = "ssl.truststore";
+       static final String SSL_TRUSTSTOREPASSWORD = "ssl.truststorepassword";
+       static final String SSL_TRUSTSTORETYPE = "ssl.truststoretype";
+
+       private BundleContext bc = FrameworkUtil.getBundle(CmsJettyCustomizer.class).getBundleContext();
+
+       public final static String WEBSOCKET_ENABLED = "argeo.websocket.enabled";
+
+       @Override
+       public Object customizeContext(Object context, Dictionary<String, ?> settings) {
+               // WebSocket
+               Object webSocketEnabled = settings.get(WEBSOCKET_ENABLED);
+               if (webSocketEnabled != null && webSocketEnabled.toString().equals("true")) {
+                       ServletContextHandler servletContextHandler = (ServletContextHandler) context;
+                       JavaxWebSocketServletContainerInitializer.configure(servletContextHandler, new Configurator() {
+
+                               @Override
+                               public void accept(ServletContext servletContext, ServerContainer serverContainer)
+                                               throws DeploymentException {
+                                       bc.registerService(javax.websocket.server.ServerContainer.class, serverContainer, null);
+                               }
+                       });
+               }
+               return super.customizeContext(context, settings);
+
+       }
+
+       @Override
+       public Object customizeHttpsConnector(Object connector, Dictionary<String, ?> settings) {
+               ServerConnector httpsConnector = (ServerConnector) connector;
+               if (httpsConnector != null)
+                       for (ConnectionFactory connectionFactory : httpsConnector.getConnectionFactories()) {
+                               if (connectionFactory instanceof SslConnectionFactory) {
+                                       SslContextFactory.Server sslContextFactory = ((SslConnectionFactory) connectionFactory)
+                                                       .getSslContextFactory();
+                                       sslContextFactory.setTrustStorePath((String) settings.get(SSL_TRUSTSTORE));
+                                       sslContextFactory.setTrustStoreType((String) settings.get(SSL_TRUSTSTORETYPE));
+                                       sslContextFactory.setTrustStorePassword((String) settings.get(SSL_TRUSTSTOREPASSWORD));
+                               }
+                       }
+               return super.customizeHttpsConnector(connector, settings);
+       }
+
+}
diff --git a/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/package-info.java b/osgi/equinox/org.argeo.cms.lib.equinox/src/org/argeo/equinox/jetty/package-info.java
new file mode 100644 (file)
index 0000000..41c8ce9
--- /dev/null
@@ -0,0 +1,2 @@
+/** Equinox Jetty extensions. */
+package org.argeo.equinox.jetty;
\ No newline at end of file