jicarilla-sandbox/platform/components/http/impl/src/java/org/jicarilla/webserver/plumbing AbstractStage.java,NONE,1.1 BeanshellHTTPChannelFactory.java,NONE,1.1 BenchmarkStage.java,NONE,1.1 EchoStage.java,NONE,1.1 FilesystemStage.java,NONE,1.1 GeneralAndResponseHeadersStage.java,NONE,1.1 HTTPEvent.java,NONE,1.1 HTTPScreenerBuilderImpl.java,NONE,1.1 HTTPSelector.java,NONE,1.1 JettyChannelFactory.java,NONE,1.1 JettyStage.java,NONE,1.1 ParsingStage.java,NONE,1.1 ResponseCompletionStage.java,NONE,1.1 WritingStage.java,NONE,1.1 package.html,NONE,1.1

Leo Simons <[email protected]>
Newsgroups gmane.comp.java.jicarilla.cvs
Message-ID <[email protected]>
Update of /cvsroot/jicarilla/jicarilla-sandbox/platform/components/http/impl/src/java/org/jicarilla/webserver/plumbing
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20979/platform/components/http/impl/src/java/org/jicarilla/webserver/plumbing

Added Files:
	AbstractStage.java BeanshellHTTPChannelFactory.java 
	BenchmarkStage.java EchoStage.java FilesystemStage.java 
	GeneralAndResponseHeadersStage.java HTTPEvent.java 
	HTTPScreenerBuilderImpl.java HTTPSelector.java 
	JettyChannelFactory.java JettyStage.java ParsingStage.java 
	ResponseCompletionStage.java WritingStage.java package.html 
Log Message:
seperate plumbing material from the basic HTTP logic, and work on solidifying the I/O code.

--- NEW FILE: JettyChannelFactory.java ---
/* ====================================================================
The Jicarilla Software License

Copyright (c) 2003 Leo Simons.
All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
==================================================================== */
package org.jicarilla.webserver.plumbing;

import EDU.oswego.cs.dl.util.concurrent.LinkedQueue;
import org.jicarilla.lang.Assert;
import org.jicarilla.lang.RecyclingObjectFactory;
import org.jicarilla.net.Event;
import org.jicarilla.plumbing.NoopSink;
import org.jicarilla.plumbing.Stage;
import org.mortbay.http.HttpServer;

import java.net.InetAddress;

/**
 * Delegates request/response handling to Jetty completely. If you
 * use this stage, it should be the only one.
 *
 * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
 * @version $Id: JettyChannelFactory.java,v 1.1 2004/03/31 12:11:00 lsimons Exp $
 */
public class JettyChannelFactory extends RecyclingObjectFactory
{
    protected HttpServer m_delegate;
    protected InetAddress m_address;
    protected Stage m_stage;
    protected Stage m_processor;

    public JettyChannelFactory( final HttpServer delegate, final InetAddress address )
    {
        m_delegate = delegate;
        m_address = address;
        m_stage = new JettyStage(
            m_delegate,
            m_address,
            new LinkedQueue(),
            new NoopSink()
        );
        m_processor = createProcessor();
    }

    public synchronized Object makeObject() throws Exception
    {
        return m_processor;
    }

    protected Stage createProcessor()
    {
        return new Stage()
        {
            public void put( final Object o ) throws InterruptedException
            {
                final HTTPEvent e = getEvent( o );
                m_stage.put( e );
            }

            public boolean offer( final Object o, final long l ) throws InterruptedException
            {
                final HTTPEvent e = getEvent( o );
                return m_stage.offer( e, l );
            }

            protected HTTPEvent getEvent( final Object o )
            {
                Assert.assertTrue( o instanceof Event );

                if( o instanceof HTTPEvent )
                    return (HTTPEvent)o;

                final Event ev = (Event)o;
                final HTTPEvent e = new HTTPEvent();
                e.setChannel( ev.getChannel() );
                e.setContext( ev.getContext() );
                return e;
            }

            public Object take() throws InterruptedException
            {
                return m_stage.take();
            }

            public Object poll( final long l ) throws InterruptedException
            {
                return m_stage.poll( l );
            }

            public Object peek()
            {
                return m_stage.peek();
            }
        };
    }

}
--- NEW FILE: HTTPSelector.java ---
/* ====================================================================
The Jicarilla Software License

Copyright (c) 2003 Leo Simons.
All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
==================================================================== */
package org.jicarilla.webserver.plumbing;

import org.jicarilla.http.HTTPField;
import org.jicarilla.http.HTTPMessage;
import org.jicarilla.lang.RegexpSelector;
import org.jicarilla.lang.Selector;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 
 *
 * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
 * @version $Id: HTTPSelector.java,v 1.1 2004/03/31 12:11:00 lsimons Exp $
 */
public class HTTPSelector implements Selector
{
    protected List m_methodSelectors = new ArrayList();
    protected List m_uriSelectors = new ArrayList();
    protected List m_versionSelectors = new ArrayList();
    protected List m_headerSelectors = new ArrayList();
    protected List m_bodySelectors = new ArrayList();

    public final static boolean POLICY_AND = true;
    public final static boolean POLICY_OR = false;

    protected boolean m_methodSelectorPolicy = POLICY_OR;
    protected boolean m_uriSelectorPolicy = POLICY_OR;
    protected boolean m_versionSelectorPolicy = POLICY_OR;
    protected boolean m_headerSelectorPolicy = POLICY_AND;
    protected boolean m_bodySelectorPolicy = POLICY_AND;
    protected boolean m_globalPolicy = POLICY_AND;

    public boolean select( final Object object )
    {
        if(! (object instanceof HTTPEvent) )
            return false;

        final HTTPEvent event = (HTTPEvent)object;
        final HTTPMessage request = event.getHTTPRequest();

        if( m_globalPolicy == POLICY_AND )
            return selectStartLine(request) &&
                selectHeaders(request) &&
                selectBody(request);
        else
            // POLICY_OR
            return selectStartLine(request) ||
                selectHeaders(request) ||
                selectBody(request);
    }

    public void addURLPattern( final Pattern pattern )
    {
        final Selector s = new RegexpSelector( pattern );
        m_uriSelectors.add( s );
    }

    public void addVirtualHost( final InetAddress host )
    {
        final String hostname = host.getHostName();
        final Pattern pattern = Pattern.compile( "Host:[ \\t]*" + hostname,
                Pattern.CASE_INSENSITIVE );
        final Selector s = new RegexpSelector( pattern );
        m_uriSelectors.add( s );
    }

    protected boolean selectStartLine( final HTTPMessage request )
    {
        if( m_globalPolicy == POLICY_AND )
            return selectMethod(request) &&
                selectURI(request) &&
                selectVersion(request);
        else
            // POLICY_OR
            return selectMethod(request) ||
                selectURI(request) ||
                selectVersion(request);
    }

    protected boolean selectMethod( final HTTPMessage request )
    {
        if( m_methodSelectors.size() == 0 )
            return true;

        final String method = request.getField1String();
        return select( method, m_methodSelectors, m_methodSelectorPolicy );
    }

    protected boolean selectURI( final HTTPMessage request )
    {
        if( m_uriSelectors.size() == 0 )
            return true;

        final String uri = request.getField2String();
        return select( uri, m_uriSelectors, m_uriSelectorPolicy );
    }

    protected boolean selectVersion( final HTTPMessage request )
    {
        if( m_versionSelectors.size() == 0 )
            return true;

        final String version = request.getField3String();
        return select( version, m_methodSelectors, m_methodSelectorPolicy );
    }

    protected boolean selectHeaders( final HTTPMessage request )
    {
        if( m_versionSelectors.size() == 0 )
            return true;

        final List headers = request.getHeaders();
        final Iterator it = headers.iterator();
        if( m_headerSelectorPolicy == POLICY_AND )
        {
            while( it.hasNext() )
            {
                final HTTPField header = (HTTPField)it.next();
                final String headerString = header.toExternalForm();
                    if(!selectHeader( headerString, m_headerSelectors, m_headerSelectorPolicy ) )
                        return false;
            }
            return true;
        }
        else
        {
            while( it.hasNext() )
            {
                final HTTPField header = (HTTPField)it.next();
                final String headerString = header.toExternalForm();
                    if(selectHeader( headerString, m_headerSelectors, m_headerSelectorPolicy ) )
                        return true;
            }
            return true;
        }
    }

    protected boolean selectBody( final HTTPMessage request )
    {
        if( m_bodySelectors.size() == 0 )
            return true;

        return select( request.getBodyAsString(), m_bodySelectors, m_bodySelectorPolicy );
    }

    protected boolean select( final String field, final List selectors, final boolean policy )
    {
        final Iterator it = selectors.iterator();
        if( policy == POLICY_AND )
        {
            while( it.hasNext() )
            {
                final Selector selector = (Selector)it.next();
                if( !selector.select( field ) )
                    return false;
            }
            return true;
        }
        else
        {
            // POLICY_OR
            while( it.hasNext() )
            {
                final Selector selector = (Selector)it.next();
                if( selector.select( field ) )
                    return true;
            }
            return false;
        }
    }

    protected boolean selectHeader( final String header, final List selectors, final boolean policy )
    {
        final Iterator it = selectors.iterator();
        while( it.hasNext() )
        {
            final Selector selector = (Selector)it.next();
            if( selector.select( header ) )
                return true;
        }
        return false;
    }
}

--- NEW FILE: JettyStage.java ---
/* ====================================================================
The Jicarilla Software License

Copyright (c) 2003 Leo Simons.
All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
==================================================================== */
package org.jicarilla.webserver.plumbing;

import EDU.oswego.cs.dl.util.concurrent.Channel;
import org.jicarilla.http.HTTPException;
import org.jicarilla.lang.Assert;
import org.jicarilla.plumbing.Sink;
import org.mortbay.http.HttpConnection;
import org.mortbay.http.HttpListener;
import org.mortbay.http.HttpMessage;
import org.mortbay.http.HttpRequest;
import org.mortbay.http.HttpServer;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.channels.SocketChannel;

/**
 * Delegates request/response handling to Jetty completely. If you
 * use this stage, it should be the only one.
 *
 * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
 * @version $Id: JettyStage.java,v 1.1 2004/03/31 12:11:00 lsimons Exp $
 */
public class JettyStage extends AbstractStage
{
    public final static int DEFAULT_BUFFER_SIZE = 8096;

    protected HttpServer m_delegate;
    protected InetAddress m_address;

    public JettyStage( final HttpServer delegate, final InetAddress address,
            final Channel channel, final Sink errorHandler )
    {
        super( channel, errorHandler );

        Assert.assertNotNull( "delegate argument may not be null", delegate );
        Assert.assertNotNull( "address argument may not be null", address );
        m_delegate = delegate;
        m_address = address;
    }

    protected void process( final HTTPEvent e )
            throws HTTPException, IOException
    {
        final SocketChannel channel = e.getChannel();
        final InputStream request = channel.socket().getInputStream();
        final OutputStream response = channel.socket().getOutputStream();

        final Listener listener = new Listener();

        final HttpConnection con = new HttpConnection( listener, m_address, request,
                response, channel.socket() );

        con.handle();
    }

    protected class Listener implements HttpListener
    {
        protected HttpServer m_server = m_delegate;
        protected String m_host = m_address.getHostName();
        protected int m_port = 0;
        protected int m_bufferSize = DEFAULT_BUFFER_SIZE;
        protected int m_bufferReserve = 10;
        protected String m_defaultScheme = HttpMessage.__SCHEME;
        protected boolean m_lowOnResources = false;
        protected boolean m_outOfResources = false;
        protected String m_integralScheme = HttpMessage.__SSL_SCHEME;
        protected int m_integralPort = 0;
        protected String m_confidentialScheme = HttpMessage.__SSL_SCHEME;
        protected int m_confidentialPort = 0;

        protected Listener() {}

        protected Listener( final HttpServer server, final String host, final int port, final int bufferSize,
                final int bufferReserve, final String defaultScheme, final boolean lowOnResources,
                final boolean outOfResources, final String integralScheme, final int integralPort,
                final String confidentialScheme, final int confidentialPort )
        {
            m_server = server;
            m_host = host;
            m_port = port;
            m_bufferSize = bufferSize;
            m_bufferReserve = bufferReserve;
            m_defaultScheme = defaultScheme;
            m_lowOnResources = lowOnResources;
            m_outOfResources = outOfResources;
            m_integralScheme = integralScheme;
            m_integralPort = integralPort;
            m_confidentialScheme = confidentialScheme;
            m_confidentialPort = confidentialPort;
        }

        // ----------------------------------------------------------------------
        //  Getters/Setters
        // ----------------------------------------------------------------------
        public void setHttpServer( final HttpServer server )
        {
            m_server = server;
        }

        public HttpServer getHttpServer()
        {
            return m_server;
        }

        public int getPort()
        {
            return m_port;
        }

        public void setPort( final int port )
        {
            m_port = port;
        }

        public int getBufferSize()
        {
            return m_bufferSize;
        }

        public void setBufferSize( final int bufferSize )
        {
            m_bufferSize = bufferSize;
        }

        public int getBufferReserve()
        {
            return m_bufferReserve;
        }

        public void setBufferReserve( final int bufferReserve )
        {
            m_bufferReserve = bufferReserve;
        }

        public String getDefaultScheme()
        {
            return m_defaultScheme;
        }

        public void setDefaultScheme( final String defaultScheme )
        {
            m_defaultScheme = defaultScheme;
        }

        public boolean isLowOnResources()
        {
            return m_lowOnResources;
        }

        public void setLowOnResources( final boolean lowOnResources )
        {
            m_lowOnResources = lowOnResources;
        }

        public boolean isOutOfResources()
        {
            return m_outOfResources;
        }

        public void setOutOfResources( final boolean outOfResources )
        {
            m_outOfResources = outOfResources;
        }

        public String getIntegralScheme()
        {
            return m_integralScheme;
        }

        public void setIntegralScheme( final String integralScheme )
        {
            m_integralScheme = integralScheme;
        }

        public int getIntegralPort()
        {
            return m_integralPort;
        }

        public void setIntegralPort( final int integralPort )
        {
            m_integralPort = integralPort;
        }

        public String getConfidentialScheme()
        {
            return m_confidentialScheme;
        }

        public void setConfidentialScheme( final String confidentialScheme )
        {
            m_confidentialScheme = confidentialScheme;
        }

        public int getConfidentialPort()
        {
            return m_confidentialPort;
        }

        public void setConfidentialPort( final int confidentialPort )
        {
            m_confidentialPort = confidentialPort;
        }

        public void setHost( final String host ) throws UnknownHostException
        {
            m_host = host;
        }

        public String getHost()
        {
            return m_host;
        }

        // ----------------------------------------------------------------------
        //  Interface: HttpListener
        // ----------------------------------------------------------------------
        public void customizeRequest( final HttpConnection connection,
                final HttpRequest request )
        {
            // no thanks
        }

        public void persistConnection( final HttpConnection connection )
        {
            // no thanks
        }

        public boolean isIntegral( final HttpConnection connection )
        {
            return false;
        }

        public boolean isConfidential( final HttpConnection connection )
        {
            return false;
        }

        // ----------------------------------------------------------------------
        //  Interface: LifeCycle
        // ----------------------------------------------------------------------
        public void start() throws Exception
        {
        }

        public void stop() throws InterruptedException
        {
        }

        public boolean isStarted()
        {
            return true;
        }
    }
}

--- NEW FILE: HTTPEvent.java ---
/* ====================================================================
 The Jicarilla Software License

 Copyright (c) 2003 Leo Simons.
 All rights reserved.

 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
 "Software"), to deal in the Software without restriction, including
 without limitation the rights to use, copy, modify, merge, publish,
 distribute, sublicense, and/or sell copies of the Software, and to
 permit persons to whom the Software is furnished to do so, subject to
 the following conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
==================================================================== */
package org.jicarilla.webserver.plumbing;

import org.jicarilla.http.HTTPMessage;
import org.jicarilla.net.Event;

/**
 *
 *
 * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
 * @version $Id: HTTPEvent.java,v 1.1 2004/03/31 12:11:00 lsimons Exp $
 */
public class HTTPEvent extends Event
{
    public synchronized HTTPMessage getHTTPRequest()
    {
        if( getRequest() == null )
        {
            final HTTPMessage msg = new HTTPMessage();
            msg.setMessageType( HTTPMessage.TYPE_REQUEST );
            setRequest( msg );
        }
        return (HTTPMessage)getRequest();
    }
    public HTTPMessage getHTTPResponse()
    {
        if( getResponse() == null )
        {
            final HTTPMessage msg = new HTTPMessage();
            msg.setMessageType( HTTPMessage.TYPE_RESPONSE );
            setResponse( msg );
        }
        return (HTTPMessage)getResponse();
    }
}

--- NEW FILE: FilesystemStage.java ---
/* ====================================================================
 The Jicarilla Software License

 Copyright (c) 2003 Leo Simons.
 All rights reserved.

 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
 "Software"), to deal in the Software without restriction, including
 without limitation the rights to use, copy, modify, merge, publish,
 distribute, sublicense, and/or sell copies of the Software, and to
 permit persons to whom the Software is furnished to do so, subject to
 the following conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
==================================================================== */
package org.jicarilla.webserver.plumbing;

import EDU.oswego.cs.dl.util.concurrent.Channel;
import org.jicarilla.http.HTTPEncoding;
import org.jicarilla.http.HTTPException;
import org.jicarilla.http.HTTPFileReader;
import org.jicarilla.http.HTTPMessage;
import org.jicarilla.plumbing.Sink;

import java.io.IOException;

/**
 *
 *
 * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
 * @version $Id: FilesystemStage.java,v 1.1 2004/03/31 12:11:00 lsimons Exp $
 */
public class FilesystemStage extends AbstractStage
{
    protected HTTPFileReader m_fileReader;

    public FilesystemStage( final Channel queue, final Sink errorHandler, final HTTPFileReader fr )
    {
        super( queue, errorHandler );

        setFileReader( fr);
    }

    public HTTPFileReader getFileReader()
    {
        return m_fileReader;
    }

    public void setFileReader( final HTTPFileReader fileReader )
    {
        m_fileReader = fileReader;
    }

    /**
     * @todo: processing of the URL to extract the filename 
     */
    protected void process( final HTTPEvent e )
            throws HTTPException, IOException
    {
        final HTTPMessage req = e.getHTTPRequest();
        final HTTPMessage res = e.getHTTPResponse();

        final String file = req.getField2String();

        final int size = m_fileReader.readFile( file, res );

        res.addHeader( HTTPEncoding.HEADER_CONTENT_LENGTH,
                ""+size );
        res.setField1( HTTPEncoding.VERSION_10 );
        res.setStatusCode( HTTPEncoding.STATUS_200_OK );
        res.setField3( HTTPEncoding.STATUS_200_MSG );
        res.setMessageType(false);
        res.setComplete(true);
        e.getContext().put( WritingStage.CLOSE_AFTER_WRITE_CONTEXT_KEY,
                "yep!" );
    }
}

--- NEW FILE: HTTPScreenerBuilderImpl.java ---
/* ====================================================================
The Jicarilla Software License

Copyright (c) 2003 Leo Simons.
All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
==================================================================== */
package org.jicarilla.webserver.plumbing;

import org.jicarilla.lang.Assert;
import org.jicarilla.lang.Selector;
import org.jicarilla.plumbing.Screener;
import org.jicarilla.plumbing.SimpleScreener;
import org.jicarilla.plumbing.Sink;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 
 *
 * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
 * @version $Id: HTTPScreenerBuilderImpl.java,v 1.1 2004/03/31 12:11:00 lsimons Exp $
 */
public class HTTPScreenerBuilderImpl implements HTTPScreenerBuilder
{
    protected List sinks = new ArrayList();

    public Screener create() throws Exception
    {
        final Screener s = new SimpleScreener();
        populate( s );
        return s;
    }

    public HTTPScreenerBuilder addStage( final Object selectionCriterion,
            final Sink sink )
    {
        sinks.add( new Entry( selectionCriterion, sink ) );
        return this;
    }

    protected void populate( final Screener s )
    {
        final Iterator it = sinks.iterator();
        while( it.hasNext() )
        {
            final Entry entry = (Entry)it.next();
            if( entry.criterion instanceof HTTPSelector )
            {
                s.addSink( (Selector)entry.criterion, entry.sink );
                continue;
            }

            final HTTPSelector selector;

            if( entry.criterion instanceof Pattern )
            {
                selector = new HTTPSelector();
                selector.addURLPattern( (Pattern)entry.criterion );
                s.addSink( selector, entry.sink );
                continue;
            }

            if( entry.criterion instanceof InetAddress )
            {
                selector = new HTTPSelector();
                selector.addVirtualHost( (InetAddress)entry.criterion );
                s.addSink( selector, entry.sink );
                continue;
            }
        }
    }

    protected static class Entry
    {
        public Object criterion;
        public Sink sink;

        protected Entry( final Object aCriterion, final Sink aSink )
        {
            Assert.assertNotNull( "criterion argument may not be null",
                    criterion );
            Assert.assertNotNull( "sink argument may not be null", sink );

            criterion = aCriterion;
            sink = aSink;
        }
    }
}

--- NEW FILE: package.html ---
<p>This package defines the connection between the net and the
http package, defining various building blocks for creating a
request/response processing pipeline.</p>

<p>Note that, in general, pipeline stages are not
multithreaded. Request/response pairs should be sent through a
pipeline sequentially.</p>
--- NEW FILE: GeneralAndResponseHeadersStage.java ---
/* ====================================================================
The Jicarilla Software License

Copyright (c) 2003 Leo Simons.
All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
==================================================================== */
package org.jicarilla.webserver.plumbing;

import EDU.oswego.cs.dl.util.concurrent.Channel;
import org.jicarilla.http.HTTPMessage;
import org.jicarilla.lang.Assert;
import org.jicarilla.plumbing.Sink;

/**
 * 
 * @todo Connection header
 * @todo Date header
 * @todo put constants in HTTPEncoding
 * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
 * @version $Id: GeneralAndResponseHeadersStage.java,v 1.1 2004/03/31 12:11:00 lsimons Exp $
 */
public class GeneralAndResponseHeadersStage extends AbstractStage
{
    protected String m_serverIdentification;

    public GeneralAndResponseHeadersStage( final Channel channel, final Sink errorHandler,
            final String serverIdentification )
    {
        super( channel, errorHandler );
        Assert.assertNotNull( "serverIdentification argument may not be null",
                serverIdentification );
        m_serverIdentification = serverIdentification;
    }

    protected void process( final HTTPEvent event )
    {
        final HTTPMessage res = event.getHTTPResponse();

        res.addHeader( "Server", m_serverIdentification );
        res.addHeader( "Connection", "close" );
    }
}

--- NEW FILE: BenchmarkStage.java ---
/* ====================================================================
 The Jicarilla Software License

 Copyright (c) 2003 Leo Simons.
 All rights reserved.

 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
 "Software"), to deal in the Software without restriction, including
 without limitation the rights to use, copy, modify, merge, publish,
 distribute, sublicense, and/or sell copies of the Software, and to
 permit persons to whom the Software is furnished to do so, subject to
 the following conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
==================================================================== */
package org.jicarilla.webserver.plumbing;

import EDU.oswego.cs.dl.util.concurrent.Channel;
import org.jicarilla.http.HTTPException;
import org.jicarilla.plumbing.Sink;

import java.io.IOException;

/**
 *
 *
 * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
 * @version $Id: BenchmarkStage.java,v 1.1 2004/03/31 12:11:00 lsimons Exp $
 */
public class BenchmarkStage extends AbstractStage
{
    public final static double MILLISECONDS_IN_A_SECOND = 1000.0;

    public final static String BENCHMARK_STARTED_CONTEXT_KEY =
            "urn:jicarilla:http:context-key:" +
            BenchmarkStage.class.getPackage().getName() + "benchmark-started";
    public final static String BENCHMARK_START_CONTEXT_KEY =
            "urn:jicarilla:http:context-key:" +
            BenchmarkStage.class.getPackage().getName() + "benchmark-start";

    public BenchmarkStage( final Channel queue, final Sink errorHandler )
    {
        super( queue, errorHandler );
    }

    protected void process( final HTTPEvent e )
            throws HTTPException, IOException
    {
        if( !e.getContext().containsKey( BENCHMARK_START_CONTEXT_KEY ) )
        {
            final long startTime = System.currentTimeMillis();
            e.getContext().put( BENCHMARK_START_CONTEXT_KEY, new Long( startTime ) );
        }
        else
        {
            final long startTime = ((Long)e.getContext().get( BENCHMARK_START_CONTEXT_KEY )).longValue();

            e.getHTTPResponse().addHeader(
                    "Debug-Time-Taken",
                    ""+(System.currentTimeMillis() - startTime)/MILLISECONDS_IN_A_SECOND
            );

            /*e.getHTTPResponse().addBodyPart(
                    "Debugging....time taken: "
                    +(System.currentTimeMillis() - startTime)/1000.0 + "\r\n\r\n"
            );*/
        }
    }
}

--- NEW FILE: WritingStage.java ---
/* ====================================================================
 The Jicarilla Software License

 Copyright (c) 2003 Leo Simons.
 All rights reserved.

 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
 "Software"), to deal in the Software without restriction, including
 without limitation the rights to use, copy, modify, merge, publish,
 distribute, sublicense, and/or sell copies of the Software, and to
 permit persons to whom the Software is furnished to do so, subject to
 the following conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
==================================================================== */
package org.jicarilla.webserver.plumbing;

import EDU.oswego.cs.dl.util.concurrent.Channel;
import org.jicarilla.http.HTTPException;
import org.jicarilla.http.HTTPMessage;
import org.jicarilla.http.HTTPMessageWriterImpl;
import org.jicarilla.plumbing.Sink;

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

/**
 * Wraps HTTPMessageWriterImpl as a stage in the pipeline.
 * Not threadsafe.
 *
 * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
 * @version $Id: WritingStage.java,v 1.1 2004/03/31 12:11:00 lsimons Exp $
 */
public class WritingStage extends AbstractStage
{
    public final static String CLOSE_AFTER_WRITE_CONTEXT_KEY = "urn:jicarilla:http:context-key:" +
            WritingStage.class.getPackage().getName() + ":close-after-write";

    private HTTPMessageWriterImpl m_writer;

    public WritingStage( final Channel queue, final Sink errorHandler )
    {
        super( queue, errorHandler );

        // todo remove hardwiring
        m_writer = new HTTPMessageWriterImpl();
    }

    protected HTTPMessageWriterImpl getWriter()
    {
        return m_writer;
    }

    protected void setWriter( final HTTPMessageWriterImpl writer )
    {
        m_writer = writer;
    }

    public void process( final HTTPEvent e ) throws HTTPException, IOException
    {
        final HTTPMessage m = e.getHTTPResponse();
        final SocketChannel c = e.getChannel();

        getWriter().write( m, c,
                e.getContext().containsKey( CLOSE_AFTER_WRITE_CONTEXT_KEY ) );
    }
}

--- NEW FILE: ParsingStage.java ---
/* ====================================================================
 The Jicarilla Software License

 Copyright (c) 2003 Leo Simons.
 All rights reserved.

 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
 "Software"), to deal in the Software without restriction, including
 without limitation the rights to use, copy, modify, merge, publish,
 distribute, sublicense, and/or sell copies of the Software, and to
 permit persons to whom the Software is furnished to do so, subject to
 the following conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
==================================================================== */
package org.jicarilla.webserver.plumbing;

import EDU.oswego.cs.dl.util.concurrent.Channel;
import org.apache.commons.pool.impl.SoftReferenceObjectPool;
import org.jicarilla.http.HTTPEncoding;
import org.jicarilla.http.HTTPException;
import org.jicarilla.http.HTTPMessage;
import org.jicarilla.http.HTTPMessageGenerator;
import org.jicarilla.http.HTTPParser;
import org.jicarilla.http.HTTPParserImpl;
import org.jicarilla.http.MessageFactory;
import org.jicarilla.http.MessageReceivedListener;
import org.jicarilla.lang.ExceptionListener;
import org.jicarilla.plumbing.Sink;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

/**
 * Wraps HTTPParserImpl as a stage in the pipeline. Not
 * threadsafe.
 *
 * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
 * @version $Id: ParsingStage.java,v 1.1 2004/03/31 12:11:00 lsimons Exp $
 */
public class ParsingStage extends AbstractStage
{
    public final static int BUFFER_SIZE = 8096;

    protected HTTPParserImpl m_parser;
    protected HTTPMessageGenerator m_generator;
    protected Listener m_listener;

    public ParsingStage( final Channel queue, final Sink errorHandler )
    {
        super( queue, errorHandler );

        // todo: remove hard-wiring
        setListener( new Listener() );
        setGenerator(
                new HTTPMessageGenerator(
                        getListener(),
                        getListener(),
                        new SoftReferenceObjectPool( new MessageFactory() )
                )
        );
        setParser(
                new HTTPParserImpl(
                        getGenerator(),
                        getGenerator()
                )
        );
    }

    protected Listener getListener()
    {
        return m_listener;
    }

    protected void setListener( final Listener listener )
    {
        m_listener = listener;
    }

    protected HTTPMessageGenerator getGenerator()
    {
        return m_generator;
    }

    protected void setGenerator( final HTTPMessageGenerator generator )
    {
        m_generator = generator;
    }

    protected HTTPParser getParser()
    {
        return m_parser;
    }

    protected void setParser( final HTTPParserImpl parser )
    {
        m_parser = parser;
    }

    protected void process( final HTTPEvent e )
            throws HTTPException, IOException
    {
        try
        {
            // todo: robustness
            final SocketChannel c = e.getChannel();
            HTTPException ex = null;
            while( true )
            {
                if( getListener().message != null )
                    break;

                final ByteBuffer buf = ByteBuffer.allocate( BUFFER_SIZE );
                final int read = c.read( buf );

                if( read < 0 )
                    break;
                if( read == 0 )
                {
                    Thread.yield();
                    continue;
                }

                buf.rewind();

                try
                {
                    getParser().parse( buf, read );
                }
                catch( HTTPException he )
                {
                    ex = he;
                    break;
                }
            }
            if( getListener().message == null )
            {
                // note the listener will have heard of the exception
                // if the message is not null :D
                m_listener.exceptionOccurred( ex );
            }
            else
            {
                e.setRequest( getListener().message );
            }
        }
        finally
        {
            getParser().reset();
            getGenerator().newMessage();
            getListener().message = null;
        }
    }

    protected static class Listener
            implements MessageReceivedListener, ExceptionListener
    {
        public HTTPMessage message = null;

        public void messageReceived( final HTTPMessage m )
        {
            message = m;
        }

        public void exceptionOccurred( final Throwable t )
        {
            // todo improve
            final HTTPMessage exMessage = new HTTPMessage();
            exMessage.setMessageType( HTTPMessage.TYPE_RESPONSE );
            exMessage.setField1( HTTPEncoding.VERSION_10 );
            exMessage.setStatusCode(
                    HTTPEncoding.STATUS_500_Internal_Server_Error );
            exMessage.setField3( "Internal Server Error" );

            final StringWriter sw = new StringWriter();
            final PrintWriter pw = new PrintWriter(sw);

            t.printStackTrace(pw);
            exMessage.addHeader( "Content-Type", "text/html");
            exMessage.addBodyPart( "<html><head><title>Internal Server Error</title></head><body><h1>An unexpected exception occurred:</h1><pre>" );
            exMessage.addBodyPart( sw.toString() );
            exMessage.addBodyPart( "</pre></body><html>" );

            message = exMessage;
        }
    }
}

--- NEW FILE: ResponseCompletionStage.java ---
/* ====================================================================
The Jicarilla Software License

Copyright (c) 2003 Leo Simons.
All rights reserved.

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
==================================================================== */
package org.jicarilla.webserver.plumbing;

import EDU.oswego.cs.dl.util.concurrent.Channel;
import org.jicarilla.http.HTTPEncoding;
import org.jicarilla.http.HTTPField;
import org.jicarilla.http.HTTPMessage;
import org.jicarilla.http.util.NioUtil;
import org.jicarilla.plumbing.Sink;

import java.nio.ByteBuffer;
import java.util.Iterator;

/**
 * 
 *
 * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
 * @version $Id: ResponseCompletionStage.java,v 1.1 2004/03/31 12:11:00 lsimons Exp $
 */
public class ResponseCompletionStage extends AbstractStage
{
    public ResponseCompletionStage( final Channel channel, final Sink errorHandler )
    {
        super( channel, errorHandler );
    }

    protected void process( final HTTPEvent e )
    {
        ensureStartLine( e );
        ensureContentLengthHeader( e );
    }

    protected void ensureStartLine( final HTTPEvent e )
    {
        final HTTPMessage res = e.getHTTPResponse();

        if( res.getField1() == null )
            res.setField1( HTTPEncoding.VERSION_10 );
        if( res.getField2() == null )
            res.setStatusCode( HTTPEncoding.STATUS_200_OK );
        if( res.getField3() == null )
            res.setField3( HTTPEncoding.STATUS_MSG[res.getStatusCode()] );
    }

    protected void ensureContentLengthHeader( final HTTPEvent e )
    {
        final HTTPMessage req = e.getHTTPRequest();
        final HTTPMessage res = e.getHTTPResponse();

        if( contentLengthNotSet( res ) )
        {
            if( noBodySoNoContentLengthHeader( req, res ) )
                return;

            if( nonIdentifyTransferCodingPresent( req, res ) )
                return;

            final ByteBuffer[] body = res.getBodyParts();
            if( body.length == 0 )
            {
                res.addHeader(
                        HTTPEncoding.HEADER_CONTENT_LENGTH_BUFFER,
                        NioUtil.toByteBuffer( 0 )
                );
            }
            else
            {
                int size = 0;
                for( int i = 0; i < body.length; i++ )
                {
                    final ByteBuffer byteBuffer = body[i];
                    size += byteBuffer.remaining();
                }

                res.addHeader(
                        HTTPEncoding.HEADER_CONTENT_LENGTH_BUFFER,
                        NioUtil.toByteBuffer( size )
                );
            }
        }
    }

    private boolean noBodySoNoContentLengthHeader( final HTTPMessage req,
            final HTTPMessage res )
    {
        if( HTTPEncoding.METHOD_HEAD.equals( req.getField1String() ) )
            return true;

        final int responseCode = res.getStatusCode();
        if( (HTTPEncoding.STATUS_100_Continue <= responseCode && responseCode < HTTPEncoding.STATUS_200_OK) ||
                responseCode == HTTPEncoding.STATUS_204_No_Content ||
                responseCode == HTTPEncoding.STATUS_304_Not_Modified )
            return true;

        return false;
    }

    protected boolean nonIdentifyTransferCodingPresent( final HTTPMessage req,
            final HTTPMessage res )
    {
        final Iterator it = res.getHeaders().iterator();
        while( it.hasNext() )
        {
            final HTTPField field = (HTTPField)it.next();
            if( HTTPEncoding.HEADER_TRANSFER_ENCODING.equals(
                    field.getNameString() ) )
            {
                return !HTTPEncoding.CONTENT_CODING_IDENTITY.equals(
                        field.getNameString() );
            }
        }
        return false;
    }

    protected boolean contentLengthNotSet( final HTTPMessage response )
    {
        final Iterator it = response.getHeaders().iterator();
        while( it.hasNext() )
        {
            final HTTPField field = (HTTPField)it.next();
            if( field.getName().equals(
                    HTTPEncoding.HEADER_CONTENT_LENGTH_BUFFER ) )
            {
                return false;
            }
        }
        return true;
    }
}

--- NEW FILE: AbstractStage.java ---
/* ====================================================================
 The Jicarilla Software License

 Copyright (c) 2003 Leo Simons.
 All rights reserved.

 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
 "Software"), to deal in the Software without restriction, including
 without limitation the rights to use, copy, modify, merge, publish,
 distribute, sublicense, and/or sell copies of the Software, and to
 permit persons to whom the Software is furnished to do so, subject to
 the following conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
==================================================================== */
package org.jicarilla.webserver.plumbing;

import EDU.oswego.cs.dl.util.concurrent.Channel;
import junit.framework.Assert;
import org.jicarilla.http.HTTPEncoding;
import org.jicarilla.http.HTTPException;
import org.jicarilla.net.Event;
import org.jicarilla.plumbing.DefaultStage;
import org.jicarilla.plumbing.Sink;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @todo ContentNegotiationStage that handles Expect/100-Continue, etc (8.2.3)
 * @todo HostFinderStage that determines the host (5.2)
 * @todo ErrorMessageStage that adds a (configurable) message body on errors
 * @todo EntityHeaderStage that adds entity headers
 * @todo ConfigurationScreener that sends events to other pipes based on configuration (selectors on host, uri, version, method, etc)
 * @todo OptionsStage that responds to OPTIONS
 * @todo UnsupportedOperationStage that sends 501
 * @todo CacheHeaderStage that adds caching stuff (13)
 * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
 * @version $Id: AbstractStage.java,v 1.1 2004/03/31 12:11:00 lsimons Exp $
 */
public abstract class AbstractStage extends DefaultStage
{
    public final static String EXCEPTION_CONTEXT_KEY = "urn:jicarilla:http:context-key:" +
            AbstractStage.class.getPackage().getName() + "exception";

    protected AbstractStage( final Channel channel,
            final Sink errorHandler )
    {
        super( channel, errorHandler );
    }

    public void put( final Object o ) throws InterruptedException
    {
        final HTTPEvent e = (HTTPEvent)o;
        try
        {
            process( e );
            super.put( e );
        }
        catch( HTTPException he )
        {
            handleException( e, he );
        }
        catch( IOException ioe )
        {
            handleException( e,
                    new HTTPException( HTTPEncoding.STATUS_999_IO_Problem,
                            ioe ) );
        }
    }

    public boolean offer( final Object o, final long l ) throws InterruptedException
    {
        final HTTPEvent e = (HTTPEvent)o;
        try
        {
            process( e );
            final boolean result = super.offer( e, l );
            return result;
        }
        catch( HTTPException he )
        {
            handleException( e, he );
        }
        catch( IOException ioe )
        {
            handleException( e,
                    new HTTPException( HTTPEncoding.STATUS_999_IO_Problem,
                            ioe ) );
        }

        return true;
    }

    protected void process( final HTTPEvent event )
            throws HTTPException, IOException {}

    public void handleException( final HTTPEvent event, final Throwable t )
            throws InterruptedException
    {
        Assert.assertNotNull( event );

        ensureContext( event );
        final Map m = event.getContext();
        if( !m.containsKey( EXCEPTION_CONTEXT_KEY ) )
        {
            m.put( EXCEPTION_CONTEXT_KEY, t );

            if( t instanceof HTTPException )
            {
                final HTTPException he = (HTTPException)t;
                event.getHTTPResponse().setStatusCode( he.getCode() );
            }
        }
        handleError( event );
    }
    protected static void ensureContext( final Event event )
    {
        Assert.assertNotNull( event );

        if( event.getContext() == null )
            event.setContext( new HashMap() );
    }

    public static boolean checkExceptionOccured( final Event event )
    {
        Assert.assertNotNull( event );

        //ensureContext( event );
        final Map m = event.getContext();
        if( m != null && m.containsKey( EXCEPTION_CONTEXT_KEY ) )
            return true;

        return false;
    }

    public static Throwable getThrowable( final Event event )
    {
        Assert.assertNotNull( event );
        //ensureContext( event );

        final Map m = event.getContext();
        if( m != null && m.containsKey( EXCEPTION_CONTEXT_KEY ) )
            return (Throwable)m.get( EXCEPTION_CONTEXT_KEY );

        return null;
    }
}

--- NEW FILE: BeanshellHTTPChannelFactory.java ---
/* ====================================================================
 The Jicarilla Software License

 Copyright (c) 2003 Leo Simons.
 All rights reserved.

 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
 "Software"), to deal in the Software without restriction, including
 without limitation the rights to use, copy, modify, merge, publish,
 distribute, sublicense, and/or sell copies of the Software, and to
 permit persons to whom the Software is furnished to do so, subject to
 the following conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
==================================================================== */
package org.jicarilla.webserver.plumbing;

import EDU.oswego.cs.dl.util.concurrent.LinkedQueue;
import org.jicarilla.lang.Assert;
import org.jicarilla.lang.RecyclingObjectFactory;
import org.jicarilla.net.Event;
import org.jicarilla.plumbing.NoopSink;
import org.jicarilla.plumbing.PostProcessor;
import org.jicarilla.plumbing.Stage;

/**
 *
 *
 * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
 * @version $Id: BeanshellHTTPChannelFactory.java,v 1.1 2004/03/31 12:11:00 lsimons Exp $
 */
public class BeanshellHTTPChannelFactory extends RecyclingObjectFactory
{
    //private Stage m_stage;

    public synchronized Object makeObject() throws Exception
    {
        //if( m_stage == null )
        //{
            /*Interpreter i = new Interpreter();
            i.source( "create-pipeline.bsh" );

            m_stage = (Stage)i.get( "pipeline" );*/

        //    m_stage = createPipeline();
        //}
        //return m_stage;
        return createPipeline();
    }

    public Stage createPipeline()
    {
        final PostProcessor processor = new PostProcessor(
                new LinkedQueue(),
                new NoopSink()
                )
        {
            public void put( final Object o ) throws InterruptedException
            {
                final HTTPEvent e = getEvent( o );
                super.put( e );
            }

            public boolean offer( final Object o, final long l ) throws InterruptedException
            {
                final HTTPEvent e = getEvent( o );
                return super.offer( e, l );
            }

            protected HTTPEvent getEvent( final Object o )
            {
                Assert.assertTrue( o instanceof Event );

                if( o instanceof HTTPEvent )
                    return (HTTPEvent)o;

                final Event ev = (Event)o;
                final HTTPEvent e = new HTTPEvent();
                e.setChannel( ev.getChannel() );
                e.setContext( ev.getContext() );
                return e;
            }
        };

        processor.addStage(
                new BenchmarkStage( // start
                        new LinkedQueue(),
                        new NoopSink()
                )
        );
        processor.addStage(
                new ParsingStage(
                        new LinkedQueue(),
                        new NoopSink()
                )
        );
        processor.addStage(
                new EchoStage(
                        new LinkedQueue(),
                        new NoopSink()
                )
        );
        /*processor.addStage(
                new FilesystemStage(
                        new LinkedQueue(),
                        new NoopSink(),
                        new FilesystemImpl(".")
                )
        );*/
        processor.addStage(
                new BenchmarkStage( // finish
                        new LinkedQueue(),
                        new NoopSink()
                )
        );
        processor.addStage(
                new WritingStage(
                        new LinkedQueue(),
                        new NoopSink()
                )
        );

        return processor;
    }
}

--- NEW FILE: EchoStage.java ---
/* ====================================================================
 The Jicarilla Software License

 Copyright (c) 2003 Leo Simons.
 All rights reserved.

 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
 "Software"), to deal in the Software without restriction, including
 without limitation the rights to use, copy, modify, merge, publish,
 distribute, sublicense, and/or sell copies of the Software, and to
 permit persons to whom the Software is furnished to do so, subject to
 the following conditions:

 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
==================================================================== */
package org.jicarilla.webserver.plumbing;

import EDU.oswego.cs.dl.util.concurrent.Channel;
import org.jicarilla.http.HTTPEncoding;
import org.jicarilla.http.HTTPException;
import org.jicarilla.http.HTTPField;
import org.jicarilla.http.HTTPMessage;
import org.jicarilla.http.HTTPMessageWriterImpl;
import org.jicarilla.plumbing.Sink;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Iterator;

/**
 * Simple stages which sends back the request as the
 * response body.
 *
 * @author <a href="lsimons at jicarilla dot org">Leo Simons</a>
 * @version $Id: EchoStage.java,v 1.1 2004/03/31 12:11:00 lsimons Exp $
 */
public class EchoStage extends AbstractStage
{
    public EchoStage( final Channel queue, final Sink errorHandler )
    {
        super( queue, errorHandler );
    }

    protected void process( final HTTPEvent e )
            throws HTTPException, IOException
    {
        final HTTPMessage req = e.getHTTPRequest();
        final HTTPMessage res = e.getHTTPResponse();

        res.setField1( HTTPEncoding.VERSION_10 );
        res.setStatusCode( HTTPEncoding.STATUS_200_OK );
        res.setField3( "Debugging...the body should equal your request" );

        res.addHeader( "Content-Type", "text/plain");

        res.addBodyPart( req.getField1() );
        res.addBodyPart( HTTPMessageWriterImpl.SP );
        res.addBodyPart( req.getField2() );
        res.addBodyPart( HTTPMessageWriterImpl.SP );
        res.addBodyPart( req.getField3() );
        res.addBodyPart( HTTPMessageWriterImpl.CRLF );

        final Iterator it = req.getHeaders().iterator();

        while( it.hasNext() )
        {
            final HTTPField field = (HTTPField)it.next();

            res.addBodyPart( field.getName() );
            res.addBodyPart( HTTPMessageWriterImpl.COLON_SP );
            res.addBodyPart( field.getValue() );
            res.addBodyPart( HTTPMessageWriterImpl.CRLF );
        }
        res.addBodyPart( HTTPMessageWriterImpl.CRLF );

        final ByteBuffer[] bp = req.getBodyParts();
        res.addBodyParts( bp );

        e.getContext().put( WritingStage.CLOSE_AFTER_WRITE_CONTEXT_KEY,
                "yep!" );
    }
}



-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials
Free Linux tutorial presented by Daniel Robbins, President and CEO of
GenToo technologies. Learn everything from fundamentals to system
administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.