//======================================================================== //$$Id: JettyHttpServer.java 549 2007-11-02 12:41:46Z lorban $$ // //------------------------------------------------------------------------ //Licensed under the Apache License, Version 2.0 (the "License"); //you may not use this file except in compliance with the License. //You may obtain a copy of the License at //http://www.apache.org/licenses/LICENSE-2.0 //Unless required by applicable law or agreed to in writing, software //distributed under the License is distributed on an "AS IS" BASIS, //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //See the License for the specific language governing permissions and //limitations under the License. //======================================================================== package org.mortbay.jetty.j2se6; import java.io.IOException; import java.net.InetSocketAddress; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; import org.mortbay.jetty.Connector; import org.mortbay.jetty.Handler; import org.mortbay.jetty.Server; import org.mortbay.jetty.handler.ContextHandler; import org.mortbay.jetty.handler.HandlerCollection; import org.mortbay.jetty.nio.SelectChannelConnector; import org.mortbay.log.Log; import com.sun.net.httpserver.HttpContext; import com.sun.net.httpserver.HttpHandler; /** * Jetty implementation of {@link com.sun.net.httpserver.HttpServer}. * @author lorban */ public class JettyHttpServer extends com.sun.net.httpserver.HttpServer { private Server _server; private boolean _noServerCleanup; private InetSocketAddress _addr; private ThreadPoolExecutor _executor; private Map<String, JettyHttpContext> _contexts = new HashMap<String, JettyHttpContext>(); private Map<String, Connector> _connectors = new HashMap<String, Connector>(); public JettyHttpServer(Server server, boolean noServerCleanUp) { this._server = server; this._noServerCleanup = noServerCleanUp; } @Override public void bind(InetSocketAddress addr, int backlog) throws IOException { this._addr = addr; // check if there is already a connector listening Connector[] connectors = _server.getConnectors(); if (connectors != null) { for (int i = 0; i < connectors.length; i++) { if (connectors[i].getPort() == addr.getPort()) { if (Log.isDebugEnabled()) Log.debug("server already bound to port " + addr.getPort() + ", no need to rebind"); return; } } } if (_executor != null && _server.getThreadPool() == null) { if (Log.isDebugEnabled()) Log.debug("using given Executor for server thread pool"); _server.setThreadPool(new ThreadPoolExecutorAdapter(_executor)); } SelectChannelConnector connector = new SelectChannelConnector(); connector.setAcceptors(1); connector.setPort(addr.getPort()); connector.setHost(addr.getHostName()); _server.addConnector(connector); _connectors.put(addr.getHostName() + addr.getPort(), connector); } @Override public InetSocketAddress getAddress() { return _addr; } @Override public void start() { if (_noServerCleanup) return; try { _server.start(); } catch (Exception ex) { throw new RuntimeException(ex); } } @Override public void setExecutor(Executor executor) { if (!(executor instanceof ThreadPoolExecutor)) throw new IllegalArgumentException("only ThreadPoolExecutor are allowed"); this._executor = (ThreadPoolExecutor) executor; } @Override public Executor getExecutor() { return _executor; } @Override public void stop(int delay) { cleanUpContexts(); cleanUpConnectors(); if (_noServerCleanup) return; try { _server.stop(); } catch (Exception ex) { throw new RuntimeException(ex); } } private void cleanUpContexts() { Iterator<Map.Entry<String, JettyHttpContext>> it = _contexts.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, JettyHttpContext> entry = (Map.Entry<String, JettyHttpContext>) it.next(); JettyHttpContext context = entry.getValue(); _server.removeHandler(context.getJettyContextHandler()); } _contexts.clear(); } private void cleanUpConnectors() { Iterator<Map.Entry<String, Connector>> it = _connectors.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, Connector> entry = (Map.Entry<String, Connector>) it.next(); Connector connector = entry.getValue(); try { connector.stop(); } catch (Exception ex) { Log.warn(ex); } _server.removeConnector(connector); } _connectors.clear(); } @Override public HttpContext createContext(String path, HttpHandler handler) { checkIfContextIsFree(path); JettyHttpContext context = new JettyHttpContext(this, path, handler); J2SE6ContextHandler jettyContextHandler = context.getJettyContextHandler(); HandlerCollection hc = null; Handler[] handlers = _server.getHandlers(); for (int i = 0; i < handlers.length; i++) { if (handlers[i] instanceof HandlerCollection) { hc = (HandlerCollection) handlers[i]; break; } } if (hc == null) throw new RuntimeException("could not find HandlerCollection, you must configure one"); try { jettyContextHandler.start(); } catch (Exception ex) { throw new RuntimeException("could not start created context at path " + jettyContextHandler.getContextPath(), ex); } hc.addHandler(jettyContextHandler); _contexts.put(path, context); return context; } private void checkIfContextIsFree(String path) { Handler handler = _server.getHandler(); if (handler instanceof ContextHandler) { ContextHandler ctx = (ContextHandler) handler; if (ctx.getContextPath().equals(path)) throw new RuntimeException("another context already bound to path " + path); } Handler[] handlers = _server.getHandlers(); if (handlers == null) return; for (int i = 0; i < handlers.length; i++) { if (handlers[i] instanceof ContextHandler) { ContextHandler ctx = (ContextHandler) handlers[i]; if (ctx.getContextPath().equals(path)) throw new RuntimeException("another context already bound to path " + path); } } } @Override public HttpContext createContext(String path) { return createContext(path, null); } @Override public void removeContext(String path) throws IllegalArgumentException { JettyHttpContext context = _contexts.remove(path); if (context == null) return; _server.removeHandler(context.getJettyContextHandler()); } @Override public void removeContext(HttpContext context) { removeContext(context.getPath()); } }