]> git.argeo.org Git - lgpl/argeo-commons.git/blob - jetty/JettyConfig.java
Prepare next development cycle
[lgpl/argeo-commons.git] / jetty / JettyConfig.java
1 package org.argeo.cms.servlet.internal.jetty;
2
3 import java.util.Dictionary;
4 import java.util.Hashtable;
5 import java.util.Map;
6 import java.util.concurrent.ForkJoinPool;
7
8 import javax.websocket.DeploymentException;
9 import javax.websocket.server.ServerContainer;
10 import javax.websocket.server.ServerEndpointConfig;
11
12 import org.argeo.api.cms.CmsConstants;
13 import org.argeo.api.cms.CmsLog;
14 import org.argeo.api.cms.CmsState;
15 import org.argeo.cms.CmsDeployProperty;
16 import org.argeo.cms.websocket.javax.server.CmsWebSocketConfigurator;
17 import org.argeo.cms.websocket.javax.server.TestEndpoint;
18 import org.argeo.util.LangUtils;
19 import org.eclipse.equinox.http.jetty.JettyConfigurator;
20 import org.osgi.framework.BundleContext;
21 import org.osgi.framework.FrameworkUtil;
22 import org.osgi.framework.ServiceReference;
23 import org.osgi.util.tracker.ServiceTracker;
24
25 public class JettyConfig {
26 private final static CmsLog log = CmsLog.getLog(JettyConfig.class);
27
28 final static String CMS_JETTY_CUSTOMIZER_CLASS = "org.argeo.equinox.jetty.CmsJettyCustomizer";
29
30 private CmsState cmsState;
31
32 private final BundleContext bc = FrameworkUtil.getBundle(JettyConfig.class).getBundleContext();
33
34 //private static final String JETTY_PROPERTY_PREFIX = "org.eclipse.equinox.http.jetty.";
35
36 public void start() {
37 // We need to start asynchronously so that Jetty bundle get started by lazy init
38 // due to the non-configurable behaviour of its activator
39 ForkJoinPool.commonPool().execute(() -> {
40 Dictionary<String, ?> properties = getHttpServerConfig();
41 startServer(properties);
42 });
43
44 ServiceTracker<ServerContainer, ServerContainer> serverSt = new ServiceTracker<ServerContainer, ServerContainer>(
45 bc, ServerContainer.class, null) {
46
47 @Override
48 public ServerContainer addingService(ServiceReference<ServerContainer> reference) {
49 ServerContainer serverContainer = super.addingService(reference);
50
51 BundleContext bc = reference.getBundle().getBundleContext();
52 ServiceReference<ServerEndpointConfig.Configurator> srConfigurator = bc
53 .getServiceReference(ServerEndpointConfig.Configurator.class);
54 ServerEndpointConfig.Configurator endpointConfigurator = bc.getService(srConfigurator);
55 ServerEndpointConfig config = ServerEndpointConfig.Builder
56 .create(TestEndpoint.class, "/ws/test/events/").configurator(endpointConfigurator).build();
57 try {
58 serverContainer.addEndpoint(config);
59 } catch (DeploymentException e) {
60 throw new IllegalStateException("Cannot initalise the WebSocket server runtime.", e);
61 }
62 return serverContainer;
63 }
64
65 };
66 serverSt.open();
67
68 // check initialisation
69 // ServiceTracker<?, ?> httpSt = new ServiceTracker<HttpService, HttpService>(bc, HttpService.class, null) {
70 //
71 // @Override
72 // public HttpService addingService(ServiceReference<HttpService> sr) {
73 // Object httpPort = sr.getProperty("http.port");
74 // Object httpsPort = sr.getProperty("https.port");
75 // log.info(httpPortsMsg(httpPort, httpsPort));
76 // close();
77 // return super.addingService(sr);
78 // }
79 // };
80 // httpSt.open();
81 }
82
83 public void stop() {
84 try {
85 JettyConfigurator.stopServer(CmsConstants.DEFAULT);
86 } catch (Exception e) {
87 log.error("Cannot stop default Jetty server.", e);
88 }
89
90 }
91
92 public void startServer(Dictionary<String, ?> properties) {
93 // Explicitly configures Jetty so that the default server is not started by the
94 // activator of the Equinox Jetty bundle.
95 Map<String, String> config = LangUtils.dictToStringMap(properties);
96 if (!config.isEmpty()) {
97 config.put("customizer.class", CMS_JETTY_CUSTOMIZER_CLASS);
98
99 // TODO centralise with Jetty extender
100 Object webSocketEnabled = config.get(CmsDeployProperty.WEBSOCKET_ENABLED.getProperty());
101 if (webSocketEnabled != null && webSocketEnabled.toString().equals("true")) {
102 bc.registerService(ServerEndpointConfig.Configurator.class, new CmsWebSocketConfigurator(), null);
103 // config.put(WEBSOCKET_ENABLED, "true");
104 }
105 }
106
107 int tryCount = 30;
108 try {
109 tryGettyJetty: while (tryCount > 0) {
110 try {
111 // FIXME deal with multiple ids
112 JettyConfigurator.startServer(CmsConstants.DEFAULT, new Hashtable<>(config));
113
114 Object httpPort = config.get(JettyHttpConstants.HTTP_PORT);
115 Object httpsPort = config.get(JettyHttpConstants.HTTPS_PORT);
116 log.info(httpPortsMsg(httpPort, httpsPort));
117
118 // Explicitly starts Jetty OSGi HTTP bundle, so that it gets triggered if OSGi
119 // configuration is not cleaned
120 FrameworkUtil.getBundle(JettyConfigurator.class).start();
121 break tryGettyJetty;
122 } catch (IllegalStateException e) {
123 // e.printStackTrace();
124 // Jetty may not be ready
125 try {
126 Thread.sleep(1000);
127 } catch (Exception e1) {
128 // silent
129 }
130 tryCount--;
131 }
132 }
133 } catch (Exception e) {
134 log.error("Cannot start default Jetty server with config " + properties, e);
135 }
136
137 }
138
139 private String httpPortsMsg(Object httpPort, Object httpsPort) {
140 return (httpPort != null ? "HTTP " + httpPort + " " : " ") + (httpsPort != null ? "HTTPS " + httpsPort : "");
141 }
142
143 /** Override the provided config with the framework properties */
144 public Dictionary<String, Object> getHttpServerConfig() {
145 String httpPort = getFrameworkProp(CmsDeployProperty.HTTP_PORT);
146 String httpsPort = getFrameworkProp(CmsDeployProperty.HTTPS_PORT);
147 /// TODO make it more generic
148 String httpHost = getFrameworkProp(CmsDeployProperty.HOST);
149 // String httpsHost = getFrameworkProp(
150 // JettyConfig.JETTY_PROPERTY_PREFIX + CmsHttpConstants.HTTPS_HOST);
151 String webSocketEnabled = getFrameworkProp(CmsDeployProperty.WEBSOCKET_ENABLED);
152
153 final Hashtable<String, Object> props = new Hashtable<String, Object>();
154 // try {
155 if (httpPort != null || httpsPort != null) {
156 boolean httpEnabled = httpPort != null;
157 props.put(JettyHttpConstants.HTTP_ENABLED, httpEnabled);
158 boolean httpsEnabled = httpsPort != null;
159 props.put(JettyHttpConstants.HTTPS_ENABLED, httpsEnabled);
160
161 if (httpEnabled) {
162 props.put(JettyHttpConstants.HTTP_PORT, httpPort);
163 if (httpHost != null)
164 props.put(JettyHttpConstants.HTTP_HOST, httpHost);
165 }
166
167 if (httpsEnabled) {
168 props.put(JettyHttpConstants.HTTPS_PORT, httpsPort);
169 if (httpHost != null)
170 props.put(JettyHttpConstants.HTTPS_HOST, httpHost);
171
172 props.put(JettyHttpConstants.SSL_KEYSTORETYPE, getFrameworkProp(CmsDeployProperty.SSL_KEYSTORETYPE));
173 props.put(JettyHttpConstants.SSL_KEYSTORE, getFrameworkProp(CmsDeployProperty.SSL_KEYSTORE));
174 props.put(JettyHttpConstants.SSL_PASSWORD, getFrameworkProp(CmsDeployProperty.SSL_PASSWORD));
175
176 // client certificate authentication
177 String wantClientAuth = getFrameworkProp(CmsDeployProperty.SSL_WANTCLIENTAUTH);
178 if (wantClientAuth != null)
179 props.put(JettyHttpConstants.SSL_WANTCLIENTAUTH, Boolean.parseBoolean(wantClientAuth));
180 String needClientAuth = getFrameworkProp(CmsDeployProperty.SSL_NEEDCLIENTAUTH);
181 if (needClientAuth != null)
182 props.put(JettyHttpConstants.SSL_NEEDCLIENTAUTH, Boolean.parseBoolean(needClientAuth));
183 }
184
185 // web socket
186 if (webSocketEnabled != null && webSocketEnabled.equals("true"))
187 props.put(CmsDeployProperty.WEBSOCKET_ENABLED.getProperty(), true);
188
189 props.put(CmsConstants.CN, CmsConstants.DEFAULT);
190 }
191 return props;
192 }
193
194 private String getFrameworkProp(CmsDeployProperty deployProperty) {
195 return cmsState.getDeployProperty(deployProperty.getProperty());
196 }
197
198 public void setCmsState(CmsState cmsState) {
199 this.cmsState = cmsState;
200 }
201
202 }