]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms.lib.jetty/src/org/argeo/cms/jetty/JettyHttpServer.java
Fix SSHD packages.
[lgpl/argeo-commons.git] / org.argeo.cms.lib.jetty / src / org / argeo / cms / jetty / JettyHttpServer.java
1 package org.argeo.cms.jetty;
2
3 import java.io.IOException;
4 import java.net.InetSocketAddress;
5 import java.util.Map;
6 import java.util.TreeMap;
7 import java.util.concurrent.Executor;
8 import java.util.concurrent.ThreadPoolExecutor;
9
10 import javax.servlet.ServletException;
11
12 import org.argeo.api.cms.CmsLog;
13 import org.argeo.cms.CmsDeployProperty;
14 import org.argeo.util.http.HttpServerUtils;
15 import org.eclipse.jetty.http.UriCompliance;
16 import org.eclipse.jetty.server.HttpConfiguration;
17 import org.eclipse.jetty.server.HttpConnectionFactory;
18 import org.eclipse.jetty.server.SecureRequestCustomizer;
19 import org.eclipse.jetty.server.Server;
20 import org.eclipse.jetty.server.ServerConnector;
21 import org.eclipse.jetty.server.SslConnectionFactory;
22 import org.eclipse.jetty.server.handler.ContextHandlerCollection;
23 import org.eclipse.jetty.servlet.ServletContextHandler;
24 import org.eclipse.jetty.util.ssl.SslContextFactory;
25 import org.eclipse.jetty.util.thread.ExecutorThreadPool;
26 import org.eclipse.jetty.util.thread.QueuedThreadPool;
27 import org.eclipse.jetty.util.thread.ThreadPool;
28
29 import com.sun.net.httpserver.HttpContext;
30 import com.sun.net.httpserver.HttpHandler;
31 import com.sun.net.httpserver.HttpsConfigurator;
32 import com.sun.net.httpserver.HttpsServer;
33
34 public class JettyHttpServer extends HttpsServer {
35 private final static CmsLog log = CmsLog.getLog(JettyHttpServer.class);
36
37 private static final int DEFAULT_IDLE_TIMEOUT = 30000;
38
39 private Server server;
40
41 protected ServerConnector httpConnector;
42 protected ServerConnector httpsConnector;
43
44 private InetSocketAddress address;
45
46 private ThreadPoolExecutor executor;
47
48 private HttpsConfigurator httpsConfigurator;
49
50 private final Map<String, JettyHttpContext> contexts = new TreeMap<>();
51
52 protected final ContextHandlerCollection contextHandlerCollection = new ContextHandlerCollection();
53
54 private boolean started;
55
56 @Override
57 public void bind(InetSocketAddress addr, int backlog) throws IOException {
58 throw new UnsupportedOperationException();
59 }
60
61 @Override
62 public void start() {
63 try {
64
65 ThreadPool threadPool = null;
66 if (executor != null) {
67 threadPool = new ExecutorThreadPool(executor);
68 } else {
69 // TODO make it configurable
70 threadPool = new QueuedThreadPool(10, 1);
71 }
72
73 server = new Server(threadPool);
74
75 configureConnectors();
76
77 if (httpConnector != null) {
78 httpConnector.open();
79 server.addConnector(httpConnector);
80 }
81
82 if (httpsConnector != null) {
83 httpsConnector.open();
84 server.addConnector(httpsConnector);
85 }
86
87 // holder
88
89 // context
90 ServletContextHandler rootContextHandler = createRootContextHandler();
91 // httpContext.addServlet(holder, "/*");
92 if (rootContextHandler != null)
93 configureRootContextHandler(rootContextHandler);
94 // server.setHandler(rootContextHandler);
95
96 // ContextHandlerCollection contextHandlers = new ContextHandlerCollection();
97 if (rootContextHandler != null && !contexts.containsKey("/"))
98 contextHandlerCollection.addHandler(rootContextHandler);
99 // for (String contextPath : contexts.keySet()) {
100 // JettyHttpContext ctx = contexts.get(contextPath);
101 // contextHandlers.addHandler(ctx.getContextHandler());
102 // }
103
104 server.setHandler(contextHandlerCollection);
105
106 //
107 // START
108 server.start();
109 //
110
111 Runtime.getRuntime().addShutdownHook(new Thread(() -> stop(), "Jetty shutdown"));
112
113 log.info(httpPortsMsg());
114 started = true;
115 } catch (Exception e) {
116 throw new IllegalStateException("Cannot start Jetty HTTPS server", e);
117 }
118 }
119
120 @Override
121 public void stop(int delay) {
122 // TODO wait for processing to complete
123 stop();
124
125 }
126
127 public void stop() {
128 try {
129 // serverConnector.close();
130 server.stop();
131 // TODO delete temp dir
132 started = false;
133 } catch (Exception e) {
134 e.printStackTrace();
135 }
136
137 }
138
139 @Override
140 public void setExecutor(Executor executor) {
141 if (!(executor instanceof ThreadPoolExecutor))
142 throw new IllegalArgumentException("Only " + ThreadPoolExecutor.class.getName() + " are supported");
143 this.executor = (ThreadPoolExecutor) executor;
144 }
145
146 @Override
147 public Executor getExecutor() {
148 return executor;
149 }
150
151 @Override
152 public synchronized HttpContext createContext(String path, HttpHandler handler) {
153 HttpContext httpContext = createContext(path);
154 httpContext.setHandler(handler);
155 return httpContext;
156 }
157
158 @Override
159 public synchronized HttpContext createContext(String path) {
160 if (contexts.containsKey(path))
161 throw new IllegalArgumentException("Context " + path + " already exists");
162 JettyHttpContext httpContext = new JettyHttpContext(this, path);
163 contexts.put(path, httpContext);
164
165 contextHandlerCollection.addHandler(httpContext.getContextHandler());
166 return httpContext;
167 }
168
169 @Override
170 public synchronized void removeContext(String path) throws IllegalArgumentException {
171 if (!contexts.containsKey(path))
172 throw new IllegalArgumentException("Context " + path + " does not exist");
173 JettyHttpContext httpContext = contexts.remove(path);
174 // TODO stop handler first?
175 contextHandlerCollection.removeHandler(httpContext.getContextHandler());
176 }
177
178 @Override
179 public synchronized void removeContext(HttpContext context) {
180 removeContext(context.getPath());
181 }
182
183 @Override
184 public InetSocketAddress getAddress() {
185 return address;
186 }
187
188 @Override
189 public void setHttpsConfigurator(HttpsConfigurator config) {
190 this.httpsConfigurator = config;
191 }
192
193 @Override
194 public HttpsConfigurator getHttpsConfigurator() {
195 return httpsConfigurator;
196 }
197
198
199
200 protected void configureConnectors() {
201 HttpConfiguration httpConfiguration = new HttpConfiguration();
202
203 String httpPortStr = getDeployProperty(CmsDeployProperty.HTTP_PORT);
204 String httpsPortStr = getDeployProperty(CmsDeployProperty.HTTPS_PORT);
205
206 /// TODO make it more generic
207 String httpHost = getDeployProperty(CmsDeployProperty.HOST);
208 // String httpsHost = getFrameworkProp(
209 // JettyConfig.JETTY_PROPERTY_PREFIX + CmsHttpConstants.HTTPS_HOST);
210
211 // try {
212 if (httpPortStr != null || httpsPortStr != null) {
213 boolean httpEnabled = httpPortStr != null;
214 // props.put(JettyHttpConstants.HTTP_ENABLED, httpEnabled);
215 boolean httpsEnabled = httpsPortStr != null;
216 // props.put(JettyHttpConstants.HTTPS_ENABLED, httpsEnabled);
217 if (httpsEnabled) {
218 int httpsPort = Integer.parseInt(httpsPortStr);
219 httpConfiguration.setSecureScheme("https");
220 httpConfiguration.setSecurePort(httpsPort);
221 }
222
223 if (httpEnabled) {
224 int httpPort = Integer.parseInt(httpPortStr);
225 httpConnector = new ServerConnector(server, new HttpConnectionFactory(httpConfiguration));
226 httpConnector.setPort(httpPort);
227 httpConnector.setHost(httpHost);
228 httpConnector.setIdleTimeout(DEFAULT_IDLE_TIMEOUT);
229 }
230
231 if (httpsEnabled) {
232
233 SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
234 // sslContextFactory.setKeyStore(KeyS)
235
236 sslContextFactory.setKeyStoreType(getDeployProperty(CmsDeployProperty.SSL_KEYSTORETYPE));
237 sslContextFactory.setKeyStorePath(getDeployProperty(CmsDeployProperty.SSL_KEYSTORE));
238 sslContextFactory.setKeyStorePassword(getDeployProperty(CmsDeployProperty.SSL_PASSWORD));
239 // sslContextFactory.setKeyManagerPassword(getFrameworkProp(CmsDeployProperty.SSL_KEYPASSWORD));
240 sslContextFactory.setProtocol("TLS");
241
242 sslContextFactory.setTrustStoreType(getDeployProperty(CmsDeployProperty.SSL_TRUSTSTORETYPE));
243 sslContextFactory.setTrustStorePath(getDeployProperty(CmsDeployProperty.SSL_TRUSTSTORE));
244 sslContextFactory.setTrustStorePassword(getDeployProperty(CmsDeployProperty.SSL_TRUSTSTOREPASSWORD));
245
246 String wantClientAuth = getDeployProperty(CmsDeployProperty.SSL_WANTCLIENTAUTH);
247 if (wantClientAuth != null && wantClientAuth.equals(Boolean.toString(true)))
248 sslContextFactory.setWantClientAuth(true);
249 String needClientAuth = getDeployProperty(CmsDeployProperty.SSL_NEEDCLIENTAUTH);
250 if (needClientAuth != null && needClientAuth.equals(Boolean.toString(true)))
251 sslContextFactory.setNeedClientAuth(true);
252
253 // HTTPS Configuration
254 HttpConfiguration https_config = new HttpConfiguration(httpConfiguration);
255 https_config.addCustomizer(new SecureRequestCustomizer());
256 https_config.setUriCompliance(UriCompliance.LEGACY);
257
258 // HTTPS connector
259 httpsConnector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, "http/1.1"),
260 new HttpConnectionFactory(https_config));
261 int httpsPort = Integer.parseInt(httpsPortStr);
262 httpsConnector.setPort(httpsPort);
263 httpsConnector.setHost(httpHost);
264 }
265
266 }
267
268 }
269
270 protected String getDeployProperty(CmsDeployProperty deployProperty) {
271 return System.getProperty(deployProperty.getProperty());
272 }
273
274 private String httpPortsMsg() {
275
276 return (httpConnector != null ? "HTTP " + getHttpPort() + " " : " ")
277 + (httpsConnector != null ? "HTTPS " + getHttpsPort() : "");
278 }
279
280 public Integer getHttpPort() {
281 if (httpConnector == null)
282 return null;
283 return httpConnector.getLocalPort();
284 }
285
286 public Integer getHttpsPort() {
287 if (httpsConnector == null)
288 return null;
289 return httpsConnector.getLocalPort();
290 }
291
292 protected ServletContextHandler createRootContextHandler() {
293 return null;
294 }
295
296 protected void configureRootContextHandler(ServletContextHandler servletContextHandler) throws ServletException {
297
298 }
299
300
301 public boolean isStarted() {
302 return started;
303 }
304
305 public static void main(String... args) {
306 JettyHttpServer httpServer = new JettyHttpServer();
307 System.setProperty("argeo.http.port", "8080");
308 httpServer.createContext("/", (exchange) -> {
309 exchange.getResponseBody().write("Hello World!".getBytes());
310 });
311 httpServer.start();
312 httpServer.createContext("/sub/context", (exchange) -> {
313 final String key = "count";
314 Integer count = (Integer) exchange.getHttpContext().getAttributes().get(key);
315 if (count == null)
316 exchange.getHttpContext().getAttributes().put(key, 0);
317 else
318 exchange.getHttpContext().getAttributes().put(key, count + 1);
319 StringBuilder sb = new StringBuilder();
320 sb.append("Subcontext:");
321 sb.append(" " + key + "=" + exchange.getHttpContext().getAttributes().get(key));
322 sb.append(" relativePath=" + HttpServerUtils.relativize(exchange));
323 exchange.getResponseBody().write(sb.toString().getBytes());
324 });
325 }
326 }