1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.http.spi;
20
21 import java.io.IOException;
22 import java.net.InetSocketAddress;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.Map;
26 import java.util.concurrent.Executor;
27 import java.util.concurrent.ThreadPoolExecutor;
28
29 import org.eclipse.jetty.server.Connector;
30 import org.eclipse.jetty.server.Handler;
31 import org.eclipse.jetty.server.HttpConfiguration;
32 import org.eclipse.jetty.server.HttpConnectionFactory;
33 import org.eclipse.jetty.server.NetworkConnector;
34 import org.eclipse.jetty.server.Server;
35 import org.eclipse.jetty.server.ServerConnector;
36 import org.eclipse.jetty.server.handler.ContextHandler;
37 import org.eclipse.jetty.server.handler.ContextHandlerCollection;
38 import org.eclipse.jetty.server.handler.HandlerCollection;
39 import org.eclipse.jetty.util.log.Log;
40 import org.eclipse.jetty.util.log.Logger;
41 import org.eclipse.jetty.util.thread.ThreadPool;
42
43 import com.sun.net.httpserver.HttpContext;
44 import com.sun.net.httpserver.HttpHandler;
45
46
47
48
49 public class JettyHttpServer extends com.sun.net.httpserver.HttpServer
50 {
51 private static final Logger LOG = Log.getLogger(JettyHttpServer.class);
52
53 private final HttpConfiguration _httpConfiguration;
54
55 private final Server _server;
56
57 private boolean _serverShared;
58
59 private InetSocketAddress _addr;
60
61
62 private Map<String, JettyHttpContext> _contexts = new HashMap<String, JettyHttpContext>();
63
64 private Map<String, Connector> _connectors = new HashMap<String, Connector>();
65
66
67 public JettyHttpServer(Server server, boolean shared)
68 {
69 this(server,shared,new HttpConfiguration());
70 }
71
72 public JettyHttpServer(Server server, boolean shared, HttpConfiguration configuration)
73 {
74 this._server = server;
75 this._serverShared = shared;
76 this._httpConfiguration = configuration;
77 }
78
79 public HttpConfiguration getHttpConfiguration()
80 {
81 return _httpConfiguration;
82 }
83
84 @Override
85 public void bind(InetSocketAddress addr, int backlog) throws IOException
86 {
87
88 Collection<NetworkConnector> connectors = _server.getBeans(NetworkConnector.class);
89 if (connectors != null)
90 {
91 for (NetworkConnector connector : connectors)
92 {
93 if (connector.getPort() == addr.getPort()) {
94 if (LOG.isDebugEnabled()) LOG.debug("server already bound to port " + addr.getPort() + ", no need to rebind");
95 return;
96 }
97 }
98 }
99
100 if (_serverShared)
101 throw new IOException("jetty server is not bound to port " + addr.getPort());
102
103 this._addr = addr;
104
105 if (LOG.isDebugEnabled()) LOG.debug("binding server to port " + addr.getPort());
106 ServerConnector connector = new ServerConnector(_server);
107 connector.setPort(addr.getPort());
108 connector.setHost(addr.getHostName());
109 _server.addConnector(connector);
110
111 _connectors.put(addr.getHostName() + addr.getPort(), connector);
112 }
113
114 protected ServerConnector newServerConnector(InetSocketAddress addr,int backlog)
115 {
116 ServerConnector connector = new ServerConnector(_server,new HttpConnectionFactory(_httpConfiguration));
117 connector.setPort(addr.getPort());
118 connector.setHost(addr.getHostName());
119 return connector;
120 }
121
122 @Override
123 public InetSocketAddress getAddress()
124 {
125 return _addr;
126 }
127
128 @Override
129 public void start()
130 {
131 if (_serverShared) return;
132
133 try
134 {
135 _server.start();
136 }
137 catch (Exception ex)
138 {
139 throw new RuntimeException(ex);
140 }
141 }
142
143 @Override
144 public void setExecutor(Executor executor)
145 {
146 if (executor == null)
147 throw new IllegalArgumentException("missing required 'executor' argument");
148 ThreadPool threadPool = _server.getThreadPool();
149 if (threadPool instanceof DelegatingThreadPool)
150 ((DelegatingThreadPool)_server.getThreadPool()).setExecutor(executor);
151 else
152 throw new UnsupportedOperationException("!DelegatingThreadPool");
153 }
154
155 @Override
156 public Executor getExecutor()
157 {
158 ThreadPool threadPool = _server.getThreadPool();
159 if (threadPool instanceof DelegatingThreadPool)
160 return ((DelegatingThreadPool)_server.getThreadPool()).getExecutor();
161 return threadPool;
162 }
163
164 @Override
165 public void stop(int delay)
166 {
167 cleanUpContexts();
168 cleanUpConnectors();
169
170 if (_serverShared) return;
171
172 try
173 {
174 _server.stop();
175 }
176 catch (Exception ex)
177 {
178 throw new RuntimeException(ex);
179 }
180 }
181
182 private void cleanUpContexts()
183 {
184 for (Map.Entry<String, JettyHttpContext> stringJettyHttpContextEntry : _contexts.entrySet())
185 {
186 JettyHttpContext context = stringJettyHttpContextEntry.getValue();
187 _server.removeBean(context.getJettyContextHandler());
188 }
189 _contexts.clear();
190 }
191
192 private void cleanUpConnectors()
193 {
194 for (Map.Entry<String, Connector> stringConnectorEntry : _connectors.entrySet())
195 {
196 Connector connector = stringConnectorEntry.getValue();
197 try
198 {
199 connector.stop();
200 }
201 catch (Exception ex)
202 {
203 LOG.warn(ex);
204 }
205 _server.removeConnector(connector);
206 }
207 _connectors.clear();
208 }
209
210 @Override
211 public HttpContext createContext(String path, HttpHandler httpHandler)
212 {
213 checkIfContextIsFree(path);
214
215 JettyHttpContext context = new JettyHttpContext(this, path, httpHandler);
216 HttpSpiContextHandler jettyContextHandler = context.getJettyContextHandler();
217
218 ContextHandlerCollection chc = findContextHandlerCollection(_server.getHandlers());
219 if (chc == null)
220 throw new RuntimeException("could not find ContextHandlerCollection, you must configure one");
221
222 chc.addHandler(jettyContextHandler);
223 _contexts.put(path, context);
224
225 return context;
226 }
227
228 private ContextHandlerCollection findContextHandlerCollection(Handler[] handlers)
229 {
230 if (handlers == null)
231 return null;
232
233 for (Handler handler : handlers)
234 {
235 if (handler instanceof ContextHandlerCollection)
236 {
237 return (ContextHandlerCollection) handler;
238 }
239
240 if (handler instanceof HandlerCollection)
241 {
242 HandlerCollection hc = (HandlerCollection) handler;
243 ContextHandlerCollection chc = findContextHandlerCollection(hc.getHandlers());
244 if (chc != null)
245 return chc;
246 }
247 }
248 return null;
249 }
250
251 private void checkIfContextIsFree(String path)
252 {
253 Handler serverHandler = _server.getHandler();
254 if (serverHandler instanceof ContextHandler)
255 {
256 ContextHandler ctx = (ContextHandler) serverHandler;
257 if (ctx.getContextPath().equals(path))
258 throw new RuntimeException("another context already bound to path " + path);
259 }
260
261 Handler[] handlers = _server.getHandlers();
262 if (handlers == null) return;
263
264 for (Handler handler : handlers)
265 {
266 if (handler instanceof ContextHandler) {
267 ContextHandler ctx = (ContextHandler) handler;
268 if (ctx.getContextPath().equals(path))
269 throw new RuntimeException("another context already bound to path " + path);
270 }
271 }
272 }
273
274 @Override
275 public HttpContext createContext(String path)
276 {
277 return createContext(path, null);
278 }
279
280 @Override
281 public void removeContext(String path) throws IllegalArgumentException
282 {
283 JettyHttpContext context = _contexts.remove(path);
284 if (context == null) return;
285 _server.removeBean(context.getJettyContextHandler());
286 }
287
288 @Override
289 public void removeContext(HttpContext context)
290 {
291 removeContext(context.getPath());
292 }
293
294 }