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