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