//======================================================================== // Parts Copyright 2006 Mort Bay Consulting Pty. Ltd. //------------------------------------------------------------------------ // 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.grizzly; import com.sun.grizzly.Context; import com.sun.grizzly.Controller; import com.sun.grizzly.Controller.Protocol; import com.sun.grizzly.DefaultPipeline; import com.sun.grizzly.DefaultProtocolChain; import com.sun.grizzly.DefaultProtocolChainInstanceHandler; import com.sun.grizzly.DefaultSelectionKeyHandler; import com.sun.grizzly.Pipeline; import com.sun.grizzly.ProtocolChain; import com.sun.grizzly.TCPSelectorHandler; import com.sun.grizzly.filter.ReadFilter; import com.sun.grizzly.util.WorkerThread; import java.io.IOException; import java.net.InetAddress; import java.nio.ByteBuffer; import java.util.concurrent.ConcurrentLinkedQueue; import org.mortbay.io.EndPoint; import org.mortbay.io.nio.NIOBuffer; import org.mortbay.jetty.Connector; import org.mortbay.jetty.Handler; import org.mortbay.jetty.HttpConnection; import org.mortbay.jetty.HttpParser; import org.mortbay.jetty.Request; import org.mortbay.jetty.Server; import org.mortbay.jetty.handler.ContextHandlerCollection; import org.mortbay.jetty.handler.DefaultHandler; import org.mortbay.jetty.handler.HandlerCollection; import org.mortbay.jetty.nio.AbstractNIOConnector; import org.mortbay.jetty.security.HashUserRealm; import org.mortbay.jetty.security.UserRealm; import org.mortbay.jetty.webapp.WebAppContext; import org.mortbay.log.Log; import org.mortbay.thread.BoundedThreadPool; import org.mortbay.thread.QueuedThreadPool; /* ------------------------------------------------------------------------------- */ /** * @author gregw * */ public class GrizzlyConnector extends AbstractNIOConnector { protected Controller controller; /* ------------------------------------------------------------------------------- */ /** * Constructor. * */ public GrizzlyConnector() { } /* ------------------------------------------------------------ */ public Object getConnection() { return controller.getSelectorHandler(Protocol.TCP); } /* ------------------------------------------------------------ */ /* * @see org.mortbay.jetty.AbstractConnector#doStart() */ protected void doStart() throws Exception { super.doStart(); // TODO - is there a non-blocking way to do this? new Thread() { public void run() { try { controller.start(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }.start(); } /* ------------------------------------------------------------ */ /* * @see org.mortbay.jetty.AbstractConnector#doStop() */ protected void doStop() throws Exception { super.doStop(); controller.stop(); } /* ------------------------------------------------------------ */ public void open() throws IOException { controller = new Controller(); TCPSelectorHandler selectorHandler = new TCPSelectorHandler(); selectorHandler.setPort(getPort()); if (getHost() != null) { selectorHandler.setInet(InetAddress.getByName(getHost())); } controller.setSelectorHandler(selectorHandler); selectorHandler.setSelectionKeyHandler(new DefaultSelectionKeyHandler()); DefaultProtocolChainInstanceHandler instanceHandler = new DefaultProtocolChainInstanceHandler() { private ConcurrentLinkedQueue protocolChains = new ConcurrentLinkedQueue(); @Override public ProtocolChain poll() { ProtocolChain pc = protocolChains.poll(); if (pc == null) { final GrizzlyEndPoint endPoint; final HttpParser parser; try { endPoint=new GrizzlyEndPoint(GrizzlyConnector.this,null); parser=(HttpParser)((HttpConnection)endPoint.getHttpConnection()).getParser(); } catch (IOException ex) { throw new RuntimeException(ex); } pc = new DefaultProtocolChain(); ReadFilter readFilter = new JettyReadFilter(parser); pc.addFilter(readFilter); HttpProtocolFilter httpProtocolFilter = new HttpProtocolFilter(); httpProtocolFilter.setParser(parser); httpProtocolFilter.setEndPoint(endPoint); pc.addFilter(httpProtocolFilter); } return pc; } /** * Pool an instance of ProtocolChain. */ @Override public boolean offer(ProtocolChain pc) { return protocolChains.offer(pc); } }; controller.setProtocolChainInstanceHandler(instanceHandler); Pipeline pipeline = new DefaultPipeline(); if(getServer().getThreadPool() instanceof BoundedThreadPool) pipeline.setMaxThreads(((BoundedThreadPool)getServer().getThreadPool()).getMaxThreads()); else if (getServer().getThreadPool() instanceof QueuedThreadPool) pipeline.setMaxThreads(((QueuedThreadPool)getServer().getThreadPool()).getMaxThreads()); controller.setPipeline(pipeline); } private class JettyReadFilter extends ReadFilter { public HttpParser parser; public JettyReadFilter(HttpParser parser) { this.parser = parser; } public boolean execute(Context ctx) throws IOException { WorkerThread workerThread = (WorkerThread)Thread.currentThread(); // Use Jetty's ByteBuffer ByteBuffer bb = ((NIOBuffer)parser.getHeaderBuffer()).getByteBuffer(); workerThread.setByteBuffer(bb); return super.execute(ctx); } } /* ------------------------------------------------------------ */ public void close() throws IOException { // TODO Close server socket // XXX Only supported when calling selectorThread.stopEndpoint(); } /* ------------------------------------------------------------ */ public void accept(int acceptorID) throws IOException { try { // TODO - this may not exactly be right. accept is called in a loop, so we // may need to wait on the _selectorThread somehow? // maybe we just set acceptors to zero and don't need to bother here as // grizzly has it's own accepting threads. if (controller.isStarted()) { Thread.sleep(5000); } } catch (Throwable e) { // TODO Auto-generated catch block Log.ignore(e); } } /* ------------------------------------------------------------ */ public void stopAccept(int acceptorID) throws Exception { // TODO } /* ------------------------------------------------------------------------------- */ public void customize(EndPoint endpoint, Request request) throws IOException { super.customize(endpoint, request); } /* ------------------------------------------------------------------------------- */ public int getLocalPort() { // TODO return the actual port we are listening on return getPort(); } /* ------------------------------------------------------------------------------- */ /** temp main - just to help testing */ public static void main(String[] args) throws Exception { Server server = new Server(); Connector connector=new GrizzlyConnector(); connector.setPort(8080); server.setConnectors(new Connector[]{connector}); HandlerCollection handlers = new HandlerCollection(); ContextHandlerCollection contexts = new ContextHandlerCollection(); handlers.setHandlers(new Handler[]{contexts,new DefaultHandler()}); server.setHandler(handlers); // TODO add javadoc context to contexts WebAppContext.addWebApplications(server, "../../webapps", "org/mortbay/jetty/webapp/webdefault.xml", true, false); HashUserRealm userRealm = new HashUserRealm(); userRealm.setName("Test Realm"); userRealm.setConfig("../../etc/realm.properties"); server.setUserRealms(new UserRealm[]{userRealm}); server.start(); server.join(); } }