//
// $Id$

package com.samskivert.nexus.server;

import java.io.IOException;
import java.nio.channels.SocketChannel;

import org.eclipse.jetty.http.HttpException;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

import com.samskivert.nexus.distrib.NexusException;
import com.samskivert.nexus.io.GWTIO;
import com.samskivert.nexus.net.GWTConnection;

import static com.samskivert.nexus.util.Log.log;

/**
 * Handles starting a Jetty server and configuring it to listen for GWTIO WebSocket requests on a
 * specified port. For systems that don't otherwise make use of Jetty, this simplifies things.
 * Systems that do make use of Jetty can simply wire up the {@link GWTIOJettyServlet} themselves.
 */
public class GWTConnectionManager
{
    public GWTConnectionManager (SessionManager smgr, GWTIO.Serializer szer,
                                 String hostname, int port)
    {
        _jetty = new Server();

        // use a custom connector that works around some jetty non-awesomeness
        _jetty.setConnectors(new Connector[] {
            new SaneChannelConnector(hostname, port)
        });

//         // this will magically cause addHandler() to work and dispatch to our contexts
//         _jetty.setHandler(new ContextHandlerCollection());

        ServletContextHandler context = new ServletContextHandler();
        context.setContextPath("/");
        GWTIOJettyServlet servlet = new GWTIOJettyServlet(smgr, szer);
        context.addServlet(new ServletHolder(servlet), "/" + GWTConnection.WS_PATH);

        // context.setResourceBase(new File(_config.getAppRoot(), "samsara").getPath());
        // context.setWelcomeFiles(new String[] { "index.html" });
        _jetty.setHandler(context);
    }

    public void start ()
    {
        try {
            _jetty.start();
        } catch (Exception e) {
            throw new NexusException(e);
        }
    }

    public void shutdown ()
    {
        try {
            _jetty.stop();
        } catch (Exception e) {
            throw new NexusException(e);
        }
    }

    protected static class SaneChannelConnector extends SelectChannelConnector
    {
        public SaneChannelConnector (String httpHost, int httpPort) {
            setHost(httpHost);
            setPort(httpPort);
        }

        @Override // from SelectChannelConnector
        protected Connection newConnection (SocketChannel chan, SelectChannelEndPoint ep) {
            return new HttpConnection(this, ep, getServer()) {
                @Override public Connection handle () throws IOException {
                    try {
                        return super.handle();
                    } catch (NumberFormatException nfe) {
                        // TODO: demote this to log.info in a week or two
                        log.warning("Failing invalid HTTP request", "uri", _uri, "error", nfe);
                        throw new HttpException(400); // bad request
                    } catch (IOException ioe) {
                        if (ioe.getClass() == IOException.class) { // grr
                            log.warning("Failing invalid HTTP request", "uri", _uri, "error", ioe);
                            throw new HttpException(400); // bad request
                        } else {
                            throw ioe;
                        }
                    }
                }
            };
        }
    }

    protected Server _jetty;
}

@@ -39,24 +39,45 @@
 us.server;%0A%0A
+import java.io.File;%0A
 import java.
@@ -308,32 +308,73 @@
 rver.Connector;%0A
+import org.eclipse.jetty.server.Handler;%0A
 import org.eclip
@@ -441,24 +441,134 @@
 ver.Server;%0A
+import org.eclipse.jetty.server.handler.HandlerList;%0Aimport org.eclipse.jetty.server.handler.ResourceHandler;%0A
 import org.e
@@ -1610,26 +1610,24 @@
    %7D);%0A%0A
-//
         
  // this
@@ -1622,188 +1622,38 @@
     
- // this will magically cause addHandler() to work and dispatch to our contexts%0A//         _jetty.setHandler(new ContextHandlerCollection());%0A%0A        ServletContextHandler context
+ServletContextHandler shandler
  = n
@@ -1688,23 +1688,24 @@
         
-context
+shandler
 .setCont
@@ -1730,36 +1730,46 @@
     
-GWTIOJettyServlet servlet = 
+shandler.addServlet(new ServletHolder(
 new 
@@ -1797,17 +1797,18 @@
 r, szer)
-;
+),
 %0A       
@@ -1812,275 +1812,486 @@
     
-context.addServlet(new ServletHolder(servlet), %22/%22 + GWTConnection.WS_PATH);%0A%0A        // context.setResourceBase(new File(_config.getAppRoot(), %22samsara%22).getPath());%0A        // context.setWelcomeFiles(new String%5B%5D %7B %22index.html%22 %7D);%0A        _jetty.setHandler(context
+                    %22/%22 + GWTConnection.WS_PATH);%0A%0A        _rhandler = new ResourceHandler();%0A        _rhandler.setResourceBase(%22disabled%22);%0A        _rhandler.setWelcomeFiles(new String%5B%5D %7B %22index.html%22 %7D);%0A%0A        HandlerList handlers = new HandlerList();%0A        handlers.setHandlers(new Handler%5B%5D %7B _rhandler, shandler %7D);%0A        _jetty.setHandler(handlers);%0A    %7D%0A%0A    public void setDocRoot (File docroot)%0A    %7B%0A        _rhandler.setResourceBase(docroot.getAbsolutePath()
 );%0A 
@@ -3995,10 +3995,51 @@
 _jetty;%0A
+    protected ResourceHandler _rhandler;%0A
 %7D%0A

Allow a document root to be set for simple service of GWT static files.