Moved the old coyote-specific servlet api impl to coyote/servlet
authorcostin <costin@13f79535-47bb-0310-9956-ffa450edef68>
Thu, 26 Nov 2009 06:48:42 +0000 (06:48 +0000)
committercostin <costin@13f79535-47bb-0310-9956-ffa450edef68>
Thu, 26 Nov 2009 06:48:42 +0000 (06:48 +0000)
Added (10% working) coyote connector that uses the new http impl

git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@884418 13f79535-47bb-0310-9956-ffa450edef68

61 files changed:
modules/tomcat-lite/java/org/apache/coyote/lite/LiteProtocolHandler.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/BodyReader.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/BodyWriter.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/CharsetMapperDefault.properties [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/ClientAbortException.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/Connector.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/CoyoteConnector.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/FilterChainImpl.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/FilterConfigImpl.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/JspLoader.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/Locale2Charset.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/ParameterMap.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/RequestDispatcherImpl.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/ServletConfigImpl.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/ServletContextImpl.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/ServletInputStreamImpl.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/ServletOutputStreamImpl.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/ServletReaderImpl.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/ServletRequestImpl.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/ServletRequestWrapperImpl.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/ServletResponseImpl.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/ServletResponseIncludeWrapper.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/ServletWriterImpl.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/TomcatLite.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/WebappContextMapper.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/WebappFilterMapper.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/WebappServletMapper.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/coyote/servlet/config.properties [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/tomcat/lite/BodyReader.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/BodyWriter.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/CharsetMapperDefault.properties [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/ClientAbortException.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/Connector.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/ContextPreinitListener.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/FilterChainImpl.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/FilterConfigImpl.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/Locale2Charset.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/ParameterMap.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/RequestDispatcherImpl.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/ServletConfigImpl.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/ServletContextImpl.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/ServletInputStreamImpl.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/ServletOutputStreamImpl.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/ServletReaderImpl.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestImpl.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestWrapperImpl.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseImpl.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseIncludeWrapper.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/ServletWriterImpl.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/TomcatLite.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/WebappContextMapper.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/WebappFilterMapper.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/WebappServletMapper.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/config.properties [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/CoyoteConnector.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/service/IOStatus.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/tomcat/lite/service/JMXProxy.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/tomcat/lite/service/LogConfig.java [new file with mode: 0644]
modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/ServletContextConfig.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/TomcatLiteWebXmlConfig.java [deleted file]
modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/WebXml.java [deleted file]

diff --git a/modules/tomcat-lite/java/org/apache/coyote/lite/LiteProtocolHandler.java b/modules/tomcat-lite/java/org/apache/coyote/lite/LiteProtocolHandler.java
new file mode 100644 (file)
index 0000000..1c6da20
--- /dev/null
@@ -0,0 +1,151 @@
+package org.apache.coyote.lite;
+
+
+
+import java.io.IOException;
+import java.util.Iterator;
+
+import org.apache.coyote.Adapter;
+import org.apache.coyote.InputBuffer;
+import org.apache.coyote.OutputBuffer;
+import org.apache.coyote.ProtocolHandler;
+import org.apache.coyote.Request;
+import org.apache.coyote.Response;
+import org.apache.tomcat.lite.http.HttpConnector;
+import org.apache.tomcat.lite.http.HttpRequest;
+import org.apache.tomcat.lite.http.HttpResponse;
+import org.apache.tomcat.lite.http.HttpChannel.HttpService;
+import org.apache.tomcat.lite.io.CBuffer;
+import org.apache.tomcat.lite.io.SocketConnector;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+
+/**
+ * Work in progress - use the refactored http as a coyote connector.
+ * Just basic requests work right now - need to implement all the 
+ * methods of coyote.
+ * 
+ * 
+ * @author Costin Manolache
+ */
+public class LiteProtocolHandler implements ProtocolHandler {
+
+    Adapter adapter;
+    
+    @Override
+    public void destroy() throws Exception {
+    }
+
+    @Override
+    public Adapter getAdapter() {
+        return adapter;
+    }
+
+    @Override
+    public Object getAttribute(String name) {
+        return null;
+    }
+
+    @Override
+    public Iterator<String> getAttributeNames() {
+        return null;
+    }
+
+    @Override
+    public void init() throws Exception {
+    }
+
+    @Override
+    public void pause() throws Exception {
+    }
+
+    @Override
+    public void resume() throws Exception {
+    }
+
+    @Override
+    public void setAdapter(Adapter adapter) {
+        this.adapter = adapter;
+        
+    }
+
+    int port = 8999;
+    
+    public void setPort(int port) {
+        this.port = port;
+    }
+    
+    @Override
+    public void setAttribute(String name, Object value) {
+        System.err.println("setAttribute " + name + " " + value);
+    }
+
+    @Override
+    public void start() throws Exception {
+        HttpConnector c = new HttpConnector(new SocketConnector());
+        c.setPort(port);
+        
+//        c.setDebug(true);
+//        c.setDebugHttp(true);
+        
+        c.getDispatcher().setDefaultService(new HttpService() {
+            @Override
+            public void service(HttpRequest httpReq, HttpResponse httpRes)
+                    throws IOException {
+                coyoteService(httpReq, httpRes);
+            }
+
+        });
+        c.start();
+    }
+    
+    private void wrap(MessageBytes dest, CBuffer buffer) {
+        dest.setChars(buffer.array(), buffer.position(), 
+                buffer.length());
+    }
+
+    private void coyoteService(HttpRequest httpReq, final HttpResponse httpRes) {
+        Request req = new Request();
+        req.setInputBuffer(new InputBuffer() {
+            @Override
+            public int doRead(ByteChunk chunk, Request request)
+                    throws IOException {
+                // TODO
+                return 0;
+            }
+        });
+        Response res = new Response();
+        res.setOutputBuffer(new OutputBuffer() {
+
+            @Override
+            public int doWrite(org.apache.tomcat.util.buf.ByteChunk chunk,
+                    Response response) throws IOException {
+                httpRes.getBody().append(chunk.getBuffer(), chunk.getStart(),
+                        chunk.getLength());
+                return chunk.getLength();
+            }
+            
+        });
+        
+        // TODO: turn http request into a coyote request - copy all fields, 
+        // add hooks where needed.
+        
+        wrap(req.decodedURI(), httpReq.decodedURI());
+        wrap(req.method(), httpReq.method());
+        wrap(req.protocol(), httpReq.protocol());
+        wrap(req.requestURI(), httpReq.requestURI());
+        // Same for response.
+        
+        try {
+            
+            adapter.service(req, res);
+            
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+    
+    
+    
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/BodyReader.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/BodyReader.java
new file mode 100644 (file)
index 0000000..228edea
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.coyote.servlet;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.HashMap;
+
+import org.apache.tomcat.util.buf.B2CConverter;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.CharChunk;
+
+/**
+ * Refactored from catalina.connector.InputBuffer. Renamed to avoid conflict
+ * with coyote class.
+ * 
+ */
+
+/**
+ * The buffer used by Tomcat request. This is a derivative of the Tomcat 3.3
+ * OutputBuffer, adapted to handle input instead of output. This allows 
+ * complete recycling of the facade objects (the ServletInputStream and the
+ * BufferedReader).
+ *
+ * @author Remy Maucherat
+ */
+public class BodyReader extends Reader
+    implements ByteChunk.ByteInputChannel, CharChunk.CharInputChannel,
+               CharChunk.CharOutputChannel {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    public static final String DEFAULT_ENCODING = 
+        org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
+    public static final int DEFAULT_BUFFER_SIZE = 8*1024;
+
+    // The buffer can be used for byte[] and char[] reading
+    // ( this is needed to support ServletInputStream and BufferedReader )
+    public final int INITIAL_STATE = 0;
+    public final int CHAR_STATE = 1;
+    public final int BYTE_STATE = 2;
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The byte buffer. More data may be added to it while reading.
+     */
+    private ByteChunk bb;
+
+
+    /**
+     * The chunk buffer, will be filled in from the bb.
+     */
+    private CharChunk cb;
+
+
+    /**
+     * State of the output buffer.
+     */
+    private int state = 0;
+
+
+    /**
+     * Number of bytes read.
+     */
+    private int bytesRead = 0;
+
+
+    /**
+     * Number of chars read.
+     */
+    private int charsRead = 0;
+
+
+    /**
+     * Flag which indicates if the input buffer is closed.
+     */
+    private boolean closed = false;
+
+    /**
+     * Encoding to use.
+     */
+    private String enc;
+
+
+    /**
+     * Encoder is set.
+     */
+    private boolean gotEnc = false;
+
+
+    /**
+     * Cached encoders.
+     */
+    protected HashMap<String, B2CConverter> encoders = 
+      new HashMap<String, B2CConverter>();
+
+
+    /**
+     * Current byte to char converter.
+     */
+    protected B2CConverter conv;
+
+
+    /**
+     * Associated Coyote request.
+     */
+    private ServletRequestImpl coyoteRequest;
+    Connector connector;
+
+    /**
+     * Buffer position.
+     */
+    private int markPos = -1;
+
+
+    /**
+     * Buffer size.
+     */
+    private int size = -1;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Default constructor. Allocate the buffer with the default buffer size.
+     */
+    public BodyReader() {
+        this(DEFAULT_BUFFER_SIZE);
+    }
+
+
+    /**
+     * Alternate constructor which allows specifying the initial buffer size.
+     * 
+     * @param size Buffer size to use
+     */
+    public BodyReader(int size) {
+        this.size = size;
+        bb = new ByteChunk(size);
+        bb.setLimit(size);
+        bb.setByteInputChannel(this);
+        cb = new CharChunk(size);
+        cb.setLimit(size);
+        cb.setOptimizedWrite(false);
+        cb.setCharInputChannel(this);
+        cb.setCharOutputChannel(this);
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Associated Coyote request.
+     * 
+     * @param coyoteRequest Associated Coyote request
+     */
+    public void setConnector(Connector c, ServletRequestImpl coyoteRequest) {
+        this.connector = c;
+        this.coyoteRequest = coyoteRequest;
+    }
+
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Recycle the output buffer.
+     */
+    public void recycle() {
+        
+        state = INITIAL_STATE;
+        bytesRead = 0;
+        charsRead = 0;
+        
+        // If usage of mark made the buffer too big, reallocate it
+        if (cb.getChars().length > size) {
+            cb = new CharChunk(size);
+            cb.setLimit(size);
+            cb.setCharInputChannel(this);
+            cb.setCharOutputChannel(this);
+        } else {
+            cb.recycle();
+        }
+        markPos = -1;
+        bb.recycle(); 
+        closed = false;
+        
+        if (conv != null) {
+            conv.recycle();
+        }
+        
+        gotEnc = false;
+        enc = null;
+        
+    }
+
+
+    /**
+     * Close the input buffer.
+     * 
+     * @throws IOException An underlying IOException occurred
+     */
+    public void close()
+        throws IOException {
+        closed = true;
+    }
+
+
+    public int available()
+        throws IOException {
+        if (state == BYTE_STATE) {
+            return bb.getLength();
+        } else if (state == CHAR_STATE) {
+            return cb.getLength();
+        } else {
+            return 0;
+        }
+    }
+
+
+    // ------------------------------------------------- Bytes Handling Methods
+
+
+    /** 
+     * Reads new bytes in the byte chunk.
+     * 
+     * @param cbuf Byte buffer to be written to the response
+     * @param off Offset
+     * @param len Length
+     * 
+     * @throws IOException An underlying IOException occurred
+     */
+    public int realReadBytes(byte cbuf[], int off, int len)
+       throws IOException {
+
+        if (closed)
+            return -1;
+        if (coyoteRequest == null)
+            return -1;
+
+        state = BYTE_STATE;
+
+        int result = connector.doRead(coyoteRequest, bb);
+
+        return result;
+
+    }
+
+
+    public int readByte()
+        throws IOException {
+        return bb.substract();
+    }
+
+
+    public int read(byte[] b, int off, int len)
+        throws IOException {
+        return bb.substract(b, off, len);
+    }
+
+
+    // ------------------------------------------------- Chars Handling Methods
+
+
+    /**
+     * Since the converter will use append, it is possible to get chars to
+     * be removed from the buffer for "writing". Since the chars have already
+     * been read before, they are ignored. If a mark was set, then the
+     * mark is lost.
+     */
+    public void realWriteChars(char c[], int off, int len) 
+        throws IOException {
+        markPos = -1;
+    }
+
+
+    public void setEncoding(String s) {
+        enc = s;
+    }
+
+    /** 
+     * Called when a read(char[]) operation is lacking data. It will read
+     * bytes.
+     */
+    public int realReadChars(char cbuf[], int off, int len)
+        throws IOException {
+
+        if (!gotEnc)
+            setConverter();
+
+        if (bb.getLength() <= 0) {
+            int nRead = realReadBytes(bb.getBytes(), 0, bb.getBytes().length);
+            if (nRead < 0) {
+                return -1;
+            }
+        }
+
+        if (markPos == -1) {
+            cb.setOffset(0);
+            cb.setEnd(0);
+        }
+
+        conv.convert(bb, cb, -1);
+        bb.setOffset(bb.getEnd());
+        state = CHAR_STATE;
+
+        return cb.getLength();
+
+    }
+
+
+    public int read()
+        throws IOException {
+        return cb.substract();
+    }
+
+
+    public int read(char[] cbuf)
+        throws IOException {
+        return read(cbuf, 0, cbuf.length);
+    }
+
+
+    public int read(char[] cbuf, int off, int len)
+        throws IOException {
+        return cb.substract(cbuf, off, len);
+    }
+
+
+    public long skip(long n)
+        throws IOException {
+
+        if (n < 0) {
+            throw new IllegalArgumentException();
+        }
+
+        long nRead = 0;
+        while (nRead < n) {
+            if (cb.getLength() >= n) {
+                cb.setOffset(cb.getStart() + (int) n);
+                nRead = n;
+            } else {
+                nRead += cb.getLength();
+                cb.setOffset(cb.getEnd());
+                int toRead = 0;
+                if (cb.getChars().length < (n - nRead)) {
+                    toRead = cb.getChars().length;
+                } else {
+                    toRead = (int) (n - nRead);
+                }
+                int nb = realReadChars(cb.getChars(), 0, toRead);
+                if (nb < 0)
+                    break;
+            }
+        }
+
+        return nRead;
+
+    }
+
+
+    public boolean ready()
+        throws IOException {
+        return (cb.getLength() > 0);
+    }
+
+
+    public boolean markSupported() {
+        return true;
+    }
+
+
+    public void mark(int readAheadLimit)
+        throws IOException {
+        if (cb.getLength() <= 0) {
+            cb.setOffset(0);
+            cb.setEnd(0);
+        } else {
+            if ((cb.getBuffer().length > (2 * size)) 
+                && (cb.getLength()) < (cb.getStart())) {
+                System.arraycopy(cb.getBuffer(), cb.getStart(), 
+                                 cb.getBuffer(), 0, cb.getLength());
+                cb.setEnd(cb.getLength());
+                cb.setOffset(0);
+            }
+        }
+        int offset = readAheadLimit;
+        if (offset < size) {
+            offset = size;
+        }
+        cb.setLimit(cb.getStart() + offset);
+        markPos = cb.getStart();
+    }
+
+
+    public void reset()
+        throws IOException {
+        if (state == CHAR_STATE) {
+            if (markPos < 0) {
+                cb.recycle();
+                markPos = -1;
+                throw new IOException();
+            } else {
+                cb.setOffset(markPos);
+            }
+        } else {
+            bb.recycle();
+        }
+    }
+
+
+    protected void setConverter()
+        throws IOException {
+        if (coyoteRequest != null)
+            enc = coyoteRequest.getCharacterEncoding();
+
+        gotEnc = true;
+        if (enc == null)
+            enc = DEFAULT_ENCODING;
+        conv = (B2CConverter) encoders.get(enc);
+        if (conv == null) {
+          conv = new B2CConverter(enc);
+          encoders.put(enc, conv);
+        }
+    }
+    
+    public class MRInputStream extends InputStream {
+        public long skip(long n)
+                throws IOException {
+            return BodyReader.this.skip(n);
+        }
+
+        public void mark(int readAheadLimit)
+        {
+            try {
+                BodyReader.this.mark(readAheadLimit);
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+
+
+        public void reset()
+        throws IOException {
+            BodyReader.this.reset();
+        }
+
+
+
+        public int read()
+        throws IOException {    
+            return BodyReader.this.readByte();
+        }
+
+        public int available() throws IOException {
+            return BodyReader.this.available();
+        }
+
+        public int read(final byte[] b) throws IOException {
+            return BodyReader.this.read(b, 0, b.length);
+        }
+
+
+        public int read(final byte[] b, final int off, final int len)
+        throws IOException {
+
+            return BodyReader.this.read(b, off, len);
+        }
+
+
+        /** 
+         * Close the stream
+         * Since we re-cycle, we can't allow the call to super.close()
+         * which would permantely disable us.
+         */
+        public void close() throws IOException {
+            BodyReader.this.close();
+        }
+    }
+    
+    MRInputStream is = new MRInputStream();
+    
+    public InputStream asInputStream() {
+        return is;
+    }
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/BodyWriter.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/BodyWriter.java
new file mode 100644 (file)
index 0000000..e88097f
--- /dev/null
@@ -0,0 +1,671 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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.apache.coyote.servlet;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.HashMap;
+
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.C2BConverter;
+import org.apache.tomcat.util.buf.CharChunk;
+
+/**
+ * Implement buffering and character translation acording to the
+ * servlet spec.
+ *
+ * This class handles both chars and bytes.
+ *
+ * It is tightly integrated with servlet response, sending headers
+ * and updating the commit state.
+ *
+ * TODO: add 'extension' interface that allows direct access to
+ * the async connector non-copy non-blocking queue. Same for the
+ * OutputStream. Maybe switch the buffer to the brigade.
+ *
+ * @author Costin Manolache
+ */
+public class BodyWriter extends Writer {
+
+    // used in getWriter, until a method is added to res.
+    protected static final int WRITER_NOTE = 3;
+
+
+    private ByteChunk.ByteOutputChannel byteFlusher =
+        new ByteChunk.ByteOutputChannel() {
+
+        @Override
+        public void realWriteBytes(byte[] cbuf, int off, int len)
+                throws IOException {
+            BodyWriter.this.realWriteBytes(cbuf, off, len);
+        }
+    };
+
+    private CharChunk.CharOutputChannel charFlusher =
+        new CharChunk.CharOutputChannel() {
+        @Override
+        public void realWriteChars(char[] cbuf, int off, int len)
+                throws IOException {
+            BodyWriter.this.realWriteChars(cbuf, off, len);
+        }
+    };
+
+
+    public static final String DEFAULT_ENCODING =
+        org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
+    public static final int DEFAULT_BUFFER_SIZE = 8*1024;
+
+
+    // The buffer can be used for byte[] and char[] writing
+    // ( this is needed to support ServletOutputStream and for
+    // efficient implementations of templating systems )
+    public final int CHAR_STATE = 1;
+    public final int BYTE_STATE = 2;
+
+    boolean headersSent = false;
+    // ----------------------------------------------------- Instance Variables
+    ServletResponseImpl res;
+
+    /**
+     * The byte buffer.
+     */
+    protected ByteChunk bb;
+
+
+    /**
+     * The chunk buffer.
+     */
+    protected CharChunk cb;
+
+
+    /**
+     * State of the output buffer.
+     */
+    protected int state = 0;
+
+
+    /**
+     * Number of bytes written.
+     */
+    protected int bytesWritten = 0;
+
+
+    /**
+     * Number of chars written.
+     */
+    protected int charsWritten = 0;
+
+
+    /**
+     * Flag which indicates if the output buffer is closed.
+     */
+    protected boolean closed = false;
+
+
+    /**
+     * Do a flush on the next operation.
+     */
+    protected boolean doFlush = false;
+
+
+    /**
+     * Byte chunk used to output bytes. This is just used to wrap the byte[]
+     * to match the coyote OutputBuffer interface
+     */
+    protected ByteChunk outputChunk = new ByteChunk();
+
+
+    /**
+     * Encoding to use.
+     * TODO: isn't it redundant ? enc, gotEnc, conv plus the enc in the bb
+     */
+    protected String enc;
+
+
+    /**
+     * Encoder is set.
+     */
+    protected boolean gotEnc = false;
+
+
+    /**
+     * List of encoders. The writer is reused - the encoder mapping
+     * avoids creating expensive objects. In future it'll contain nio.Charsets
+     */
+    protected HashMap encoders = new HashMap();
+
+
+    /**
+     * Current char to byte converter. TODO: replace with Charset
+     */
+    protected C2BConverter conv;
+
+    /**
+     * Suspended flag. All output bytes will be swallowed if this is true.
+     */
+    protected boolean suspended = false;
+
+    private Connector connector;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Default constructor. Allocate the buffer with the default buffer size.
+     */
+    public BodyWriter() {
+
+        this(DEFAULT_BUFFER_SIZE);
+
+    }
+
+
+    /**
+     * Alternate constructor which allows specifying the initial buffer size.
+     *
+     * @param size Buffer size to use
+     */
+    public BodyWriter(int size) {
+
+        bb = new ByteChunk(size);
+        bb.setLimit(size);
+        bb.setByteOutputChannel(byteFlusher);
+        cb = new CharChunk(size);
+        cb.setCharOutputChannel(charFlusher);
+        cb.setLimit(size);
+
+    }
+
+    public void setConnector(Connector c, ServletResponseImpl res) {
+        this.res = res;
+        this.connector = c;
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * Is the response output suspended ?
+     *
+     * @return suspended flag value
+     */
+    public boolean isSuspended() {
+        return this.suspended;
+    }
+
+
+    /**
+     * Set the suspended flag.
+     *
+     * @param suspended New suspended flag value
+     */
+    public void setSuspended(boolean suspended) {
+        this.suspended = suspended;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Recycle the output buffer.
+     */
+    public void recycle() {
+
+        state = BYTE_STATE;
+        headersSent = false;
+        bytesWritten = 0;
+        charsWritten = 0;
+
+        cb.recycle();
+        bb.recycle();
+        closed = false;
+        suspended = false;
+
+        if (conv!= null) {
+            conv.recycle();
+        }
+
+        gotEnc = false;
+        enc = null;
+
+    }
+
+
+    /**
+     * Close the output buffer. This tries to calculate the response size if
+     * the response has not been committed yet.
+     *
+     * @throws IOException An underlying IOException occurred
+     */
+    public void close()
+        throws IOException {
+
+        if (closed)
+            return;
+        if (suspended)
+            return;
+
+        if (state == CHAR_STATE) {
+            cb.flushBuffer();
+            state = BYTE_STATE;
+        }
+        connector.beforeClose(res, bb.getLength());
+
+        doFlush(false);
+        closed = true;
+
+        connector.finishResponse(res);
+    }
+
+
+    /**
+     * Flush bytes or chars contained in the buffer.
+     *
+     * @throws IOException An underlying IOException occurred
+     */
+    public void flush()
+        throws IOException {
+        doFlush(true);
+    }
+
+    /**
+     * Flush bytes or chars contained in the buffer.
+     *
+     * @throws IOException An underlying IOException occurred
+     */
+    protected void doFlush(boolean realFlush)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        doFlush = true;
+        if (!headersSent) {
+            // If the buffers are empty, commit the response header
+            connector.sendHeaders(res);
+            headersSent = true;
+        }
+        if (state == CHAR_STATE) {
+            cb.flushBuffer();
+            state = BYTE_STATE;
+        }
+        if (state == BYTE_STATE) {
+            bb.flushBuffer();
+        }
+        doFlush = false;
+
+        if (realFlush) {
+            connector.realFlush(res);
+        }
+
+    }
+
+
+    // ------------------------------------------------- Bytes Handling Methods
+
+
+    /**
+     * Sends the buffer data to the client output, checking the
+     * state of Response and calling the right interceptors.
+     *
+     * @param buf Byte buffer to be written to the response
+     * @param off Offset
+     * @param cnt Length
+     *
+     * @throws IOException An underlying IOException occurred
+     */
+    private void realWriteBytes(byte buf[], int off, int cnt)
+        throws IOException {
+
+        if (closed)
+            return;
+
+        // If we really have something to write
+        if (cnt > 0) {
+            // real write to the adapter
+            outputChunk.setBytes(buf, off, cnt);
+            try {
+                connector.doWrite(res, outputChunk);
+            } catch (IOException e) {
+                // An IOException on a write is almost always due to
+                // the remote client aborting the request.  Wrap this
+                // so that it can be handled better by the error dispatcher.
+                throw new ClientAbortException(e);
+            }
+        }
+
+    }
+
+
+    public void write(byte b[], int off, int len) throws IOException {
+
+        if (suspended)
+            return;
+
+        if (state == CHAR_STATE)
+            cb.flushBuffer();
+        state = BYTE_STATE;
+        writeBytes(b, off, len);
+
+    }
+
+
+    private void writeBytes(byte b[], int off, int len)
+        throws IOException {
+
+        if (closed)
+            return;
+
+        bb.append(b, off, len);
+        bytesWritten += len;
+
+        // if called from within flush(), then immediately flush
+        // remaining bytes
+        if (doFlush) {
+            bb.flushBuffer();
+        }
+
+    }
+
+
+    public void writeByte(int b)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        if (state == CHAR_STATE)
+            cb.flushBuffer();
+        state = BYTE_STATE;
+
+        bb.append( (byte)b );
+        bytesWritten++;
+
+    }
+
+
+    // ------------------------------------------------- Chars Handling Methods
+
+
+    public void write(int c)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        state = CHAR_STATE;
+
+        cb.append((char) c);
+        charsWritten++;
+
+    }
+
+
+    public void write(char c[])
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        write(c, 0, c.length);
+
+    }
+
+
+    public void write(char c[], int off, int len)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        state = CHAR_STATE;
+
+        cb.append(c, off, len);
+        charsWritten += len;
+
+    }
+
+
+    public void write(StringBuilder sb)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        state = CHAR_STATE;
+
+        int len = sb.length();
+        charsWritten += len;
+        cb.append(sb.toString());
+
+    }
+
+
+    /**
+     * Append a string to the buffer
+     */
+    public void write(String s, int off, int len)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        state=CHAR_STATE;
+
+        charsWritten += len;
+        if (s==null)
+            s="null";
+        cb.append( s, off, len );
+
+    }
+
+
+    public void write(String s)
+        throws IOException {
+
+        if (suspended)
+            return;
+
+        state = CHAR_STATE;
+        if (s==null)
+            s="null";
+        write(s, 0, s.length());
+
+    }
+
+    public void println() throws IOException {
+        write("\n");
+    }
+
+    public void println(String s) throws IOException {
+        write(s);
+        write("\n");
+    }
+
+    public void print(String s) throws IOException {
+        write(s);
+    }
+
+    public void flushChars()
+        throws IOException {
+
+        cb.flushBuffer();
+        state = BYTE_STATE;
+
+    }
+
+
+    public boolean flushCharsNeeded() {
+        return state == CHAR_STATE;
+    }
+
+
+    public void setEncoding(String s) {
+        enc = s;
+    }
+
+
+    private void realWriteChars(char c[], int off, int len)
+        throws IOException {
+
+        if (!gotEnc)
+            setConverter();
+
+        conv.convert(c, off, len);
+        conv.flushBuffer();     // ???
+
+    }
+
+
+    public void checkConverter()
+        throws IOException {
+
+        if (!gotEnc)
+            setConverter();
+
+    }
+
+
+    protected void setConverter()
+        throws IOException {
+
+        enc = res.getCharacterEncoding();
+
+        gotEnc = true;
+        if (enc == null)
+            enc = DEFAULT_ENCODING;
+        conv = (C2BConverter) encoders.get(enc);
+        if (conv == null) {
+
+            if (System.getSecurityManager() != null){
+                try{
+                    conv = (C2BConverter)AccessController.doPrivileged(
+                            new PrivilegedExceptionAction(){
+
+                                public Object run() throws IOException{
+                                    return new C2BConverter(bb, enc);
+                                }
+
+                            }
+                    );
+                }catch(PrivilegedActionException ex){
+                    Exception e = ex.getException();
+                    if (e instanceof IOException)
+                        throw (IOException)e;
+                }
+            } else {
+                conv = new C2BConverter(bb, enc);
+            }
+
+            encoders.put(enc, conv);
+
+        }
+    }
+
+
+    // --------------------  BufferedOutputStream compatibility
+
+
+    /**
+     * Real write - this buffer will be sent to the client
+     */
+    public void flushBytes()
+        throws IOException {
+
+        bb.flushBuffer();
+
+    }
+
+
+    public int getBytesWritten() {
+        return bytesWritten;
+    }
+
+
+    public int getCharsWritten() {
+        return charsWritten;
+    }
+
+
+    public int getContentWritten() {
+        return bytesWritten + charsWritten;
+    }
+
+
+    /**
+     * True if this buffer hasn't been used ( since recycle() ) -
+     * i.e. no chars or bytes have been added to the buffer.
+     */
+    public boolean isNew() {
+        return (bytesWritten == 0) && (charsWritten == 0);
+    }
+
+
+    public void setBufferSize(int size) {
+        if (size > bb.getLimit()) {// ??????
+            bb.setLimit(size);
+        }
+    }
+
+
+    public void reset() {
+
+        //count=0;
+        bb.recycle();
+        bytesWritten = 0;
+        cb.recycle();
+        charsWritten = 0;
+        gotEnc = false;
+        enc = null;
+        state = BYTE_STATE;
+    }
+
+
+    public int getBufferSize() {
+        return bb.getLimit();
+    }
+
+    public ByteChunk getByteBuffer() {
+      return outputChunk;
+    }
+
+}
+//{
+//    public abstract int getBytesWritten();
+//    public abstract int getCharsWritten();
+//    public abstract void recycle();
+//    public abstract void setSuspended(boolean suspended);
+//    public abstract boolean isSuspended();
+//
+//    public abstract void reset();
+//    public abstract int getBufferSize();
+//    public abstract void setBufferSize(int n);
+//    public abstract void checkConverter() throws IOException;
+//    public boolean isNew() {
+//        return getBytesWritten() == 0 && getCharsWritten() == 0;
+//    }
+//    public abstract void write(byte[] b, int off, int len) throws IOException;
+//    public abstract void writeByte(int b) throws IOException;
+//
+//}
\ No newline at end of file
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/CharsetMapperDefault.properties b/modules/tomcat-lite/java/org/apache/coyote/servlet/CharsetMapperDefault.properties
new file mode 100644 (file)
index 0000000..c73a8fc
--- /dev/null
@@ -0,0 +1,2 @@
+en=ISO-8859-1
+fr=ISO-8859-1
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/ClientAbortException.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/ClientAbortException.java
new file mode 100644 (file)
index 0000000..b4c6909
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.coyote.servlet;
+
+import java.io.IOException;
+
+/**
+ * Wrap an IOException identifying it as being caused by an abort
+ * of a request by a remote client.
+ *
+ * @author Glenn L. Nielsen
+ * @version $Revision: 304063 $ $Date: 2005-08-18 06:25:18 -0700 (Thu, 18 Aug 2005) $
+ */
+
+public final class ClientAbortException extends IOException {
+
+
+    //------------------------------------------------------------ Constructors
+
+
+    /**
+     * Construct a new ClientAbortException with no other information.
+     */
+    public ClientAbortException() {
+
+        this(null, null);
+
+    }
+
+
+    /**
+     * Construct a new ClientAbortException for the specified message.
+     *
+     * @param message Message describing this exception
+     */
+    public ClientAbortException(String message) {
+
+        this(message, null);
+
+    }
+
+
+    /**
+     * Construct a new ClientAbortException for the specified throwable.
+     *
+     * @param throwable Throwable that caused this exception
+     */
+    public ClientAbortException(Throwable throwable) {
+
+        this(null, throwable);
+
+    }
+
+
+    /**
+     * Construct a new ClientAbortException for the specified message
+     * and throwable.
+     *
+     * @param message Message describing this exception
+     * @param throwable Throwable that caused this exception
+     */
+    public ClientAbortException(String message, Throwable throwable) {
+
+        super();
+        this.message = message;
+        this.throwable = throwable;
+
+    }
+
+
+    //------------------------------------------------------ Instance Variables
+
+
+    /**
+     * The error message passed to our constructor (if any)
+     */
+    protected String message = null;
+
+
+    /**
+     * The underlying exception or error passed to our constructor (if any)
+     */
+    protected Throwable throwable = null;
+
+
+    //---------------------------------------------------------- Public Methods
+
+
+    /**
+     * Returns the message associated with this exception, if any.
+     */
+    public String getMessage() {
+
+        return (message);
+
+    }
+
+
+    /**
+     * Returns the cause that caused this exception, if any.
+     */
+    public Throwable getCause() {
+        
+        return (throwable);
+        
+    }
+
+    
+    /**
+     * Return a formatted string that describes this exception.
+     */
+    public String toString() {
+
+        StringBuilder sb = new StringBuilder("ClientAbortException:  ");
+        if (message != null) {
+            sb.append(message);
+            if (throwable != null) {
+                sb.append(":  ");
+            }
+        }
+        if (throwable != null) {
+            sb.append(throwable.toString());
+        }
+        return (sb.toString());
+
+    }
+
+
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/Connector.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/Connector.java
new file mode 100644 (file)
index 0000000..3a997a9
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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.apache.coyote.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tomcat.integration.ObjectManager;
+import org.apache.tomcat.util.buf.ByteChunk;
+
+/**
+ * What we need to plugin a connector.
+ * 
+ * Currently we have lots of deps on coyote Request, but I plan to
+ * change this and allow other HTTP implementations - like MINA, the
+ * experimental async connector, etc. Most important will be 
+ * different support for IO - i.e. a more non-blocking mode.
+ * We'll probably keep MessageBytes as wrappers for request/res
+ * properties. 
+ * 
+ * This interface has no dep on coyote.
+ *  
+ */
+public interface Connector {
+
+    public void setDaemon(boolean b);
+    
+    public void start() throws IOException;
+    
+    public void stop() throws Exception;
+    
+    /**
+     * Called during close() - either on explicit output close, or 
+     * after the request is completed. 
+     * 
+     * @throws IOException
+     */
+    public abstract void finishResponse(HttpServletResponse res) throws IOException;
+   
+    /**
+     * Called before flushing the output during close.
+     * Content-Length may be updated.
+     * @param len 
+     * 
+     * @throws IOException
+     */
+    public abstract void beforeClose(HttpServletResponse res, int len) throws IOException;
+    
+    /** 
+     * Called when the first flush() is called.
+     * @throws IOException
+     */
+    public abstract void sendHeaders(HttpServletResponse res) throws IOException;
+    
+    /**
+     * Send data to the client.
+     * @throws IOException
+     */
+    public abstract void realFlush(HttpServletResponse res) throws IOException;
+
+    /**
+     * Write to the connector underlying buffer.
+     * The chunk will be reused (currently).
+     */
+    public abstract void doWrite(HttpServletResponse res, ByteChunk outputChunk2) throws IOException;
+
+    
+    //public void finishResponse(HttpServletResponse res) throws IOException;
+    
+    public void acknowledge(HttpServletResponse res) throws IOException;
+
+    public void reset(HttpServletResponse res);
+    
+    public void recycle(HttpServletRequest req, HttpServletResponse res);
+
+    void initRequest(HttpServletRequest req, HttpServletResponse res);
+
+    public void setTomcatLite(TomcatLite tomcatLite);
+
+    public void setObjectManager(ObjectManager objectManager);
+    
+    public String getRemoteHost(HttpServletRequest req);
+    
+    public String getRemoteAddr(HttpServletRequest req);
+    
+    public int doRead(ServletRequestImpl coyoteRequest, ByteChunk bb) throws IOException;
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/CoyoteConnector.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/CoyoteConnector.java
new file mode 100644 (file)
index 0000000..4e8cd52
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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.apache.coyote.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.coyote.ActionCode;
+import org.apache.coyote.ActionHook;
+import org.apache.coyote.Adapter;
+import org.apache.coyote.ProtocolHandler;
+import org.apache.coyote.Request;
+import org.apache.coyote.Response;
+import org.apache.coyote.http11.Http11NioProtocol;
+import org.apache.tomcat.integration.ObjectManager;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.UriNormalizer;
+import org.apache.tomcat.util.http.HttpRequest;
+import org.apache.tomcat.util.http.HttpResponse;
+import org.apache.tomcat.util.net.SocketStatus;
+
+public class CoyoteConnector implements Adapter, Connector {
+
+    private TomcatLite lite;
+
+    public CoyoteConnector() {
+    }
+
+
+
+    public void acknowledge(HttpServletResponse res) throws IOException {
+        Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse;
+        cres.acknowledge();
+    }
+
+    public void reset(HttpServletResponse res) {
+        Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse;
+        cres.reset();
+    }
+
+    public void recycle(HttpServletRequest req, HttpServletResponse res) {
+
+    }
+
+    public static HttpResponse getResponse(final Response cres) {
+        HttpResponse hres = new HttpResponse() {
+            public int getStatus() {
+                return cres.getStatus();
+            }
+            public void setStatus(int i) {
+                super.setStatus(i);
+                cres.setStatus(i);
+            }
+            public void setMessage(String s) {
+                super.setMessage(s);
+                cres.setMessage(s);
+            }
+            public String getMessage() {
+                return cres.getMessage();
+            }
+            public boolean isCommitted() {
+                return cres.isCommitted();
+            }
+
+            public void setCommitted(boolean b) {
+                cres.setCommitted(b);
+            }
+        };
+
+        hres.setMimeHeaders(cres.getMimeHeaders());
+        hres.nativeResponse = cres;
+
+        return hres;
+    }
+
+    public static HttpRequest getRequest(Request req) {
+
+        HttpRequest httpReq = new HttpRequest(req.scheme(),
+                req.method(),
+                req.unparsedURI(),
+                req.protocol(),
+                req.getMimeHeaders(),
+                req.requestURI(),
+                req.decodedURI(),
+                req.query(), req.getParameters(),
+                req.serverName(),
+                req.getCookies()) {
+
+        };
+        httpReq.nativeRequest = req;
+
+        // TODO: anything else computed in coyote ?
+
+        return httpReq;
+    }
+
+    @Override
+    public void initRequest(HttpServletRequest hreq, HttpServletResponse hres) {
+        ServletRequestImpl req = (ServletRequestImpl) hreq;
+        ServletResponseImpl res = (ServletResponseImpl) hres;
+        req.setConnector(this);
+
+        Request creq = new Request();
+        Response cres = new Response();
+        HttpResponse nRes = getResponse(cres);
+
+        BodyWriter out = new BodyWriter(4096);
+        out.setConnector(this, res);
+
+        res.setHttpResponse(nRes, out);
+
+        cres.setRequest(creq);
+        cres.setHook(new ActionHook() {
+          public void action(ActionCode actionCode,
+                             Object param) {
+          }
+        });
+
+        BodyReader in = new BodyReader();
+        in.setConnector(this, req);
+        HttpRequest nReq = getRequest(creq);
+        req.setHttpRequest(nReq, in);
+
+    }
+
+
+    // ---- Coyote Adapter interface ---
+
+    @Override
+    public void service(Request creq, Response cres) throws Exception {
+        long t0 = System.currentTimeMillis();
+
+        // compute decodedURI - not done by connector
+        UriNormalizer.decodeRequest(creq.decodedURI(), creq.requestURI(), creq.getURLDecoder());
+
+        // find the facades
+        ServletRequestImpl req = (ServletRequestImpl) creq.getNote(ADAPTER_REQ_NOTE);
+        ServletResponseImpl res = (ServletResponseImpl) cres.getNote(ADAPTER_RES_NOTE);
+
+
+        if (req == null) {
+          req = new ServletRequestImpl();
+          res = req.getResponse();
+
+          BodyReader in = new BodyReader();
+          in.setConnector(this, req);
+
+          HttpRequest nReq = getRequest(creq);
+          nReq.setServerPort(creq.getServerPort());
+          HttpResponse nRes = getResponse(cres);
+
+          req.setHttpRequest(nReq, in);
+          BodyWriter out = new BodyWriter(4096);
+          out.setConnector(this, res);
+
+          res.setHttpResponse(nRes, out);
+
+          creq.setNote(ADAPTER_REQ_NOTE, req);
+          cres.setNote(ADAPTER_RES_NOTE, res);
+
+        }
+        req.setConnector(this);
+
+        try {
+            lite.service(req, res);
+        } catch(IOException ex) {
+            throw ex;
+        } catch( Throwable t ) {
+            t.printStackTrace();
+        } finally {
+            long t1 = System.currentTimeMillis();
+
+//            log.info("<<<<<<<< DONE: " + creq.method() + " " +
+//                    creq.decodedURI() + " " +
+//                    res.getStatus() + " " +
+//                    (t1 - t0));
+
+            // Final processing
+            // TODO: only if not commet, this doesn't work with the
+            // other connectors since we don't have the info
+            // TODO: add this note in the nio/apr connectors
+            // TODO: play nice with TomcatLite, other adapters that flush/close
+            if (cres.getNote(COMET_RES_NOTE) == null) {
+
+                if (!res.isCommitted()) {
+                    cres.sendHeaders();
+                }
+                res.getOutputBuffer().flush();
+
+                BodyWriter mw = res.getBodyWriter();
+                //MessageWriter.getWriter(creq, cres, 0);
+                mw.flush();
+                mw.recycle();
+
+                BodyReader reader = req.getBodyReader();
+                //getReader(creq);
+                reader.recycle();
+
+                cres.finish();
+
+                creq.recycle();
+                cres.recycle();
+
+                req.recycle();
+                res.recycle();
+            }
+        }
+    }
+
+    @Override
+    public boolean event(Request req, Response res, SocketStatus status)
+        throws Exception {
+      return false;
+    }
+
+
+    public void setTomcatLite(TomcatLite lite) {
+        this.lite = lite;
+    }
+
+
+    public String getRemoteHost(HttpServletRequest hreq) {
+        ServletRequestImpl req = (ServletRequestImpl) hreq;
+
+        Request creq = (Request) req.getHttpRequest().nativeRequest;
+        creq.action(ActionCode.ACTION_REQ_HOST_ATTRIBUTE, creq);
+        return creq.remoteHost().toString();
+    }
+
+    public String getRemoteAddr(HttpServletRequest hreq) {
+        ServletRequestImpl req = (ServletRequestImpl) hreq;
+
+        Request creq = (Request) req.getHttpRequest().nativeRequest;
+        creq.action(ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE, creq);
+        return creq.remoteAddr().toString();
+    }
+
+
+    @Override
+    public void beforeClose(HttpServletResponse res, int len) throws IOException {
+        Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse;
+
+        if ((!cres.isCommitted())
+                && (cres.getContentLengthLong() == -1)) {
+                // Flushing the char buffer
+                // If this didn't cause a commit of the response, the final content
+                // length can be calculated
+                if (!cres.isCommitted()) {
+                    cres.setContentLength(len);
+                }
+            }
+    }
+
+    public int doRead(ServletRequestImpl hreq, ByteChunk bb) throws IOException {
+        ServletRequestImpl req = (ServletRequestImpl) hreq;
+
+        Request creq = (Request) req.getHttpRequest().nativeRequest;
+        return creq.doRead(bb);
+    }
+
+    @Override
+    public void doWrite(HttpServletResponse res, ByteChunk chunk)
+            throws IOException {
+        Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse;
+        cres.doWrite(chunk);
+
+    }
+
+
+    @Override
+    public void realFlush(HttpServletResponse res) throws IOException {
+        Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse;
+        cres.action(ActionCode.ACTION_CLIENT_FLUSH,
+                cres);
+        // If some exception occurred earlier, or if some IOE occurred
+        // here, notify the servlet with an IOE
+        if (cres.isExceptionPresent()) {
+            throw new ClientAbortException
+            (cres.getErrorException());
+        }
+
+    }
+
+
+    @Override
+    public void sendHeaders(HttpServletResponse res) throws IOException {
+        Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse;
+
+        // This should happen before 'prepareResponse' is called !!
+        // Now update coyote response based on response
+        // don't set charset/locale - they're computed in lite
+        cres.setContentType(res.getContentType());
+        cres.sendHeaders();
+    }
+
+    @Override
+    public void finishResponse(HttpServletResponse res) throws IOException {
+        Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse;
+        cres.finish();
+    }
+
+    protected int port = 8800;
+    protected boolean daemon = false;
+
+    /**
+     * Note indicating the response is COMET.
+     */
+    public static final int COMET_RES_NOTE = 2;
+    public static final int COMET_REQ_NOTE = 2;
+
+    public static final int ADAPTER_RES_NOTE = 1;
+    public static final int ADAPTER_REQ_NOTE = 1;
+
+    protected ProtocolHandler proto;
+
+    //protected Adapter adapter = new MapperAdapter();
+    protected int maxThreads = 20;
+    boolean started = false;
+    boolean async = false; // use old nio connector
+
+    protected ObjectManager om;
+
+
+    public void setObjectManager(ObjectManager om) {
+        this.om = om;
+    }
+
+    /**
+     * Add an adapter. If more than the 'default' adapter is
+     * added, a MapperAdapter will be inserted.
+     *
+     * @param path Use "/" for the default.
+     * @param adapter
+     */
+//    public void addAdapter(String path, Adapter added) {
+//        if ("/".equals(path)) {
+//            ((MapperAdapter) adapter).setDefaultAdapter(added);
+//        } else {
+//            ((MapperAdapter) adapter).getMapper().addWrapper(path, added);
+//        }
+//    }
+
+    /**
+     */
+    public void run() {
+        try {
+            init();
+            start();
+        } catch(IOException ex) {
+            ex.printStackTrace();
+        }
+    }
+
+    public void setDaemon(boolean b) {
+      daemon = b;
+    }
+
+    protected void initAdapters() {
+        if (proto == null) {
+            addProtocolHandler(port, daemon);
+        }
+      // adapter = ...
+      // Adapter secondaryadapter = ...
+      //registry.registerComponent(secondaryadapter, ":name=adapter", null);
+    }
+
+    public void stop() throws Exception {
+      if (!started) {
+        return;
+      }
+      proto.destroy();
+      started = false;
+    }
+
+//    /**
+//     *  Simple CLI support - arg is a path:className pair.
+//     */
+//    public void setAdapter(String arg)  {
+//      String[] pathClass = arg.split(":", 2);
+//      try {
+//        Class c = Class.forName(pathClass[1]);
+//        Adapter a = (Adapter) c.newInstance();
+//        addAdapter(pathClass[0],a);
+//      } catch (Throwable e) {
+//        e.printStackTrace();
+//      }
+//    }
+
+    public void setConnector(ProtocolHandler h) {
+        this.proto = h;
+        h.setAttribute("port", Integer.toString(port));
+
+        om.bind("ProtocolHandler:" + "ep-" + port, proto);
+    }
+
+    public void addProtocolHandler(int port, boolean daemon) {
+        Http11NioProtocol proto = new Http11NioProtocol();
+        proto.setCompression("on");
+        proto.setCompressionMinSize(32);
+        proto.setPort(port);
+        //proto.getEndpoint().setDaemon(daemon);
+        setConnector(proto);
+        setPort(port);
+        setDaemon(daemon);
+    }
+
+    public void addProtocolHandler(ProtocolHandler proto,
+                                   int port, boolean daemon) {
+        setConnector(proto);
+        setPort(port);
+        setDaemon(daemon);
+    }
+
+    public void setPort(int port) {
+        if (proto != null) {
+            proto.setAttribute("port", Integer.toString(port));
+        }
+        this.port = port;
+      }
+
+
+    public void init() {
+        //JdkLoggerConfig.loadCustom();
+        om.bind("CoyoteConnector:" + "CoyoteConnector-" + port,
+                this);
+    }
+
+
+    public void start() throws IOException {
+      try {
+        if (started) {
+          return;
+        }
+        init();
+        initAdapters();
+
+        // not required - should run fine without a connector.
+        if (proto != null) {
+            proto.setAdapter(this);
+
+            proto.init();
+            proto.start();
+        }
+
+        started = true;
+      } catch (Throwable e) {
+        e.printStackTrace();
+        throw new RuntimeException(e);
+      }
+    }
+
+    public boolean getStarted() {
+      return started;
+    }
+
+    public boolean asyncDispatch(Request req,Response res, SocketStatus status) throws Exception {
+        // implement me
+        return false;
+    }
+
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/FilterChainImpl.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/FilterChainImpl.java
new file mode 100644 (file)
index 0000000..7cbb54a
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2009 The Apache Software Foundation.
+ * 
+ * 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.apache.coyote.servlet;
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+/**
+ * Wraps the list of filters for the current request. One instance 
+ * associated with each RequestImpl, reused. 
+ * 
+ * Populated by the mapper ( WebappFilterMapper for example ), which
+ * determines the filters for the current request.
+ * 
+ * Not thread safe.
+ */
+public final class FilterChainImpl implements FilterChain {
+    private List<FilterConfigImpl> filters =  new ArrayList<FilterConfigImpl>();
+
+
+    /**
+     * The int which is used to maintain the current position 
+     * in the filter chain.
+     */
+    private int pos = 0;
+
+    /**
+     * The servlet instance to be executed by this chain.
+     */
+    private Servlet servlet = null;
+
+
+    private ServletConfigImpl wrapper;
+
+
+    public FilterChainImpl() {
+        super();
+    }
+
+
+    /**
+     * Invoke the next filter in this chain, passing the specified request
+     * and response.  If there are no more filters in this chain, invoke
+     * the <code>service()</code> method of the servlet itself.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public void doFilter(ServletRequest request, ServletResponse response)
+        throws IOException, ServletException {
+
+
+        // Call the next filter if there is one
+        if (pos < filters.size()) {
+            FilterConfigImpl filterConfig = filters.get(pos++);
+            Filter filter = null;
+            try {
+                filter = filterConfig.getFilter();
+                filter.doFilter(request, response, this);
+            } catch (IOException e) {
+                throw e;
+            } catch (ServletException e) {
+                throw e;
+            } catch (RuntimeException e) {
+                throw e;
+            } catch (Throwable e) {
+                e.printStackTrace();
+                throw new ServletException("Throwable", e);
+            }
+            return;
+        }
+
+        // We fell off the end of the chain -- call the servlet instance
+        try {
+            if (servlet != null) 
+                servlet.service(request, response);
+        } catch (IOException e) {
+            throw e;
+        } catch (ServletException e) {
+            throw e;
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Throwable e) {
+            throw new ServletException("Throwable", e);
+        }
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+
+    /**
+     * Add a filter to the set of filters that will be executed in this chain.
+     *
+     * @param filterConfig The FilterConfig for the servlet to be executed
+     */
+    public void addFilter(FilterConfigImpl filterConfig) {
+        filters.add(filterConfig);
+    }
+
+
+    /**
+     * Release references to the filters and wrapper executed by this chain.
+     */
+    public void release() {
+        filters.clear();
+        pos = 0;
+        servlet = null;
+    }
+
+
+    /**
+     * Set the servlet that will be executed at the end of this chain.
+     * Set by the mapper filter 
+     */
+    public void setServlet(ServletConfigImpl wrapper, Servlet servlet) {
+        this.wrapper = wrapper;
+        this.servlet = servlet;
+    }
+
+    // ------ Getters for information ------------ 
+    
+    public int getSize() {
+        return filters.size();
+    }
+    
+    public FilterConfigImpl getFilter(int i) {
+        return filters.get(i);
+    }
+    
+    public Servlet getServlet() {
+        return servlet;
+    }
+    
+    public ServletConfigImpl getServletConfig() {
+        return wrapper;
+    }
+    
+    public int getPos() {
+        return pos;
+    }
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/FilterConfigImpl.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/FilterConfigImpl.java
new file mode 100644 (file)
index 0000000..2baf77a
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * 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.apache.coyote.servlet;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
+import javax.servlet.FilterRegistration;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.FilterRegistration.Dynamic;
+
+import org.apache.tomcat.servlets.util.Enumerator;
+
+
+/**
+ * A Filter is configured in web.xml by:
+ *  - name - used in mappings
+ *  - className - used to instantiate the filter
+ *  - init params
+ *  - other things not used in the servlet container ( icon, descr, etc )
+ *
+ * Alternatively, in API mode you can pass the actual filter.
+ *
+ * @see ServletConfigImpl
+ */
+public final class FilterConfigImpl implements FilterConfig, FilterRegistration {
+
+    DynamicFilterRegistration dynamic = new DynamicFilterRegistration();
+
+    public FilterConfigImpl(ServletContextImpl context) {
+        this.ctx = context;
+    }
+
+    boolean asyncSupported;
+
+    private ServletContextImpl ctx = null;
+
+    /**
+     * The application Filter we are configured for.
+     */
+    private transient Filter filter = null;
+
+    String descryption;
+
+    private String filterName;
+
+    private String filterClassName;
+
+    Map<String, String> initParams;
+
+    private Class<? extends Filter> filterClass;
+
+    public void setData(String filterName, String filterClass,
+                        Map<String, String> params) {
+        this.filterName = filterName;
+        this.filterClassName = filterClass;
+        this.initParams = params;
+    }
+
+    public void setFilter(Filter f) {
+        filter = f;
+    }
+
+    public String getFilterName() {
+        return filterName;
+    }
+
+    public void setFilterClass(Class<? extends Filter> filterClass2) {
+        this.filterClass = filterClass2;
+    }
+
+
+    public String getInitParameter(String name) {
+        if (initParams == null) return null;
+        return initParams.get(name);
+    }
+
+    /**
+     * Return an <code>Enumeration</code> of the names of the initialization
+     * parameters for this Filter.
+     */
+    public Enumeration getInitParameterNames() {
+        if (initParams == null)
+            return (new Enumerator(new ArrayList()));
+        else
+            return (new Enumerator(initParams.keySet()));
+    }
+
+
+    /**
+     * Return the ServletContext of our associated web application.
+     */
+    public ServletContext getServletContext() {
+        return ctx;
+    }
+
+    /**
+     * Return the application Filter we are configured for.
+     */
+    public Filter createFilter() throws ClassCastException, ClassNotFoundException,
+        IllegalAccessException, InstantiationException, ServletException {
+
+        // Return the existing filter instance, if any
+        if (filter != null)
+            return filter;
+
+        ClassLoader classLoader = ctx.getClassLoader();
+
+        ClassLoader oldCtxClassLoader =
+            Thread.currentThread().getContextClassLoader();
+        if (classLoader != oldCtxClassLoader) {
+            Thread.currentThread().setContextClassLoader(classLoader);
+        }
+        try {
+            if (filterClass == null) {
+                filterClass = (Class<? extends Filter>) classLoader.loadClass(filterClassName);
+            }
+            this.filter = (Filter) filterClass.newInstance();
+        } finally {
+            if (classLoader != oldCtxClassLoader) {
+                Thread.currentThread().setContextClassLoader(oldCtxClassLoader);
+            }
+        }
+
+        // TODO: resource injection
+
+        return filter;
+    }
+
+    public Filter getFilter() throws ClassCastException, ClassNotFoundException, IllegalAccessException, InstantiationException, ServletException {
+        Filter filter = createFilter();
+        filter.init(this);
+        return (this.filter);
+    }
+
+
+    /**
+     * Release the Filter instance associated with this FilterConfig,
+     * if there is one.
+     */
+    public void release() {
+        if (this.filter != null){
+            filter.destroy();
+        }
+        this.filter = null;
+     }
+
+
+   @Override
+    public void addMappingForServletNames(EnumSet<DispatcherType> dispatcherTypes,
+                                          boolean isMatchAfter,
+                                          String... servletNames) {
+        if (ctx.startDone) {
+            // Use the context method instead of the servlet API to
+            // add mappings after context init.
+            throw new IllegalStateException();
+        }
+        ArrayList<String> dispatchers = new ArrayList<String>();
+        for (DispatcherType dt: dispatcherTypes) {
+            dispatchers.add(dt.name());
+        }
+        for (String servletName: servletNames) {
+            ctx.getFilterMapper().addMapping(getFilterName(),
+                    null, servletName, (String[]) dispatchers.toArray(), isMatchAfter);
+        }
+    }
+
+
+   @Override
+    public void addMappingForUrlPatterns(EnumSet<DispatcherType> dispatcherTypes,
+                                         boolean isMatchAfter,
+                                         String... urlPatterns) {
+        if (ctx.startDone) {
+            // Use the context method instead of the servlet API to
+            // add mappings after context init.
+            throw new IllegalStateException();
+        }
+        ArrayList<String> dispatchers = new ArrayList<String>();
+        for (DispatcherType dt: dispatcherTypes) {
+            dispatchers.add(dt.name());
+        }
+        for (String url: urlPatterns) {
+            ctx.getFilterMapper().addMapping(getFilterName(),
+                    url, null, (String[]) dispatchers.toArray(), isMatchAfter);
+        }
+    }
+
+
+   @Override
+    public boolean setInitParameter(String name, String value)
+            throws IllegalArgumentException, IllegalStateException {
+        return ServletContextImpl.setInitParameter(ctx, initParams,
+                name, value);
+    }
+
+
+   @Override
+    public Set<String> setInitParameters(Map<String, String> initParameters)
+    throws IllegalArgumentException, IllegalStateException {
+        return ServletContextImpl.setInitParameters(ctx, initParams,
+                initParameters);
+    }
+
+    public Dynamic getDynamic() {
+        return dynamic;
+    }
+
+    public class DynamicFilterRegistration implements Dynamic {
+
+
+       @Override
+        public void addMappingForServletNames(EnumSet<DispatcherType> dispatcherTypes,
+                                              boolean isMatchAfter,
+                                              String... servletNames) {
+            FilterConfigImpl.this.addMappingForServletNames(dispatcherTypes, isMatchAfter, servletNames);
+        }
+
+
+       @Override
+        public void addMappingForUrlPatterns(EnumSet<DispatcherType> dispatcherTypes,
+                                             boolean isMatchAfter,
+                                             String... urlPatterns) {
+            FilterConfigImpl.this.addMappingForUrlPatterns(dispatcherTypes, isMatchAfter, urlPatterns);
+        }
+
+
+       @Override
+        public boolean setInitParameter(String name, String value)
+                throws IllegalArgumentException, IllegalStateException {
+            return ServletContextImpl.setInitParameter(ctx, initParams,
+                    name, value);
+        }
+
+
+       @Override
+        public Set<String> setInitParameters(Map<String, String> initParameters)
+                throws IllegalArgumentException, IllegalStateException {
+            return ServletContextImpl.setInitParameters(ctx, initParams,
+                    initParameters);
+        }
+
+
+       @Override
+        public void setAsyncSupported(boolean isAsyncSupported)
+                throws IllegalStateException {
+            asyncSupported = isAsyncSupported;
+        }
+
+
+        public void setDescription(String description)
+                throws IllegalStateException {
+            FilterConfigImpl.this.descryption = description;
+        }
+
+       @Override
+        public Collection<String> getUrlPatternMappings() {
+            // implement me
+            return null;
+        }
+
+       @Override
+        public Collection<String> getServletNameMappings() {
+            // implement me
+            return null;
+        }
+
+       @Override
+        public Map<String, String> getInitParameters() {
+            // implement me
+            return null;
+        }
+
+       @Override
+        public String getInitParameter(String name) {
+            if (initParams == null) return null;
+            return initParams.get(name);
+        }
+
+       @Override
+        public String getClassName() {
+            // implement me
+            return null;
+        }
+
+       @Override
+        public String getName() {
+            // implement me
+            return null;
+        }
+    }
+
+   @Override
+    public Collection<String> getUrlPatternMappings() {
+        // implement me
+        return null;
+    }
+
+   @Override
+    public Collection<String> getServletNameMappings() {
+        // implement me
+        return null;
+    }
+
+   @Override
+    public Map<String, String> getInitParameters() {
+        // implement me
+        return null;
+    }
+
+   @Override
+    public String getClassName() {
+        // implement me
+        return null;
+    }
+
+   @Override
+    public String getName() {
+        // implement me
+        return null;
+    }
+
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/JspLoader.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/JspLoader.java
new file mode 100644 (file)
index 0000000..d07644d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * 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.apache.coyote.servlet;
+
+import javax.servlet.ServletContext;
+
+import org.apache.tomcat.servlets.jsp.BaseJspLoader;
+
+public class JspLoader extends BaseJspLoader {
+
+    public ClassLoader getClassLoader(ServletContext ctx) {
+        return ((ServletContextImpl) ctx).getClassLoader();
+    }
+
+    public String getClassPath(ServletContext ctx) {
+        return ((ServletContextImpl) ctx).getClassPath();
+    }    
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/Locale2Charset.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/Locale2Charset.java
new file mode 100644 (file)
index 0000000..84a644c
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * 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.apache.coyote.servlet;
+
+
+import java.io.InputStream;
+import java.util.Locale;
+import java.util.Properties;
+
+
+
+/**
+ * One instance per Context. Holds the 
+ * 
+ * Utility class that attempts to map from a Locale to the corresponding
+ * character set to be used for interpreting input text (or generating
+ * output text) when the Content-Type header does not include one.  You
+ * can customize the behavior of this class by modifying the mapping data
+ * it loads, or by subclassing it (to change the algorithm) and then using
+ * your own version for a particular web application.
+ *
+ * @author Craig R. McClanahan
+ */
+public class Locale2Charset {
+
+
+    // ---------------------------------------------------- Manifest Constants
+
+
+    /**
+     * Default properties resource name.
+     */
+    public static final String DEFAULT_RESOURCE =
+      "/org/apache/coyote/servlet/CharsetMapperDefault.properties";
+
+    
+
+    // ---------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new CharsetMapper using the default properties resource.
+     */
+    public Locale2Charset() {
+      String name = DEFAULT_RESOURCE;
+      if (defaultMap == null) { // once !
+        try {
+          defaultMap = new Properties();
+          InputStream stream =
+            this.getClass().getResourceAsStream(name);
+          defaultMap.load(stream);
+          stream.close();
+        } catch (Throwable t) {
+          throw new IllegalArgumentException(t.toString());
+        }
+      }
+      map = defaultMap;
+    }
+
+
+    // ---------------------------------------------------- Instance Variables
+
+
+    private static Properties defaultMap; // shared for all apps
+    
+    /**
+     * The mapping properties that have been initialized from the specified or
+     * default properties resource.
+     */
+    private Properties map;
+
+
+    // ------------------------------------------------------- Public Methods
+
+
+    /**
+     * Calculate the name of a character set to be assumed, given the specified
+     * Locale and the absence of a character set specified as part of the
+     * content type header.
+     *
+     * @param locale The locale for which to calculate a character set
+     */
+    public String getCharset(Locale locale) {
+        // Match full language_country_variant first, then language_country, 
+        // then language only
+        String charset = map.getProperty(locale.toString());
+        if (charset == null) {
+            charset = map.getProperty(locale.getLanguage() + "_" 
+                    + locale.getCountry());
+            if (charset == null) {
+                charset = map.getProperty(locale.getLanguage());
+            }
+        }
+        return (charset);
+    }
+
+    
+    /**
+     * The deployment descriptor can have a
+     * locale-encoding-mapping-list element which describes the
+     * webapp's desired mapping from locale to charset.  This method
+     * gets called when processing the web.xml file for a context
+     *
+     * @param locale The locale for a character set
+     * @param charset The charset to be associated with the locale
+     */
+    public void addCharsetMapping(String locale, String charset) {
+      if (map == defaultMap) { 
+        // new copy, don't modify original
+        map = new Properties(defaultMap);
+      }
+      map.put(locale, charset);
+    }
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/ParameterMap.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/ParameterMap.java
new file mode 100644 (file)
index 0000000..eb05317
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * 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.apache.coyote.servlet;
+
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * Extended implementation of <strong>HashMap</strong> that includes a
+ * <code>locked</code> property.  This class can be used to safely expose
+ * Catalina internal parameter map objects to user classes without having
+ * to clone them in order to avoid modifications.  When first created, a
+ * <code>ParmaeterMap</code> instance is not locked.
+ *
+ * @author Craig R. McClanahan
+ * @version $Revision$ $Date$
+ */
+
+public final class ParameterMap extends HashMap {
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new, empty map with the default initial capacity and
+     * load factor.
+     */
+    public ParameterMap() {
+
+        super();
+
+    }
+
+
+    /**
+     * Construct a new, empty map with the specified initial capacity and
+     * default load factor.
+     *
+     * @param initialCapacity The initial capacity of this map
+     */
+    public ParameterMap(int initialCapacity) {
+
+        super(initialCapacity);
+
+    }
+
+
+    /**
+     * Construct a new, empty map with the specified initial capacity and
+     * load factor.
+     *
+     * @param initialCapacity The initial capacity of this map
+     * @param loadFactor The load factor of this map
+     */
+    public ParameterMap(int initialCapacity, float loadFactor) {
+
+        super(initialCapacity, loadFactor);
+
+    }
+
+
+    /**
+     * Construct a new map with the same mappings as the given map.
+     *
+     * @param map Map whose contents are dupliated in the new map
+     */
+    public ParameterMap(Map map) {
+
+        super(map);
+
+    }
+
+
+    // ------------------------------------------------------------- Properties
+
+
+    /**
+     * The current lock state of this parameter map.
+     */
+    private boolean locked = false;
+
+
+    /**
+     * Return the locked state of this parameter map.
+     */
+    public boolean isLocked() {
+
+        return (this.locked);
+
+    }
+
+
+    /**
+     * Set the locked state of this parameter map.
+     *
+     * @param locked The new locked state
+     */
+    public void setLocked(boolean locked) {
+
+        this.locked = locked;
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+
+    /**
+     * Remove all mappings from this map.
+     *
+     * @exception IllegalStateException if this map is currently locked
+     */
+    public void clear() {
+
+        if (locked)
+            throw new IllegalStateException
+                ("parameterMap.locked");
+        super.clear();
+
+    }
+
+
+    /**
+     * Associate the specified value with the specified key in this map.  If
+     * the map previously contained a mapping for this key, the old value is
+     * replaced.
+     *
+     * @param key Key with which the specified value is to be associated
+     * @param value Value to be associated with the specified key
+     *
+     * @return The previous value associated with the specified key, or
+     *  <code>null</code> if there was no mapping for key
+     *
+     * @exception IllegalStateException if this map is currently locked
+     */
+    public Object put(Object key, Object value) {
+
+        if (locked)
+            throw new IllegalStateException
+                ("parameterMap.locked");
+        return (super.put(key, value));
+
+    }
+
+
+    /**
+     * Copy all of the mappings from the specified map to this one.  These
+     * mappings replace any mappings that this map had for any of the keys
+     * currently in the specified Map.
+     *
+     * @param map Mappings to be stored into this map
+     *
+     * @exception IllegalStateException if this map is currently locked
+     */
+    public void putAll(Map map) {
+
+        if (locked)
+            throw new IllegalStateException
+                ("parameterMap.locked");
+        super.putAll(map);
+
+    }
+
+
+    /**
+     * Remove the mapping for this key from the map if present.
+     *
+     * @param key Key whose mapping is to be removed from the map
+     *
+     * @return The previous value associated with the specified key, or
+     *  <code>null</code> if there was no mapping for that key
+     *
+     * @exception IllegalStateException if this map is currently locked
+     */
+    public Object remove(Object key) {
+
+        if (locked)
+            throw new IllegalStateException
+                ("parameterMap.locked");
+        return (super.remove(key));
+
+    }
+
+
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/RequestDispatcherImpl.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/RequestDispatcherImpl.java
new file mode 100644 (file)
index 0000000..fbbbfef
--- /dev/null
@@ -0,0 +1,853 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.coyote.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletRequestWrapper;
+import javax.servlet.ServletResponse;
+import javax.servlet.ServletResponseWrapper;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.mapper.MappingData;
+
+/**
+ *
+ */
+public final class RequestDispatcherImpl implements RequestDispatcher {
+    /**
+     * The request attribute under which the original servlet path is stored
+     * on an forwarded dispatcher request.
+     */
+    public static final String FORWARD_SERVLET_PATH_ATTR =
+        "javax.servlet.forward.servlet_path";
+
+
+    /**
+     * The request attribute under which the original query string is stored
+     * on an forwarded dispatcher request.
+     */
+    public static final String FORWARD_QUERY_STRING_ATTR =
+        "javax.servlet.forward.query_string";
+
+    /**
+     * The request attribute under which the original request URI is stored
+     * on an forwarded dispatcher request.
+     */
+    public static final String FORWARD_REQUEST_URI_ATTR =
+        "javax.servlet.forward.request_uri";
+    
+    
+    /**
+     * The request attribute under which the original context path is stored
+     * on an forwarded dispatcher request.
+     */
+    public static final String FORWARD_CONTEXT_PATH_ATTR =
+        "javax.servlet.forward.context_path";
+
+
+    /**
+     * The request attribute under which the original path info is stored
+     * on an forwarded dispatcher request.
+     */
+    public static final String FORWARD_PATH_INFO_ATTR =
+        "javax.servlet.forward.path_info";
+
+    /**
+     * The request attribute under which we store the servlet name on a
+     * named dispatcher request.
+     */
+    public static final String NAMED_DISPATCHER_ATTR =
+        "org.apache.catalina.NAMED";
+
+    /**
+     * The request attribute under which the request URI of the included
+     * servlet is stored on an included dispatcher request.
+     */
+    public static final String INCLUDE_REQUEST_URI_ATTR =
+        "javax.servlet.include.request_uri";
+
+
+    /**
+     * The request attribute under which the context path of the included
+     * servlet is stored on an included dispatcher request.
+     */
+    public static final String INCLUDE_CONTEXT_PATH_ATTR =
+        "javax.servlet.include.context_path";
+
+
+    /**
+     * The request attribute under which the path info of the included
+     * servlet is stored on an included dispatcher request.
+     */
+    public static final String INCLUDE_PATH_INFO_ATTR =
+        "javax.servlet.include.path_info";
+
+
+    /**
+     * The request attribute under which the servlet path of the included
+     * servlet is stored on an included dispatcher request.
+     */
+    public static final String INCLUDE_SERVLET_PATH_ATTR =
+        "javax.servlet.include.servlet_path";
+
+
+    /**
+     * The request attribute under which the query string of the included
+     * servlet is stored on an included dispatcher request.
+     */
+    public static final String INCLUDE_QUERY_STRING_ATTR =
+        "javax.servlet.include.query_string";
+
+    /**
+     * The request attribute under which we expose the value of the
+     * <code>&lt;jsp-file&gt;</code> value associated with this servlet,
+     * if any.
+     */
+    public static final String JSP_FILE_ATTR =
+        "org.apache.catalina.jsp_file";
+
+
+    // ----------------------------------------------------- Instance Variables
+
+    private static Logger log = Logger.getLogger(RequestDispatcherImpl.class.getName());
+
+    private ServletContextImpl ctx = null;
+
+    /**
+     * The servlet name for a named dispatcher.
+     */
+    private String name = null;
+
+    // Path for a path dispatcher
+    private String path;
+
+    /**
+     * MappingData object - per thread for buffering.
+     */
+    private transient ThreadLocal localMappingData = new ThreadLocal();
+
+    /*
+      OrigRequest(ServletRequestImpl) -> include/forward * -> this include
+      
+      On the path: user-defined RequestWrapper or our ServletRequestWrapper
+
+      include() is called with a RequestWrapper(->...->origRequest) or origRequest
+      
+      Based on params, etc -> we wrap the req / response in ServletRequestWrapper,
+       call filters+servlet. Inside, the req can be wrapped again in 
+       userReqWrapper, and other include called. 
+       
+      
+     */
+    
+    /**
+     * The outermost request that will be passed on to the invoked servlet.
+     */
+    private ServletRequest outerRequest = null;
+
+    /**
+     * The outermost response that will be passed on to the invoked servlet.
+     */
+    private ServletResponse outerResponse = null;
+
+    /**
+     * The request wrapper we have created and installed (if any).
+     */
+    private ServletRequest wrapRequest = null;
+
+    /**
+     * The response wrapper we have created and installed (if any).
+     */
+    private ServletResponse wrapResponse = null;
+
+    // Parameters used when constructing the dispatcvher 
+    /**
+     * The extra path information for this RequestDispatcher.
+     */
+    private String pathInfo = null;
+    /**
+     * The query string parameters for this RequestDispatcher.
+     */
+    private String queryString = null;
+    /**
+     * The request URI for this RequestDispatcher.
+     */
+    private String requestURI = null;
+    /**
+     * The servlet path for this RequestDispatcher.
+     */
+    private String servletPath = null;
+
+    //
+    private String origServletPath = null;
+    
+    /**
+     * The Wrapper associated with the resource that will be forwarded to
+     * or included.
+     */
+    private ServletConfigImpl wrapper = null;
+    
+    private Servlet servlet; 
+
+    /** Named dispatcher 
+     */
+    public RequestDispatcherImpl(ServletConfigImpl wrapper, String name) {
+        this.wrapper = wrapper;
+        this.name = name;
+        this.ctx = (ServletContextImpl) wrapper.getServletContext();
+
+    }
+    
+    public RequestDispatcherImpl(ServletContextImpl ctx, String path) {
+        this.path = path;
+        this.ctx = ctx;
+    }
+   
+
+
+    /**
+     * Forward this request and response to another resource for processing.
+     * Any runtime exception, IOException, or ServletException thrown by the
+     * called servlet will be propogated to the caller.
+     *
+     * @param request The servlet request to be forwarded
+     * @param response The servlet response to be forwarded
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public void forward(ServletRequest request, ServletResponse response)
+        throws ServletException, IOException
+    {
+        // Reset any output that has been buffered, but keep headers/cookies
+        if (response.isCommitted()) {
+            throw new IllegalStateException("forward(): response.isComitted()");
+        }
+        
+        try {
+            response.resetBuffer();
+        } catch (IllegalStateException e) {
+            throw e;
+        }
+
+        // Set up to handle the specified request and response
+        setup(request, response, false);
+
+        // Identify the HTTP-specific request and response objects (if any)
+        HttpServletRequest hrequest = (HttpServletRequest) request;
+
+        ServletRequestWrapperImpl wrequest =
+            (ServletRequestWrapperImpl) wrapRequest();
+
+        
+        if (name != null) {
+            wrequest.setRequestURI(hrequest.getRequestURI());
+            wrequest.setContextPath(hrequest.getContextPath());
+            wrequest.setServletPath(hrequest.getServletPath());
+            wrequest.setPathInfo(hrequest.getPathInfo());
+            wrequest.setQueryString(hrequest.getQueryString());
+
+            
+        } else { // path based
+            mapPath();
+            if (wrapper == null) {
+                throw new ServletException("Forward not found " + 
+                        path);
+            }
+            String contextPath = ctx.getContextPath();
+            if (hrequest.getAttribute(FORWARD_REQUEST_URI_ATTR) == null) {
+                wrequest.setAttribute(FORWARD_REQUEST_URI_ATTR,
+                                      hrequest.getRequestURI());
+                wrequest.setAttribute(FORWARD_CONTEXT_PATH_ATTR,
+                                      hrequest.getContextPath());
+                wrequest.setAttribute(FORWARD_SERVLET_PATH_ATTR,
+                                      hrequest.getServletPath());
+                wrequest.setAttribute(FORWARD_PATH_INFO_ATTR,
+                                      hrequest.getPathInfo());
+                wrequest.setAttribute(FORWARD_QUERY_STRING_ATTR,
+                                      hrequest.getQueryString());
+            }
+            wrequest.setContextPath(contextPath);
+            wrequest.setRequestURI(requestURI);
+            wrequest.setServletPath(servletPath);
+            wrequest.setPathInfo(pathInfo);
+            if (queryString != null) {
+                wrequest.setQueryString(queryString);
+                wrequest.setQueryParams(queryString);
+            }
+        }
+        processRequest(outerRequest, outerResponse);
+
+        wrequest.recycle();
+        unwrapRequest();
+
+        // This is not a real close in order to support error processing
+//        if ( log.isDebugEnabled() )
+//            log.debug(" Disabling the response for futher output");
+
+        if  (response instanceof ServletResponseImpl) {
+            ((ServletResponseImpl) response).flushBuffer();
+            ((ServletResponseImpl) response).setSuspended(true);
+        } else {
+            // Servlet SRV.6.2.2. The Resquest/Response may have been wrapped
+            // and may no longer be instance of RequestFacade 
+            if (log.isLoggable(Level.FINE)){
+                log.fine( " The Response is vehiculed using a wrapper: " 
+                           + response.getClass().getName() );
+            }
+
+            // Close anyway
+            try {
+                PrintWriter writer = response.getWriter();
+                writer.close();
+            } catch (IllegalStateException e) {
+                try {
+                    ServletOutputStream stream = response.getOutputStream();
+                    stream.close();
+                } catch (IllegalStateException f) {
+                    ;
+                } catch (IOException f) {
+                    ;
+                }
+            } catch (IOException e) {
+                ;
+            }
+        }
+    }
+
+    
+    
+    /**
+     * Include the response from another resource in the current response.
+     * Any runtime exception, IOException, or ServletException thrown by the
+     * called servlet will be propogated to the caller.
+     *
+     * @param request The servlet request that is including this one
+     * @param response The servlet response to be appended to
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet exception occurs
+     */
+    public void include(ServletRequest request, ServletResponse response)
+        throws ServletException, IOException
+    {
+
+        // Set up to handle the specified request and response
+        setup(request, response, true);
+
+        // Create a wrapped response to use for this request
+        // this actually gets inserted somewhere in the chain - it's not 
+        // the last one, but first non-user response
+        wrapResponse();
+        ServletRequestWrapperImpl wrequest =
+            (ServletRequestWrapperImpl) wrapRequest();
+
+
+        // Handle an HTTP named dispatcher include
+        if (name != null) {
+            wrequest.setAttribute(NAMED_DISPATCHER_ATTR, name);
+            if (servletPath != null) wrequest.setServletPath(servletPath);
+            wrequest.setAttribute(WebappFilterMapper.DISPATCHER_TYPE_ATTR,
+                                  new Integer(WebappFilterMapper.INCLUDE));
+            wrequest.setAttribute(WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR, 
+                                  origServletPath);
+        } else {
+            mapPath();
+            String contextPath = ctx.getContextPath();
+            if (requestURI != null)
+                wrequest.setAttribute(INCLUDE_REQUEST_URI_ATTR,
+                                      requestURI);
+            if (contextPath != null)
+                wrequest.setAttribute(INCLUDE_CONTEXT_PATH_ATTR,
+                                      contextPath);
+            if (servletPath != null)
+                wrequest.setAttribute(INCLUDE_SERVLET_PATH_ATTR,
+                                      servletPath);
+            if (pathInfo != null)
+                wrequest.setAttribute(INCLUDE_PATH_INFO_ATTR,
+                                      pathInfo);
+            if (queryString != null) {
+                wrequest.setAttribute(INCLUDE_QUERY_STRING_ATTR,
+                                      queryString);
+                wrequest.setQueryParams(queryString);
+            }
+            
+            wrequest.setAttribute(WebappFilterMapper.DISPATCHER_TYPE_ATTR,
+                                  new Integer(WebappFilterMapper.INCLUDE));
+            wrequest.setAttribute(WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR, 
+                                  origServletPath);
+        }
+
+        invoke(outerRequest, outerResponse);
+
+        wrequest.recycle();
+        unwrapRequest();
+        unwrapResponse();
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+    public void mapPath() {
+        if (path == null || servletPath != null) return;
+        
+        // Retrieve the thread local URI, used for mapping
+        // TODO: recycle RequestDispatcher stack and associated objects
+        // instead of this object
+        
+        // Retrieve the thread local mapping data
+        MappingData mappingData = (MappingData) localMappingData.get();
+        if (mappingData == null) {
+            mappingData = new MappingData();
+            localMappingData.set(mappingData);
+        }
+
+        // Get query string
+        int pos = path.indexOf('?');
+        if (pos >= 0) {
+            queryString = path.substring(pos + 1);
+        } else {
+            pos = path.length();
+        }
+        // Map the URI
+        MessageBytes uriMB = MessageBytes.newInstance();
+        CharChunk charBuffer = new CharChunk();
+        //mappingData.localURIBytes;
+        uriMB.recycle();
+        //CharChunk uriCC = uriMB.getCharChunk();
+        try {
+            /*
+             * Ignore any trailing path params (separated by ';') for mapping
+             * purposes.
+             * This is sometimes broken - path params can be on any path 
+             * component, not just last.
+             */
+            int semicolon = path.indexOf(';');
+            if (pos >= 0 && semicolon > pos) {
+                semicolon = -1;
+            }
+            if (ctx.getContextPath().length() > 1 ) {
+                charBuffer.append(ctx.getContextPath());
+            }
+            charBuffer.append(path, 0, 
+                semicolon > 0 ? semicolon : pos);
+
+            // Wrap the buffer 
+            uriMB.setChars(charBuffer.getBuffer(),
+                    charBuffer.getOffset(),
+                    charBuffer.getLength());
+
+            // TODO: make charBuffer part of request or something
+            ctx.getMapper().map(uriMB, mappingData);
+            
+            // at least default wrapper must be returned
+            
+            /*
+             * Append any trailing path params (separated by ';') that were
+             * ignored for mapping purposes, so that they're reflected in the
+             * RequestDispatcher's requestURI
+             */
+            if (semicolon > 0) {
+                // I don't think this will be used in future
+                charBuffer.append(path, 
+                    semicolon, pos - semicolon);
+            }
+        } catch (Exception e) {
+            log.log(Level.SEVERE, "getRequestDispatcher()", e);
+        }
+
+        wrapper = (ServletConfigImpl) mappingData.wrapper;
+        servletPath = mappingData.wrapperPath.toString();
+        pathInfo = mappingData.pathInfo.toString();
+
+        mappingData.recycle();
+
+    }
+    
+
+    /**
+     * Prepare the request based on the filter configuration.
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    private void processRequest(ServletRequest request, 
+                                ServletResponse response)
+            throws IOException, ServletException {
+        Integer disInt = 
+            (Integer) request.getAttribute(WebappFilterMapper.DISPATCHER_TYPE_ATTR);
+        if (disInt != null) {
+            if (disInt.intValue() != WebappFilterMapper.ERROR) {
+                outerRequest.setAttribute
+                    (WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR,
+                     origServletPath);
+                outerRequest.setAttribute
+                    (WebappFilterMapper.DISPATCHER_TYPE_ATTR,
+                     new Integer(WebappFilterMapper.FORWARD));
+            }
+            invoke(outerRequest, response);
+        }
+
+    }
+    
+    
+    
+
+    /**
+     * Ask the resource represented by this RequestDispatcher to process
+     * the associated request, and create (or append to) the associated
+     * response.
+     * <p>
+     * <strong>IMPLEMENTATION NOTE</strong>: This implementation assumes
+     * that no filters are applied to a forwarded or included resource,
+     * because they were already done for the original request.
+     *
+     * @param request The servlet request we are processing
+     * @param response The servlet response we are creating
+     *
+     * @exception IOException if an input/output error occurs
+     * @exception ServletException if a servlet error occurs
+     */
+    private void invoke(ServletRequest request, ServletResponse response)
+            throws IOException, ServletException {
+
+        // Checking to see if the context classloader is the current context
+        // classloader. If it's not, we're saving it, and setting the context
+        // classloader to the Context classloader
+        ClassLoader oldCCL = Thread.currentThread().getContextClassLoader();
+        ClassLoader contextClassLoader = ctx.getClassLoader();
+
+        if (oldCCL != contextClassLoader) {
+            Thread.currentThread().setContextClassLoader(contextClassLoader);
+        } else {
+            oldCCL = null;
+        }
+
+        // Initialize local variables we may need
+        HttpServletResponse hresponse = (HttpServletResponse) response;
+        IOException ioException = null;
+        ServletException servletException = null;
+        RuntimeException runtimeException = null;
+        
+        servletException = allocateServlet(hresponse, servletException);
+                
+        // Get the FilterChain Here
+        WebappFilterMapper factory = 
+            ((ServletContextImpl)wrapper.getServletContext()).getFilterMapper();
+        
+        FilterChainImpl filterChain = factory.createFilterChain(request,
+                                                                wrapper,
+                                                                servlet);
+
+        // Call the service() method for the allocated servlet instance
+        try {
+            String jspFile = wrapper.getJspFile();
+            if (jspFile != null)
+                request.setAttribute(JSP_FILE_ATTR, jspFile);
+            else
+                request.removeAttribute(JSP_FILE_ATTR);
+            // for includes/forwards
+            if ((servlet != null) && (filterChain != null)) {
+               filterChain.doFilter(request, response);
+             }
+        } catch (IOException e) {
+            ctx.getLogger().log(Level.WARNING, "RequestDispatcherImpl error " + 
+                    wrapper.getServletName(), e);
+            ioException = e;
+        } catch (UnavailableException e) {
+            ctx.getLogger().log(Level.WARNING, "RequestDispatcherImpl error " + 
+                    wrapper.getServletName(), e);
+            servletException = e;
+            wrapper.unavailable(e);
+        } catch (ServletException e) {
+            servletException = e;
+        } catch (RuntimeException e) {
+            ctx.getLogger().log(Level.WARNING, "RequestDispatcherImpl error " + 
+                    wrapper.getServletName(), e);
+            runtimeException = e;
+        }
+        request.removeAttribute(JSP_FILE_ATTR);
+
+        // Release the filter chain (if any) for this request
+        if (filterChain != null)
+            filterChain.release();
+
+        servletException = servletDealocate(servletException);
+
+        // Reset the old context class loader
+        if (oldCCL != null)
+            Thread.currentThread().setContextClassLoader(oldCCL);
+        
+        // Unwrap request/response if needed
+        unwrapRequest();
+        unwrapResponse();
+
+        // Rethrow an exception if one was thrown by the invoked servlet
+        if (ioException != null)
+            throw ioException;
+        if (servletException != null)
+            throw servletException;
+        if (runtimeException != null)
+            throw runtimeException;
+
+    }
+
+    private ServletException servletDealocate(ServletException servletException)
+    {
+        if (servlet != null) {
+            wrapper.deallocate(servlet);
+        }
+        return servletException;
+    }
+
+    private ServletException allocateServlet(HttpServletResponse hresponse,
+                                             ServletException servletException)
+        throws IOException
+    {
+        boolean unavailable = false;
+
+        // Check for the servlet being marked unavailable
+        if (wrapper.isUnavailable()) {
+            ctx.getLogger().log(Level.WARNING, "isUnavailable() " + wrapper.getServletName());
+            long available = wrapper.getAvailable();
+            if ((available > 0L) && (available < Long.MAX_VALUE))
+                hresponse.setDateHeader("Retry-After", available);
+            hresponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, 
+                    "Unavailable"); // No need to include internal info: wrapper.getServletName();
+            unavailable = true;
+        }
+
+        // Allocate a servlet instance to process this request
+        try {
+            if (!unavailable) {
+                servlet = wrapper.allocate();
+            }
+        } catch (ServletException e) {
+            ctx.getLogger().log(Level.WARNING, "RequestDispatcher: allocate " + 
+                             wrapper.toString());
+            servletException = e;
+            servlet = null;
+        } catch (Throwable e) {
+            ctx.getLogger().log(Level.WARNING, "allocate() error " + wrapper.getServletName(), e);
+            servletException = new ServletException
+                ("Allocate error " + wrapper.getServletName(), e);
+            servlet = null;
+        }
+        return servletException;
+    }
+
+
+    /**
+     * Set up to handle the specified request and response
+     *
+     * @param request The servlet request specified by the caller
+     * @param response The servlet response specified by the caller
+     * @param including Are we performing an include() as opposed to
+     *  a forward()?
+     */
+    private void setup(ServletRequest request, ServletResponse response,
+                       boolean including) {
+
+        this.outerRequest = request;
+        this.outerResponse = response;
+    }
+
+
+    /**
+     * Unwrap the request if we have wrapped it. Not sure how it could end
+     * up in the middle. 
+     */
+    private void unwrapRequest() {
+        if (wrapRequest == null)
+            return;
+
+        ServletRequest previous = null;
+        ServletRequest current = outerRequest;
+        while (current != null) {
+            // If we run into the container request we are done
+            if (current instanceof ServletRequestImpl)
+                break;
+
+            // Remove the current request if it is our wrapper
+            if (current == wrapRequest) {
+                ServletRequest next =
+                  ((ServletRequestWrapper) current).getRequest();
+                if (previous == null)
+                    outerRequest = next;
+                else
+                    ((ServletRequestWrapper) previous).setRequest(next);
+                break;
+            }
+
+            // Advance to the next request in the chain
+            previous = current;
+            current = ((ServletRequestWrapper) current).getRequest();
+        }
+    }
+
+
+    /**
+     * Unwrap the response if we have wrapped it.
+     */
+    private void unwrapResponse() {
+        if (wrapResponse == null)
+            return;
+
+        ServletResponse previous = null;
+        ServletResponse current = outerResponse;
+        while (current != null) {
+            // If we run into the container response we are done
+            if (current instanceof ServletResponseImpl)
+                break;
+
+            // Remove the current response if it is our wrapper
+            if (current == wrapResponse) {
+                ServletResponse next =
+                  ((ServletResponseWrapper) current).getResponse();
+                if (previous == null)
+                    outerResponse = next;
+                else
+                    ((ServletResponseWrapper) previous).setResponse(next);
+                break;
+            }
+            // Advance to the next response in the chain
+            previous = current;
+            current = ((ServletResponseWrapper) current).getResponse();
+        }
+    }
+
+
+    /**
+     * Create and return a request wrapper that has been inserted in the
+     * appropriate spot in the request chain.
+     */
+    private ServletRequest wrapRequest() {
+        // Locate the request we should insert in front of
+        ServletRequest previous = null;
+        ServletRequest current = outerRequest;
+        while (current != null) {
+            if (!(current instanceof ServletRequestWrapper))
+                break;
+            if (current instanceof ServletRequestWrapperImpl)
+                break;
+            if (current instanceof ServletRequestImpl)
+                break;
+            // user-specified
+            previous = current;
+            current = ((ServletRequestWrapper) current).getRequest();
+        }
+        // now previous will be a user-specified wrapper, 
+        // and current one of our own wrappers ( deeper in stack )
+        // ... current USER_previous USER USER
+        // previous is null if the top request is ours.
+
+        // Instantiate a new wrapper at this point and insert it in the chain
+        ServletRequest wrapper = null;
+        
+        // Compute a crossContext flag
+        boolean crossContext = isCrossContext();
+        wrapper = 
+            new ServletRequestWrapperImpl((HttpServletRequest) current, 
+                                          ctx, crossContext);
+
+        if (previous == null) {
+            // outer becomes the wrapper, includes orig wrapper inside
+            outerRequest = wrapper;
+        } else {
+            // outer remains user-specified sersvlet, delegating to 
+            // our wrapper, which delegates to real request or our wrapper.
+            ((ServletRequestWrapper) previous).setRequest(wrapper);
+        }
+        wrapRequest = wrapper;
+        return (wrapper);
+    }
+
+    private boolean isCrossContext() {
+        boolean crossContext = false;
+        if ((outerRequest instanceof ServletRequestWrapperImpl) ||
+                (outerRequest instanceof ServletRequestImpl) ||
+                (outerRequest instanceof HttpServletRequest)) {
+            HttpServletRequest houterRequest = 
+                (HttpServletRequest) outerRequest;
+            Object contextPath = 
+                houterRequest.getAttribute(INCLUDE_CONTEXT_PATH_ATTR);
+            if (contextPath == null) {
+                // Forward
+                contextPath = houterRequest.getContextPath();
+            }
+            crossContext = !(ctx.getContextPath().equals(contextPath));
+        }
+        return crossContext;
+    }
+
+
+    /**
+     * Create and return a response wrapper that has been inserted in the
+     * appropriate spot in the response chain.
+     * 
+     * Side effect: updates outerResponse, wrapResponse.
+     * The chain is updated with a wrapper below lowest user wrapper
+     */
+    private ServletResponse wrapResponse() {
+        // Locate the response we should insert in front of
+        ServletResponse previous = null;
+        ServletResponse current = outerResponse;
+        while (current != null) {
+            if (!(current instanceof ServletResponseWrapper))
+                break;
+            if (current instanceof ServletResponseImpl)
+                break;
+            previous = current;
+            current = ((ServletResponseWrapper) current).getResponse();
+        }
+
+        // Instantiate a new wrapper at this point and insert it in the chain
+        ServletResponse wrapper = 
+             new ServletResponseIncludeWrapper(current);
+            
+        if (previous == null) {
+            // outer is ours, we can wrap on top
+            outerResponse = wrapper;
+        } else {
+            // outer is user-specified, leave it alone. 
+            // we insert ourself below the lowest user-specified response
+            ((ServletResponseWrapper) previous).setResponse(wrapper);
+        }
+        wrapResponse = wrapper;
+        return (wrapper);
+
+    }
+
+
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletConfigImpl.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletConfigImpl.java
new file mode 100644 (file)
index 0000000..c8ef7ca
--- /dev/null
@@ -0,0 +1,982 @@
+/*
+ * Copyright 1999-2002,2004 The Apache Software Foundation.
+ *
+ * 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.apache.coyote.servlet;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Stack;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.servlet.MultipartConfigElement;
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+import javax.servlet.ServletSecurityElement;
+import javax.servlet.SingleThreadModel;
+import javax.servlet.UnavailableException;
+
+import org.apache.tomcat.servlets.jsp.BaseJspLoader;
+import org.apache.tomcat.servlets.util.Enumerator;
+import org.apache.tomcat.util.IntrospectionUtils;
+
+/**
+ * Based on Wrapper.
+ *
+ * Standard implementation of the <b>Wrapper</b> interface that represents
+ * an individual servlet definition.  No child Containers are allowed, and
+ * the parent Container must be a Context.
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ */
+@SuppressWarnings("deprecation")
+public class ServletConfigImpl implements ServletConfig, ServletRegistration {
+
+    ServletDynamicRegistration dynamic = new ServletDynamicRegistration();
+
+    protected boolean asyncSupported;
+
+    private static Logger log=
+        Logger.getLogger(ServletConfigImpl.class.getName());
+
+    private static final String[] DEFAULT_SERVLET_METHODS = new String[] {
+                                                    "GET", "HEAD", "POST" };
+
+    // TODO: refactor all 'stm' to separate class (not implemented)
+    //    public static final String SINGLE_THREADED_PROXY =
+    //             "org.apache.tomcat.servlets.jsp.SingleThreadedProxyServlet";
+
+    protected String description;
+    protected Map<String, String> initParams = new HashMap<String, String>();
+    protected String servletName;
+    protected String servletClassName;
+    protected String jspFile;
+    protected int loadOnStartup = -1;
+    protected String runAs;
+    protected Map securityRoleRef = new HashMap(); // roleName -> [roleLink]
+
+    /**
+     * The date and time at which this servlet will become available (in
+     * milliseconds since the epoch), or zero if the servlet is available.
+     * If this value equals Long.MAX_VALUE, the unavailability of this
+     * servlet is considered permanent.
+     */
+    private transient long available = 0L;
+
+    private ServletContextImpl ctx;
+
+    /**
+     * The (single) initialized instance of this servlet.
+     */
+    private transient Servlet instance = null;
+
+    /**
+     * Are we unloading our servlet instance at the moment?
+     */
+    private transient boolean unloading = false;
+
+    private Class servletClass = null;
+
+    // Support for SingleThreaded
+    /**
+     * The count of allocations that are currently active (even if they
+     * are for the same instance, as will be true on a non-STM servlet).
+     */
+    private transient int countAllocated = 0;
+
+    private transient boolean singleThreadModel = false;
+    /**
+     * Stack containing the STM instances.
+     */
+    private transient Stack instancePool = null;
+
+
+    // Statistics
+    private transient long loadTime=0;
+    private transient int classLoadTime=0;
+
+    // ------------------------------------------------------------- Properties
+    public ServletConfigImpl(ServletContextImpl ctx, String name,
+                             String classname) {
+        this.servletName = name;
+        this.servletClassName = classname;
+        this.ctx = ctx;
+        ctx.facade.notifyAdd(this);
+    }
+
+    /**
+     * Return the available date/time for this servlet, in milliseconds since
+     * the epoch.  If this date/time is Long.MAX_VALUE, it is considered to mean
+     * that unavailability is permanent and any request for this servlet will return
+     * an SC_NOT_FOUND error.  If this date/time is in the future, any request for
+     * this servlet will return an SC_SERVICE_UNAVAILABLE error.  If it is zero,
+     * the servlet is currently available.
+     */
+    public long getAvailable() {
+        return (this.available);
+    }
+
+
+    /**
+     * Set the available date/time for this servlet, in milliseconds since the
+     * epoch.  If this date/time is Long.MAX_VALUE, it is considered to mean
+     * that unavailability is permanent and any request for this servlet will return
+     * an SC_NOT_FOUND error. If this date/time is in the future, any request for
+     * this servlet will return an SC_SERVICE_UNAVAILABLE error.
+     *
+     * @param available The new available date/time
+     */
+    public void setAvailable(long available) {
+
+        long oldAvailable = this.available;
+        if (available > System.currentTimeMillis())
+            this.available = available;
+        else
+            this.available = 0L;
+
+    }
+
+
+    /**
+     * Return the number of active allocations of this servlet, even if they
+     * are all for the same instance (as will be true for servlets that do
+     * not implement <code>SingleThreadModel</code>.
+     */
+    public int getCountAllocated() {
+        return (this.countAllocated);
+    }
+
+    /**
+     * Return the jsp-file setting for this servlet.
+     */
+    public String getJspFile() {
+        return jspFile;
+    }
+
+    public void setJspFile(String s) {
+      this.jspFile = s;
+    }
+
+    /**
+     * Return the load-on-startup order value (negative value means
+     * load on first call).
+     */
+    public int getLoadOnStartup() {
+        return loadOnStartup;
+    }
+
+    /**
+     * Return the fully qualified servlet class name for this servlet.
+     */
+    public String getServletClass() {
+        return servletClassName;
+    }
+
+    /**
+     * Is this servlet currently unavailable?
+     */
+    public boolean isUnavailable() {
+        if (available == 0L)
+            return (false);
+        else if (available <= System.currentTimeMillis()) {
+            available = 0L;
+            return (false);
+        } else
+            return (true);
+
+    }
+
+
+    /**
+     * Gets the names of the methods supported by the underlying servlet.
+     *
+     * This is the same set of methods included in the Allow response header
+     * in response to an OPTIONS request method processed by the underlying
+     * servlet.
+     *
+     * @return Array of names of the methods supported by the underlying
+     * servlet
+     */
+    public String[] getServletMethods() throws ServletException {
+
+        Class servletClazz = loadServlet().getClass();
+        if (!javax.servlet.http.HttpServlet.class.isAssignableFrom(
+                                                        servletClazz)) {
+            return DEFAULT_SERVLET_METHODS;
+        }
+
+        HashSet allow = new HashSet();
+        allow.add("TRACE");
+        allow.add("OPTIONS");
+
+        Method[] methods = getAllDeclaredMethods(servletClazz);
+        for (int i=0; methods != null && i<methods.length; i++) {
+            Method m = methods[i];
+
+            if (m.getName().equals("doGet")) {
+                allow.add("GET");
+                allow.add("HEAD");
+            } else if (m.getName().equals("doPost")) {
+                allow.add("POST");
+            } else if (m.getName().equals("doPut")) {
+                allow.add("PUT");
+            } else if (m.getName().equals("doDelete")) {
+                allow.add("DELETE");
+            }
+        }
+
+        String[] methodNames = new String[allow.size()];
+        return (String[]) allow.toArray(methodNames);
+
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Extract the root cause from a servlet exception.
+     *
+     * @param e The servlet exception
+     */
+    public static Throwable getRootCause(ServletException e) {
+        Throwable rootCause = e;
+        Throwable rootCauseCheck = null;
+        // Extra aggressive rootCause finding
+        do {
+            try {
+                rootCauseCheck = (Throwable)IntrospectionUtils.getProperty
+                                            (rootCause, "rootCause");
+                if (rootCauseCheck!=null)
+                    rootCause = rootCauseCheck;
+
+            } catch (ClassCastException ex) {
+                rootCauseCheck = null;
+            }
+        } while (rootCauseCheck != null);
+        return rootCause;
+    }
+
+    /**
+     *  MUST be called before service()
+     *  This method should be called to get the servlet. After
+     *  service(), dealocate should be called. This deals with STM and
+     *  update use counters.
+     *
+     *  Normally called from RequestDispatcher and TomcatLite.
+     */
+    public Servlet allocate() throws ServletException {
+        // If we are currently unloading this servlet, throw an exception
+        if (unloading)
+            throw new ServletException
+              ("allocate() while unloading " + getServletName());
+
+        Servlet servlet = null;
+        if (instance == null && !singleThreadModel) {
+            // never loaded.
+            synchronized (this) {
+                if (instance == null && !singleThreadModel) {
+                    try {
+                        servlet = loadServlet();
+                    } catch (ServletException e) {
+                        throw e;
+                    } catch (Throwable e) {
+                        throw new ServletException("loadServlet()", e);
+                    }
+                    if (servlet != null && !singleThreadModel) {
+                        setServlet(servlet);
+                    }
+                }
+            }
+        }
+
+        // If not SingleThreadedModel, return the same instance every time
+        if (instance != null) {
+            countAllocated++;
+            return (instance);
+        }
+
+        // Simpler policy for ST: unbound number of servlets ( can grow to
+        // one per thread )
+
+        synchronized (instancePool) {
+            if (instancePool.isEmpty()) {
+                try {
+                    if (servlet != null) {
+                        // this is the first invocation
+                        countAllocated++;
+                        return servlet;
+                    }
+                    countAllocated++;
+                    Servlet newServlet = loadServlet();
+                    log.fine("New STM servet " + newServlet + " " +
+                            countAllocated);
+                    return newServlet;
+                } catch (ServletException e) {
+                    throw e;
+                } catch (Throwable e) {
+                    throw new ServletException("allocate " + getServletName(),
+                            e);
+                }
+            }
+            log.fine("Get from pool " + instancePool.size() +  " " +
+                    countAllocated);
+            Servlet s = (Servlet) instancePool.pop();
+            countAllocated++;
+            log.fine("After get " + instancePool.size() + " " + s  +
+                    " " + countAllocated);
+            return s;
+        }
+    }
+
+
+    /**
+     * MUST be called after service().
+     */
+    public void deallocate(Servlet servlet) {
+        // If not SingleThreadModel, no action is required
+        if (!singleThreadModel) {
+            countAllocated--;
+            return;
+        }
+
+        // Unlock and free this instance
+        synchronized (instancePool) {
+            countAllocated--;
+            if (instancePool.contains(servlet)) {
+                System.err.println("Aleady in pool " + servlet + " "
+                        + instancePool.size()+ " " + countAllocated);
+                return;
+            }
+            System.err.println("return  pool " + servlet +  " " +
+                    instancePool.size() + " " + countAllocated);
+            instancePool.push(servlet);
+        }
+    }
+
+    public Servlet newInstance() throws ServletException {
+        String actualClass = servletClassName;
+
+        if (instance != null) {
+            return instance;
+        }
+        if (actualClass == null) {
+            // No explicit name. Try to use the framework
+            if (jspFile != null) {
+
+                // Named JSPs can be handled by a servlet or by the mapper.
+                    BaseJspLoader mapper = new JspLoader();
+                    try {
+                        return mapper.loadProxy(jspFile, ctx, this);
+                    } catch (IOException e) {
+                        throw new ServletException(e);
+                    }
+            }
+            if (actualClass == null) {
+                // Covers 'default-" and "jspwildcard-" servlets as well
+                Servlet res = (Servlet) ctx.getObjectManager().get( servletName +
+                        "-servlet");
+                if (res != null) {
+                    servletClass = res.getClass();
+                    actualClass = servletClass.getName();
+                    return res;
+                }
+            }
+
+            //ctx.getObjectManager().getObject(c);
+            //ctx.getObjectManager().getObject(servletName);
+        }
+
+
+        if (servletClass == null) {
+            // set classClass
+            loadClass(actualClass);
+        }
+
+
+        // jsp-file case. Load the JspProxyServlet instead, with the
+        // right params. Note the JspProxyServlet is _not_ jasper,
+        // nor 'jsp' servlet - it is just a proxy with no special
+        // params. It calls the jsp servlet and jasper to generate the
+        // real class.
+
+        // this is quite different from catalina, where an ugly kludge was
+        // used to use the same jsp servlet in 2 roles
+
+        // the jsp proxy is replaced by the web.xml processor
+
+        if (servletClass == null) {
+            unavailable(null);
+            throw new UnavailableException("ClassNotFound: " + actualClass);
+        }
+
+        // Instantiate and initialize an instance of the servlet class itself
+        try {
+            return (Servlet) servletClass.newInstance();
+        } catch (ClassCastException e) {
+            unavailable(null);
+            throw new UnavailableException("ClassCast: (Servlet)" +
+                    actualClass);
+        } catch (Throwable e) {
+            unavailable(null);
+
+            // Added extra log statement for Bugzilla 36630:
+            // http://issues.apache.org/bugzilla/show_bug.cgi?id=36630
+            if(log.isLoggable(Level.FINE)) {
+                log.log(Level.FINE, "newInstance() error: servlet-name: " +
+                        getServletName() +
+                        " servlet-class: " + actualClass, e);
+            }
+
+            // Restore the context ClassLoader
+            throw new ServletException("newInstance() error " + getServletName() +
+                    " " + actualClass, e);
+        }
+    }
+
+    /**
+     * Load and initialize an instance of this servlet, if there is not already
+     * at least one initialized instance.  This can be used, for example, to
+     * load servlets that are marked in the deployment descriptor to be loaded
+     * at server startup time.
+     */
+    public synchronized Servlet loadServlet() throws ServletException {
+        // Nothing to do if we already have an instance or an instance pool
+        if (!singleThreadModel && (instance != null))
+            return instance;
+
+        long t1=System.currentTimeMillis();
+
+        Servlet servlet = newInstance();
+
+        classLoadTime=(int) (System.currentTimeMillis() -t1);
+
+        // Call the initialization method of this servlet
+        try {
+            servlet.init(this);
+        } catch (UnavailableException f) {
+            unavailable(f);
+            throw f;
+        } catch (ServletException f) {
+            throw f;
+        } catch (Throwable f) {
+            getServletContext().log("StandardWrapper.Throwable", f );
+            throw new ServletException("Servlet.init()", f);
+        }
+
+        // Register our newly initialized instance
+        singleThreadModel = servlet instanceof SingleThreadModel;
+        if (singleThreadModel) {
+            if (instancePool == null)
+                instancePool = new Stack();
+        }
+        loadTime=System.currentTimeMillis() -t1;
+
+        return servlet;
+    }
+
+
+    private void loadClass(String actualClass) throws ServletException {
+        // Complain if no servlet class has been specified
+        if (actualClass == null) {
+            unavailable(null);
+            throw new ServletException("servlet-class missing " +
+                    getServletName());
+        }
+
+        ClassLoader classLoader = ctx.getClassLoader();
+        if (classLoader == null )
+            classLoader = this.getClass().getClassLoader();
+
+        // Load the specified servlet class from the appropriate class loader
+        try {
+            servletClass = classLoader.loadClass(actualClass);
+        } catch (ClassNotFoundException e) {
+            servletClass = null;
+        }
+    }
+
+    /**
+     * Return a String representation of this component.
+     */
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        if (ctx != null) {
+            sb.append(ctx.toString());
+            sb.append(".");
+        }
+        sb.append("Servlet[");
+        sb.append(getServletName()).append(" ");
+        sb.append(servletClassName);
+        if (jspFile != null) {
+            sb.append(" jsp=").append(jspFile);
+        }
+        sb.append("]");
+        return (sb.toString());
+    }
+
+
+    /**
+     * Process an UnavailableException, marking this servlet as unavailable
+     * for the specified amount of time.
+     *
+     * @param unavailable The exception that occurred, or <code>null</code>
+     *  to mark this servlet as permanently unavailable
+     */
+    public void unavailable(UnavailableException unavailable) {
+        getServletContext().log("UnavailableException:" + getServletName());
+        if (unavailable == null)
+            setAvailable(Long.MAX_VALUE);
+        else if (unavailable.isPermanent())
+            setAvailable(Long.MAX_VALUE);
+        else {
+            int unavailableSeconds = unavailable.getUnavailableSeconds();
+            if (unavailableSeconds <= 0)
+                unavailableSeconds = 60;        // Arbitrary default
+            setAvailable(System.currentTimeMillis() +
+                         (unavailableSeconds * 1000L));
+        }
+
+    }
+
+
+    /**
+     * Unload all initialized instances of this servlet, after calling the
+     * <code>destroy()</code> method for each instance.  This can be used,
+     * for example, prior to shutting down the entire servlet engine, or
+     * prior to reloading all of the classes from the Loader associated with
+     * our Loader's repository.
+     *
+     * @exception ServletException if an exception is thrown by the
+     *  destroy() method
+     */
+    public synchronized void unload() throws ServletException {
+        setAvailable(Long.MAX_VALUE);
+
+        // Nothing to do if we have never loaded the instance
+        if (!singleThreadModel && (instance == null))
+            return;
+        unloading = true;
+
+        // Loaf a while if the current instance is allocated
+        // (possibly more than once if non-STM)
+        if (countAllocated > 0) {
+            int nRetries = 0;
+            long delay = ctx.getUnloadDelay() / 20;
+            while ((nRetries < 21) && (countAllocated > 0)) {
+                if ((nRetries % 10) == 0) {
+                    log.info("Servlet.unload() timeout " +
+                            countAllocated);
+                }
+                try {
+                    Thread.sleep(delay);
+                } catch (InterruptedException e) {
+                    ;
+                }
+                nRetries++;
+            }
+        }
+
+        ClassLoader oldCtxClassLoader =
+            Thread.currentThread().getContextClassLoader();
+        if (instance != null) {
+            ClassLoader classLoader = instance.getClass().getClassLoader();
+
+            PrintStream out = System.out;
+            // Call the servlet destroy() method
+            try {
+                Thread.currentThread().setContextClassLoader(classLoader);
+                instance.destroy();
+            } catch (Throwable t) {
+                instance = null;
+                //instancePool = null;
+                unloading = false;
+                throw new ServletException("Servlet.destroy() " +
+                        getServletName(), t);
+            } finally {
+                // restore the context ClassLoader
+                Thread.currentThread().setContextClassLoader(oldCtxClassLoader);
+            }
+
+            // Deregister the destroyed instance
+            instance = null;
+        }
+        if (singleThreadModel && (instancePool != null)) {
+            try {
+                ClassLoader classLoader = ctx.getClassLoader();
+                Thread.currentThread().setContextClassLoader(classLoader);
+                while (!instancePool.isEmpty()) {
+                    ((Servlet) instancePool.pop()).destroy();
+                }
+            } catch (Throwable t) {
+                instancePool = null;
+                unloading = false;
+                throw new ServletException("Servlet.destroy() " + getServletName(), t);
+            } finally {
+                // restore the context ClassLoader
+                Thread.currentThread().setContextClassLoader
+                    (oldCtxClassLoader);
+            }
+            instancePool = null;
+        }
+
+        singleThreadModel = false;
+
+        unloading = false;
+    }
+
+
+    /**
+     * Return the initialization parameter value for the specified name,
+     * if any; otherwise return <code>null</code>.
+     *
+     * @param name Name of the initialization parameter to retrieve
+     */
+    public String getInitParameter(String name) {
+        return initParams.get(name);
+    }
+
+
+    /**
+     * Return the set of initialization parameter names defined for this
+     * servlet.  If none are defined, an empty Enumeration is returned.
+     */
+    public Enumeration getInitParameterNames() {
+        synchronized (initParams) {
+            return (new Enumerator(initParams.keySet()));
+        }
+    }
+
+
+    /**
+     * Return the servlet context with which this servlet is associated.
+     */
+    public ServletContext getServletContext() {
+        return ctx;
+    }
+
+
+    /**
+     * Return the name of this servlet.
+     */
+    public String getServletName() {
+        return servletName;
+    }
+
+//    public long getProcessingTime() {
+//        return swValve.getProcessingTime();
+//    }
+//
+//    public void setProcessingTime(long processingTime) {
+//        swValve.setProcessingTime(processingTime);
+//    }
+//
+//    public long getMaxTime() {
+//        return swValve.getMaxTime();
+//    }
+//
+//    public void setMaxTime(long maxTime) {
+//        swValve.setMaxTime(maxTime);
+//    }
+//
+//    public long getMinTime() {
+//        return swValve.getMinTime();
+//    }
+//
+//    public void setMinTime(long minTime) {
+//        swValve.setMinTime(minTime);
+//    }
+//
+//    public int getRequestCount() {
+//        return swValve.getRequestCount();
+//    }
+//
+//    public void setRequestCount(int requestCount) {
+//        swValve.setRequestCount(requestCount);
+//    }
+//
+//    public int getErrorCount() {
+//        return swValve.getErrorCount();
+//    }
+//
+//    public void setErrorCount(int errorCount) {
+//           swValve.setErrorCount(errorCount);
+//    }
+//
+//    /**
+//     * Increment the error count used for monitoring.
+//     */
+//    public void incrementErrorCount(){
+//        swValve.setErrorCount(swValve.getErrorCount() + 1);
+//    }
+//
+//    public long getLoadTime() {
+//        return loadTime;
+//    }
+//
+//    public void setLoadTime(long loadTime) {
+//        this.loadTime = loadTime;
+//    }
+//
+//    public int getClassLoadTime() {
+//        return classLoadTime;
+//    }
+
+    // -------------------------------------------------------- Package Methods
+
+
+    // -------------------------------------------------------- Private Methods
+
+    private Method[] getAllDeclaredMethods(Class c) {
+
+        if (c.equals(javax.servlet.http.HttpServlet.class)) {
+            return null;
+        }
+
+        Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
+
+        Method[] thisMethods = c.getDeclaredMethods();
+        if (thisMethods == null) {
+            return parentMethods;
+        }
+
+        if ((parentMethods != null) && (parentMethods.length > 0)) {
+            Method[] allMethods =
+                new Method[parentMethods.length + thisMethods.length];
+        System.arraycopy(parentMethods, 0, allMethods, 0,
+                             parentMethods.length);
+        System.arraycopy(thisMethods, 0, allMethods, parentMethods.length,
+                             thisMethods.length);
+
+        thisMethods = allMethods;
+    }
+
+    return thisMethods;
+    }
+
+    /** Specify the instance. Avoids the class lookup, disables unloading.
+     *  Use for embedded case, or to control the allocation.
+     *
+     * @param servlet
+     */
+    public void setServlet(Servlet servlet) {
+        instance = servlet;
+        ctx.getObjectManager().bind("Servlet:" +
+                ctx.getContextPath() + ":" + getServletName(),
+                this);
+    }
+
+    public String getSecurityRoleRef(String role) {
+        return (String)securityRoleRef.get(role);
+    }
+
+    public void setSecurityRoleRef(Map securityRoles) {
+      this.securityRoleRef = securityRoles;
+    }
+
+    public void setConfig(Map initParams) {
+      this.initParams = initParams;
+    }
+
+    public void setLoadOnStartup(int loadOnStartup) {
+      this.loadOnStartup = loadOnStartup;
+    }
+
+   @Override
+    public Set<String> addMapping(String... urlPatterns) {
+        if (ctx.startDone) {
+            // Use the context method instead of the servlet API to
+            // add mappings after context init.
+            throw new IllegalStateException();
+        }
+        Set<String> failed = new HashSet<String>();
+        for (String url: urlPatterns) {
+            if (url == null) {
+                throw new IllegalArgumentException();
+            }
+            if (ctx.contextConfig.servletMapping.get(url) != null) {
+                failed.add(url);
+            } else {
+                ctx.contextConfig.servletMapping.put(url, getServletName());
+                ctx.addMapping(url, this);
+            }
+        }
+        return failed;
+    }
+
+
+   @Override
+    public boolean setInitParameter(String name, String value)
+            throws IllegalArgumentException, IllegalStateException {
+        return ServletContextImpl.setInitParameter(ctx, initParams,
+                name, value);
+    }
+
+
+   @Override
+    public Set<String> setInitParameters(Map<String, String> initParameters)
+            throws IllegalArgumentException, IllegalStateException {
+        return ServletContextImpl.setInitParameters(ctx, initParams,
+                initParameters);
+    }
+
+    public Dynamic getDynamic() {
+        return dynamic;
+    }
+
+    class ServletDynamicRegistration implements Dynamic {
+
+
+        @Override
+        public void setAsyncSupported(boolean isAsyncSupported)
+                throws IllegalStateException {
+            asyncSupported = isAsyncSupported;
+        }
+
+
+        public void setDescription(String description)
+                throws IllegalStateException {
+            ServletConfigImpl.this.description = description;
+        }
+
+        @Override
+        public Set<String> setServletSecurity(ServletSecurityElement constraint) {
+            //implement me
+            return null;
+        }
+
+        @Override
+        public void setLoadOnStartup(int loadOnStartup) {
+            //implement me - here to compile
+        }
+
+        @Override
+        public void setMultipartConfig(MultipartConfigElement multipartConfig) {
+            //implement me - here to compile
+        }
+
+        @Override
+        public void setRunAsRole(String roleName) {
+            //implement me - here to compile
+        }
+
+        @Override
+        public String getRunAsRole() {
+            //implement me - here to compile
+            return null;
+        }
+
+        @Override
+        public Collection<String> getMappings() {
+            //implement me
+            return null;
+        }
+
+        @Override
+        public Set<String> addMapping(String... urlPatterns) {
+            //implement me
+            return null;
+        }
+
+        @Override
+        public Map<String, String> getInitParameters() {
+            // implement me
+            return null;
+        }
+
+        @Override
+        public Set<String> setInitParameters(Map<String, String> initParameters)
+                throws IllegalArgumentException, IllegalStateException {
+            // implement me
+            return null;
+        }
+
+        @Override
+        public String getClassName() {
+            // implement me
+            return null;
+        }
+
+        @Override
+        public String getName() {
+            // implement me
+            return null;
+        }
+
+        @Override
+        public String getInitParameter(String name) {
+            // implement me
+            return null;
+        }
+
+        @Override
+        public boolean setInitParameter(String name, String value)
+                throws IllegalArgumentException, IllegalStateException {
+            // implement me
+            return false;
+        }
+
+    }
+
+   @Override
+    public Collection<String> getMappings() {
+        //implement me
+        return null;
+    }
+
+    public void setServletClass(Class<? extends Servlet> servletClass2) {
+        servletClass = servletClass2;
+    }
+
+
+   @Override
+    public String getRunAsRole() {
+        //implement me
+        return null;
+    }
+
+
+   @Override
+    public Map<String, String> getInitParameters() {
+        // implement me
+        return null;
+    }
+
+   @Override
+    public String getClassName() {
+        // implement me
+        return null;
+    }
+
+   @Override
+    public String getName() {
+        // implement me
+        return null;
+    }
+
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletContextImpl.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletContextImpl.java
new file mode 100644 (file)
index 0000000..85a5883
--- /dev/null
@@ -0,0 +1,1699 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.coyote.servlet;
+
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Enumeration;
+import java.util.EventListener;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.naming.NamingException;
+import javax.servlet.DispatcherType;
+import javax.servlet.Filter;
+import javax.servlet.FilterRegistration;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletContextAttributeEvent;
+import javax.servlet.ServletContextAttributeListener;
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+import javax.servlet.SessionCookieConfig;
+import javax.servlet.SessionTrackingMode;
+import javax.servlet.FilterRegistration.Dynamic;
+import javax.servlet.descriptor.JspConfigDescriptor;
+
+import org.apache.tomcat.InstanceManager;
+import org.apache.tomcat.servlets.session.UserSessionManager;
+import org.apache.tomcat.integration.ObjectManager;
+import org.apache.tomcat.servlets.config.ConfigLoader;
+import org.apache.tomcat.servlets.config.ServletContextConfig;
+import org.apache.tomcat.servlets.config.ServletContextConfig.FilterData;
+import org.apache.tomcat.servlets.config.ServletContextConfig.FilterMappingData;
+import org.apache.tomcat.servlets.config.ServletContextConfig.ServletData;
+import org.apache.tomcat.servlets.config.deploy.WarDeploy;
+import org.apache.tomcat.servlets.util.Enumerator;
+import org.apache.tomcat.servlets.util.RequestUtil;
+import org.apache.tomcat.servlets.util.UrlUtils;
+import org.apache.tomcat.util.http.MimeMap;
+
+
+/**
+ * Context - initialized from web.xml or using APIs.
+ *
+ * Initialization order:
+ *
+ *  - add all listeners
+ *  - add all filters
+ *  - add all servlets
+ *
+ *  - session parameters
+ *  -
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @version $Revision$ $Date$
+ */
+
+public class ServletContextImpl implements ServletContext {
+
+    /**
+     * Empty collection to serve as the basis for empty enumerations.
+     */
+    private transient static final ArrayList empty = new ArrayList();
+
+    transient Logger log;
+
+    /**
+     * Base path - the directory root of the webapp
+     */
+    protected String basePath = null;
+
+    protected String contextPath;
+
+    // All config from web.xml
+    protected ServletContextConfig contextConfig = new ServletContextConfig();
+
+    MimeMap contentTypes = new MimeMap();
+
+    /**
+     * The context attributes for this context.
+     */
+    protected transient Map<String, Object> attributes = new HashMap<String, Object>();
+
+    /**
+     * List of read only attributes for this context.
+     * In catalina - used to protect workdir att. We trust the app, so no need
+     * for extra complexity.
+     */
+    //protected transient HashMap readOnlyAttributes = new HashMap();
+
+    protected transient ArrayList<EventListener> lifecycleListeners = new ArrayList();
+
+    protected UserSessionManager manager;
+
+    HashMap<String, FilterConfigImpl> filters = new HashMap<String, FilterConfigImpl>();
+
+    HashMap<String, ServletConfigImpl> servlets = new HashMap<String, ServletConfigImpl>();
+
+    ArrayList<String> securityRoles = new ArrayList<String>();
+
+    /** Mapper for filters.
+     */
+    protected WebappFilterMapper webappFilterMapper;
+
+    /** Internal mapper for request dispatcher, must have all
+     *  context mappings.
+     */
+    protected WebappServletMapper mapper;
+
+    transient Locale2Charset charsetMapper = new Locale2Charset();
+
+    transient TomcatLite facade;
+
+    ObjectManager om;
+
+    private String hostname;
+
+
+    boolean initDone = false;
+
+    boolean startDone = false;
+    
+    String jspcServlet = "org.apache.tomcat.servlets.jspc.JspcServlet";
+
+
+    // ------------------------------------------------- ServletContext Methods
+    public ServletContextImpl() {
+    }
+
+    public void setTomcat(TomcatLite facade) {
+        this.facade = facade;
+    }
+
+    /**
+     * Registry/framework interface associated with the context.
+     * Also available as a context attribute.
+     * @return
+     */
+    public ObjectManager getObjectManager() {
+        if (om == null) {
+            om = facade.getObjectManager();
+        }
+        return om;
+    }
+
+    public void setObjectManager(ObjectManager om) {
+        this.om = om;
+    }
+
+    public Locale2Charset getCharsetMapper() {
+        return charsetMapper;
+    }
+
+    /**
+     * Set the context path, starting with "/" - "/" for ROOT
+     * @param path
+     */
+    public void setContextPath(String path) {
+        this.contextPath = path;
+        log = Logger.getLogger("webapp" + path.replace('/', '.'));
+    }
+
+    public void setHostname(String hostname) {
+        this.hostname = hostname;
+    }
+
+    public String getHostname() {
+        return hostname;
+    }
+
+    /** The directory where this app is based. May be null.
+     *
+     * @param basePath
+     */
+    public void setBasePath(String basePath) {
+        this.basePath = basePath;
+    }
+
+    public ServletContextConfig getContextConfig() {
+        return contextConfig;
+    }
+
+    /** The directory where this app is based.
+     *
+     * @param basePath
+     */
+    public String getBasePath() {
+        return basePath;
+    }
+
+    public String getEncodedPath() {
+        return null;
+    }
+
+
+    public boolean getCookies() {
+        return false;
+    }
+
+
+    public ServletContext getServletContext() {
+        return this;
+    }
+
+    public List<EventListener> getListeners() {
+        return lifecycleListeners;
+    }
+
+    public void addListener(Class <? extends EventListener> listenerClass) {
+        // implement me
+    }
+
+    public void addListener(String className) {
+        // implement me
+    }
+
+    public <T extends EventListener> void addListener(T t) {
+      lifecycleListeners.add(t);
+    }
+
+
+    public void removeListener(EventListener listener) {
+      lifecycleListeners.remove(listener);
+    }
+
+
+
+    public Logger getLogger() {
+        return log;
+    }
+
+    public long getUnloadDelay() {
+        return 0;
+    }
+
+    public ServletConfigImpl getServletConfig(String jsp_servlet_name) {
+        return (ServletConfigImpl)servlets.get(jsp_servlet_name);
+    }
+
+    public Map getServletConfigs() {
+        return servlets;
+    }
+
+    /**
+     *  Add a servlet to the context.
+     *  Called from processWebAppData()
+     *
+     * @param servletConfig
+     */
+    public void addServletConfig(ServletConfigImpl servletConfig) {
+        servlets.put(servletConfig.getServletName(), servletConfig);
+    }
+
+    public boolean getPrivileged() {
+        return false;
+    }
+
+
+    public Map getFilters() {
+        return filters;
+    }
+
+
+    protected boolean getCrossContext() {
+        return true;
+    }
+
+    public void addMimeType(String ext, String type) {
+        contentTypes.addContentType(ext, type);
+    }
+
+    public WebappServletMapper getMapper() {
+        if (mapper == null) {
+            Object customMapper = getObjectManager().get(WebappServletMapper.class);
+            if (customMapper == null) {
+                mapper = new WebappServletMapper();
+            } else {
+                mapper = (WebappServletMapper) customMapper;
+            }
+            mapper.setServletContext(this);
+        }
+
+        return mapper;
+    }
+
+    public WebappFilterMapper getFilterMapper() {
+        if (webappFilterMapper == null) {
+            Object customMapper = getObjectManager().get(WebappFilterMapper.class);
+            if (customMapper == null) {
+                webappFilterMapper = new WebappFilterMapper();
+            } else {
+                webappFilterMapper = (WebappFilterMapper) customMapper;
+            }
+            webappFilterMapper.setServletContext(this);
+        }
+
+        return webappFilterMapper ;
+    }
+
+    public FilterConfigImpl getFilter(String name) {
+        return (FilterConfigImpl)filters.get(name);
+    }
+
+    /**
+     * Return the value of the specified context attribute, if any;
+     * otherwise return <code>null</code>.
+     *
+     * @param name Name of the context attribute to return
+     */
+    public Object getAttribute(String name) {
+        if ("ObjectManager".equals(name)) {
+            return om;
+        }
+        if ("context-listeners".equals(name)) {
+            return lifecycleListeners;
+        }
+        return (attributes.get(name));
+    }
+
+    /**
+     * Return an enumeration of the names of the context attributes
+     * associated with this context.
+     */
+    public Enumeration getAttributeNames() {
+        return new Enumerator(attributes.keySet(), true);
+    }
+
+
+    public void addSecurityRole(String role) {
+        securityRoles.add(role);
+    }
+
+    public List getSecurityRoles() {
+        return securityRoles;
+    }
+
+    /**
+     * Return a <code>ServletContext</code> object that corresponds to a
+     * specified URI on the server.  This method allows servlets to gain
+     * access to the context for various parts of the server, and as needed
+     * obtain <code>RequestDispatcher</code> objects or resources from the
+     * context.  The given path must be absolute (beginning with a "/"),
+     * and is interpreted based on our virtual host's document root.
+     *
+     * @param uri Absolute URI of a resource on the server
+     */
+    public ServletContext getContext(String uri) {
+        // TODO: support real uri ( http://host/path )
+        // Validate the format of the specified argument
+        if ((uri == null) || (!uri.startsWith("/")))
+            return (null);
+
+        ServletContextImpl child = null;
+        try {
+            child = facade.getContext(this, uri);
+        } catch (IOException e) {
+        } catch (ServletException e) {
+        }
+
+        if (child == null)
+            return (null);
+
+        if (this.getCrossContext()) {
+            // If crossContext is enabled, can always return the context
+            return child.getServletContext();
+        } else if (child == this) {
+            // Can still return the current context
+            return this.getServletContext();
+        } else {
+            // Nothing to return
+            return (null);
+        }
+    }
+
+
+    /**
+     * Return the main path associated with this context.
+     */
+    public String getContextPath() {
+        return contextPath;
+    }
+
+
+    /**
+     * Return the value of the specified initialization parameter, or
+     * <code>null</code> if this parameter does not exist.
+     *
+     * @param name Name of the initialization parameter to retrieve
+     */
+    public String getInitParameter(final String name) {
+        return ((String) contextConfig.contextParam.get(name));
+    }
+
+
+    /**
+     * Return the names of the context's initialization parameters, or an
+     * empty enumeration if the context has no initialization parameters.
+     */
+    public Enumeration getInitParameterNames() {
+        return (new Enumerator(contextConfig.contextParam.keySet()));
+    }
+
+    public void setContextParams(Map newParams) {
+      contextConfig.contextParam = (HashMap) newParams;
+    }
+
+    /**
+     * Return the major version of the Java Servlet API that we implement.
+     */
+    public int getMajorVersion() {
+        return 3;
+    }
+
+
+    /**
+     * Return the minor version of the Java Servlet API that we implement.
+     */
+    public int getMinorVersion() {
+        return 0;
+    }
+
+
+    /**
+     * Return the MIME type of the specified file, or <code>null</code> if
+     * the MIME type cannot be determined.
+     *
+     * @param file Filename for which to identify a MIME type
+     */
+    public String getMimeType(String file) {
+        return contentTypes.getMimeType(file);
+    }
+
+    /**
+     * Return the real path for a given virtual path, if possible; otherwise
+     * return <code>null</code>.
+     *
+     * @param path The path to the desired resource
+     */
+    public String getRealPath(String path) {
+        if (path == null) {
+            return null;
+        }
+
+        File file = new File(basePath, path);
+        return (file.getAbsolutePath());
+    }
+
+    /**
+     * Return a <code>RequestDispatcher</code> object that acts as a
+     * wrapper for the named servlet.
+     *
+     * @param name Name of the servlet for which a dispatcher is requested
+     */
+    public RequestDispatcher getNamedDispatcher(String name) {
+        if (name == null) return null;
+        ServletConfigImpl wrapper =
+            (ServletConfigImpl) this.getServletConfig(name);
+        if (wrapper == null) return null;
+
+        return new RequestDispatcherImpl(wrapper, name);
+    }
+
+
+    /**
+     * Return a <code>RequestDispatcher</code> instance that acts as a
+     * wrapper for the resource at the given path.  The path must begin
+     * with a "/" and is interpreted as relative to the current context root.
+     *
+     * @param path The path to the desired resource.
+     */
+    public RequestDispatcher getRequestDispatcher(String path) {
+        if (path == null) return null;
+
+        if (!path.startsWith("/"))
+            throw new IllegalArgumentException(path);
+
+        path = UrlUtils.normalize(path);
+        if (path == null)  return (null);
+
+
+        return new RequestDispatcherImpl(this, path);
+    }
+
+    public RequestDispatcher getRequestDispatcher(String path,
+                                                  int type,
+                                                  String dispatcherPath) {
+        RequestDispatcher dispatcher = getRequestDispatcher(path);
+        //((RequestDispatcherImpl)dispatcher);
+        return dispatcher;
+    }
+
+    ThreadLocal requestDispatcherStack = new ThreadLocal();
+
+    private String classPath;
+    
+    protected ClassLoader classLoader;
+
+//    protected RequestDispatcherImpl getRequestDispatcher() {
+//        ArrayList/*<RequestDispatcherImpl>*/ list =
+//            (ArrayList)requestDispatcherStack.get();
+//        if (list == null) {
+//            list = new ArrayList();
+//            requestDispatcherStack.set(list);
+//        }
+//
+//
+//        return null;
+//    }
+
+    public void resetDispatcherStack() {
+
+    }
+
+    /**
+     * Return the URL to the resource that is mapped to a specified path.
+     * The path must begin with a "/" and is interpreted as relative to the
+     * current context root.
+     *
+     * @param path The path to the desired resource
+     *
+     * @exception MalformedURLException if the path is not given
+     *  in the correct form
+     */
+    public URL getResource(String path)
+        throws MalformedURLException {
+
+        if (path == null || !path.startsWith("/")) {
+            throw new MalformedURLException("getResource() " + path);
+        }
+
+        path = UrlUtils.normalize(path);
+        if (path == null)
+            return (null);
+
+        String libPath = "/WEB-INF/lib/";
+        if ((path.startsWith(libPath)) && (path.endsWith(".jar"))) {
+            File jarFile = null;
+            jarFile = new File(basePath, path);
+            if (jarFile.exists()) {
+                return jarFile.toURL();
+            } else {
+                return null;
+            }
+        } else {
+            File resFile = new File(basePath + path);
+            if (resFile.exists()) {
+                return resFile.toURL();
+            }
+        }
+
+        return (null);
+
+    }
+
+    /**
+     * Return the requested resource as an <code>InputStream</code>.  The
+     * path must be specified according to the rules described under
+     * <code>getResource</code>.  If no such resource can be identified,
+     * return <code>null</code>.
+     *
+     * @param path The path to the desired resource.
+     */
+    public InputStream getResourceAsStream(String path) {
+
+        path = UrlUtils.normalize(path);
+        if (path == null)
+            return (null);
+
+        File resFile = new File(basePath + path);
+        if (!resFile.exists())
+            return null;
+
+        try {
+            return new FileInputStream(resFile);
+        } catch (FileNotFoundException e) {
+            return null;
+        }
+
+    }
+
+
+    /**
+     * Return a Set containing the resource paths of resources member of the
+     * specified collection. Each path will be a String starting with
+     * a "/" character. The returned set is immutable.
+     *
+     * @param path Collection path
+     */
+    public Set getResourcePaths(String path) {
+
+        // Validate the path argument
+        if (path == null) {
+            return null;
+        }
+        if (!path.startsWith("/")) {
+            throw new IllegalArgumentException("getResourcePaths() " + path);
+        }
+
+        path = UrlUtils.normalize(path);
+        if (path == null)
+            return (null);
+
+        File f = new File(basePath + path);
+        File[] files = f.listFiles();
+        if (files == null) return null;
+        if (!path.endsWith("/")) {
+          path = path + "/";
+        }
+
+        HashSet result = new HashSet();
+        for (int i=0; i < files.length; i++) {
+            if (files[i].isDirectory() ) {
+                result.add(path + files[i].getName() + "/");
+            } else {
+                result.add(path + files[i].getName());
+            }
+        }
+        return result;
+    }
+
+
+
+    /**
+     * Return the name and version of the servlet container.
+     */
+    public String getServerInfo() {
+        return "Apache Tomcat Lite";
+    }
+
+    /**
+     * @deprecated As of Java Servlet API 2.1, with no direct replacement.
+     */
+    public Servlet getServlet(String name) {
+        return (null);
+    }
+
+
+    /**
+     * Return the display name of this web application.
+     */
+    public String getServletContextName() {
+        return contextConfig.displayName;
+    }
+
+
+    /**
+     * @deprecated As of Java Servlet API 2.1, with no direct replacement.
+     */
+    public Enumeration getServletNames() {
+        return (new Enumerator(empty));
+    }
+
+
+    /**
+     * @deprecated As of Java Servlet API 2.1, with no direct replacement.
+     */
+    public Enumeration getServlets() {
+        return (new Enumerator(empty));
+    }
+
+
+    /**
+     * Writes the specified message to a servlet log file.
+     *
+     * @param message Message to be written
+     */
+    public void log(String message) {
+        this.getLogger().info(message);
+    }
+
+
+    /**
+     * Writes the specified exception and message to a servlet log file.
+     *
+     * @param exception Exception to be reported
+     * @param message Message to be written
+     *
+     * @deprecated As of Java Servlet API 2.1, use
+     *  <code>log(String, Throwable)</code> instead
+     */
+    public void log(Exception exception, String message) {
+        this.getLogger().log(Level.INFO, message, exception);
+    }
+
+
+    /**
+     * Writes the specified message and exception to a servlet log file.
+     *
+     * @param message Message to be written
+     * @param throwable Exception to be reported
+     */
+    public void log(String message, Throwable throwable) {
+        this.getLogger().log(Level.INFO, message, throwable);
+    }
+
+    /**
+     * Remove the context attribute with the specified name, if any.
+     *
+     * @param name Name of the context attribute to be removed
+     */
+    public void removeAttribute(String name) {
+
+        Object value = null;
+        boolean found = false;
+
+        // Remove the specified attribute
+        // Check for read only attribute
+        found = attributes.containsKey(name);
+        if (found) {
+            value = attributes.get(name);
+            attributes.remove(name);
+        } else {
+            return;
+        }
+
+        // Notify interested application event listeners
+        List listeners = this.getListeners();
+        if (listeners.size() == 0)
+            return;
+        ServletContextAttributeEvent event = null;
+        for (int i = 0; i < listeners.size(); i++) {
+            if (!(listeners.get(i) instanceof ServletContextAttributeListener))
+                continue;
+            ServletContextAttributeListener listener =
+                (ServletContextAttributeListener) listeners.get(i);
+            try {
+                if (event == null) {
+                    event = new ServletContextAttributeEvent(this.getServletContext(),
+                            name, value);
+
+                }
+                listener.attributeRemoved(event);
+            } catch (Throwable t) {
+                // FIXME - should we do anything besides log these?
+                log("ServletContextAttributeListener", t);
+            }
+        }
+    }
+
+
+    /**
+     * Bind the specified value with the specified context attribute name,
+     * replacing any existing value for that name.
+     *
+     * @param name Attribute name to be bound
+     * @param value New attribute value to be bound
+     */
+    public void setAttribute(String name, Object value) {
+        // Name cannot be null
+        if (name == null)
+            throw new IllegalArgumentException
+                ("name == null");
+
+        // Null value is the same as removeAttribute()
+        if (value == null) {
+            removeAttribute(name);
+            return;
+        }
+
+        Object oldValue = null;
+        boolean replaced = false;
+
+        // Add or replace the specified attribute
+        synchronized (attributes) {
+            // Check for read only attribute
+            oldValue = attributes.get(name);
+            if (oldValue != null)
+                replaced = true;
+            attributes.put(name, value);
+        }
+
+        // Notify interested application event listeners
+        List listeners = this.getListeners();
+        if (listeners.size() == 0)
+            return;
+        ServletContextAttributeEvent event = null;
+        for (int i = 0; i < listeners.size(); i++) {
+            if (!(listeners.get(i) instanceof ServletContextAttributeListener))
+                continue;
+            ServletContextAttributeListener listener =
+                (ServletContextAttributeListener) listeners.get(i);
+            try {
+                if (event == null) {
+                    if (replaced)
+                        event =
+                            new ServletContextAttributeEvent(this.getServletContext(),
+                                                             name, oldValue);
+                    else
+                        event =
+                            new ServletContextAttributeEvent(this.getServletContext(),
+                                                             name, value);
+
+                }
+                if (replaced) {
+                    listener.attributeReplaced(event);
+                } else {
+                    listener.attributeAdded(event);
+                }
+            } catch (Throwable t) {
+                // FIXME - should we do anything besides log these?
+                log("ServletContextAttributeListener error", t);
+            }
+        }
+
+    }
+
+    /**
+     * Clear all application-created attributes.
+     */
+    void clearAttributes() {
+        // Create list of attributes to be removed
+        ArrayList list = new ArrayList();
+        synchronized (attributes) {
+            Iterator iter = attributes.keySet().iterator();
+            while (iter.hasNext()) {
+                list.add(iter.next());
+            }
+        }
+
+        // Remove application originated attributes
+        // (read only attributes will be left in place)
+        Iterator keys = list.iterator();
+        while (keys.hasNext()) {
+            String key = (String) keys.next();
+            removeAttribute(key);
+        }
+    }
+
+    public void initFilters() throws ServletException {
+        Iterator fI = getFilters().values().iterator();
+        while (fI.hasNext()) {
+            FilterConfigImpl fc = (FilterConfigImpl)fI.next();
+            try {
+                fc.getFilter(); // will triger init()
+            } catch (Throwable e) {
+                log.log(Level.WARNING, getContextPath() + " Filter.init() " +
+                        fc.getFilterName(), e);
+            }
+
+        }
+    }
+
+    public void initServlets() throws ServletException {
+        Iterator fI = getServletConfigs().values().iterator();
+        Map/*<Integer, List<ServletConfigImpl>>*/ onStartup =
+            new TreeMap/*<Integer, List<ServletConfigImpl>>*/();
+        while (fI.hasNext()) {
+            ServletConfigImpl fc = (ServletConfigImpl)fI.next();
+            if (fc.getLoadOnStartup() > 0 ) {
+                Integer i = new Integer(fc.getLoadOnStartup());
+                List/*<ServletConfigImpl>*/ old = (List)onStartup.get(i);
+                if (old == null) {
+                    old = new ArrayList/*<ServletConfigImpl>*/();
+                    onStartup.put(i, old);
+                }
+                old.add(fc);
+            }
+        }
+        Iterator keys = onStartup.keySet().iterator();
+        while (keys.hasNext()) {
+            Integer key = (Integer)keys.next();
+            List/*<ServletConfigImpl>*/ servlets = (List)onStartup.get(key);
+            Iterator servletsI = servlets.iterator();
+            while (servletsI.hasNext()) {
+                ServletConfigImpl fc = (ServletConfigImpl) servletsI.next();
+                try {
+                    fc.loadServlet();
+                } catch (Throwable e) {
+                    log.log(Level.WARNING, "Error initializing  " + fc.getServletName(), e);
+                }
+            }
+        }
+    }
+
+    public void initListeners() throws ServletException {
+        Iterator fI = contextConfig.listenerClass.iterator();
+        while (fI.hasNext()) {
+            String listenerClass = (String)fI.next();
+            try {
+                Object l =
+                    getClassLoader().loadClass(listenerClass).newInstance();
+                lifecycleListeners.add((EventListener) l);
+            } catch (Throwable e) {
+                log.log(Level.WARNING, "Error initializing listener " + listenerClass, e);
+            }
+        }
+    }
+
+    public ClassLoader getClassLoader() {
+        return classLoader;
+    }
+
+    public void addMapping(String path, String name) {
+      ServletConfigImpl wrapper = getServletConfig(name);
+      addMapping(path, wrapper);
+    }
+
+    public void addMapping(String path, ServletConfig wrapper) {
+        getMapper().addWrapper(getMapper().contextMapElement, path, wrapper);
+    }
+
+
+
+    public void setWelcomeFiles(String[] name) {
+      getMapper().contextMapElement.welcomeResources = name;
+    }
+
+    public String[] getWelcomeFiles() {
+      return getMapper().contextMapElement.welcomeResources;
+    }
+
+    public void setSessionTimeout(int to) {
+      getManager().setSessionTimeout(to);
+    }
+
+    /**
+     * Initialize the context from the parsed config.
+     *
+     * Note that WebAppData is serializable.
+     */
+    public void processWebAppData(ServletContextConfig d) throws ServletException {
+        this.contextConfig = d;
+
+        for (String k: d.mimeMapping.keySet()) {
+            addMimeType(k, d.mimeMapping.get(k));
+        }
+
+        String[] wFiles = (String[])d.welcomeFileList.toArray(new String[0]);
+        if (wFiles.length == 0) {
+            wFiles = new String[] {"index.html" };
+        }
+        if (basePath != null) {
+          getMapper().contextMapElement.resources = new File(getBasePath());
+        }
+        setWelcomeFiles(wFiles);
+
+        Iterator i2 = d.filters.values().iterator();
+        while (i2.hasNext()) {
+            FilterData fd = (FilterData)i2.next();
+            addFilter(fd.name, fd.className, fd.initParams);
+        }
+
+        Iterator i3 = d.servlets.values().iterator();
+        while (i3.hasNext()) {
+            ServletData sd = (ServletData) i3.next();
+            // jsp-file
+            if (sd.className == null) {
+                if (sd.jspFile == null) {
+                    log.log(Level.WARNING, "Missing servlet class for " + sd.name);
+                    continue;
+                }
+            }
+
+            ServletConfigImpl sw =
+              new ServletConfigImpl(this, sd.name, sd.className);
+            sw.setConfig(sd.initParams);
+            sw.setJspFile(sd.jspFile);
+            sw.setLoadOnStartup(sd.loadOnStartup);
+            //sw.setRunAs(sd.runAs);
+            sw.setSecurityRoleRef(sd.securityRoleRef);
+
+            addServletConfig(sw);
+        }
+
+        for (String k: d.servletMapping.keySet()) {
+            addMapping(k, d.servletMapping.get(k));
+        }
+
+        Iterator i5 = d.filterMappings.iterator();
+        while (i5.hasNext()) {
+            FilterMappingData k = (FilterMappingData) i5.next();
+            String[] disp = new String[k.dispatcher.size()];
+            if (k.urlPattern != null) {
+              addFilterMapping(k.urlPattern,
+                  k.filterName,
+                  (String[])k.dispatcher.toArray(disp));
+            }
+            if (k.servletName != null) {
+              addFilterServletMapping(k.servletName,
+                  k.filterName,
+                  (String[])k.dispatcher.toArray(disp));
+            }
+         }
+
+        for (String n: d.localeEncodingMapping.keySet()) {
+            getCharsetMapper().addCharsetMapping(n,
+                    d.localeEncodingMapping.get(n));
+        }
+    }
+
+    public void addServlet(String servletName, String servletClass,
+                           String jspFile, Map params) {
+      ServletConfigImpl sc = new ServletConfigImpl(this, servletName,
+          servletClass);
+      sc.setJspFile(jspFile);
+      sc.setConfig(params);
+      addServletConfig(sc);
+    }
+
+    @Override
+    public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
+      ServletConfigImpl sc = new ServletConfigImpl(this, servletName, null);
+      sc.setServlet(servlet);
+      addServletConfig(sc);
+      return sc.getDynamic();
+    }
+
+    public void addServletSec(String serlvetName, String runAs, Map roles) {
+      // TODO
+    }
+
+
+
+    public void addFilterMapping(String path, String filterName,
+                                 String[] dispatcher) {
+      getFilterMapper().addMapping(filterName,
+          path, null, dispatcher, true);
+
+    }
+
+    public void addFilterServletMapping(String servlet,
+                                        String filterName,
+                                        String[] dispatcher) {
+      getFilterMapper().addMapping(filterName,
+          null, servlet,
+          dispatcher, true);
+    }
+
+    /**
+     * Called from TomcatLite.init(), required before start.
+     *
+     * Will initialize defaults and load web.xml unless webAppData is
+     * already set and recent. No other processing is done except reading
+     * the config - you can add or alter it before start() is called.
+     *
+     * @throws ServletException
+     */
+    public void init() throws ServletException {
+        if (initDone) {
+            return;
+        }
+        initDone = true;
+        // Load global init params from the facade
+        initEngineDefaults();
+
+        initTempDir();
+
+
+        // Merge in web.xml - or other config source ( programmatic, etc )
+        ConfigLoader cfg = new WarDeploy(); 
+        contextConfig = cfg.loadConfig(getBasePath());
+        
+        processWebAppData(contextConfig);
+
+        // if not defined yet:
+        addDefaultServlets();
+    }
+
+
+    protected void initTempDir() throws ServletException {
+        // We need a base path - at least for temp files, req. by spec
+        if (basePath == null) {
+            basePath = ("/".equals(contextPath)) ?
+                    facade.getWork().getAbsolutePath() + "/ROOT" :
+                    facade.getWork().getAbsolutePath() + contextPath;
+        }
+
+        File f = new File(basePath + "/WEB-INF/tmp");
+        f.mkdirs();
+        setAttribute("javax.servlet.context.tempdir", f);
+    }
+
+    /**
+     * Static file handler ( default )
+     * *.jsp support
+     *
+     */
+    protected void addDefaultServlets() throws ServletException {
+        if (servlets.get("default") == null) {
+            ServletConfigImpl fileS = new ServletConfigImpl(this,
+                    "default", null);
+            addServletConfig(fileS);
+            addMapping("/", fileS);
+        }
+
+        // *.jsp support
+        if (servlets.get("jspwildcard") == null) {
+            ServletConfigImpl fileS = new ServletConfigImpl(this,
+                        "jspwildcard", null);
+            fileS.initParams.put("mapper", JspLoader.class.getName());            
+            addServletConfig(fileS);
+            addMapping("*.jsp", fileS);
+        }
+        
+        ServletConfigImpl jspcS = new ServletConfigImpl(this,
+                "jspc", jspcServlet);
+        addServletConfig(jspcS);
+    }
+
+    protected void initEngineDefaults() throws ServletException {
+
+        // TODO: make this customizable, avoid loading it on startup
+        // Set the class name as default in the addon support
+        for (String sname: facade.ctxDefaultInitParam.keySet()) {
+            String path = facade.ctxDefaultInitParam.get(sname);
+            contextConfig.contextParam.put(sname, path);
+        }
+
+        for (String sname: facade.preloadServlets.keySet()) {
+            String sclass = facade.preloadServlets.get(sname);
+            ServletConfigImpl fileS = new ServletConfigImpl(this, sname, sclass);
+            addServletConfig(fileS);
+        }
+
+        for (String sname: facade.preloadMappings.keySet()) {
+            String path = facade.preloadMappings.get(sname);
+            ServletConfigImpl servletConfig = getServletConfig(sname);
+            addMapping(path, servletConfig);
+        }
+
+        // JSP support 
+        setAttribute(InstanceManager.class.getName(),
+                new LiteInstanceManager(getObjectManager()));
+        
+    }
+
+    private void addClasspathLib(ArrayList res, File directory) {
+        
+        if (!directory.isDirectory() || !directory.exists()
+                || !directory.canRead()) {
+            return;
+        }
+        
+        File[] jars = directory.listFiles(new FilenameFilter() {
+            public boolean accept(File dir, String name) {
+              return name.endsWith(".jar");
+            }
+          });
+        
+        for (int j = 0; j < jars.length; j++) {
+            try {
+                URL url = jars[j].toURL();
+                res.add(url);
+            } catch (MalformedURLException e) {
+            }
+        }
+    }
+    
+    private void addClasspathDir(ArrayList res, File classesDir) {
+        
+        if (classesDir.isDirectory() && classesDir.exists() &&
+                classesDir.canRead()) {
+            try {
+                URL url = classesDir.toURL();
+                res.add(url);
+            } catch (MalformedURLException e) {
+            }
+        }
+    }
+    public String getClassPath() {
+        return classPath;
+    }
+
+    public void start() throws ServletException {
+        if (startDone) {
+            return;
+        }
+        String base = getBasePath();
+
+        ArrayList urls = new ArrayList();
+        
+        addClasspathDir(urls, new File(base + "/WEB-INF/classes"));
+        addClasspathDir(urls, new File(base + "/WEB-INF/tmp"));
+        addClasspathLib(urls, new File(base + "/WEB-INF/lib"));
+        
+        URL[] urlsA = new URL[urls.size()];
+        urls.toArray(urlsA);
+
+        URLClassLoader parentLoader =
+            getEngine().getContextParentLoader();
+
+        // create a class loader.
+        // TODO: reimplement special 'deploy' dirs
+
+        /*
+          Repository ctxRepo = new Repository();
+          ctxRepo.setParentClassLoader(parentLoader);
+          ctxRepo.addURL(urlsA);
+          repository = ctxRepo;
+        */
+
+        StringBuilder cp = new StringBuilder();
+        
+        for (URL cpUrl : urlsA) {
+            cp.append(":").append(cpUrl.getFile());
+        }
+        classPath = cp.toString();
+        
+        classLoader = new URLClassLoader(urlsA, parentLoader);
+
+        // JMX should know about us ( TODO: is it too early ? )
+        facade.notifyAdd(this);
+
+        initListeners();
+
+        List listeners = this.getListeners();
+        ServletContextEvent event = null;
+        for (int i = 0; i < listeners.size(); i++) {
+            if (!(listeners.get(i) instanceof ServletContextListener))
+                continue;
+            ServletContextListener listener =
+                (ServletContextListener) listeners.get(i);
+            if (event == null) {
+                event = new ServletContextEvent(this);
+            }
+            try {
+                // May add servlets/filters
+                listener.contextInitialized(event);
+            } catch (Throwable t) {
+                log.log(Level.WARNING, "Context.init() contextInitialized() error:", t);
+            }
+        }
+
+
+        initFilters();
+        initServlets();
+
+        startDone = true;
+    }
+
+    public UserSessionManager getManager() {
+      if (manager == null) {
+          manager = (UserSessionManager) getObjectManager().get(
+                  UserSessionManager.class);
+          manager.setContext(this);
+          if (contextConfig.sessionTimeout > 0 ) {
+              manager.setSessionTimeout(contextConfig.sessionTimeout);
+          }
+      }
+      return manager;
+    }
+
+
+    // TODO: configurable ? init-params
+    public String getSessionCookieName() {
+        return "JSESSIONID";
+    }
+
+
+
+    public void destroy() throws ServletException {
+        // destroy filters
+        Iterator fI = filters.values().iterator();
+        while(fI.hasNext()) {
+            FilterConfigImpl fc = (FilterConfigImpl) fI.next();
+            try {
+                fc.getFilter().destroy();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+        // destroy servlets
+        fI = servlets.values().iterator();
+        while(fI.hasNext()) {
+            ServletConfigImpl fc = (ServletConfigImpl) fI.next();
+            try {
+                fc.unload();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public TomcatLite getEngine() {
+        return facade;
+    }
+
+    public String findStatusPage(int status) {
+        if (contextConfig.errorPageCode.size() == 0) {
+            return null;
+        }
+        if (status == 200) {
+            return null;
+        }
+
+        return (String) contextConfig.errorPageCode.get(Integer.toString(status));
+    }
+
+    public void handleStatusPage(ServletRequestImpl req,
+                                 ServletResponseImpl res,
+                                 int status,
+                                 String statusPage) {
+       String message = RequestUtil.filter(res.getMessage());
+       if (message == null)
+           message = "";
+       setErrorAttributes(req, status, message);
+       dispatchError(req, res, statusPage);
+   }
+
+   protected void setErrorAttributes(ServletRequestImpl req,
+                                   int status,
+                                   String message) {
+       req.setAttribute("javax.servlet.error.status_code",
+               new Integer(status));
+       if (req.getWrapper() != null) {
+           req.setAttribute("javax.servlet.error.servlet_name",
+                   req.getWrapper().servletName);
+       }
+       req.setAttribute("javax.servlet.error.request_uri",
+               req.getRequestURI());
+       req.setAttribute("javax.servlet.error.message",
+               message);
+
+   }
+
+   public void handleError(ServletRequestImpl req,
+                           ServletResponseImpl res,
+                           Throwable t) {
+       Throwable realError = t;
+       if (realError instanceof ServletException) {
+           realError = ((ServletException) realError).getRootCause();
+           if (realError == null) {
+               realError = t;
+           }
+       }
+      //if (realError instanceof ClientAbortException ) {
+
+       String errorPage = findErrorPage(t);
+       if ((errorPage == null) && (realError != t)) {
+           errorPage = findErrorPage(realError);
+       }
+
+       if (errorPage != null) {
+           setErrorAttributes(req, 500, t.getMessage());
+           req.setAttribute("javax.servlet.error.exception", realError);
+           req.setAttribute("javax.servlet.error.exception_type",
+                   realError.getClass());
+           dispatchError(req, res, errorPage);
+       } else {
+           log("Unhandled error", t);
+           if (t instanceof ServletException &&
+                   ((ServletException)t).getRootCause() != null) {
+               log("RootCause:", ((ServletException)t).getRootCause());
+           }
+           if (res.getStatus() < 500) {
+               res.setStatus(500);
+           }
+       }
+   }
+
+   protected void dispatchError(ServletRequestImpl req,
+                              ServletResponseImpl res,
+                              String errorPage) {
+       RequestDispatcher rd =
+           getRequestDispatcher(errorPage);
+       try {
+           // will clean up the buffer
+           rd.forward(req, res);
+           return; // handled
+       } catch (ServletException e) {
+           // TODO
+       } catch (IOException e) {
+           // TODO
+       }
+   }
+
+   protected String findErrorPage(Throwable exception) {
+       if (contextConfig.errorPageException.size() == 0) {
+           return null;
+       }
+       if (exception == null)
+           return (null);
+       Class clazz = exception.getClass();
+       String name = clazz.getName();
+       while (!Object.class.equals(clazz)) {
+           String page = (String)contextConfig.errorPageException.get(name);
+           if (page != null)
+               return (page);
+           clazz = clazz.getSuperclass();
+           if (clazz == null)
+               break;
+           name = clazz.getName();
+       }
+       return (null);
+
+   }
+
+
+   @Override
+   public EnumSet<SessionTrackingMode> getDefaultSessionTrackingModes() {
+       return null;
+   }
+
+
+   @Override
+   public EnumSet<SessionTrackingMode> getEffectiveSessionTrackingModes() {
+       return null;
+   }
+
+
+   @Override
+   public SessionCookieConfig getSessionCookieConfig() {
+       return null;
+   }
+
+
+   @Override
+   public void setSessionTrackingModes(EnumSet<SessionTrackingMode> sessionTrackingModes) {
+   }
+
+
+   public void addFilter(String filterName, String filterClass,
+                         Map params) {
+       FilterConfigImpl fc = new FilterConfigImpl(this);
+       fc.setData(filterName, filterClass, params);
+       filters.put(filterName, fc);
+   }
+
+
+   @Override
+   public Dynamic addFilter(String filterName, String className) {
+       FilterConfigImpl fc = new FilterConfigImpl(this);
+       fc.setData(filterName, className, new HashMap());
+       filters.put(filterName, fc);
+       return fc.getDynamic();
+   }
+
+
+   @Override
+   public Dynamic addFilter(String filterName, Filter filter) {
+       FilterConfigImpl fc = new FilterConfigImpl(this);
+       fc.setData(filterName, null, new HashMap());
+       fc.setFilter(filter);
+       filters.put(filterName, fc);
+       return fc.getDynamic();
+   }
+
+
+   @Override
+   public Dynamic addFilter(String filterName, Class<? extends Filter> filterClass) {
+       FilterConfigImpl fc = new FilterConfigImpl(this);
+       fc.setData(filterName, null, new HashMap());
+       fc.setFilterClass(filterClass);
+       filters.put(filterName, fc);
+       return fc.getDynamic();
+   }
+
+
+   @Override
+   public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName,
+                                                        String className) {
+       ServletConfigImpl sc = new ServletConfigImpl(this, servletName, className);
+       addServletConfig(sc);
+       return sc.getDynamic();
+   }
+
+
+   @Override
+   public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName,
+                                                        Class<? extends Servlet> servletClass) {
+       ServletConfigImpl sc = new ServletConfigImpl(this, servletName, servletClass.getName());
+       sc.setServletClass(servletClass);
+       addServletConfig(sc);
+       return sc.getDynamic();
+   }
+
+   // That's tricky - this filter will have no name. We need to generate one
+   // because our code relies on names.
+   AtomicInteger autoName = new AtomicInteger();
+
+
+   @Override
+   public <T extends Filter> T createFilter(Class<T> c) throws ServletException {
+       FilterConfigImpl fc = new FilterConfigImpl(this);
+       String filterName = "_tomcat_auto_filter_" + autoName.incrementAndGet();
+       fc.setData(filterName, null, new HashMap());
+       fc.setFilterClass(c);
+       filters.put(filterName, fc);
+
+       try {
+           return (T) fc.createFilter();
+       } catch (ClassCastException e) {
+           throw new ServletException(e);
+       } catch (ClassNotFoundException e) {
+           throw new ServletException(e);
+       } catch (IllegalAccessException e) {
+           throw new ServletException(e);
+       } catch (InstantiationException e) {
+           throw new ServletException(e);
+       }
+   }
+
+
+   @Override
+   public <T extends Servlet> T createServlet(Class<T> c) throws ServletException {
+       String filterName = "_tomcat_auto_servlet_" + autoName.incrementAndGet();
+       ServletConfigImpl fc = new ServletConfigImpl(this, filterName, null);
+       fc.setServletClass(c);
+       servlets.put(filterName, fc);
+
+       try {
+           return (T) fc.newInstance();
+       } catch (ClassCastException e) {
+           throw new ServletException(e);
+       }
+   }
+
+
+   public FilterRegistration findFilterRegistration(String filterName) {
+       return filters.get(filterName);
+   }
+
+
+   public ServletRegistration findServletRegistration(String servletName) {
+       return servlets.get(servletName);
+   }
+
+
+   @Override
+   public boolean setInitParameter(String name, String value) {
+       HashMap<String, String> params = contextConfig.contextParam;
+       return setInitParameter(this, params, name, value);
+   }
+
+
+   static Set<String> setInitParameters(ServletContextImpl ctx,
+           Map<String, String> params,
+           Map<String, String> initParameters)
+           throws IllegalArgumentException, IllegalStateException {
+       if (ctx.startDone) {
+           throw new IllegalStateException();
+       }
+       Set<String> result = new HashSet<String>();
+       for (String name: initParameters.keySet()) {
+           String value = initParameters.get(name);
+           if (name == null || value == null) {
+               throw new IllegalArgumentException();
+           }
+           if (!setInitParameter(ctx, params, name, value)) {
+               result.add(name);
+           }
+       }
+       return result;
+   }
+
+   /**
+    * true if the context initialization parameter with the given name and value was set successfully on this ServletContext, and false if it was not set because this ServletContext already contains a context initialization parameter with a matching name
+    * Throws:
+    * java.lang.IllegalStateException - if this ServletContext has already been initialized
+    */
+   static boolean setInitParameter(ServletContextImpl ctx, Map<String, String> params,
+                                   String name, String value) {
+       if (name == null || value == null) {
+           throw new IllegalArgumentException();
+       }
+       if (ctx.startDone) {
+           throw new IllegalStateException();
+       }
+       String oldValue = params.get(name);
+       if (oldValue != null) {
+           return false;
+       } else {
+           params.put(name, value);
+           return true;
+       }
+   }
+
+    public JspConfigDescriptor getJspConfigDescriptor() {
+        // fix me - just here to compile
+        return null;
+    }
+
+
+
+    public void declareRoles(String... roleNames) {
+        // implement me
+    }
+
+    public <T extends EventListener> T createListener(Class<T> c) throws ServletException {
+        // implement me
+        return null;
+    }
+
+    public Collection<String> getMappings() {
+        // implement me
+        return null;
+    }
+
+    public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
+        // implement me
+        return null;
+    }
+
+    public FilterRegistration getFilterRegistration(String filterName) {
+        // implement me
+        return null;
+    }
+
+    public Map<String, ? extends ServletRegistration> getServletRegistrations() {
+        // implement me
+        return null;
+    }
+
+    public ServletRegistration getServletRegistration(String servletName) {
+        // implement me
+        return null;
+    }
+
+    public int getEffectiveMinorVersion() {
+        // implement me
+        return -1;
+    }
+
+    public int getEffectiveMajorVersion() {
+        // implement me
+        return -1;
+    }
+
+    private final class LiteInstanceManager implements InstanceManager {
+        private ObjectManager om;
+
+        public LiteInstanceManager(ObjectManager objectManager) {
+            this.om = objectManager;
+        }
+
+        @Override
+        public void destroyInstance(Object o)
+                throws IllegalAccessException,
+                InvocationTargetException {
+        }
+
+        @Override
+        public Object newInstance(String className)
+                throws IllegalAccessException,
+                InvocationTargetException, NamingException,
+                InstantiationException,
+                ClassNotFoundException {
+            return om.get(className);
+        }
+
+        @Override
+        public Object newInstance(String fqcn,
+                ClassLoader classLoader)
+                throws IllegalAccessException,
+                InvocationTargetException, NamingException,
+                InstantiationException,
+                ClassNotFoundException {
+            return om.get(fqcn);
+        }
+
+        @Override
+        public void newInstance(Object o)
+                throws IllegalAccessException,
+                InvocationTargetException, NamingException {
+            om.bind(o.getClass().getName(), o);
+        }
+    }
+    
+}
+
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletInputStreamImpl.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletInputStreamImpl.java
new file mode 100644 (file)
index 0000000..c566dc5
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * 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.apache.coyote.servlet;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.servlet.ServletInputStream;
+
+
+/**
+ * Wrapper around MessageReader
+ * 
+ * @author Remy Maucherat
+ * @author Jean-Francois Arcand
+ * @author Costin Manolache
+ */
+public class ServletInputStreamImpl extends ServletInputStream {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    protected InputStream ib;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public ServletInputStreamImpl(InputStream ib) {
+        this.ib = ib;
+    }
+
+    // --------------------------------------------- ServletInputStream Methods
+
+    public long skip(long n)
+        throws IOException {
+        return ib.skip(n);
+    }
+    
+    public void mark(int readAheadLimit)
+    {
+        //try {
+        ib.mark(readAheadLimit);
+//        } catch (IOException e) {
+//            e.printStackTrace();
+//        }
+    }
+
+
+    public void reset()
+        throws IOException {
+        ib.reset();
+    }
+    
+
+
+    public int read()
+        throws IOException {    
+        return ib.read();
+    }
+
+    public int available() throws IOException {
+        return ib.available();
+    }
+
+    public int read(final byte[] b) throws IOException {
+        return ib.read(b, 0, b.length);
+    }
+
+
+    public int read(final byte[] b, final int off, final int len)
+        throws IOException {
+            
+        return ib.read(b, off, len);
+    }
+
+
+    public int readLine(byte[] b, int off, int len) throws IOException {
+        return super.readLine(b, off, len);
+    }
+
+    /** 
+     * Close the stream
+     * Since we re-cycle, we can't allow the call to super.close()
+     * which would permantely disable us.
+     */
+    public void close() throws IOException {
+        ib.close();
+    }
+
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletOutputStreamImpl.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletOutputStreamImpl.java
new file mode 100644 (file)
index 0000000..5f2225a
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * 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.apache.coyote.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.ServletOutputStream;
+
+
+/**
+ * Coyote implementation of the servlet output stream.
+ * 
+ * @author Costin Manolache
+ * @author Remy Maucherat
+ */
+public class ServletOutputStreamImpl 
+    extends ServletOutputStream {
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    protected BodyWriter ob;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public ServletOutputStreamImpl(BodyWriter ob) {
+        this.ob = ob;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Prevent cloning the facade.
+     */
+    protected Object clone()
+        throws CloneNotSupportedException {
+        throw new CloneNotSupportedException();
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Clear facade.
+     */
+    void clear() {
+        ob = null;
+    }
+
+
+    // --------------------------------------------------- OutputStream Methods
+
+
+    public void write(int i)
+        throws IOException {
+        ob.writeByte(i);
+    }
+
+
+    public void write(byte[] b)
+        throws IOException {
+        write(b, 0, b.length);
+    }
+
+
+    public void write(byte[] b, int off, int len)
+        throws IOException {
+        ob.write(b, off, len);
+    }
+
+
+    /**
+     * Will send the buffer to the client.
+     */
+    public void flush()
+        throws IOException {
+        ob.flush();
+    }
+
+
+    public void close()
+        throws IOException {
+        ob.close();
+    }
+
+
+    // -------------------------------------------- ServletOutputStream Methods
+
+
+    public void print(String s)
+        throws IOException {
+        ob.write(s);
+    }
+
+
+}
+
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletReaderImpl.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletReaderImpl.java
new file mode 100644 (file)
index 0000000..62bfb2e
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * 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.apache.coyote.servlet;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+
+
+
+/**
+ * Coyote implementation of the buffred reader.
+ * 
+ * @author Remy Maucherat
+ */
+public class ServletReaderImpl
+    extends BufferedReader {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    private static final char[] LINE_SEP = { '\r', '\n' };
+    private static final int MAX_LINE_LENGTH = 4096;
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    protected Reader ib;
+
+
+    protected char[] lineBuffer = null;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public ServletReaderImpl(Reader ib) {
+        super(ib, 1);
+        this.ib = ib;
+    }
+    
+    public void close()
+        throws IOException {
+        ib.close();
+    }
+
+
+    public int read()
+        throws IOException {
+        return ib.read();
+    }
+
+
+    public int read(char[] cbuf)
+        throws IOException {
+        return ib.read(cbuf, 0, cbuf.length);
+    }
+
+
+    public int read(char[] cbuf, int off, int len)
+        throws IOException {
+        return ib.read(cbuf, off, len);
+    }
+
+
+    public long skip(long n)
+        throws IOException {
+        return ib.skip(n);
+    }
+
+
+    public boolean ready()
+        throws IOException {
+        return ib.ready();
+    }
+
+
+    public boolean markSupported() {
+        return true;
+    }
+
+
+    public void mark(int readAheadLimit)
+        throws IOException {
+        ib.mark(readAheadLimit);
+    }
+
+
+    public void reset()
+        throws IOException {
+        ib.reset();
+    }
+
+
+    // TODO: move the readLine functionality to base coyote IO
+    public String readLine()
+        throws IOException {
+
+        if (lineBuffer == null) {
+            lineBuffer = new char[MAX_LINE_LENGTH];
+       }
+
+        String result = null;
+
+        int pos = 0;
+        int end = -1;
+        int skip = -1;
+        StringBuilder aggregator = null;
+        while (end < 0) {
+            mark(MAX_LINE_LENGTH);
+            while ((pos < MAX_LINE_LENGTH) && (end < 0)) {
+                int nRead = read(lineBuffer, pos, MAX_LINE_LENGTH - pos);
+                if (nRead < 0) {
+                    if (pos == 0) {
+                        return null;
+                    }
+                    end = pos;
+                    skip = pos;
+                }
+                for (int i = pos; (i < (pos + nRead)) && (end < 0); i++) {
+                    if (lineBuffer[i] == LINE_SEP[0]) {
+                        end = i;
+                        skip = i + 1;
+                        char nextchar;
+                        if (i == (pos + nRead - 1)) {
+                            nextchar = (char) read();
+                        } else {
+                            nextchar = lineBuffer[i+1];
+                        }
+                        if (nextchar == LINE_SEP[1]) {
+                            skip++;
+                        }
+                    } else if (lineBuffer[i] == LINE_SEP[1]) {
+                        end = i;
+                        skip = i + 1;
+                    }
+                }
+                if (nRead > 0) {
+                    pos += nRead;
+                }
+            }
+            if (end < 0) {
+                if (aggregator == null) {
+                    aggregator = new StringBuilder();
+                }
+                aggregator.append(lineBuffer);
+                pos = 0;
+            } else {
+                reset();
+                skip(skip);
+            }
+        }
+
+        if (aggregator == null) {
+            result = new String(lineBuffer, 0, end);
+        } else {
+            aggregator.append(lineBuffer, 0, end);
+            result = aggregator.toString();
+        }
+
+        return result;
+
+    }
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletRequestImpl.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletRequestImpl.java
new file mode 100644 (file)
index 0000000..ef22f6f
--- /dev/null
@@ -0,0 +1,2572 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * 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.apache.coyote.servlet;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.TimeZone;
+import java.util.TreeMap;
+import java.util.logging.Level;
+
+import javax.security.auth.Subject;
+import javax.servlet.AsyncContext;
+import javax.servlet.AsyncListener;
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletRequestAttributeEvent;
+import javax.servlet.ServletRequestAttributeListener;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.Part;
+
+import org.apache.tomcat.servlets.session.UserSessionManager;
+import org.apache.tomcat.servlets.util.Enumerator;
+import org.apache.tomcat.servlets.util.LocaleParser;
+import org.apache.tomcat.servlets.util.RequestUtil;
+import org.apache.tomcat.util.buf.B2CConverter;
+import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.buf.UriNormalizer;
+import org.apache.tomcat.util.http.Cookies;
+import org.apache.tomcat.util.http.FastHttpDateFormat;
+import org.apache.tomcat.util.http.HttpRequest;
+import org.apache.tomcat.util.http.Parameters;
+import org.apache.tomcat.util.http.ServerCookie;
+import org.apache.tomcat.util.http.mapper.MappingData;
+
+
+/**
+ *
+ * Wrapper object for the Coyote request.
+ *
+ * @author Remy Maucherat
+ * @author Craig R. McClanahan
+ */
+public class ServletRequestImpl implements HttpServletRequest {
+
+    /**
+     * The request attribute under which we store the array of X509Certificate
+     * objects representing the certificate chain presented by our client,
+     * if any.
+     */
+    public static final String CERTIFICATES_ATTR =
+        "javax.servlet.request.X509Certificate";
+
+    /**
+     * The request attribute under which we store the name of the cipher suite
+     * being used on an SSL connection (as an object of type
+     * java.lang.String).
+     */
+    public static final String CIPHER_SUITE_ATTR =
+        "javax.servlet.request.cipher_suite";
+
+    /**
+     * Request dispatcher state.
+     */
+    public static final String DISPATCHER_TYPE_ATTR =
+        "org.apache.catalina.core.DISPATCHER_TYPE";
+
+    /**
+     * Request dispatcher path.
+     */
+    public static final String DISPATCHER_REQUEST_PATH_ATTR =
+        "org.apache.catalina.core.DISPATCHER_REQUEST_PATH";
+
+    /**
+     * The servlet context attribute under which we store the class path
+     * for our application class loader (as an object of type String),
+     * delimited with the appropriate path delimiter for this platform.
+     */
+    public static final String CLASS_PATH_ATTR =
+        "org.apache.catalina.jsp_classpath";
+
+
+    /**
+     * The request attribute under which we forward a Java exception
+     * (as an object of type Throwable) to an error page.
+     */
+    public static final String EXCEPTION_ATTR =
+        "javax.servlet.error.exception";
+
+
+    /**
+     * The request attribute under which we forward the request URI
+     * (as an object of type String) of the page on which an error occurred.
+     */
+    public static final String EXCEPTION_PAGE_ATTR =
+        "javax.servlet.error.request_uri";
+
+
+    /**
+     * The request attribute under which we forward a Java exception type
+     * (as an object of type Class) to an error page.
+     */
+    public static final String EXCEPTION_TYPE_ATTR =
+        "javax.servlet.error.exception_type";
+
+
+    /**
+     * The request attribute under which we forward an HTTP status message
+     * (as an object of type STring) to an error page.
+     */
+    public static final String ERROR_MESSAGE_ATTR =
+        "javax.servlet.error.message";
+
+
+    /**
+     * The request attribute under which we expose the value of the
+     * <code>&lt;jsp-file&gt;</code> value associated with this servlet,
+     * if any.
+     */
+    public static final String JSP_FILE_ATTR =
+        "org.apache.catalina.jsp_file";
+
+
+    /**
+     * The request attribute under which we store the key size being used for
+     * this SSL connection (as an object of type java.lang.Integer).
+     */
+    public static final String KEY_SIZE_ATTR =
+        "javax.servlet.request.key_size";
+
+    /**
+     * The request attribute under which we store the session id being used
+     * for this SSL connection (as an object of type java.lang.String).
+     */
+    public static final String SSL_SESSION_ID_ATTR =
+        "javax.servlet.request.ssl_session";
+
+    /**
+     * The request attribute under which we forward a servlet name to
+     * an error page.
+     */
+    public static final String SERVLET_NAME_ATTR =
+        "javax.servlet.error.servlet_name";
+
+
+    /**
+     * The name of the cookie used to pass the session identifier back
+     * and forth with the client.
+     */
+    public static final String SESSION_COOKIE_NAME = "JSESSIONID";
+
+
+    /**
+     * The name of the path parameter used to pass the session identifier
+     * back and forth with the client.
+     */
+    public static final String SESSION_PARAMETER_NAME = "jsessionid";
+
+
+    /**
+     * The request attribute under which we forward an HTTP status code
+     * (as an object of type Integer) to an error page.
+     */
+    public static final String STATUS_CODE_ATTR =
+        "javax.servlet.error.status_code";
+
+
+    /**
+     * The subject under which the AccessControlContext is running.
+     */
+    public static final String SUBJECT_ATTR =
+        "javax.security.auth.subject";
+
+
+    /**
+     * The servlet context attribute under which we store a temporary
+     * working directory (as an object of type File) for use by servlets
+     * within this web application.
+     */
+    public static final String WORK_DIR_ATTR =
+        "javax.servlet.context.tempdir";
+
+    protected static final TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT");
+
+
+    /**
+     * The default Locale if none are specified.
+     */
+    protected static Locale defaultLocale = Locale.getDefault();
+
+    // ApplicationFilterFactory. What's the use ???
+    private static Integer REQUEST_INTEGER = new Integer(8);
+
+    /**
+     * The match string for identifying a session ID parameter.
+     */
+    private static final String match = ";" + SESSION_PARAMETER_NAME + "=";
+
+    /**
+     * The set of cookies associated with this Request.
+     */
+    protected Cookie[] cookies = null;
+
+
+    /**
+     * The set of SimpleDateFormat formats to use in getDateHeader().
+     *
+     * Notice that because SimpleDateFormat is not thread-safe, we can't
+     * declare formats[] as a static variable.
+     */
+    protected SimpleDateFormat formats[] = null;
+
+
+    /**
+     * The attributes associated with this Request, keyed by attribute name.
+     */
+    protected HashMap attributes = new HashMap();
+
+
+    /**
+     * List of read only attributes for this Request.
+     */
+    //private HashMap readOnlyAttributes = new HashMap();
+
+
+    /**
+     * The preferred Locales assocaited with this Request.
+     */
+    protected ArrayList locales = new ArrayList();
+
+
+    /**
+     * Authentication type.
+     */
+    protected String authType = null;
+
+    /**
+     * User principal.
+     */
+    protected Principal userPrincipal = null;
+
+
+    /**
+     * The Subject associated with the current AccessControllerContext
+     */
+    protected transient Subject subject = null;
+
+
+    /**
+     * The current dispatcher type.
+     */
+    protected Object dispatcherType = null;
+
+
+    /**
+     * The associated input buffer.
+     */
+    protected BodyReader inputBuffer;
+
+    Connector connector;
+
+    /**
+     * ServletInputStream.
+     */
+    protected ServletInputStreamImpl inputStream;
+
+
+    /**
+     * Reader.
+     */
+    protected BufferedReader reader;
+
+
+    /**
+     * Using stream flag.
+     */
+    protected boolean usingInputStream = false;
+
+
+    /**
+     * Using writer flag.
+     */
+    protected boolean usingReader = false;
+
+
+    /**
+     * Session parsed flag.
+     */
+    protected boolean sessionParsed = false;
+
+
+    /**
+     * Request parameters parsed flag.
+     */
+    protected boolean parametersParsed = false;
+
+
+    /**
+     * Cookies parsed flag.
+     */
+    protected boolean cookiesParsed = false;
+
+
+    /**
+     * Secure flag.
+     */
+    protected boolean secure = false;
+
+
+    /**
+     * Hash map used in the getParametersMap method.
+     */
+    protected ParameterMap parameterMap = new ParameterMap();
+
+
+    /**
+     * The currently active session for this request.
+     */
+    protected HttpSession session = null;
+
+
+    /**
+     * The current request dispatcher path.
+     */
+    protected Object requestDispatcherPath = null;
+
+
+    /**
+     * Was the requested session ID received in a cookie?
+     */
+    protected boolean requestedSessionCookie = false;
+
+
+    /**
+     * The requested session ID (if any) for this request.
+     */
+    protected String requestedSessionId = null;
+
+
+    /**
+     * Was the requested session ID received in a URL?
+     */
+    protected boolean requestedSessionURL = false;
+
+
+    /**
+     * Parse locales.
+     */
+    protected boolean localesParsed = false;
+
+
+    /**
+     * Associated context.
+     */
+    protected ServletContextImpl context = null;
+
+
+
+    // --------------------------------------------------------- Public Methods
+
+    /**
+     * Filter chain associated with the request.
+     */
+    protected FilterChainImpl filterChain = new FilterChainImpl();
+
+    /**
+     * Mapping data.
+     */
+    protected MappingData mappingData = new MappingData();
+
+
+    // -------------------------------------------------------- Request Methods
+
+    /**
+     * The response with which this request is associated.
+     */
+    protected ServletResponseImpl response = new ServletResponseImpl();
+
+    /**
+     * URI byte to char converter (not recycled).
+     */
+   // protected B2CConverter URIConverter = null;
+
+    /**
+     * Associated wrapper.
+     */
+    protected ServletConfigImpl wrapper = null;
+
+    /**
+     * Post data buffer.
+     */
+    public final static int CACHED_POST_LEN = 8192;
+
+    public  byte[] postData = null;
+
+
+    private HttpRequest httpRequest;
+
+    /** New IO/buffer model
+     */
+    //protected Http11Connection con;
+
+
+    public ServletRequestImpl() {
+        response.setRequest(this);
+    }
+
+
+//    /**
+//     * Return the Host within which this Request is being processed.
+//     */
+//    public Host getHost() {
+//        if (getContext() == null)
+//            return null;
+//        return (Host) getContext().getParent();
+//        //return ((Host) mappingData.host);
+//    }
+//
+//
+//    /**
+//     * Set the Host within which this Request is being processed.  This
+//     * must be called as soon as the appropriate Host is identified, and
+//     * before the Request is passed to a context.
+//     *
+//     * @param host The newly associated Host
+//     */
+//    public void setHost(Host host) {
+//        mappingData.host = host;
+//    }
+
+    /**
+     * Add a Cookie to the set of Cookies associated with this Request.
+     *
+     * @param cookie The new cookie
+     */
+    public void addCookie(Cookie cookie) {
+
+        if (!cookiesParsed)
+            parseCookies();
+
+        int size = 0;
+        if (cookies != null) {
+            size = cookies.length;
+        }
+
+        Cookie[] newCookies = new Cookie[size + 1];
+        for (int i = 0; i < size; i++) {
+            newCookies[i] = cookies[i];
+        }
+        newCookies[size] = cookie;
+
+        cookies = newCookies;
+
+    }
+
+    /**
+     * Add a Header to the set of Headers associated with this Request.
+     *
+     * @param name The new header name
+     * @param value The new header value
+     */
+    public void addHeader(String name, String value) {
+        // Not used
+    }
+
+    public void setConnector(Connector c) {
+        connector = c;
+    }
+
+    public Connector getConnector() {
+        return connector;
+    }
+
+    /**
+     * Add a Locale to the set of preferred Locales for this Request.  The
+     * first added Locale will be the first one returned by getLocales().
+     *
+     * @param locale The new preferred Locale
+     */
+    public void addLocale(Locale locale) {
+        locales.add(locale);
+    }
+
+
+    /**
+     * Add a parameter name and corresponding set of values to this Request.
+     * (This is used when restoring the original request on a form based
+     * login).
+     *
+     * @param name Name of this request parameter
+     * @param values Corresponding values for this request parameter
+     */
+    public void addParameter(String name, String values[]) {
+        httpRequest.getParameters().addParameterValues(name, values);
+    }
+
+    /**
+     * Clear the collection of Cookies associated with this Request.
+     */
+    public void clearCookies() {
+        cookiesParsed = true;
+        cookies = null;
+    }
+
+    /**
+     * Clear the collection of Headers associated with this Request.
+     */
+    public void clearHeaders() {
+        // Not used
+    }
+
+    /**
+     * Clear the collection of Locales associated with this Request.
+     */
+    public void clearLocales() {
+        locales.clear();
+    }
+
+    /**
+     * Clear the collection of parameters associated with this Request.
+     */
+    public void clearParameters() {
+        // Not used
+    }
+
+
+    /**
+     * Create and return a ServletInputStream to read the content
+     * associated with this Request.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public ServletInputStream createInputStream()
+        throws IOException {
+        return inputStream;
+    }
+
+    /**
+     * Perform whatever actions are required to flush and close the input
+     * stream or reader, in a single operation.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void finishRequest() throws IOException {
+        // The reader and input stream don't need to be closed
+    }
+
+
+    /**
+     * Return the specified request attribute if it exists; otherwise, return
+     * <code>null</code>.
+     *
+     * @param name Name of the request attribute to return
+     */
+    public Object getAttribute(String name) {
+
+        if (name.equals(ServletRequestImpl.DISPATCHER_TYPE_ATTR)) {
+            return (dispatcherType == null)
+                ? REQUEST_INTEGER
+                : dispatcherType;
+        } else if (name.equals(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR)) {
+            return (requestDispatcherPath == null)
+                ? getRequestPathMB().toString()
+                : requestDispatcherPath.toString();
+        }
+
+        Object attr=attributes.get(name);
+
+        if(attr!=null)
+            return(attr);
+
+//        attr =  reqB.getAttribute(name);
+//        if(attr != null)
+//            return attr;
+//        if( isSSLAttribute(name) ) {
+//            reqB.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE,
+//                                 reqB);
+//            attr = reqB.getAttribute(ServletRequestImpl.CERTIFICATES_ATTR);
+//            if( attr != null) {
+//                attributes.put(ServletRequestImpl.CERTIFICATES_ATTR, attr);
+//            }
+//            attr = reqB.getAttribute(ServletRequestImpl.CIPHER_SUITE_ATTR);
+//            if(attr != null) {
+//                attributes.put(ServletRequestImpl.CIPHER_SUITE_ATTR, attr);
+//            }
+//            attr = reqB.getAttribute(ServletRequestImpl.KEY_SIZE_ATTR);
+//            if(attr != null) {
+//                attributes.put(ServletRequestImpl.KEY_SIZE_ATTR, attr);
+//            }
+//            attr = reqB.getAttribute(ServletRequestImpl.SSL_SESSION_ID_ATTR);
+//            if(attr != null) {
+//                attributes.put(ServletRequestImpl.SSL_SESSION_ID_ATTR, attr);
+//            }
+//            attr = attributes.get(name);
+//        }
+        return attr;
+    }
+
+    /**
+     * Return the names of all request attributes for this Request, or an
+     * empty <code>Enumeration</code> if there are none.
+     */
+    public Enumeration getAttributeNames() {
+        if (isSecure()) {
+            getAttribute(ServletRequestImpl.CERTIFICATES_ATTR);
+        }
+        return new Enumerator(attributes.keySet(), true);
+    }
+
+
+    /**
+     * Return the authentication type used for this Request.
+     */
+    public String getAuthType() {
+        return (authType);
+    }
+
+
+    // ------------------------------------------------- Request Public Methods
+
+
+    /**
+     * Return the character encoding for this Request.
+     */
+    public String getCharacterEncoding() {
+      return (httpRequest.getCharacterEncoding());
+    }
+
+
+    /**
+     * Return the content length for this Request.
+     */
+    public int getContentLength() {
+        return (httpRequest.getContentLength());
+    }
+
+
+//    /**
+//     * Return the object bound with the specified name to the internal notes
+//     * for this request, or <code>null</code> if no such binding exists.
+//     *
+//     * @param name Name of the note to be returned
+//     */
+//    public Object getNote(String name) {
+//        return (notes.get(name));
+//    }
+//
+//
+//    /**
+//     * Return an Iterator containing the String names of all notes bindings
+//     * that exist for this request.
+//     */
+//    public Iterator getNoteNames() {
+//        return (notes.keySet().iterator());
+//    }
+//
+//
+//    /**
+//     * Remove any object bound to the specified name in the internal notes
+//     * for this request.
+//     *
+//     * @param name Name of the note to be removed
+//     */
+//    public void removeNote(String name) {
+//        notes.remove(name);
+//    }
+//
+//
+//    /**
+//     * Bind an object to a specified name in the internal notes associated
+//     * with this request, replacing any existing binding for this name.
+//     *
+//     * @param name Name to which the object should be bound
+//     * @param value Object to be bound to the specified name
+//     */
+//    public void setNote(String name, Object value) {
+//        notes.put(name, value);
+//    }
+//
+
+    /**
+     * Return the content type for this Request.
+     */
+    public String getContentType() {
+        return (httpRequest.getContentType());
+    }
+
+
+    /**
+     * Return the Context within which this Request is being processed.
+     */
+    public ServletContextImpl getContext() {
+        return (this.context);
+    }
+
+
+    /**
+     * Return the portion of the request URI used to select the Context
+     * of the Request.
+     */
+    public String getContextPath() {
+        return (mappingData.contextPath.toString());
+    }
+
+
+    /**
+     * Get the context path.
+     *
+     * @return the context path
+     */
+    public MessageBytes getContextPathMB() {
+        return (mappingData.contextPath);
+    }
+
+
+    /**
+     * Return the set of Cookies received with this Request.
+     */
+    public Cookie[] getCookies() {
+
+        if (!cookiesParsed)
+            parseCookies();
+
+        return cookies;
+
+    }
+
+
+    /**
+     * Return the value of the specified date header, if any; otherwise
+     * return -1.
+     *
+     * @param name Name of the requested date header
+     *
+     * @exception IllegalArgumentException if the specified header value
+     *  cannot be converted to a date
+     */
+    public long getDateHeader(String name) {
+
+        String value = getHeader(name);
+        if (value == null)
+            return (-1L);
+        if (formats == null) {
+            formats = new SimpleDateFormat[] {
+                new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
+                new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
+                new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
+            };
+            formats[0].setTimeZone(GMT_ZONE);
+            formats[1].setTimeZone(GMT_ZONE);
+            formats[2].setTimeZone(GMT_ZONE);
+        }
+
+        // Attempt to convert the date header in a variety of formats
+        long result = FastHttpDateFormat.parseDate(value, formats);
+        if (result != (-1L)) {
+            return result;
+        }
+        throw new IllegalArgumentException(value);
+
+    }
+
+
+    /**
+     * Get the decoded request URI.
+     *
+     * @return the URL decoded request URI
+     */
+    public String getDecodedRequestURI() {
+        return (httpRequest.decodedURI().toString());
+    }
+
+
+    /**
+     * Get the decoded request URI.
+     *
+     * @return the URL decoded request URI
+     */
+    public MessageBytes getDecodedRequestURIMB() {
+        return (httpRequest.decodedURI());
+    }
+
+
+    /**
+     * Get filter chain associated with the request.
+     */
+    public FilterChainImpl getFilterChain() {
+        return (this.filterChain);
+    }
+
+
+    // ------------------------------------------------- ServletRequest Methods
+
+    /**
+     * Return the first value of the specified header, if any; otherwise,
+     * return <code>null</code>
+     *
+     * @param name Name of the requested header
+     */
+    public String getHeader(String name) {
+        return httpRequest.getHeader(name);
+    }
+
+    /**
+     * Return the names of all headers received with this request.
+     */
+    public Enumeration getHeaderNames() {
+        return httpRequest.getMimeHeaders().names();
+    }
+
+
+    /**
+     * Return all of the values of the specified header, if any; otherwise,
+     * return an empty enumeration.
+     *
+     * @param name Name of the requested header
+     */
+    public Enumeration getHeaders(String name) {
+        return httpRequest.getMimeHeaders().values(name);
+    }
+
+    /**
+     * Return the servlet input stream for this Request.  The default
+     * implementation returns a servlet input stream created by
+     * <code>createInputStream()</code>.
+     *
+     * @exception IllegalStateException if <code>getReader()</code> has
+     *  already been called for this request
+     * @exception IOException if an input/output error occurs
+     */
+    public ServletInputStream getInputStream() throws IOException {
+
+        if (usingReader)
+            throw new IllegalStateException
+                ("usingReader");
+
+        usingInputStream = true;
+        return inputStream;
+
+    }
+
+
+    /**
+     * Return the value of the specified header as an integer, or -1 if there
+     * is no such header for this request.
+     *
+     * @param name Name of the requested header
+     *
+     * @exception IllegalArgumentException if the specified header value
+     *  cannot be converted to an integer
+     */
+    public int getIntHeader(String name) {
+
+        String value = getHeader(name);
+        if (value == null) {
+            return (-1);
+        } else {
+            return (Integer.parseInt(value));
+        }
+
+    }
+
+
+    /**
+     * Returns the Internet Protocol (IP) address of the interface on
+     * which the request  was received.
+     */
+    public String getLocalAddr(){
+        return httpRequest.localAddr().toString();
+    }
+
+
+    /**
+     * Return the preferred Locale that the client will accept content in,
+     * based on the value for the first <code>Accept-Language</code> header
+     * that was encountered.  If the request did not specify a preferred
+     * language, the server's default Locale is returned.
+     */
+    public Locale getLocale() {
+
+        if (!localesParsed)
+            parseLocales();
+
+        if (locales.size() > 0) {
+            return ((Locale) locales.get(0));
+        } else {
+            return (defaultLocale);
+        }
+
+    }
+
+
+    /**
+     * Return the set of preferred Locales that the client will accept
+     * content in, based on the values for any <code>Accept-Language</code>
+     * headers that were encountered.  If the request did not specify a
+     * preferred language, the server's default Locale is returned.
+     */
+    public Enumeration getLocales() {
+
+        if (!localesParsed)
+            parseLocales();
+
+        if (locales.size() > 0)
+            return (new Enumerator(locales));
+        ArrayList results = new ArrayList();
+        results.add(defaultLocale);
+        return (new Enumerator(results));
+
+    }
+
+
+    /**
+     * Returns the host name of the Internet Protocol (IP) interface on
+     * which the request was received.
+     */
+    public String getLocalName(){
+        return httpRequest.localName().toString();
+    }
+
+
+    /**
+     * Returns the Internet Protocol (IP) port number of the interface
+     * on which the request was received.
+     */
+    public int getLocalPort(){
+        return httpRequest.getLocalPort();
+    }
+
+
+    /**
+     * Return mapping data.
+     */
+    public MappingData getMappingData() {
+        return (mappingData);
+    }
+
+
+
+    /**
+     * Return the HTTP request method used in this Request.
+     */
+    public String getMethod() {
+        return httpRequest.method().toString();
+    }
+
+
+    /**
+     * Return the value of the specified request parameter, if any; otherwise,
+     * return <code>null</code>.  If there is more than one value defined,
+     * return only the first one.
+     *
+     * @param name Name of the desired request parameter
+     */
+    public String getParameter(String name) {
+
+        if (!parametersParsed)
+            parseParameters();
+
+        return httpRequest.getParameters().getParameter(name);
+
+    }
+
+
+    /**
+     * Returns a <code>Map</code> of the parameters of this request.
+     * Request parameters are extra information sent with the request.
+     * For HTTP servlets, parameters are contained in the query string
+     * or posted form data.
+     *
+     * @return A <code>Map</code> containing parameter names as keys
+     *  and parameter values as map values.
+     */
+    public Map getParameterMap() {
+
+        if (parameterMap.isLocked())
+            return parameterMap;
+
+        Enumeration enumeration = getParameterNames();
+        while (enumeration.hasMoreElements()) {
+            String name = enumeration.nextElement().toString();
+            String[] values = getParameterValues(name);
+            parameterMap.put(name, values);
+        }
+
+        parameterMap.setLocked(true);
+
+        return parameterMap;
+
+    }
+
+
+    /**
+     * Return the names of all defined request parameters for this request.
+     */
+    public Enumeration getParameterNames() {
+
+        if (!parametersParsed)
+            parseParameters();
+
+        return httpRequest.getParameters().getParameterNames();
+
+    }
+
+
+    /**
+     * Return the defined values for the specified request parameter, if any;
+     * otherwise, return <code>null</code>.
+     *
+     * @param name Name of the desired request parameter
+     */
+    public String[] getParameterValues(String name) {
+
+        if (!parametersParsed)
+            parseParameters();
+
+        return httpRequest.getParameters().getParameterValues(name);
+
+    }
+
+
+    /**
+     * Return the path information associated with this Request.
+     */
+    public String getPathInfo() {
+        return (mappingData.pathInfo.toString());
+    }
+
+
+    /**
+     * Get the path info.
+     *
+     * @return the path info
+     */
+    public MessageBytes getPathInfoMB() {
+        return (mappingData.pathInfo);
+    }
+
+
+    /**
+     * Return the extra path information for this request, translated
+     * to a real path.
+     */
+    public String getPathTranslated() {
+
+        if (context == null)
+            return (null);
+
+        if (getPathInfo() == null) {
+            return (null);
+        } else {
+            return (context.getServletContext().getRealPath(getPathInfo()));
+        }
+
+    }
+
+    /**
+     * Return the principal that has been authenticated for this Request.
+     */
+    public Principal getPrincipal() {
+        return (userPrincipal);
+    }
+
+    /**
+     * Return the protocol and version used to make this Request.
+     */
+    public String getProtocol() {
+        return httpRequest.protocol().toString();
+    }
+
+    /**
+     * Return the query string associated with this request.
+     */
+    public String getQueryString() {
+        String queryString = httpRequest.queryString().toString();
+        if (queryString == null || queryString.equals("")) {
+            return (null);
+        } else {
+            return queryString;
+        }
+    }
+
+
+    /**
+     * Read the Reader wrapping the input stream for this Request.  The
+     * default implementation wraps a <code>BufferedReader</code> around the
+     * servlet input stream returned by <code>createInputStream()</code>.
+     *
+     * @exception IllegalStateException if <code>getInputStream()</code>
+     *  has already been called for this request
+     * @exception IOException if an input/output error occurs
+     */
+    public BufferedReader getReader() throws IOException {
+
+        if (usingInputStream)
+            throw new IllegalStateException
+                ("usingInputStream");
+
+        usingReader = true;
+        //inputBuffer.setConverter();// getB2C());
+        return reader;
+
+    }
+
+    /**
+     * Cached list of encoders.
+     */
+    protected HashMap encoders = new HashMap();
+
+    public static final String DEFAULT_CHARACTER_ENCODING="ISO-8859-1";
+
+    /**
+     *  Converter for the encoding associated with the request.
+     *  If encoding is changed - a different encoder will be returned.
+     *
+     *  Encoders are cached ( per request ) - at least 8K per charset
+     */
+    public B2CConverter getB2C() throws IOException {
+      String enc = getCharacterEncoding();
+      if (enc == null) {
+        enc = DEFAULT_CHARACTER_ENCODING;
+      }
+      B2CConverter conv =
+        (B2CConverter) encoders.get(enc);
+      if (conv == null) {
+        conv = new B2CConverter(enc);
+        encoders.put(enc, conv);
+      }
+      return conv;
+    }
+
+    /**
+     * Return the real path of the specified virtual path.
+     *
+     * @param path Path to be translated
+     *
+     * @deprecated As of version 2.1 of the Java Servlet API, use
+     *  <code>ServletContext.getRealPath()</code>.
+     */
+    public String getRealPath(String path) {
+
+        if (context == null)
+            return (null);
+        ServletContext servletContext = context; // .getServletContext();
+        if (servletContext == null)
+            return (null);
+        else {
+            try {
+                return (servletContext.getRealPath(path));
+            } catch (IllegalArgumentException e) {
+                return (null);
+            }
+        }
+
+    }
+
+
+    /**
+     * Return the remote IP address making this Request.
+     */
+    public String getRemoteAddr() {
+      if (httpRequest.remoteAddr().isNull()) {
+        httpRequest.remoteAddr().setString(connector.getRemoteAddr(this));
+      }
+      return httpRequest.remoteAddr().toString();
+    }
+
+
+    /**
+     * Return the remote host name making this Request.
+     */
+    public String getRemoteHost() {
+      if (httpRequest.remoteHost().isNull()) {
+        httpRequest.remoteHost().setString(connector.getRemoteHost(this));
+      }
+      return httpRequest.remoteHost().toString();
+    }
+
+
+    /**
+     * Returns the Internet Protocol (IP) source port of the client
+     * or last proxy that sent the request.
+     */
+    public int getRemotePort(){
+        return httpRequest.getRemotePort();
+    }
+
+
+    /**
+     * Return the name of the remote user that has been authenticated
+     * for this Request.
+     */
+    public String getRemoteUser() {
+
+        if (userPrincipal != null) {
+            return (userPrincipal.getName());
+        } else {
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * Return the <code>ServletRequest</code> for which this object
+     * is the facade.  This method must be implemented by a subclass.
+     */
+    public HttpServletRequest getRequest() {
+        return this;
+    }
+
+    public HttpRequest getHttpRequest() {
+      return httpRequest;
+    }
+
+    public void setHttpRequest(HttpRequest req, BodyReader in) {
+      this.httpRequest = req;
+      inputBuffer = in;
+      inputStream = new ServletInputStreamImpl(inputBuffer.asInputStream());
+      reader = new ServletReaderImpl(inputBuffer);
+    }
+
+    public BodyReader getBodyReader() {
+        return inputBuffer;
+    }
+
+    /**
+     * Return a RequestDispatcher that wraps the resource at the specified
+     * path, which may be interpreted as relative to the current request path.
+     *
+     * @param path Path of the resource to be wrapped
+     */
+    public RequestDispatcher getRequestDispatcher(String path) {
+
+        if (context == null)
+            return (null);
+
+        // If the path is already context-relative, just pass it through
+        if (path == null)
+            return (null);
+        else if (path.startsWith("/"))
+            return (context.getRequestDispatcher(path));
+
+        // Convert a request-relative path to a context-relative one
+        String servletPath = (String) getAttribute(RequestDispatcherImpl.INCLUDE_SERVLET_PATH_ATTR);
+        if (servletPath == null)
+            servletPath = getServletPath();
+
+        // Add the path info, if there is any
+        String pathInfo = getPathInfo();
+        String requestPath = null;
+
+        if (pathInfo == null) {
+            requestPath = servletPath;
+        } else {
+            requestPath = servletPath + pathInfo;
+        }
+
+        int pos = requestPath.lastIndexOf('/');
+        String relative = null;
+        if (pos >= 0) {
+            relative = RequestUtil.normalize
+                (requestPath.substring(0, pos + 1) + path);
+        } else {
+            relative = RequestUtil.normalize(requestPath + path);
+        }
+
+        return (context.getRequestDispatcher(relative));
+
+    }
+
+
+    /**
+     * Return the session identifier included in this request, if any.
+     */
+    public String getRequestedSessionId() {
+        return (requestedSessionId);
+    }
+
+
+    // ---------------------------------------------------- HttpRequest Methods
+
+
+    /**
+     * Get the request path.
+     *
+     * @return the request path
+     */
+    public MessageBytes getRequestPathMB() {
+        return (mappingData.requestPath);
+    }
+
+
+    /**
+     * Return the request URI for this request.
+     */
+    public String getRequestURI() {
+        return httpRequest.requestURI().toString();
+    }
+
+    /**
+     */
+    public void setRequestURI(String uri) {
+      httpRequest.decodedURI().setString(uri);
+      try {
+        UriNormalizer.decodeRequest(httpRequest.decodedURI(),
+                httpRequest.requestURI(), httpRequest.getURLDecoder());
+      } catch(IOException ioe) {
+        ioe.printStackTrace();
+        return;
+      }
+    }
+
+
+
+    /**
+     * Reconstructs the URL the client used to make the request.
+     * The returned URL contains a protocol, server name, port
+     * number, and server path, but it does not include query
+     * string parameters.
+     * <p>
+     * Because this method returns a <code>StringBuffer</code>,
+     * not a <code>String</code>, you can modify the URL easily,
+     * for example, to append query parameters.
+     * <p>
+     * This method is useful for creating redirect messages and
+     * for reporting errors.
+     *
+     * @return A <code>StringBuffer</code> object containing the
+     *  reconstructed URL
+     */
+    public StringBuffer getRequestURL() {
+
+        StringBuffer url = new StringBuffer();
+        String scheme = getScheme();
+        int port = getServerPort();
+        if (port < 0)
+            port = 80; // Work around java.net.URL bug
+
+        url.append(scheme);
+        url.append("://");
+        url.append(getServerName());
+        if ((scheme.equals("http") && (port != 80))
+            || (scheme.equals("https") && (port != 443))) {
+            url.append(':');
+            url.append(port);
+        }
+        url.append(getRequestURI());
+
+        return (url);
+
+    }
+
+
+    /**
+     * Return the Response with which this Request is associated.
+     */
+    public ServletResponseImpl getResponse() {
+        return (this.response);
+    }
+
+
+    /**
+     * Return the scheme used to make this Request.
+     */
+    public String getScheme() {
+        String scheme = httpRequest.scheme().toString();
+        if (scheme == null) {
+            scheme = (isSecure() ? "https" : "http");
+        }
+        return scheme;
+    }
+
+
+    /**
+     * Return the server name responding to this Request.
+     */
+    public String getServerName() {
+        return (httpRequest.serverName().toString());
+    }
+
+
+    /**
+     * Return the server port responding to this Request.
+     */
+    public int getServerPort() {
+        return (httpRequest.getServerPort());
+    }
+
+
+    /**
+     * Return the portion of the request URI used to select the servlet
+     * that will process this request.
+     */
+    public String getServletPath() {
+        return (mappingData.wrapperPath.toString());
+    }
+
+
+    /**
+     * Get the servlet path.
+     *
+     * @return the servlet path
+     */
+    public MessageBytes getServletPathMB() {
+        return (mappingData.wrapperPath);
+    }
+
+
+
+    /**
+     * Return the input stream associated with this Request.
+     */
+    public InputStream getStream() {
+        return inputStream;
+    }
+
+
+    /**
+     * Return the principal that has been authenticated for this Request.
+     */
+    public Principal getUserPrincipal() {
+        return userPrincipal;
+    }
+
+
+    /**
+     * Return the Wrapper within which this Request is being processed.
+     */
+    public ServletConfigImpl getWrapper() {
+        return (this.wrapper);
+    }
+
+
+    /**
+     * Return <code>true</code> if the session identifier included in this
+     * request came from a cookie.
+     */
+    public boolean isRequestedSessionIdFromCookie() {
+
+        if (requestedSessionId != null)
+            return (requestedSessionCookie);
+        else
+            return (false);
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the session identifier included in this
+     * request came from the request URI.
+     *
+     * @deprecated As of Version 2.1 of the Java Servlet API, use
+     *  <code>isRequestedSessionIdFromURL()</code> instead.
+     */
+    public boolean isRequestedSessionIdFromUrl() {
+        return (isRequestedSessionIdFromURL());
+    }
+
+
+    /**
+     * Return <code>true</code> if the session identifier included in this
+     * request came from the request URI.
+     */
+    public boolean isRequestedSessionIdFromURL() {
+
+        if (requestedSessionId != null)
+            return (requestedSessionURL);
+        else
+            return (false);
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the session identifier included in this
+     * request identifies a valid session.
+     */
+    public boolean isRequestedSessionIdValid() {
+
+        if (requestedSessionId == null)
+            return (false);
+        if (context == null)
+            return (false);
+        UserSessionManager manager = context.getManager();
+        if (manager == null)
+            return (false);
+        HttpSession session = null;
+        try {
+            session = manager.findSession(requestedSessionId);
+        } catch (IOException e) {
+            session = null;
+        }
+        if ((session != null) && manager.isValid(session))
+            return (true);
+        else
+            return (false);
+
+    }
+
+    /**
+     * Was this request received on a secure connection?
+     */
+    public boolean isSecure() {
+        return (secure);
+    }
+
+
+    /**
+     * Return <code>true</code> if the authenticated user principal
+     * possesses the specified role name.
+     *
+     * @param role Role name to be validated
+     */
+    public boolean isUserInRole(String role) {
+        // Have we got an authenticated principal at all?
+        Principal userPrincipal = getPrincipal();
+        if (userPrincipal == null)
+            return (false);
+
+        // Identify the Realm we will use for checking role assignmenets
+        if (context == null)
+            return (false);
+
+        // Check for a role alias defined in a <security-role-ref> element
+        if (wrapper != null) {
+            String realRole = wrapper.getSecurityRoleRef(role);
+            if (realRole != null) {
+                role = realRole;
+            }
+        }
+
+        if (role.equals(userPrincipal.getName())) {
+            return true;
+        }
+
+        // TODO: check !!!!
+        // Check for a role defined directly as a <security-role>
+        return false;
+    }
+
+    /**
+     * Release all object references, and initialize instance variables, in
+     * preparation for reuse of this object.
+     */
+    public void recycle() {
+
+        wrapper = null;
+
+        dispatcherType = null;
+        requestDispatcherPath = null;
+
+        authType = null;
+        inputBuffer.recycle();
+        usingInputStream = false;
+        usingReader = false;
+        userPrincipal = null;
+        subject = null;
+        sessionParsed = false;
+        parametersParsed = false;
+        cookiesParsed = false;
+        locales.clear();
+        localesParsed = false;
+        secure = false;
+
+        attributes.clear();
+        //notes.clear();
+        cookies = null;
+
+        if (session != null) {
+            context.getManager().endAccess(session);
+        }
+        context = null;
+        session = null;
+        requestedSessionCookie = false;
+        requestedSessionId = null;
+        requestedSessionURL = false;
+
+        parameterMap.setLocked(false);
+        parameterMap.clear();
+
+        mappingData.recycle();
+        httpRequest.recycle();
+    }
+
+
+    /**
+     * Remove the specified request attribute if it exists.
+     *
+     * @param name Name of the request attribute to remove
+     */
+    public void removeAttribute(String name) {
+        Object value = null;
+        boolean found = false;
+
+        // Remove the specified attribute
+        // Check for read only attribute
+        // requests are per thread so synchronization unnecessary
+//        if (readOnlyAttributes.containsKey(name)) {
+//            return;
+//        }
+        found = attributes.containsKey(name);
+        if (found) {
+            value = attributes.get(name);
+            attributes.remove(name);
+        } else {
+            return;
+        }
+
+        // Notify interested application event listeners
+        List listeners = context.getListeners();
+        if (listeners.size() == 0)
+            return;
+        ServletRequestAttributeEvent event = null;
+        for (int i = 0; i < listeners.size(); i++) {
+            if (!(listeners.get(i) instanceof ServletRequestAttributeListener))
+                continue;
+            ServletRequestAttributeListener listener =
+                (ServletRequestAttributeListener) listeners.get(i);
+            try {
+                if (event == null) {
+                    event =
+                        new ServletRequestAttributeEvent(context.getServletContext(),
+                            getRequest(), name, value);
+                }
+                listener.attributeRemoved(event);
+            } catch (Throwable t) {
+                context.getLogger().log(Level.WARNING, "ServletRequestAttributeListner.attributeRemoved()", t);
+                // Error valve will pick this execption up and display it to user
+                attributes.put( ServletRequestImpl.EXCEPTION_ATTR, t );
+            }
+        }
+    }
+
+
+    /**
+     * Set the specified request attribute to the specified value.
+     *
+     * @param name Name of the request attribute to set
+     * @param value The associated value
+     */
+    public void setAttribute(String name, Object value) {
+
+        // Name cannot be null
+        if (name == null)
+            throw new IllegalArgumentException
+                ("setAttribute() name == null");
+
+        // Null value is the same as removeAttribute()
+        if (value == null) {
+            removeAttribute(name);
+            return;
+        }
+
+        if (name.equals(ServletRequestImpl.DISPATCHER_TYPE_ATTR)) {
+            dispatcherType = value;
+            return;
+        } else if (name.equals(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR)) {
+            requestDispatcherPath = value;
+            return;
+        }
+
+        Object oldValue = null;
+        boolean replaced = false;
+
+        // Add or replace the specified attribute
+        // Check for read only attribute
+        // requests are per thread so synchronization unnecessary
+//        if (readOnlyAttributes.containsKey(name)) {
+//            return;
+//        }
+
+        oldValue = attributes.put(name, value);
+        if (oldValue != null) {
+            replaced = true;
+        }
+
+        // Pass special attributes to the native layer
+//        if (name.startsWith("org.apache.tomcat.")) {
+//            reqB.setAttribute(name, value);
+//        }
+//
+        // Notify interested application event listeners
+        List listeners = context.getListeners();
+        if (listeners.size() == 0)
+            return;
+        ServletRequestAttributeEvent event = null;
+
+        for (int i = 0; i < listeners.size(); i++) {
+            if (!(listeners.get(i) instanceof ServletRequestAttributeListener))
+                continue;
+            ServletRequestAttributeListener listener =
+                (ServletRequestAttributeListener) listeners.get(i);
+            try {
+                if (event == null) {
+                    if (replaced)
+                        event =
+                            new ServletRequestAttributeEvent(context.getServletContext(),
+                                                             getRequest(), name, oldValue);
+                    else
+                        event =
+                            new ServletRequestAttributeEvent(context.getServletContext(),
+                                                             getRequest(), name, value);
+                }
+                if (replaced) {
+                    listener.attributeReplaced(event);
+                } else {
+                    listener.attributeAdded(event);
+                }
+            } catch (Throwable t) {
+                context.getLogger().log(Level.WARNING, "ServletRequestAttributeListener error", t);
+                // Error valve will pick this execption up and display it to user
+                attributes.put( ServletRequestImpl.EXCEPTION_ATTR, t );
+            }
+        }
+    }
+
+
+    // --------------------------------------------- HttpServletRequest Methods
+
+
+    /**
+     * Set the authentication type used for this request, if any; otherwise
+     * set the type to <code>null</code>.  Typical values are "BASIC",
+     * "DIGEST", or "SSL".
+     *
+     * @param type The authentication type used
+     */
+    public void setAuthType(String type) {
+        this.authType = type;
+    }
+
+
+    /**
+     * Overrides the name of the character encoding used in the body of
+     * this request.  This method must be called prior to reading request
+     * parameters or reading input using <code>getReader()</code>.
+     *
+     * @param enc The character encoding to be used
+     *
+     * @exception UnsupportedEncodingException if the specified encoding
+     *  is not supported
+     *
+     * @since Servlet 2.3
+     */
+    public void setCharacterEncoding(String enc)
+        throws UnsupportedEncodingException {
+
+        // Ensure that the specified encoding is valid
+        byte buffer[] = new byte[1];
+        buffer[0] = (byte) 'a';
+        String dummy = new String(buffer, enc);
+
+        // Save the validated encoding
+        httpRequest.setCharacterEncoding(enc);
+
+    }
+
+
+//    public void setConnection(Http11Connection con) {
+//        this.con = con;
+//        //reqB.messageWriter.setConnection(con);
+//        //inputBuffer.setRequest(req);
+//    }
+
+
+    /**
+     * Set the content length associated with this Request.
+     *
+     * @param length The new content length
+     */
+    public void setContentLength(int length) {
+        // Not used
+    }
+
+
+    /**
+     * Set the content type (and optionally the character encoding)
+     * associated with this Request.  For example,
+     * <code>text/html; charset=ISO-8859-4</code>.
+     *
+     * @param type The new content type
+     */
+    public void setContentType(String type) {
+        // Not used
+    }
+
+
+    /**
+     * Set the Context within which this Request is being processed.  This
+     * must be called as soon as the appropriate Context is identified, because
+     * it identifies the value to be returned by <code>getContextPath()</code>,
+     * and thus enables parsing of the request URI.
+     *
+     * @param context The newly associated Context
+     */
+    public void setContext(ServletContextImpl context) {
+        this.context = context;
+    }
+
+
+    /**
+     * Set the context path for this Request.  This will normally be called
+     * when the associated Context is mapping the Request to a particular
+     * Wrapper.
+     *
+     * @param path The context path
+     */
+    public void setContextPath(String path) {
+
+        if (path == null) {
+            mappingData.contextPath.setString("");
+        } else {
+            mappingData.contextPath.setString(path);
+        }
+
+    }
+
+
+    /**
+     * Set the set of cookies recieved with this Request.
+     */
+    public void setCookies(Cookie[] cookies) {
+
+        this.cookies = cookies;
+
+    }
+
+
+    /**
+     * Set the decoded request URI.
+     *
+     * @param uri The decoded request URI
+     */
+    public void setDecodedRequestURI(String uri) {
+        // Not used
+    }
+
+
+    /**
+     * Set the HTTP request method used for this Request.
+     *
+     * @param method The request method
+     */
+    public void setMethod(String method) {
+      httpRequest.method().setString(method);
+    }
+
+
+    /**
+     * Set the path information for this Request.  This will normally be called
+     * when the associated Context is mapping the Request to a particular
+     * Wrapper.
+     *
+     * @param path The path information
+     */
+    public void setPathInfo(String path) {
+        mappingData.pathInfo.setString(path);
+    }
+
+
+    /**
+     * Set the protocol name and version associated with this Request.
+     *
+     * @param protocol Protocol name and version
+     */
+    public void setProtocol(String protocol) {
+        // Not used
+    }
+
+
+    /**
+     * Set the query string for this Request.  This will normally be called
+     * by the HTTP Connector, when it parses the request headers.
+     *
+     * @param query The query string
+     */
+    public void setQueryString(String query) {
+        // Not used
+    }
+
+
+    /**
+     * Set the IP address of the remote client associated with this Request.
+     *
+     * @param remoteAddr The remote IP address
+     */
+    public void setRemoteAddr(String remoteAddr) {
+        // Not used
+    }
+
+
+    /**
+     * Set the fully qualified name of the remote client associated with this
+     * Request.
+     *
+     * @param remoteHost The remote host name
+     */
+    public void setRemoteHost(String remoteHost) {
+        // Not used
+    }
+
+
+    /**
+     * Set a flag indicating whether or not the requested session ID for this
+     * request came in through a cookie.  This is normally called by the
+     * HTTP Connector, when it parses the request headers.
+     *
+     * @param flag The new flag
+     */
+    public void setRequestedSessionCookie(boolean flag) {
+
+        this.requestedSessionCookie = flag;
+
+    }
+
+
+    /**
+     * Set the requested session ID for this request.  This is normally called
+     * by the HTTP Connector, when it parses the request headers.
+     *
+     * @param id The new session id
+     */
+    public void setRequestedSessionId(String id) {
+
+        this.requestedSessionId = id;
+
+    }
+
+
+    /**
+     * Set a flag indicating whether or not the requested session ID for this
+     * request came in through a URL.  This is normally called by the
+     * HTTP Connector, when it parses the request headers.
+     *
+     * @param flag The new flag
+     */
+    public void setRequestedSessionURL(boolean flag) {
+
+        this.requestedSessionURL = flag;
+
+    }
+
+
+    /**
+     * Set the name of the scheme associated with this request.  Typical values
+     * are <code>http</code>, <code>https</code>, and <code>ftp</code>.
+     *
+     * @param scheme The scheme
+     */
+    public void setScheme(String scheme) {
+        // Not used
+    }
+
+
+    /**
+     * Set the value to be returned by <code>isSecure()</code>
+     * for this Request.
+     *
+     * @param secure The new isSecure value
+     */
+    public void setSecure(boolean secure) {
+        this.secure = secure;
+    }
+
+
+    /**
+     * Set the name of the server (virtual host) to process this request.
+     *
+     * @param name The server name
+     */
+    public void setServerName(String name) {
+        httpRequest.serverName().setString(name);
+    }
+
+
+    /**
+     * Set the port number of the server to process this request.
+     *
+     * @param port The server port
+     */
+    public void setServerPort(int port) {
+        httpRequest.setServerPort(port);
+    }
+
+
+    /**
+     * Set the servlet path for this Request.  This will normally be called
+     * when the associated Context is mapping the Request to a particular
+     * Wrapper.
+     *
+     * @param path The servlet path
+     */
+    public void setServletPath(String path) {
+        if (path != null)
+            mappingData.wrapperPath.setString(path);
+    }
+
+
+    /**
+     * Set the input stream associated with this Request.
+     *
+     * @param stream The new input stream
+     */
+    public void setStream(InputStream stream) {
+        // Ignore
+    }
+
+
+    /**
+     * Set the Principal who has been authenticated for this Request.  This
+     * value is also used to calculate the value to be returned by the
+     * <code>getRemoteUser()</code> method.
+     *
+     * @param principal The user Principal
+     */
+    public void setUserPrincipal(Principal principal) {
+
+        if (System.getSecurityManager() != null){
+            HttpSession session = getSession(false);
+            if ( (subject != null) &&
+                 (!subject.getPrincipals().contains(principal)) ){
+                subject.getPrincipals().add(principal);
+            } else if (session != null &&
+                        session.getAttribute(ServletRequestImpl.SUBJECT_ATTR) == null) {
+                subject = new Subject();
+                subject.getPrincipals().add(principal);
+            }
+            if (session != null){
+                session.setAttribute(ServletRequestImpl.SUBJECT_ATTR, subject);
+            }
+        }
+
+        this.userPrincipal = principal;
+    }
+
+
+    /**
+     * Set the Wrapper within which this Request is being processed.  This
+     * must be called as soon as the appropriate Wrapper is identified, and
+     * before the Request is ultimately passed to an application servlet.
+     * @param wrapper The newly associated Wrapper
+     */
+    public void setWrapper(ServletConfigImpl wrapper) {
+        this.wrapper = wrapper;
+    }
+
+
+    public String toString() {
+        return httpRequest.requestURI().toString();
+    }
+
+
+    /**
+     * Configures the given JSESSIONID cookie.
+     *
+     * @param cookie The JSESSIONID cookie to be configured
+     */
+    protected void configureSessionCookie(Cookie cookie) {
+        cookie.setMaxAge(-1);
+        String contextPath = null;
+        if (//!connector.getEmptySessionPath() &&
+                (getContext() != null)) {
+            contextPath = getContext().getEncodedPath();
+        }
+        if ((contextPath != null) && (contextPath.length() > 0)) {
+            cookie.setPath(contextPath);
+        } else {
+            cookie.setPath("/");
+        }
+        if (isSecure()) {
+            cookie.setSecure(true);
+        }
+    }
+
+
+    /**
+     * Return the session associated with this Request, creating one
+     * if necessary.
+     */
+    public HttpSession getSession() {
+        return getSession(true);
+    }
+
+
+    public HttpSession getSession(boolean create) {
+
+        // There cannot be a session if no context has been assigned yet
+        if (context == null)
+            return (null);
+
+
+        // Return the requested session if it exists and is valid
+        UserSessionManager manager = null;
+        if (context != null)
+            manager = context.getManager();
+        if (manager == null)
+            return (null);      // Sessions are not supported
+
+        // Return the current session if it exists and is valid
+        if ((session != null) && !manager.isValid(session))
+            session = null;
+        if (session != null)
+            return (session);
+
+
+        if (requestedSessionId != null) {
+            try {
+                session = manager.findSession(requestedSessionId);
+            } catch (IOException e) {
+                session = null;
+            }
+            if ((session != null) && !manager.isValid(session))
+                session = null;
+            if (session != null) {
+                manager.access(session);
+                return (session);
+            }
+        }
+
+        // Create a new session if requested and the response is not committed
+        if (!create)
+            return (null);
+        if ((context != null) && (response != null) &&
+            context.getCookies() &&
+            getResponse().isCommitted()) {
+            throw new IllegalStateException
+              ("isCommited()");
+        }
+
+        // Attempt to reuse session id if one was submitted in a cookie
+        // Do not reuse the session id if it is from a URL, to prevent possible
+        // phishing attacks
+        if (// connector.getEmptySessionPath() &&
+                isRequestedSessionIdFromCookie()) {
+            session = manager.createSession(getRequestedSessionId());
+        } else {
+            session = manager.createSession(null);
+        }
+
+        // Creating a new session cookie based on that session
+        if ((session != null) && (getContext() != null)
+               && getContext().getCookies()) {
+            Cookie cookie = new Cookie(ServletRequestImpl.SESSION_COOKIE_NAME,
+                                       session.getId());
+            configureSessionCookie(cookie);
+            response.addCookie(cookie);
+        }
+
+        if (session != null) {
+            manager.access(session);
+            return (session);
+        } else {
+            return (null);
+        }
+
+    }
+
+
+    /**
+     * Return the URI converter.
+     */
+//    protected B2CConverter getURIConverter() {
+//        return URIConverter;
+//    }
+//
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Parse cookies.
+     */
+    protected void parseCookies() {
+
+        cookiesParsed = true;
+
+        Cookies serverCookies = httpRequest.getCookies();
+        int count = serverCookies.getCookieCount();
+        if (count <= 0)
+            return;
+
+        cookies = new Cookie[count];
+
+        int idx=0;
+        for (int i = 0; i < count; i++) {
+            ServerCookie scookie = serverCookies.getCookie(i);
+            try {
+                Cookie cookie = new Cookie(scookie.getName().toString(),
+                                           scookie.getValue().toString());
+                cookie.setPath(scookie.getPath().toString());
+                cookie.setVersion(scookie.getVersion());
+                String domain = scookie.getDomain().toString();
+                if (domain != null) {
+                    cookie.setDomain(scookie.getDomain().toString());
+                }
+                cookies[idx++] = cookie;
+            } catch(IllegalArgumentException e) {
+                // Ignore bad cookie
+            }
+        }
+        if( idx < count ) {
+            Cookie [] ncookies = new Cookie[idx];
+            System.arraycopy(cookies, 0, ncookies, 0, idx);
+            cookies = ncookies;
+        }
+
+    }
+
+    /**
+     * Parse request locales.
+     */
+    protected void parseLocales() {
+
+        localesParsed = true;
+
+        Enumeration values = getHeaders("accept-language");
+
+        while (values.hasMoreElements()) {
+            String value = values.nextElement().toString();
+            parseLocalesHeader(value);
+        }
+
+    }
+
+    /**
+     * Parse accept-language header value.
+     */
+    protected void parseLocalesHeader(String value) {
+
+      TreeMap locales = new LocaleParser().parseLocale(value);
+      // Process the quality values in highest->lowest order (due to
+      // negating the Double value when creating the key)
+      Iterator keys = locales.keySet().iterator();
+      while (keys.hasNext()) {
+        Double key = (Double) keys.next();
+        ArrayList list = (ArrayList) locales.get(key);
+        Iterator values = list.iterator();
+        while (values.hasNext()) {
+          Locale locale = (Locale) values.next();
+          addLocale(locale);
+        }
+      }
+
+    }
+
+    /**
+     * Parse request parameters.
+     */
+    protected void parseParameters() {
+
+        parametersParsed = true;
+
+        Parameters parameters = httpRequest.getParameters();
+
+        // getCharacterEncoding() may have been overridden to search for
+        // hidden form field containing request encoding
+        String enc = getCharacterEncoding();
+
+//        boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();
+        if (enc != null) {
+            parameters.setEncoding(enc);
+//            if (useBodyEncodingForURI) {
+//                parameters.setQueryStringEncoding(enc);
+//            }
+        } else {
+            parameters.setEncoding(DEFAULT_CHARACTER_ENCODING);
+//            if (useBodyEncodingForURI) {
+//                parameters.setQueryStringEncoding
+//                    (DEFAULT_CHARACTER_ENCODING);
+//            }
+        }
+
+        parameters.handleQueryParameters();
+
+        if (usingInputStream || usingReader)
+            return;
+
+        if (!getMethod().equalsIgnoreCase("POST"))
+            return;
+
+        String contentType = getContentType();
+        if (contentType == null)
+            contentType = "";
+        int semicolon = contentType.indexOf(';');
+        if (semicolon >= 0) {
+            contentType = contentType.substring(0, semicolon).trim();
+        } else {
+            contentType = contentType.trim();
+        }
+        if (!("application/x-www-form-urlencoded".equals(contentType)))
+            return;
+
+        int len = getContentLength();
+
+        if (len > 0) {
+//            int maxPostSize = connector.getMaxPostSize();
+//            if ((maxPostSize > 0) && (len > maxPostSize)) {
+//                context.getLogger().info
+//                    (sm.getString("reqB.postTooLarge"));
+//                throw new IllegalStateException("Post too large");
+//            }
+            try {
+                byte[] formData = null;
+                if (len < CACHED_POST_LEN) {
+                    if (postData == null)
+                        postData = new byte[CACHED_POST_LEN];
+                    formData = postData;
+                } else {
+                    formData = new byte[len];
+                }
+                int actualLen = readPostBody(formData, len);
+                if (actualLen == len) {
+                    parameters.processParameters(formData, 0, len);
+                }
+            } catch (Throwable t) {
+                ; // Ignore
+            }
+        }
+
+    }
+
+
+    /**
+     * Parse session id in URL. Done in request for performance.
+     * TODO: should be done in manager
+     */
+    protected void parseSessionCookiesId() {
+        String sessionCookieName = context.getSessionCookieName();
+
+        // Parse session id from cookies
+        Cookies serverCookies = httpRequest.getCookies();
+        int count = serverCookies.getCookieCount();
+        if (count <= 0)
+            return;
+
+        for (int i = 0; i < count; i++) {
+            ServerCookie scookie = serverCookies.getCookie(i);
+            if (scookie.getName().equals(sessionCookieName)) {
+                // Override anything requested in the URL
+                if (!isRequestedSessionIdFromCookie()) {
+                    // Accept only the first session id cookie
+                    //scookie.getValue().convertToAscii();
+
+                    setRequestedSessionId
+                        (scookie.getValue().toString());
+                    setRequestedSessionCookie(true);
+                    setRequestedSessionURL(false);
+                } else {
+                    if (!isRequestedSessionIdValid()) {
+                        // Replace the session id until one is valid
+                        //scookie.getValue().convertToAscii();
+                        setRequestedSessionId
+                            (scookie.getValue().toString());
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Parse session id in URL.
+     */
+    protected void parseSessionId() {
+        ServletRequestImpl request = this;
+        ByteChunk uriBC = httpRequest.requestURI().getByteChunk();
+        int semicolon = uriBC.indexOf(match, 0, match.length(), 0);
+
+        if (semicolon > 0) {
+
+            // Parse session ID, and extract it from the decoded request URI
+            int start = uriBC.getStart();
+            int end = uriBC.getEnd();
+
+            int sessionIdStart = semicolon + match.length();
+            int semicolon2 = uriBC.indexOf(';', sessionIdStart);
+            if (semicolon2 >= 0) {
+                request.setRequestedSessionId
+                    (new String(uriBC.getBuffer(), start + sessionIdStart,
+                            semicolon2 - sessionIdStart));
+                // Extract session ID from request URI
+                byte[] buf = uriBC.getBuffer();
+                for (int i = 0; i < end - start - semicolon2; i++) {
+                    buf[start + semicolon + i]
+                        = buf[start + i + semicolon2];
+                }
+                uriBC.setBytes(buf, start, end - start - semicolon2 + semicolon);
+            } else {
+                request.setRequestedSessionId
+                    (new String(uriBC.getBuffer(), start + sessionIdStart,
+                            (end - start) - sessionIdStart));
+                uriBC.setEnd(start + semicolon);
+            }
+            request.setRequestedSessionURL(true);
+
+        } else {
+            request.setRequestedSessionId(null);
+            request.setRequestedSessionURL(false);
+        }
+
+    }
+
+
+    /**
+     * Read post body in an array.
+     */
+    protected int readPostBody(byte body[], int len)
+        throws IOException {
+
+        int offset = 0;
+        do {
+            int inputLen = getStream().read(body, offset, len - offset);
+            if (inputLen <= 0) {
+                return offset;
+            }
+            offset += inputLen;
+        } while ((len - offset) > 0);
+        return len;
+
+    }
+
+
+    /**
+     * Test if a given name is one of the special Servlet-spec SSL attributes.
+     */
+    static boolean isSSLAttribute(String name) {
+        return ServletRequestImpl.CERTIFICATES_ATTR.equals(name) ||
+            ServletRequestImpl.CIPHER_SUITE_ATTR.equals(name) ||
+            ServletRequestImpl.KEY_SIZE_ATTR.equals(name)  ||
+            ServletRequestImpl.SSL_SESSION_ID_ATTR.equals(name);
+    }
+
+
+    public void addAsyncListener(AsyncListener listener) {
+    }
+
+
+
+    public void addAsyncListener(AsyncListener listener,
+                                 ServletRequest servletRequest,
+                                 ServletResponse servletResponse) {
+    }
+
+
+
+    @Override
+    public AsyncContext getAsyncContext() {
+        return null;
+    }
+
+
+
+    @Override
+    public ServletContext getServletContext() {
+        return null;
+    }
+
+
+
+    @Override
+    public boolean isAsyncStarted() {
+        return false;
+    }
+
+
+
+    @Override
+    public boolean isAsyncSupported() {
+        return false;
+    }
+
+
+    public void setAsyncTimeout(long timeout) {
+    }
+
+
+
+   @Override
+    public AsyncContext startAsync() throws IllegalStateException {
+        return null;
+    }
+
+
+   @Override
+    public AsyncContext startAsync(ServletRequest servletRequest,
+                                   ServletResponse servletResponse)
+            throws IllegalStateException {
+        return null;
+    }
+
+
+
+   @Override
+    public boolean authenticate(HttpServletResponse response)
+            throws IOException, ServletException {
+        return false;
+    }
+
+
+
+   @Override
+    public Part getPart(String name) {
+        return null;
+    }
+
+
+
+   @Override
+    public void login(String username, String password) throws ServletException {
+    }
+
+
+
+   @Override
+    public void logout() throws ServletException {
+    }
+
+
+
+    public long getAsyncTimeout() {
+        return 0;
+    }
+
+
+
+   @Override
+    public DispatcherType getDispatcherType() {
+        return null;
+    }
+
+
+   @Override
+    public Collection<Part> getParts() throws IOException, ServletException {
+        return null;
+    }
+
+
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletRequestWrapperImpl.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletRequestWrapperImpl.java
new file mode 100644 (file)
index 0000000..908b3c6
--- /dev/null
@@ -0,0 +1,943 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * 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.apache.coyote.servlet;
+
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.servlet.http.HttpSession;
+
+import org.apache.tomcat.servlets.session.UserSessionManager;
+import org.apache.tomcat.servlets.util.Enumerator;
+import org.apache.tomcat.servlets.util.RequestUtil;
+
+
+/**
+ * Wrapper around a <code>javax.servlet.http.HttpServletRequest</code>
+ * that transforms an application request object (which might be the original
+ * one passed to a servlet, or might be based on the 2.3
+ * <code>javax.servlet.http.HttpServletRequestWrapper</code> class)
+ * back into an internal <code>org.apache.catalina.HttpRequest</code>.
+ * <p>
+ * <strong>WARNING</strong>:  Due to Java's lack of support for multiple
+ * inheritance, all of the logic in <code>ApplicationRequest</code> is
+ * duplicated in <code>ApplicationHttpRequest</code>.  Make sure that you
+ * keep these two classes in synchronization when making changes!
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ */
+public class ServletRequestWrapperImpl extends HttpServletRequestWrapper {
+
+
+    // ------------------------------------------------------- Static Variables
+
+
+    /**
+     * The set of attribute names that are special for request dispatchers.
+     */
+    protected static final String specials[] =
+    { RequestDispatcherImpl.INCLUDE_REQUEST_URI_ATTR, 
+      RequestDispatcherImpl.INCLUDE_CONTEXT_PATH_ATTR,
+      RequestDispatcherImpl.INCLUDE_SERVLET_PATH_ATTR, 
+      RequestDispatcherImpl.INCLUDE_PATH_INFO_ATTR,
+      RequestDispatcherImpl.INCLUDE_QUERY_STRING_ATTR, 
+      RequestDispatcherImpl.FORWARD_REQUEST_URI_ATTR, 
+      RequestDispatcherImpl.FORWARD_CONTEXT_PATH_ATTR, 
+      RequestDispatcherImpl.FORWARD_SERVLET_PATH_ATTR, 
+      RequestDispatcherImpl.FORWARD_PATH_INFO_ATTR, 
+      RequestDispatcherImpl.FORWARD_QUERY_STRING_ATTR };
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    /**
+     * Construct a new wrapped request around the specified servlet request.
+     *
+     * @param request The servlet request being wrapped
+     */
+    public ServletRequestWrapperImpl(HttpServletRequest request, 
+                                     ServletContextImpl context,
+                                     boolean crossContext) {
+
+        super(request);
+        this.context = context;
+        this.crossContext = crossContext;
+        setRequest(request);
+
+    }
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    /**
+     * The context for this request.
+     */
+    protected ServletContextImpl context = null;
+
+
+    /**
+     * The context path for this request.
+     */
+    protected String contextPath = null;
+
+
+    /**
+     * If this request is cross context, since this changes session accesss
+     * behavior.
+     */
+    protected boolean crossContext = false;
+
+
+    /**
+     * The current dispatcher type.
+     */
+    protected Object dispatcherType = null;
+
+
+    /**
+     * Descriptive information about this implementation.
+     */
+    protected static final String info =
+        "org.apache.catalina.core.ApplicationHttpRequest/1.0";
+
+
+    /**
+     * The request parameters for this request.  This is initialized from the
+     * wrapped request, but updates are allowed.
+     */
+    protected Map parameters = null;
+
+
+    /**
+     * Have the parameters for this request already been parsed?
+     */
+    private boolean parsedParams = false;
+
+
+    /**
+     * The path information for this request.
+     */
+    protected String pathInfo = null;
+
+
+    /**
+     * The query parameters for the current request.
+     */
+    private String queryParamString = null;
+
+
+    /**
+     * The query string for this request.
+     */
+    protected String queryString = null;
+
+
+    /**
+     * The current request dispatcher path.
+     */
+    protected Object requestDispatcherPath = null;
+
+
+    /**
+     * The request URI for this request.
+     */
+    protected String requestURI = null;
+
+
+    /**
+     * The servlet path for this request.
+     */
+    protected String servletPath = null;
+
+
+    /**
+     * The currently active session for this request.
+     */
+    protected HttpSession session = null;
+
+
+    /**
+     * Special attributes.
+     */
+    protected Object[] specialAttributes = new Object[specials.length];
+
+
+    // ------------------------------------------------- ServletRequest Methods
+
+
+    /**
+     * Override the <code>getAttribute()</code> method of the wrapped request.
+     *
+     * @param name Name of the attribute to retrieve
+     */
+    public Object getAttribute(String name) {
+
+        if (name.equals(ServletRequestImpl.DISPATCHER_TYPE_ATTR)) {
+            return dispatcherType;
+        } else if (name.equals(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR)) {
+            if ( requestDispatcherPath != null ){
+                return requestDispatcherPath.toString();
+            } else {
+                return null;   
+            }
+        }
+
+        int pos = getSpecial(name);
+        if (pos == -1) {
+            return getRequest().getAttribute(name);
+        } else {
+            if ((specialAttributes[pos] == null) 
+                && (specialAttributes[5] == null) && (pos >= 5)) {
+                // If it's a forward special attribute, and null, it means this
+                // is an include, so we check the wrapped request since 
+                // the request could have been forwarded before the include
+                return getRequest().getAttribute(name);
+            } else {
+                return specialAttributes[pos];
+            }
+        }
+
+    }
+
+
+    /**
+     * Override the <code>getAttributeNames()</code> method of the wrapped
+     * request.
+     */
+    public Enumeration getAttributeNames() {
+        return (new AttributeNamesEnumerator());
+    }
+
+
+    /**
+     * Override the <code>removeAttribute()</code> method of the
+     * wrapped request.
+     *
+     * @param name Name of the attribute to remove
+     */
+    public void removeAttribute(String name) {
+
+        if (!removeSpecial(name))
+            getRequest().removeAttribute(name);
+
+    }
+
+
+    /**
+     * Override the <code>setAttribute()</code> method of the
+     * wrapped request.
+     *
+     * @param name Name of the attribute to set
+     * @param value Value of the attribute to set
+     */
+    public void setAttribute(String name, Object value) {
+
+        if (name.equals(ServletRequestImpl.DISPATCHER_TYPE_ATTR)) {
+            dispatcherType = value;
+            return;
+        } else if (name.equals(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR)) {
+            requestDispatcherPath = value;
+            return;
+        }
+
+        if (!setSpecial(name, value)) {
+            getRequest().setAttribute(name, value);
+        }
+
+    }
+
+
+    /**
+     * Return a RequestDispatcher that wraps the resource at the specified
+     * path, which may be interpreted as relative to the current request path.
+     *
+     * @param path Path of the resource to be wrapped
+     */
+    public RequestDispatcher getRequestDispatcher(String path) {
+
+        if (context == null)
+            return (null);
+
+        // If the path is already context-relative, just pass it through
+        if (path == null)
+            return (null);
+        else if (path.startsWith("/"))
+            return (context.getServletContext().getRequestDispatcher(path));
+
+        // Convert a request-relative path to a context-relative one
+        String servletPath = 
+            (String) getAttribute(RequestDispatcherImpl.INCLUDE_SERVLET_PATH_ATTR);
+        if (servletPath == null)
+            servletPath = getServletPath();
+
+        // Add the path info, if there is any
+        String pathInfo = getPathInfo();
+        String requestPath = null;
+
+        if (pathInfo == null) {
+            requestPath = servletPath;
+        } else {
+            requestPath = servletPath + pathInfo;
+        }
+
+        int pos = requestPath.lastIndexOf('/');
+        String relative = null;
+        if (pos >= 0) {
+            relative = RequestUtil.normalize
+                (requestPath.substring(0, pos + 1) + path);
+        } else {
+            relative = RequestUtil.normalize(requestPath + path);
+        }
+
+        return (context.getServletContext().getRequestDispatcher(relative));
+
+    }
+
+
+    // --------------------------------------------- HttpServletRequest Methods
+
+
+    /**
+     * Override the <code>getContextPath()</code> method of the wrapped
+     * request.
+     */
+    public String getContextPath() {
+
+        return (this.contextPath);
+
+    }
+
+
+    /**
+     * Override the <code>getParameter()</code> method of the wrapped request.
+     *
+     * @param name Name of the requested parameter
+     */
+    public String getParameter(String name) {
+
+       parseParameters();
+
+        Object value = parameters.get(name);
+        if (value == null)
+            return (null);
+        else if (value instanceof String[])
+            return (((String[]) value)[0]);
+        else if (value instanceof String)
+            return ((String) value);
+        else
+            return (value.toString());
+
+    }
+
+
+    /**
+     * Override the <code>getParameterMap()</code> method of the
+     * wrapped request.
+     */
+    public Map getParameterMap() {
+
+       parseParameters();
+        return (parameters);
+
+    }
+
+
+    /**
+     * Override the <code>getParameterNames()</code> method of the
+     * wrapped request.
+     */
+    public Enumeration getParameterNames() {
+
+       parseParameters();
+        return (new Enumerator(parameters.keySet()));
+
+    }
+
+
+    /**
+     * Override the <code>getParameterValues()</code> method of the
+     * wrapped request.
+     *
+     * @param name Name of the requested parameter
+     */
+    public String[] getParameterValues(String name) {
+
+       parseParameters();
+        Object value = parameters.get(name);
+        if (value == null)
+            return ((String[]) null);
+        else if (value instanceof String[])
+            return ((String[]) value);
+        else if (value instanceof String) {
+            String values[] = new String[1];
+            values[0] = (String) value;
+            return (values);
+        } else {
+            String values[] = new String[1];
+            values[0] = value.toString();
+            return (values);
+        }
+
+    }
+
+
+    /**
+     * Override the <code>getPathInfo()</code> method of the wrapped request.
+     */
+    public String getPathInfo() {
+
+        return (this.pathInfo);
+
+    }
+
+
+    /**
+     * Override the <code>getQueryString()</code> method of the wrapped
+     * request.
+     */
+    public String getQueryString() {
+
+        return (this.queryString);
+
+    }
+
+
+    /**
+     * Override the <code>getRequestURI()</code> method of the wrapped
+     * request.
+     */
+    public String getRequestURI() {
+
+        return (this.requestURI);
+
+    }
+
+
+    /**
+     * Override the <code>getRequestURL()</code> method of the wrapped
+     * request.
+     */
+    public StringBuffer getRequestURL() {
+
+        StringBuffer url = new StringBuffer();
+        String scheme = getScheme();
+        int port = getServerPort();
+        if (port < 0)
+            port = 80; // Work around java.net.URL bug
+
+        url.append(scheme);
+        url.append("://");
+        url.append(getServerName());
+        if ((scheme.equals("http") && (port != 80))
+            || (scheme.equals("https") && (port != 443))) {
+            url.append(':');
+            url.append(port);
+        }
+        url.append(getRequestURI());
+
+        return (url);
+
+    }
+
+
+    /**
+     * Override the <code>getServletPath()</code> method of the wrapped
+     * request.
+     */
+    public String getServletPath() {
+
+        return (this.servletPath);
+
+    }
+
+
+    /**
+     * Return the session associated with this Request, creating one
+     * if necessary.
+     */
+    public HttpSession getSession() {
+        return (getSession(true));
+    }
+
+
+    /**
+     * Return the session associated with this Request, creating one
+     * if necessary and requested.
+     *
+     * @param create Create a new session if one does not exist
+     */
+    public HttpSession getSession(boolean create) {
+
+        if (crossContext) {
+            
+            // There cannot be a session if no context has been assigned yet
+            if (context == null)
+                return (null);
+            UserSessionManager manager = context.getManager();
+            // Return the current session if it exists and is valid
+            if (session != null && manager.isValid(session)) {
+                return session;
+            }
+
+            HttpSession other = super.getSession(false);
+            if (create && (other == null)) {
+                // First create a session in the first context: the problem is
+                // that the top level request is the only one which can 
+                // create the cookie safely
+                other = super.getSession(true);
+            }
+            if (other != null) {
+                HttpSession localSession = null;
+                try {
+                    localSession =
+                      manager.findSession(other.getId());
+                } catch (IOException e) {
+                    // Ignore
+                }
+                if (localSession == null && create) {
+                    localSession = 
+                        context.getManager().createSession(other.getId());
+                }
+                if (localSession != null) {
+                    context.getManager().access(localSession);
+                    session = localSession;
+                    return session;
+                }
+            }
+            return null;
+
+        } else {
+            return super.getSession(create);
+        }
+
+    }
+
+
+    /**
+     * Returns true if the request specifies a JSESSIONID that is valid within
+     * the context of this ApplicationHttpRequest, false otherwise.
+     *
+     * @return true if the request specifies a JSESSIONID that is valid within
+     * the context of this ApplicationHttpRequest, false otherwise.
+     */
+    public boolean isRequestedSessionIdValid() {
+
+        if (crossContext) {
+
+            String requestedSessionId = getRequestedSessionId();
+            if (requestedSessionId == null)
+                return (false);
+            if (context == null)
+                return (false);
+            UserSessionManager manager = context.getManager();
+            if (manager == null)
+                return (false);
+            HttpSession session = null;
+            try {
+                session = manager.findSession(requestedSessionId);
+            } catch (IOException e) {
+                session = null;
+            }
+            if ((session != null) && manager.isValid(session)) {
+                return (true);
+            } else {
+                return (false);
+            }
+
+        } else {
+            return super.isRequestedSessionIdValid();
+        }
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Recycle this request
+     */
+    public void recycle() {
+        if (session != null) {
+            context.getManager().endAccess(session);
+        }
+    }
+
+
+    /**
+     * Return descriptive information about this implementation.
+     */
+    public String getInfo() {
+
+        return (info);
+
+    }
+
+
+    /**
+     * Perform a shallow copy of the specified Map, and return the result.
+     *
+     * @param orig Origin Map to be copied
+     */
+    Map copyMap(Map orig) {
+
+        if (orig == null)
+            return (new HashMap());
+        HashMap dest = new HashMap();
+        Iterator keys = orig.keySet().iterator();
+        while (keys.hasNext()) {
+            String key = (String) keys.next();
+            dest.put(key, orig.get(key));
+        }
+        return (dest);
+
+    }
+
+
+    /**
+     * Set the context path for this request.
+     *
+     * @param contextPath The new context path
+     */
+    void setContextPath(String contextPath) {
+
+        this.contextPath = contextPath;
+
+    }
+
+
+    /**
+     * Set the path information for this request.
+     *
+     * @param pathInfo The new path info
+     */
+    void setPathInfo(String pathInfo) {
+
+        this.pathInfo = pathInfo;
+
+    }
+
+
+    /**
+     * Set the query string for this request.
+     *
+     * @param queryString The new query string
+     */
+    void setQueryString(String queryString) {
+
+        this.queryString = queryString;
+
+    }
+
+
+    /**
+     * Set the request that we are wrapping.
+     *
+     * @param request The new wrapped request
+     */
+    void setRequest(HttpServletRequest request) {
+
+        super.setRequest(request);
+
+        // Initialize the attributes for this request
+        dispatcherType = request.getAttribute(ServletRequestImpl.DISPATCHER_TYPE_ATTR);
+        requestDispatcherPath = 
+            request.getAttribute(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR);
+
+        // Initialize the path elements for this request
+        contextPath = request.getContextPath();
+        pathInfo = request.getPathInfo();
+        queryString = request.getQueryString();
+        requestURI = request.getRequestURI();
+        servletPath = request.getServletPath();
+
+    }
+
+
+    /**
+     * Set the request URI for this request.
+     *
+     * @param requestURI The new request URI
+     */
+    void setRequestURI(String requestURI) {
+
+        this.requestURI = requestURI;
+
+    }
+
+
+    /**
+     * Set the servlet path for this request.
+     *
+     * @param servletPath The new servlet path
+     */
+    void setServletPath(String servletPath) {
+
+        this.servletPath = servletPath;
+
+    }
+
+
+    /**
+     * Parses the parameters of this request.
+     *
+     * If parameters are present in both the query string and the request
+     * content, they are merged.
+     */
+    void parseParameters() {
+
+       if (parsedParams) {
+           return;
+       }
+
+        parameters = new HashMap();
+        parameters = copyMap(getRequest().getParameterMap());
+        mergeParameters();
+        parsedParams = true;
+    }
+
+
+    /**
+     * Save query parameters for this request.
+     *
+     * @param queryString The query string containing parameters for this
+     *                    request
+     */
+    void setQueryParams(String queryString) {
+        this.queryParamString = queryString;
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Is this attribute name one of the special ones that is added only for
+     * included servlets?
+     *
+     * @param name Attribute name to be tested
+     */
+    protected boolean isSpecial(String name) {
+
+        for (int i = 0; i < specials.length; i++) {
+            if (specials[i].equals(name))
+                return (true);
+        }
+        return (false);
+
+    }
+
+
+    /**
+     * Get a special attribute.
+     *
+     * @return the special attribute pos, or -1 if it is not a special 
+     *         attribute
+     */
+    protected int getSpecial(String name) {
+        for (int i = 0; i < specials.length; i++) {
+            if (specials[i].equals(name)) {
+                return (i);
+            }
+        }
+        return (-1);
+    }
+
+
+    /**
+     * Set a special attribute.
+     * 
+     * @return true if the attribute was a special attribute, false otherwise
+     */
+    protected boolean setSpecial(String name, Object value) {
+        for (int i = 0; i < specials.length; i++) {
+            if (specials[i].equals(name)) {
+                specialAttributes[i] = value;
+                return (true);
+            }
+        }
+        return (false);
+    }
+
+
+    /**
+     * Remove a special attribute.
+     * 
+     * @return true if the attribute was a special attribute, false otherwise
+     */
+    protected boolean removeSpecial(String name) {
+        for (int i = 0; i < specials.length; i++) {
+            if (specials[i].equals(name)) {
+                specialAttributes[i] = null;
+                return (true);
+            }
+        }
+        return (false);
+    }
+
+
+    /**
+     * Merge the two sets of parameter values into a single String array.
+     *
+     * @param values1 First set of values
+     * @param values2 Second set of values
+     */
+    protected String[] mergeValues(Object values1, Object values2) {
+
+        ArrayList results = new ArrayList();
+
+        if (values1 == null)
+            ;
+        else if (values1 instanceof String)
+            results.add(values1);
+        else if (values1 instanceof String[]) {
+            String values[] = (String[]) values1;
+            for (int i = 0; i < values.length; i++)
+                results.add(values[i]);
+        } else
+            results.add(values1.toString());
+
+        if (values2 == null)
+            ;
+        else if (values2 instanceof String)
+            results.add(values2);
+        else if (values2 instanceof String[]) {
+            String values[] = (String[]) values2;
+            for (int i = 0; i < values.length; i++)
+                results.add(values[i]);
+        } else
+            results.add(values2.toString());
+
+        String values[] = new String[results.size()];
+        return ((String[]) results.toArray(values));
+
+    }
+
+
+    // ------------------------------------------------------ Private Methods
+
+
+    /**
+     * Merge the parameters from the saved query parameter string (if any), and
+     * the parameters already present on this request (if any), such that the
+     * parameter values from the query string show up first if there are
+     * duplicate parameter names.
+     */
+    private void mergeParameters() {
+
+        if ((queryParamString == null) || (queryParamString.length() < 1))
+            return;
+
+        HashMap queryParameters = new HashMap();
+        String encoding = getCharacterEncoding();
+        if (encoding == null)
+            encoding = "ISO-8859-1";
+        try {
+            RequestUtil.parseParameters
+                (queryParameters, queryParamString, encoding);
+        } catch (Exception e) {
+            ;
+        }
+        Iterator keys = parameters.keySet().iterator();
+        while (keys.hasNext()) {
+            String key = (String) keys.next();
+            Object value = queryParameters.get(key);
+            if (value == null) {
+                queryParameters.put(key, parameters.get(key));
+                continue;
+            }
+            queryParameters.put
+                (key, mergeValues(value, parameters.get(key)));
+        }
+        parameters = queryParameters;
+
+    }
+
+
+    // ----------------------------------- AttributeNamesEnumerator Inner Class
+
+
+    /**
+     * Utility class used to expose the special attributes as being available
+     * as request attributes.
+     */
+    protected class AttributeNamesEnumerator implements Enumeration {
+
+        protected int pos = -1;
+        protected int last = -1;
+        protected Enumeration parentEnumeration = null;
+        protected String next = null;
+
+        public AttributeNamesEnumerator() {
+            parentEnumeration = getRequest().getAttributeNames();
+            for (int i = 0; i < specialAttributes.length; i++) {
+                if (getAttribute(specials[i]) != null) {
+                    last = i;
+                }
+            }
+        }
+
+        public boolean hasMoreElements() {
+            return ((pos != last) || (next != null) 
+                    || ((next = findNext()) != null));
+        }
+
+        public Object nextElement() {
+            if (pos != last) {
+                for (int i = pos + 1; i <= last; i++) {
+                    if (getAttribute(specials[i]) != null) {
+                        pos = i;
+                        return (specials[i]);
+                    }
+                }
+            }
+            String result = next;
+            if (next != null) {
+                next = findNext();
+            } else {
+                throw new NoSuchElementException();
+            }
+            return result;
+        }
+
+        protected String findNext() {
+            String result = null;
+            while ((result == null) && (parentEnumeration.hasMoreElements())) {
+                String current = (String) parentEnumeration.nextElement();
+                if (!isSpecial(current)) {
+                    result = current;
+                }
+            }
+            return result;
+        }
+
+    }
+
+
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletResponseImpl.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletResponseImpl.java
new file mode 100644 (file)
index 0000000..eab7af9
--- /dev/null
@@ -0,0 +1,1463 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.coyote.servlet;
+
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.util.Vector;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.buf.UEncoder;
+import org.apache.tomcat.util.http.FastHttpDateFormat;
+import org.apache.tomcat.util.http.HttpResponse;
+import org.apache.tomcat.util.http.MimeHeaders;
+import org.apache.tomcat.util.http.ServerCookie;
+
+/**
+ * Wrapper object for the Coyote response.
+ *
+ * @author Remy Maucherat
+ * @author Craig R. McClanahan
+ * @version $Revision$ $Date$
+ */
+
+public class ServletResponseImpl
+    implements HttpServletResponse {
+
+    /**
+     * Format for http response header date field
+     * From DateTool
+     */
+    public static final String HTTP_RESPONSE_DATE_HEADER =
+        "EEE, dd MMM yyyy HH:mm:ss zzz";
+
+    // ----------------------------------------------------------- Constructors
+
+
+    ServletResponseImpl() {
+        urlEncoder.addSafeCharacter('/');
+    }
+
+
+    /**
+     * The date format we will use for creating date headers.
+     */
+    protected SimpleDateFormat format = null;
+
+
+    /**
+     * The associated output buffer.
+     */
+    protected BodyWriter outputBuffer;
+
+
+    /**
+     * The associated output stream.
+     */
+    protected ServletOutputStreamImpl outputStream;
+
+
+    /**
+     * The associated writer.
+     */
+    protected PrintWriter writer;
+
+
+    /**
+     * The application commit flag.
+     */
+    protected boolean appCommitted = false;
+
+
+    /**
+     * The included flag.
+     */
+    protected boolean included = false;
+
+
+    /**
+     * The characterEncoding flag
+     */
+    private boolean isCharacterEncodingSet = false;
+
+    /**
+     * The error flag.
+     */
+    protected boolean error = false;
+
+
+    /**
+     * The set of Cookies associated with this Response.
+     */
+    protected ArrayList cookies = new ArrayList();
+
+
+    /**
+     * Using output stream flag.
+     */
+    protected boolean usingOutputStream = false;
+
+
+    /**
+     * Using writer flag.
+     */
+    protected boolean usingWriter = false;
+
+
+    /**
+     * The request with which this response is associated.
+     */
+    protected ServletRequestImpl req = null;
+
+    /**
+     * URL encoder.
+     */
+    protected UEncoder urlEncoder = new UEncoder();
+
+
+    /**
+     * Recyclable buffer to hold the redirect URL.
+     */
+    protected CharChunk redirectURLCC = new CharChunk(1024);
+
+
+    private HttpResponse resB;
+
+
+    // Cached/derived information - reflected in headers
+    protected static Locale DEFAULT_LOCALE = Locale.getDefault();
+
+    public static final String DEFAULT_CHARACTER_ENCODING="ISO-8859-1";
+
+    protected Locale locale = DEFAULT_LOCALE;
+
+    // XXX
+    protected boolean commited = false;
+    protected String contentType = null;
+
+    /**
+     * Has the charset been explicitly set.
+     */
+    protected boolean charsetSet = false;
+    protected String characterEncoding = DEFAULT_CHARACTER_ENCODING;
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Release all object references, and initialize instance variables, in
+     * preparation for reuse of this object.
+     */
+    public void recycle() {
+
+        usingOutputStream = false;
+        usingWriter = false;
+        appCommitted = false;
+        commited = false;
+        included = false;
+        error = false;
+        isCharacterEncodingSet = false;
+
+        cookies.clear();
+
+        outputBuffer.recycle();
+
+        resB.recycle();
+    }
+
+
+    // ------------------------------------------------------- Response Methods
+
+
+    /**
+     * Return the number of bytes actually written to the output stream.
+     */
+    public int getContentCount() {
+        return outputBuffer.getBytesWritten() + outputBuffer.getCharsWritten();
+    }
+
+
+    /**
+     * Set the application commit flag.
+     *
+     * @param appCommitted The new application committed flag value
+     */
+    public void setAppCommitted(boolean appCommitted) {
+        this.appCommitted = appCommitted;
+    }
+
+
+    /**
+     * Application commit flag accessor.
+     */
+    public boolean isAppCommitted() {
+        return (this.appCommitted || isCommitted() || isSuspended()
+                || ((getHttpResponse().getContentLength() > 0)
+                    && (getContentCount() >= getHttpResponse().getContentLength())));
+    }
+
+
+    /**
+     * Return the "processing inside an include" flag.
+     */
+    public boolean getIncluded() {
+        return included;
+    }
+
+
+    /**
+     * Set the "processing inside an include" flag.
+     *
+     * @param included <code>true</code> if we are currently inside a
+     *  RequestDispatcher.include(), else <code>false</code>
+     */
+    public void setIncluded(boolean included) {
+        this.included = included;
+    }
+
+
+    /**
+     * Return the Request with which this Response is associated.
+     */
+    public ServletRequestImpl getRequest() {
+        return (this.req);
+    }
+
+    /**
+     * Set the Request with which this Response is associated.
+     *
+     * @param request The new associated request
+     */
+    public void setRequest(ServletRequestImpl request) {
+        this.req = (ServletRequestImpl) request;
+    }
+
+
+    /**
+     * Return the output stream associated with this Response.
+     */
+    public OutputStream getStream() {
+        return outputStream;
+    }
+
+
+    /**
+     * Set the output stream associated with this Response.
+     *
+     * @param stream The new output stream
+     */
+    public void setStream(OutputStream stream) {
+        // This method is evil
+    }
+
+
+    /**
+     * Set the suspended flag.
+     *
+     * @param suspended The new suspended flag value
+     */
+    public void setSuspended(boolean suspended) throws IOException {
+        //coyoteResponse.setCommitted(true);
+        flushBuffer();
+        outputBuffer.setSuspended(suspended);
+    }
+
+
+    /**
+     * Suspended flag accessor.
+     */
+    public boolean isSuspended() {
+        return outputBuffer.isSuspended();
+    }
+
+
+    /**
+     * Set the error flag.
+     */
+    public void setError() {
+        error = true;
+    }
+
+
+    /**
+     * Error flag accessor.
+     */
+    public boolean isError() {
+        return error;
+    }
+
+
+    /**
+     * Create and return a ServletOutputStream to write the content
+     * associated with this Response.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public ServletOutputStream createOutputStream()
+        throws IOException {
+        // Probably useless
+        return outputStream;
+    }
+
+    /**
+     * Return the content type that was set or calculated for this response,
+     * or <code>null</code> if no content type was set.
+     */
+    public String getContentType() {
+        String ret = contentType;
+
+        if (ret != null
+            && characterEncoding != null
+            && charsetSet) {
+            ret = ret + ";charset=" + characterEncoding;
+        }
+
+        return ret;
+    }
+
+
+    /**
+     * Return a PrintWriter that can be used to render error messages,
+     * regardless of whether a stream or writer has already been acquired.
+     *
+     * @return Writer which can be used for error reports. If the response is
+     * not an error report returned using sendError or triggered by an
+     * unexpected exception thrown during the servlet processing
+     * (and only in that case), null will be returned if the response stream
+     * has already been used.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public PrintWriter getReporter() throws IOException {
+        if (outputBuffer.isNew()) {
+            outputBuffer.checkConverter();
+            if (writer == null) {
+                writer = new ServletWriterImpl(outputBuffer);
+            }
+            return writer;
+        } else {
+            return null;
+        }
+    }
+
+
+    // ------------------------------------------------ ServletResponse Methods
+
+
+    /**
+     * Flush the buffer and commit this response.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void flushBuffer()
+        throws IOException {
+        outputBuffer.flush();
+    }
+
+
+    /**
+     * Return the actual buffer size used for this Response.
+     */
+    public int getBufferSize() {
+        return outputBuffer.getBufferSize();
+    }
+
+
+    /**
+     * Return the character encoding used for this Response.
+     */
+    public String getCharacterEncoding() {
+        return characterEncoding;
+    }
+
+
+    /**
+     * Return the servlet output stream associated with this Response.
+     *
+     * @exception IllegalStateException if <code>getWriter</code> has
+     *  already been called for this response
+     * @exception IOException if an input/output error occurs
+     */
+    public ServletOutputStream getOutputStream()
+        throws IOException {
+
+        if (usingWriter)
+            throw new IllegalStateException
+                ("usingWriter");
+
+        usingOutputStream = true;
+        return outputStream;
+
+    }
+
+    public BodyWriter getBodyWriter() {
+        return outputBuffer;
+    }
+
+    /**
+     * Return the Locale assigned to this response.
+     */
+    public Locale getLocale() {
+        return locale;
+    }
+
+
+    /**
+     * Return the writer associated with this Response.
+     *
+     * @exception IllegalStateException if <code>getOutputStream</code> has
+     *  already been called for this response
+     * @exception IOException if an input/output error occurs
+     */
+    public PrintWriter getWriter()
+        throws IOException {
+
+        if (usingOutputStream)
+            throw new IllegalStateException
+                ("usingOutputStream");
+
+        /*
+         * If the response's character encoding has not been specified as
+         * described in <code>getCharacterEncoding</code> (i.e., the method
+         * just returns the default value <code>ISO-8859-1</code>),
+         * <code>getWriter</code> updates it to <code>ISO-8859-1</code>
+         * (with the effect that a subsequent call to getContentType() will
+         * include a charset=ISO-8859-1 component which will also be
+         * reflected in the Content-Type response header, thereby satisfying
+         * the Servlet spec requirement that containers must communicate the
+         * character encoding used for the servlet response's writer to the
+         * client).
+         */
+        setCharacterEncoding(getCharacterEncoding());
+
+        usingWriter = true;
+        outputBuffer.checkConverter();
+        if (writer == null) {
+            writer = new ServletWriterImpl(outputBuffer);
+        }
+        return writer;
+
+    }
+
+
+    /**
+     * Has the output of this response already been committed?
+     */
+    public boolean isCommitted() {
+        return getHttpResponse().isCommitted();
+    }
+
+    /**
+     * Clear any content written to the buffer.
+     *
+     * @exception IllegalStateException if this response has already
+     *  been committed
+     */
+    public void reset() {
+
+        if (included)
+            return;     // Ignore any call from an included servlet
+
+        if (isCommitted())
+            throw new IllegalStateException("isCommitted");
+
+        resB.recycle(); // reset headers, status code, message
+        req.getConnector().reset(this);
+        contentType = null;
+        locale = DEFAULT_LOCALE;
+        characterEncoding = DEFAULT_CHARACTER_ENCODING;
+        charsetSet = false;
+
+        outputBuffer.reset();
+    }
+
+
+    /**
+     * Reset the data buffer but not any status or header information.
+     *
+     * @exception IllegalStateException if the response has already
+     *  been committed
+     */
+    public void resetBuffer() {
+
+        if (isCommitted())
+            throw new IllegalStateException("isCommitted");
+
+        outputBuffer.reset();
+
+    }
+
+
+    /**
+     * Set the buffer size to be used for this Response.
+     *
+     * @param size The new buffer size
+     *
+     * @exception IllegalStateException if this method is called after
+     *  output has been committed for this response
+     */
+    public void setBufferSize(int size) {
+
+        if (isCommitted() || !outputBuffer.isNew())
+            throw new IllegalStateException
+                ("isCommitted || !isNew");
+
+        outputBuffer.setBufferSize(size);
+
+    }
+
+
+    /**
+     * Set the content length (in bytes) for this Response.
+     * Ignored for writers if non-ISO-8859-1 encoding ( we could add more
+     * encodings that are constant.
+     */
+    public void setContentLength(int length) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        // writers can use variable-length encoding.
+        if (usingWriter && !"ISO-8859-1".equals(getCharacterEncoding())) {
+            return;
+        }
+        getHttpResponse().setContentLength(length);
+
+    }
+
+
+    /**
+     * Set the content type for this Response.
+     *
+     * @param type The new content type
+     */
+    public void setContentType(String type) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        // Ignore charset if getWriter() has already been called
+        if (usingWriter) {
+            if (type != null) {
+                int index = type.indexOf(";");
+                if (index != -1) {
+                    type = type.substring(0, index);
+                }
+            }
+        }
+
+        getHttpResponse().setContentType(type);
+
+        // Check to see if content type contains charset
+        if (type != null) {
+            int index = type.indexOf(";");
+            if (index != -1) {
+                int len = type.length();
+                index++;
+                while (index < len && Character.isSpace(type.charAt(index))) {
+                    index++;
+                }
+                if (index+7 < len
+                        && type.charAt(index) == 'c'
+                        && type.charAt(index+1) == 'h'
+                        && type.charAt(index+2) == 'a'
+                        && type.charAt(index+3) == 'r'
+                        && type.charAt(index+4) == 's'
+                        && type.charAt(index+5) == 'e'
+                        && type.charAt(index+6) == 't'
+                        && type.charAt(index+7) == '=') {
+                    isCharacterEncodingSet = true;
+                }
+            }
+        }
+    }
+
+
+    /*
+     * Overrides the name of the character encoding used in the body
+     * of the request. This method must be called prior to reading
+     * request parameters or reading input using getReader().
+     *
+     * @param charset String containing the name of the chararacter encoding.
+     */
+    public void setCharacterEncoding(String charset) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        // Ignore any call made after the getWriter has been invoked
+        // The default should be used
+        if (usingWriter)
+            return;
+
+        if (isCommitted())
+            return;
+        if (charset == null)
+            return;
+
+        characterEncoding = charset;
+        charsetSet=true;
+        isCharacterEncodingSet = true;
+    }
+
+
+
+    /**
+     * Set the Locale that is appropriate for this response, including
+     * setting the appropriate character encoding.
+     *
+     * @param locale The new locale
+     */
+    public void setLocale(Locale locale) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        if (locale == null) {
+            return;  // throw an exception?
+        }
+
+        // Save the locale for use by getLocale()
+        this.locale = locale;
+
+        // Set the contentLanguage for header output
+        String contentLanguage = locale.getLanguage();
+        if ((contentLanguage != null) && (contentLanguage.length() > 0)) {
+            String country = locale.getCountry();
+            StringBuffer value = new StringBuffer(contentLanguage);
+            if ((country != null) && (country.length() > 0)) {
+                value.append('-');
+                value.append(country);
+            }
+            contentLanguage = value.toString();
+        }
+        resB.setHeader("Content-Language", contentLanguage);
+
+        // Ignore any call made after the getWriter has been invoked.
+        // The default should be used
+        if (usingWriter)
+            return;
+
+        if (isCharacterEncodingSet) {
+            return;
+        }
+
+        Locale2Charset cm = req.getContext().getCharsetMapper();
+        String charset = cm.getCharset( locale );
+        if ( charset != null ){
+            setCharacterEncoding(charset);
+        }
+
+    }
+
+
+    // --------------------------------------------------- HttpResponse Methods
+
+
+    /**
+     * Return an array of all cookies set for this response, or
+     * a zero-length array if no cookies have been set.
+     */
+    public Cookie[] getCookies() {
+        return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()]));
+    }
+
+
+    /**
+     * Return the value for the specified header, or <code>null</code> if this
+     * header has not been set.  If more than one value was added for this
+     * name, only the first is returned; use getHeaderValues() to retrieve all
+     * of them.
+     *
+     * @param name Header name to look up
+     */
+    public String getHeader(String name) {
+        return getHttpResponse().getMimeHeaders().getHeader(name);
+    }
+
+
+    /**
+     * Return an array of all the header names set for this response, or
+     * a zero-length array if no headers have been set.
+     */
+    public Collection<String> getHeaderNames() {
+
+        MimeHeaders headers = getHttpResponse().getMimeHeaders();
+        int n = headers.size();
+        ArrayList<String> result = new ArrayList<String>();
+        for (int i = 0; i < n; i++) {
+            result.add(headers.getName(i).toString());
+        }
+        return result;
+    }
+
+
+    /**
+     * Return an array of all the header values associated with the
+     * specified header name, or an zero-length array if there are no such
+     * header values.
+     *
+     * @param name Header name to look up
+     */
+    public String[] getHeaderValues(String name) {
+
+        Enumeration enumeration = getHttpResponse().getMimeHeaders().values(name);
+        Vector result = new Vector();
+        while (enumeration.hasMoreElements()) {
+            result.addElement(enumeration.nextElement());
+        }
+        String[] resultArray = new String[result.size()];
+        result.copyInto(resultArray);
+        return resultArray;
+
+    }
+
+
+    /**
+     * Return the error message that was set with <code>sendError()</code>
+     * for this Response.
+     */
+    public String getMessage() {
+        return getHttpResponse().getMessage();
+    }
+
+
+    /**
+     * Return the HTTP status code associated with this Response.
+     */
+    public int getStatus() {
+        return getHttpResponse().getStatus();
+    }
+
+
+    /**
+     * Reset this response, and specify the values for the HTTP status code
+     * and corresponding message.
+     *
+     * @exception IllegalStateException if this response has already been
+     *  committed
+     */
+    public void reset(int status, String message) {
+        reset();
+        setStatus(status, message);
+    }
+
+
+    // -------------------------------------------- HttpServletResponse Methods
+
+
+    /**
+     * Add the specified Cookie to those that will be included with
+     * this Response.
+     *
+     * @param cookie Cookie to be added
+     */
+    public void addCookie(final Cookie cookie) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        cookies.add(cookie);
+
+        final StringBuffer sb = new StringBuffer();
+        ServerCookie.appendCookieValue
+        (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(),
+                cookie.getPath(), cookie.getDomain(), cookie.getComment(),
+                cookie.getMaxAge(), cookie.getSecure(), false);
+
+        // the header name is Set-Cookie for both "old" and v.1 ( RFC2109 )
+        // RFC2965 is not supported by browsers and the Servlet spec
+        // asks for 2109.
+        addHeader("Set-Cookie", sb.toString());
+
+    }
+
+
+    /**
+     * Add the specified date header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Date value to be set
+     */
+    public void addDateHeader(String name, long value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included) {
+            return;
+        }
+
+        if (format == null) {
+            format = new SimpleDateFormat(HTTP_RESPONSE_DATE_HEADER,
+                                          Locale.US);
+            format.setTimeZone(TimeZone.getTimeZone("GMT"));
+        }
+
+        addHeader(name, FastHttpDateFormat.formatDate(value, format));
+
+    }
+
+
+    /**
+     * Add the specified header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Value to be set
+     */
+    public void addHeader(String name, String value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        getHttpResponse().addHeader(name, value);
+
+    }
+
+
+    /**
+     * Add the specified integer header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Integer value to be set
+     */
+    public void addIntHeader(String name, int value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        addHeader(name, "" + value);
+
+    }
+
+
+    /**
+     * Has the specified header been set already in this response?
+     *
+     * @param name Name of the header to check
+     */
+    public boolean containsHeader(String name) {
+        // Need special handling for Content-Type and Content-Length due to
+        // special handling of these in coyoteResponse
+        char cc=name.charAt(0);
+        if(cc=='C' || cc=='c') {
+            if(name.equalsIgnoreCase("Content-Type")) {
+                // Will return null if this has not been set
+                return getContentType() != null;
+            }
+            if(name.equalsIgnoreCase("Content-Length")) {
+                // -1 means not known and is not sent to client
+                return (getHttpResponse().getContentLength() != -1);
+            }
+        }
+
+        return getHttpResponse().containsHeader(name);
+    }
+
+
+    /**
+     * Encode the session identifier associated with this response
+     * into the specified redirect URL, if necessary.
+     *
+     * @param url URL to be encoded
+     */
+    public String encodeRedirectURL(String url) {
+
+        if (isEncodeable(toAbsolute(url))) {
+            return (toEncoded(url, req.getSession().getId()));
+        } else {
+            return (url);
+        }
+
+    }
+
+
+    /**
+     * Encode the session identifier associated with this response
+     * into the specified redirect URL, if necessary.
+     *
+     * @param url URL to be encoded
+     *
+     * @deprecated As of Version 2.1 of the Java Servlet API, use
+     *  <code>encodeRedirectURL()</code> instead.
+     */
+    public String encodeRedirectUrl(String url) {
+        return (encodeRedirectURL(url));
+    }
+
+
+    /**
+     * Encode the session identifier associated with this response
+     * into the specified URL, if necessary.
+     *
+     * @param url URL to be encoded
+     */
+    public String encodeURL(String url) {
+
+        String absolute = toAbsolute(url);
+        if (isEncodeable(absolute)) {
+            // W3c spec clearly said
+            if (url.equalsIgnoreCase("")){
+                url = absolute;
+            }
+            return (toEncoded(url, req.getSession().getId()));
+        } else {
+            return (url);
+        }
+
+    }
+
+
+    /**
+     * Encode the session identifier associated with this response
+     * into the specified URL, if necessary.
+     *
+     * @param url URL to be encoded
+     *
+     * @deprecated As of Version 2.1 of the Java Servlet API, use
+     *  <code>encodeURL()</code> instead.
+     */
+    public String encodeUrl(String url) {
+        return (encodeURL(url));
+    }
+
+
+    /**
+     * Send an acknowledgment of a request.
+     *
+     * @exception IOException if an input/output error occurs
+     */
+    public void sendAcknowledgement()
+        throws IOException {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        req.getConnector().acknowledge(this);
+    }
+
+
+    /**
+     * Send an error response with the specified status and a
+     * default message.
+     *
+     * @param status HTTP status code to send
+     *
+     * @exception IllegalStateException if this response has
+     *  already been committed
+     * @exception IOException if an input/output error occurs
+     */
+    public void sendError(int status)
+        throws IOException {
+        sendError(status, null);
+    }
+
+
+    /**
+     * Send an error response with the specified status and message.
+     *
+     * @param status HTTP status code to send
+     * @param message Corresponding message to send
+     *
+     * @exception IllegalStateException if this response has
+     *  already been committed
+     * @exception IOException if an input/output error occurs
+     */
+    public void sendError(int status, String message)
+        throws IOException {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                ("isCommitted");
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        setError();
+
+        getHttpResponse().setStatus(status);
+        getHttpResponse().setMessage(message);
+
+        // Clear any data content that has been buffered
+        resetBuffer();
+
+        // Cause the response to be finished (from the application perspective)
+        String statusPage = req.getContext().findStatusPage(status);
+
+        if (statusPage != null) {
+            req.getContext().handleStatusPage(req, this, status, statusPage);
+        } else {
+            // Send a default message body.
+            // TODO: maybe other mechanism to customize default.
+            defaultStatusPage(status, message);
+        }
+        setSuspended(true);
+    }
+
+    /**
+     * Default handler for status code != 200
+     */
+    void defaultStatusPage(int status, String message)
+            throws IOException {
+        setContentType("text/html");
+        if (status > 400 && status < 600) {
+            if (getOutputBuffer().getBytesWritten() == 0) {
+                getOutputBuffer().write("<html><body><h1>Status: " +
+                        status + "</h1><h1>Message: " + message +
+                        "</h1></body></html>");
+                getOutputBuffer().flush();
+            }
+        }
+    }
+
+
+
+    /**
+     * Send a temporary redirect to the specified redirect location URL.
+     *
+     * @param location Location URL to redirect to
+     *
+     * @exception IllegalStateException if this response has
+     *  already been committed
+     * @exception IOException if an input/output error occurs
+     */
+    public void sendRedirect(String location)
+        throws IOException {
+
+        if (isCommitted())
+            throw new IllegalStateException
+                ("isCommitted");
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        // Clear any data content that has been buffered
+        resetBuffer();
+
+        // Generate a temporary redirect to the specified location
+        try {
+            String absolute = toAbsolute(location);
+            setStatus(SC_FOUND);
+            setHeader("Location", absolute);
+        } catch (IllegalArgumentException e) {
+            setStatus(SC_NOT_FOUND);
+        }
+
+        // Cause the response to be finished (from the application perspective)
+        setSuspended(true);
+
+    }
+
+
+    /**
+     * Set the specified date header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Date value to be set
+     */
+    public void setDateHeader(String name, long value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included) {
+            return;
+        }
+
+        if (format == null) {
+            format = new SimpleDateFormat(HTTP_RESPONSE_DATE_HEADER,
+                                          Locale.US);
+            format.setTimeZone(TimeZone.getTimeZone("GMT"));
+        }
+
+        setHeader(name, FastHttpDateFormat.formatDate(value, format));
+
+    }
+
+
+    /**
+     * Set the specified header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Value to be set
+     */
+    public void setHeader(String name, String value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        getHttpResponse().setHeader(name, value);
+
+    }
+
+
+    /**
+     * Set the specified integer header to the specified value.
+     *
+     * @param name Name of the header to set
+     * @param value Integer value to be set
+     */
+    public void setIntHeader(String name, int value) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        setHeader(name, "" + value);
+
+    }
+
+
+    /**
+     * Set the HTTP status to be returned with this response.
+     *
+     * @param status The new HTTP status
+     */
+    public void setStatus(int status) {
+        setStatus(status, null);
+    }
+
+
+    /**
+     * Set the HTTP status and message to be returned with this response.
+     *
+     * @param status The new HTTP status
+     * @param message The associated text message
+     *
+     * @deprecated As of Version 2.1 of the Java Servlet API, this method
+     *  has been deprecated due to the ambiguous meaning of the message
+     *  parameter.
+     */
+    public void setStatus(int status, String message) {
+
+        if (isCommitted())
+            return;
+
+        // Ignore any call from an included servlet
+        if (included)
+            return;
+
+        getHttpResponse().setStatus(status);
+        getHttpResponse().setMessage(message);
+
+    }
+
+
+    // ------------------------------------------------------ Protected Methods
+
+
+    /**
+     * Return <code>true</code> if the specified URL should be encoded with
+     * a session identifier.  This will be true if all of the following
+     * conditions are met:
+     * <ul>
+     * <li>The request we are responding to asked for a valid session
+     * <li>The requested session ID was not received via a cookie
+     * <li>The specified URL points back to somewhere within the web
+     *     application that is responding to this request
+     * </ul>
+     *
+     * @param location Absolute URL to be validated
+     */
+    protected boolean isEncodeable(final String location) {
+
+        if (location == null)
+            return (false);
+
+        // Is this an intra-document reference?
+        if (location.startsWith("#"))
+            return (false);
+
+        // Are we in a valid session that is not using cookies?
+        final ServletRequestImpl hreq = req;
+        final HttpSession session = hreq.getSession(false);
+        if (session == null)
+            return (false);
+        if (hreq.isRequestedSessionIdFromCookie())
+            return (false);
+
+        // Is this a valid absolute URL?
+        URL url = null;
+        try {
+            url = new URL(location);
+        } catch (MalformedURLException e) {
+            return (false);
+        }
+
+        // Does this URL match down to (and including) the context path?
+        if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol()))
+            return (false);
+        if (!hreq.getServerName().equalsIgnoreCase(url.getHost()))
+            return (false);
+        int serverPort = hreq.getServerPort();
+        if (serverPort == -1) {
+            if ("https".equals(hreq.getScheme()))
+                serverPort = 443;
+            else
+                serverPort = 80;
+        }
+        int urlPort = url.getPort();
+        if (urlPort == -1) {
+            if ("https".equals(url.getProtocol()))
+                urlPort = 443;
+            else
+                urlPort = 80;
+        }
+        if (serverPort != urlPort)
+            return (false);
+
+        String contextPath = req.getContext().getContextPath();
+        if (contextPath != null) {
+            String file = url.getFile();
+            if ((file == null) || !file.startsWith(contextPath))
+                return (false);
+            if( file.indexOf(";jsessionid=" + session.getId()) >= 0 )
+                return (false);
+        }
+
+        // This URL belongs to our web application, so it is encodeable
+        return (true);
+
+    }
+
+
+    /**
+     * Convert (if necessary) and return the absolute URL that represents the
+     * resource referenced by this possibly relative URL.  If this URL is
+     * already absolute, return it unchanged.
+     *
+     * @param location URL to be (possibly) converted and then returned
+     *
+     * @exception IllegalArgumentException if a MalformedURLException is
+     *  thrown when converting the relative URL to an absolute one
+     */
+    private String toAbsolute(String location) {
+
+        if (location == null)
+            return (location);
+
+        boolean leadingSlash = location.startsWith("/");
+
+        if (leadingSlash || !hasScheme(location)) {
+
+            redirectURLCC.recycle();
+
+            String scheme = req.getScheme();
+            String name = req.getServerName();
+            int port = req.getServerPort();
+
+            try {
+                redirectURLCC.append(scheme, 0, scheme.length());
+                redirectURLCC.append("://", 0, 3);
+                redirectURLCC.append(name, 0, name.length());
+                if ((scheme.equals("http") && port != 80)
+                    || (scheme.equals("https") && port != 443)) {
+                    redirectURLCC.append(':');
+                    String portS = port + "";
+                    redirectURLCC.append(portS, 0, portS.length());
+                }
+                if (!leadingSlash) {
+                    String relativePath = req.getDecodedRequestURI();
+                    int pos = relativePath.lastIndexOf('/');
+                    relativePath = relativePath.substring(0, pos);
+
+                    String encodedURI = null;
+                    encodedURI = urlEncoder.encodeURL(relativePath);
+                    redirectURLCC.append(encodedURI, 0, encodedURI.length());
+                    redirectURLCC.append('/');
+                }
+                redirectURLCC.append(location, 0, location.length());
+            } catch (IOException e) {
+                IllegalArgumentException iae =
+                    new IllegalArgumentException(location);
+                iae.initCause(e);
+                throw iae;
+            }
+
+            return redirectURLCC.toString();
+
+        } else {
+
+            return (location);
+
+        }
+
+    }
+
+
+    /**
+     * Determine if a URI string has a <code>scheme</code> component.
+     */
+    private boolean hasScheme(String uri) {
+        int len = uri.length();
+        for(int i=0; i < len ; i++) {
+            char c = uri.charAt(i);
+            if(c == ':') {
+                return i > 0;
+            } else if(!isSchemeChar(c)) {
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Determine if the character is allowed in the scheme of a URI.
+     * See RFC 2396, Section 3.1
+     */
+    private static boolean isSchemeChar(char c) {
+        return Character.isLetterOrDigit(c) ||
+            c == '+' || c == '-' || c == '.';
+    }
+
+
+    /**
+     * Return the specified URL with the specified session identifier
+     * suitably encoded.
+     *
+     * @param url URL to be encoded with the session id
+     * @param sessionId Session id to be included in the encoded URL
+     */
+    protected String toEncoded(String url, String sessionId) {
+
+        if ((url == null) || (sessionId == null))
+            return (url);
+
+        String path = url;
+        String query = "";
+        String anchor = "";
+        int question = url.indexOf('?');
+        if (question >= 0) {
+            path = url.substring(0, question);
+            query = url.substring(question);
+        }
+        int pound = path.indexOf('#');
+        if (pound >= 0) {
+            anchor = path.substring(pound);
+            path = path.substring(0, pound);
+        }
+        StringBuffer sb = new StringBuffer(path);
+        if( sb.length() > 0 ) { // jsessionid can't be first.
+            sb.append(";jsessionid=");
+            sb.append(sessionId);
+        }
+        sb.append(anchor);
+        sb.append(query);
+        return (sb.toString());
+
+    }
+
+
+    public int getBytesWritten() {
+      return outputBuffer.getBytesWritten();
+    }
+
+    public BodyWriter getOutputBuffer() {
+      return outputBuffer;
+    }
+
+    public void setWriter(BodyWriter ob) {
+        outputBuffer = ob;
+        outputStream = new ServletOutputStreamImpl(outputBuffer);
+    }
+
+    public CharSequence getResponseHeader(String name) {
+      MessageBytes v = getHttpResponse().getMimeHeaders().getValue(name);
+      return (v == null) ? null : v.toString();
+    }
+
+
+    public HttpResponse getHttpResponse() {
+      return resB;
+    }
+
+
+    public void setHttpResponse(HttpResponse resB, BodyWriter ob) {
+        this.resB = resB;
+        setWriter(ob);
+    }
+
+
+
+   @Override
+    public Collection<String> getHeaders(String name) {
+        return null;
+    }
+
+
+}
+
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletResponseIncludeWrapper.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletResponseIncludeWrapper.java
new file mode 100644 (file)
index 0000000..4c10b64
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * 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.apache.coyote.servlet;
+
+
+import java.io.IOException;
+import java.util.Locale;
+
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+
+/**
+ * Wrapper around the response object received as parameter to 
+ * RequestDispatcher.include().
+ * 
+ * @author Costin Manolache
+ */
+public class ServletResponseIncludeWrapper extends HttpServletResponseWrapper {
+    public ServletResponseIncludeWrapper(ServletResponse current) {
+        super((HttpServletResponse) current);
+    }
+
+    // Not overriden:
+    /*
+    public boolean containsHeader(String name)
+    public String encodeRedirectUrl(String url)
+    public String encodeRedirectURL(String url)
+    public String encodeUrl(String url)
+    public String encodeURL(String url)
+    public void flushBuffer() throws IOException
+    public int getBufferSize()
+    public String getCharacterEncoding()
+    public String getContentType()
+    public Locale getLocale()
+    public ServletOutputStream getOutputStream() throws IOException
+    public ServletResponse getResponse()
+    public PrintWriter getWriter() throws IOException
+    public boolean isCommitted()
+    public void resetBuffer()
+    public void setCharacterEncoding(String charset)
+    public void setResponse(ServletResponse response)
+     */
+    
+    public void reset() {
+        if (getResponse().isCommitted())
+            getResponse().reset(); 
+        else
+            throw new IllegalStateException();
+    }
+
+    public void setContentLength(int len) {
+    }
+
+    public void setContentType(String type) {
+    }
+
+    public void setLocale(Locale loc) {
+    }
+
+    public void setBufferSize(int size) {
+    }
+
+    public void addCookie(Cookie cookie) {
+    }
+
+    public void addDateHeader(String name, long value) {
+    }
+
+    public void addHeader(String name, String value) {
+    }
+
+    public void addIntHeader(String name, int value) {
+    }
+
+    public void sendError(int sc) throws IOException {
+    }
+
+    public void sendError(int sc, String msg) throws IOException {
+    }
+
+    public void sendRedirect(String location) throws IOException {
+    }
+
+    public void setDateHeader(String name, long value) {
+    }
+
+    public void setHeader(String name, String value) {
+    }
+
+    public void setIntHeader(String name, int value) {
+    }
+
+    public void setStatus(int sc) {
+    }
+
+    public void setStatus(int sc, String msg) {
+    }
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletWriterImpl.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/ServletWriterImpl.java
new file mode 100644 (file)
index 0000000..82e3e20
--- /dev/null
@@ -0,0 +1,289 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * 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.apache.coyote.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ * Coyote implementation of the servlet writer.
+ * 
+ * @author Remy Maucherat
+ */
+public class ServletWriterImpl
+    extends PrintWriter {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    private static final char[] LINE_SEP = { '\r', '\n' };
+
+
+    // ----------------------------------------------------- Instance Variables
+
+
+    protected Writer ob;
+    protected boolean error = false;
+
+
+    // ----------------------------------------------------------- Constructors
+
+
+    public ServletWriterImpl(Writer ob) {
+        super(ob);
+        this.ob = ob;
+    }
+
+
+    // --------------------------------------------------------- Public Methods
+
+
+    /**
+     * Prevent cloning the facade.
+     */
+    protected Object clone()
+        throws CloneNotSupportedException {
+        throw new CloneNotSupportedException();
+    }
+
+
+    // -------------------------------------------------------- Package Methods
+
+
+    /**
+     * Clear facade.
+     */
+    void clear() {
+        ob = null;
+    }
+
+
+    /**
+     * Recycle.
+     */
+    void recycle() {
+        error = false;
+    }
+
+
+    // --------------------------------------------------------- Writer Methods
+
+
+    public void flush() {
+
+        if (error)
+            return;
+
+        try {
+            ob.flush();
+        } catch (IOException e) {
+            error = true;
+        }
+
+    }
+
+
+    public void close() {
+
+        // We don't close the PrintWriter - super() is not called,
+        // so the stream can be reused. We close ob.
+        try {
+            ob.close();
+        } catch (IOException ex ) {
+            ;
+        }
+        error = false;
+
+    }
+
+
+    public boolean checkError() {
+        flush();
+        return error;
+    }
+
+
+    public void write(int c) {
+
+        if (error)
+            return;
+
+        try {
+            ob.write(c);
+        } catch (IOException e) {
+            error = true;
+        }
+
+    }
+
+
+    public void write(char buf[], int off, int len) {
+
+        if (error)
+            return;
+
+        try {
+            ob.write(buf, off, len);
+        } catch (IOException e) {
+            error = true;
+        }
+
+    }
+
+
+    public void write(char buf[]) {
+       write(buf, 0, buf.length);
+    }
+
+
+    public void write(String s, int off, int len) {
+
+        if (error)
+            return;
+
+        try {
+            ob.write(s, off, len);
+        } catch (IOException e) {
+            error = true;
+        }
+
+    }
+
+
+    public void write(String s) {
+        write(s, 0, s.length());
+    }
+
+
+    // ---------------------------------------------------- PrintWriter Methods
+
+
+    public void print(boolean b) {
+        if (b) {
+            write("true");
+        } else {
+            write("false");
+        }
+    }
+
+
+    public void print(char c) {
+        write(c);
+    }
+
+
+    public void print(int i) {
+        write(String.valueOf(i));
+    }
+
+
+    public void print(long l) {
+        write(String.valueOf(l));
+    }
+
+
+    public void print(float f) {
+        write(String.valueOf(f));
+    }
+
+
+    public void print(double d) {
+        write(String.valueOf(d));
+    }
+
+
+    public void print(char s[]) {
+        write(s);
+    }
+
+
+    public void print(String s) {
+        if (s == null) {
+            s = "null";
+        }
+        write(s);
+    }
+
+
+    public void print(Object obj) {
+        write(String.valueOf(obj));
+    }
+
+
+    public void println() {
+        write(LINE_SEP);
+    }
+
+
+    public void println(boolean b) {
+        print(b);
+        println();
+    }
+
+
+    public void println(char c) {
+        print(c);
+        println();
+    }
+
+
+    public void println(int i) {
+        print(i);
+        println();
+    }
+
+
+    public void println(long l) {
+        print(l);
+        println();
+    }
+
+
+    public void println(float f) {
+        print(f);
+        println();
+    }
+
+
+    public void println(double d) {
+        print(d);
+        println();
+    }
+
+
+    public void println(char c[]) {
+        print(c);
+        println();
+    }
+
+
+    public void println(String s) {
+        print(s);
+        println();
+    }
+
+
+    public void println(Object o) {
+        print(o);
+        println();
+    }
+
+
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/TomcatLite.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/TomcatLite.java
new file mode 100644 (file)
index 0000000..87e04b8
--- /dev/null
@@ -0,0 +1,646 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.coyote.servlet;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.Filter;
+import javax.servlet.Servlet;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.UnavailableException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tomcat.integration.ObjectManager;
+import org.apache.tomcat.integration.simple.SimpleObjectManager;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.buf.UriNormalizer;
+import org.apache.tomcat.util.http.mapper.MappingData;
+
+/**
+ * Simpler, lower footprint serlvet engine.  
+ * 
+ * Uses ObjectManager to integate with an embedding app 
+ * - the object names it uses:
+ * 
+ * Internal objects created by Tomcat and registered for management 
+ * and injection: 
+ * - Servlet:CONTEXT_PATH:SERVLETNAME - a ServletWrapper
+ * - ServletContext:CONTEXT_PATH
+ * - ProtocolHandler:ep-PORT - coyote ProtocolHandler
+ * - CoyoteServer:CoyoteServer-PORT
+ * - CoyoteAdapter:PATH - for the coyote used Adapter 
+ * - TomcatLite - this object.
+ * - Connector - the connector object
+ * 
+ * Plugins to be constructed by framework ( defaults set in initDefaults ):
+ * - UserSessionManager
+ * - UserTemplateClassMapper
+ * - ContextPreinitListener
+ * - Connector
+ * - WebappServletMapper
+ * - WebappFilterMapper
+ * - default-servlet  
+ * - jspwildcard-servlet
+ * - Foo-servlet - servlet named Foo
+ * 
+ * 
+ * @author Costin Manolache
+ */
+public class TomcatLite implements Runnable {
+
+    private String serverDirName;
+    private File workDir;
+    
+    // all contexts - hostMapper knows about hostnames and how they are mapped.
+    // this shouldn't be needed if we want to delegate ctx management
+    private ArrayList<ServletContextImpl> contexts = new ArrayList();
+
+    URLClassLoader contextParentLoader;
+    
+    // Discovered or default Host/Context mapper
+    Filter hostMapper;
+
+    // Servlets to preload in each context, configurable from CLI or API
+    Map<String,String> preloadServlets = new HashMap();
+    Map<String,String> preloadMappings = new HashMap();
+    
+    Map<String,String> ctxDefaultInitParam = new HashMap();
+        
+    Connector connector;
+    
+    ObjectManager om;
+    
+    static String SERVLETS_PACKAGE = "org.apache.tomcat.servlets";
+    
+    
+    protected boolean daemon = false;
+    
+    public TomcatLite() {
+    }
+
+    public TomcatLite(ObjectManager om) {
+        this.setObjectManager(om);
+    }
+
+    // --------------- start/stop ---------------
+
+    public static ObjectManager defaultObjectManager() {
+        SimpleObjectManager cfg = new SimpleObjectManager();
+        cfg.loadResource("org/apache/coyote/servlet/config.properties");
+        return cfg;
+    }
+    /**
+     * Return the object manager associated with this tomcat.
+     * If none set, create a minimal one with the default 
+     * values.
+     */
+    public ObjectManager getObjectManager() {
+        if (om == null) {
+            om = defaultObjectManager();
+        }
+        return om;
+    }
+    
+    public void setObjectManager(ObjectManager om) {
+        this.om = om;
+    }
+    
+    public List/*<ServletContextImpl>*/ getWebapps() {
+        return contexts;
+    }
+    
+    public URLClassLoader getContextParentLoader() {
+        if (contextParentLoader == null) {
+            
+            ClassLoader parent = this.getClass().getClassLoader();
+            contextParentLoader = new URLClassLoader(new URL[] {},
+                    parent);
+            
+            /*if (engineRepo == null) {
+                engineRepo = new Repository();
+                engineRepo.setParentClassLoader(parent);
+            }
+            
+            contextParentLoader = 
+                engineRepo.getClassLoader();
+            */
+        }
+        return contextParentLoader;
+    }
+        
+    public void start() throws IOException {
+        long t0 = System.currentTimeMillis();
+        
+        // start all contexts
+        // init all contexts
+        Iterator i1 = contexts.iterator();
+        while (i1.hasNext()) {
+           ServletContextImpl ctx = (ServletContextImpl) i1.next();
+           try {
+               ctx.start();
+           } catch (Throwable e) {
+               e.printStackTrace();
+           }
+        }
+        long t1 = System.currentTimeMillis();
+        System.err.println("Engine.start() " + (t1-t0));
+    }
+    
+      
+    /**
+     * Add a context - used for IntrospectionUtils.
+     * 
+     * ContextPath:ContextBaseDir
+     */
+    public void setContext(String c) throws ServletException {
+        String[] pathDir = c.split(":", 2);
+        addServletContext("", pathDir[1], pathDir[0]);
+    }
+    
+    public void setServletContexts(List<ServletContext> c) throws ServletException {
+        for (ServletContext ctx: c) {
+            addServletContext((ServletContextImpl) ctx);
+        }
+    }
+    
+    public void setPreload(String servletNameClass) {
+        String[] nv = servletNameClass.split(":");
+        preloadServlets.put(nv[0], nv[1]);
+    }
+    
+    public void addPreload(String servletName, String servletClassName) {
+        preloadServlets.put(servletName, servletClassName);
+    }
+
+    public void setDefaultInitParam(String nameValue) {
+        String[] nv = nameValue.split(":");
+        ctxDefaultInitParam.put(nv[0], nv[1]);
+    }
+    
+    public void addDefaultInitParam(String name, String value) {
+        ctxDefaultInitParam.put(name, value);
+    }
+    
+    public void setPreloadMappings(String servletPath) {
+        String[] nv = servletPath.split(":");
+        preloadMappings.put(nv[0], nv[1]);
+    }
+    
+    public void addPreloadMapping(String servletName, String path) {
+        preloadMappings.put(servletName, path);
+    }
+    
+    public void stop() {
+        Iterator i1 = contexts.iterator();
+        while (i1.hasNext()) {
+           ServletContextImpl ctx = (ServletContextImpl) i1.next();
+            try {
+                ctx.destroy();
+            } catch (Throwable e) {
+                e.printStackTrace();
+            }
+        }
+        try {
+            stopConnector();
+        } catch (Exception e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+    }
+
+    // -------------- Context add/remove --------------
+
+    public static String[] DEFAULT_WELCOME = { "index.html" };
+    
+    public void addServletContext(ServletContextImpl ctx) throws ServletException {
+        ctx.setTomcat(this);
+        if (hostMapper == null) { 
+            hostMapper = new WebappContextMapper();
+        }
+
+        ((WebappContextMapper) hostMapper).addHost(ctx.getHostname(), null);
+        ((WebappContextMapper) hostMapper).addContext(ctx.getHostname(), 
+                ctx);
+
+        contexts.add(ctx);
+        
+        getObjectManager().bind("ServletContext:" + ctx.getContextPath(), 
+                ctx);
+
+    }
+    
+    /**
+     * Add a context. 
+     * 
+     * web.xml will be read as part of init, and the initialization will be 
+     * part of start or lazy.
+     * 
+     * @param hostname - ""
+     *            if default host, or string to be matched with Host header
+     * @param basePath = directory where the webapp is installed           
+     * @param path -
+     *            context path, "/" for root, "/examples", etc
+     * @return a servlet context
+     * @throws ServletException
+     */
+    public ServletContext addServletContext(String hostname, 
+                                            String basePath,
+                                            String path)
+        throws ServletException
+    {
+        ServletContextImpl ctx = new ServletContextImpl();
+        ctx.setContextPath(path);
+        ctx.setBasePath(basePath);
+        addServletContext(ctx);
+        return ctx;
+    }
+    
+    public void removeServletContext(ServletContext sctx)
+        throws ServletException
+    {
+        ServletContextImpl ctx = (ServletContextImpl) sctx;
+        // TODO: destroy all servlets and filters
+        // TODO: clean up any other reference to the context or its loader
+        notifyRemove(ctx);
+    }
+    
+    
+    /** 
+     * Required for ServletContext.getContext(uri);
+     * @throws ServletException 
+     * @throws IOException 
+     */
+    public ServletContextImpl getContext(ServletContextImpl impl, String uri) 
+            throws IOException, ServletException {
+        // Create a request - needs to be simplified
+        ServletRequestImpl req = createMessage(impl, impl.contextPath, uri);
+        hostMapper.doFilter(req, null, null);
+        return req.getContext();
+    }
+    
+    public ServletResponseImpl service(ServletRequestImpl req) throws IOException, Exception {
+      ServletResponseImpl res = req.getResponse();
+      service(req, res);
+      endRequest(req, res);
+      return res;
+    }
+    
+    public void service(ServletRequestImpl req, ServletResponseImpl res) 
+            throws Exception, IOException {
+        // parse the session id from URI
+        req.parseSessionId();
+        
+        try {
+          UriNormalizer.decodeRequest(req.getHttpRequest().decodedURI(), 
+                  req.getHttpRequest().requestURI(),
+                  req.getHttpRequest().getURLDecoder());
+        } catch(IOException ioe) {
+            res.setStatus(400);
+            return;
+        }
+        
+        MappingData mapRes = req.getMappingData();
+        try {
+          // TODO: make hostMapper configurable, implement interface,
+          // simple to set on ROOT context
+          hostMapper.doFilter(req, null, null);
+            
+
+          ServletContextImpl ctx = (ServletContextImpl)mapRes.context;
+          if( ctx == null ) {
+            // TODO: 404
+            res.setStatus(404);
+            return;
+          }
+          req.setContext(ctx);
+
+          // bind class loader 
+          Thread.currentThread().setContextClassLoader(ctx.getClassLoader());
+
+          WebappServletMapper mapper = ctx.getMapper();
+          mapper.map(req.getHttpRequest().decodedURI(), mapRes);
+
+          // Possible redirect
+          MessageBytes redirectPathMB = mapRes.redirectPath;
+          if (!redirectPathMB.isNull()) {
+              String redirectPath = res.urlEncoder.encodeURL(redirectPathMB.toString());
+              String query = req.getQueryString();
+              if (req.isRequestedSessionIdFromURL()) {
+                  // This is not optimal, but as this is not very common, it
+                  // shouldn't matter
+                  redirectPath = redirectPath + ";" + ServletRequestImpl.SESSION_PARAMETER_NAME + "=" 
+                      + req.getRequestedSessionId();
+              }
+              if (query != null) {
+                  // This is not optimal, but as this is not very common, it
+                  // shouldn't matter
+                  redirectPath = redirectPath + "?" + query;
+              }
+              res.sendRedirect(redirectPath);
+              return;
+          }
+          
+          req.parseSessionCookiesId();
+
+          ServletConfigImpl h=(ServletConfigImpl)mapRes.wrapper;
+          if (h != null) {
+            req.setWrapper((ServletConfigImpl)mapRes.wrapper);
+            serviceServlet(ctx, req, res, h, mapRes );
+            // send the response...
+
+            //res.flushBuffer();
+
+            // Recycle the wrapper request and response
+            //req.recycle();
+            //res.recycle();
+          }
+        } finally {
+            if(mapRes != null ) 
+                mapRes.recycle();
+        }
+    }
+    
+    /** Coyote / mapper adapter. Result of the mapper.
+     *  
+     *  This replaces the valve chain, the path is: 
+     *    1. coyote calls mapper -> result Adapter 
+     *    2. service is called. Additional filters are set on the wrapper. 
+     * @param mapRes 
+     */
+    private void serviceServlet(ServletContextImpl ctx, 
+                               ServletRequestImpl req, 
+                               ServletResponseImpl res,
+                               ServletConfigImpl servletConfig, 
+                               MappingData mapRes) 
+            throws IOException {
+        Servlet servlet = null;
+        try {
+            if (servletConfig.isUnavailable()) {
+                handleUnavailable(res, servletConfig);
+                return;
+            }
+            try {
+                servlet = servletConfig.allocate();
+            } catch(ServletException ex) {
+                handleUnavailable(res, servletConfig);
+            }
+            WebappFilterMapper filterMap = ctx.getFilterMapper();
+            FilterChainImpl chain = 
+                filterMap.createFilterChain(req, servletConfig, servlet);
+            
+            try {
+                if (chain == null) {
+                    if (servlet != null) {
+                        servlet.service(req, res);
+                    } else {
+                        System.err.println("No servlet " + req.getRequestURI());
+                        res.sendError(404);
+                    }
+                } else {
+                    chain.doFilter(req, res);
+                }
+            } catch(UnavailableException ex) {
+                servletConfig.unavailable(ex);
+                handleUnavailable(res, servletConfig);
+                return;
+            }
+            
+            // servlet completed without exception. Check status
+            int status = res.getStatus();
+            if (status != 200 && !res.isCommitted()) {
+                String statusPage = ctx.findStatusPage(status);
+
+                if (statusPage != null) {
+                    ctx.handleStatusPage(req, res, status, statusPage);
+                } else {
+                    // Send a default message body.
+                    // TODO: maybe other mechanism to customize default.
+                    res.defaultStatusPage(status, res.getMessage());
+                }
+            }
+        } catch (Throwable t) {
+            ctx.handleError(req, res, t);
+        } finally {
+            if (servlet != null) {
+                servletConfig.deallocate(servlet);
+            }
+        }
+    }
+
+    private void handleUnavailable(ServletResponseImpl response, 
+                                   ServletConfigImpl servletConfig) 
+            throws IOException {
+        long available = servletConfig.getAvailable();
+        if ((available > 0L) && (available < Long.MAX_VALUE))
+            response.setDateHeader("Retry-After", available);
+        //  TODO: handle via error pages !
+        response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, 
+                "Service unavailable");
+    }
+    
+
+    // ------------ Notifications for JMX ----------------
+
+    void notifyAdd(Object o) {
+    }
+
+    void notifyRemove(Object o) {
+    }
+
+    public void setServerDir(String dir) {
+      this.serverDirName = dir;
+    }
+        
+    public File getWork() {
+        if (workDir == null) {
+          if (serverDirName == null) {
+              serverDirName = "./";
+          }
+          File rootDirFile = new File(serverDirName);
+          workDir = new File(rootDirFile, "tomcat-work");
+          if (workDir.exists()) {
+            workDir.mkdirs();
+          }
+        }
+        return workDir;
+    }
+    
+    /** 
+     * Init
+     * 
+     * @throws ServletException
+     * @throws IOException
+     */
+    public void init() throws ServletException, IOException {
+      getObjectManager().bind("TomcatLite", this);
+      if (contexts.size() == 0) {
+        setContext("/:./webapps/ROOT");
+      }
+      getConnector().setObjectManager(getObjectManager());
+      Iterator i1 = contexts.iterator();
+      while (i1.hasNext()) {
+        ServletContextImpl ctx = (ServletContextImpl) i1.next();
+        try {
+          ctx.init();
+        } catch (Throwable e) {
+          e.printStackTrace();
+        }
+      }
+    }
+    
+    /**
+     * Initialize an webapp and add it to the server. 
+     * - load web.xml
+     * - call 
+     * 
+     * @param rootDir
+     * @param path
+     * @param deployServlet
+     */
+    public void init(String rootDir, String path) 
+            throws ServletException, IOException {
+        
+        long t0 = System.currentTimeMillis();
+
+        ServletContextImpl ctx = 
+            (ServletContextImpl)addServletContext(null, 
+                                                  rootDir, 
+                                                  path);
+        ctx.init();
+        
+        long t1 = System.currentTimeMillis();
+        
+        // At this point all config is loaded. Contexts are not yet init()
+        // - this will happen on start.
+        System.err.println("Context.init() " + path + " " + (t1-t0));
+    }
+
+    /** 
+     * Get an empty request/response pair ( response available 
+     * as getResponse() ). Optional set input and output buffers.
+     * 
+     * This can be used for a connector-less interface to tomcat lite.
+     * 
+     * TODO: make it independent of coyote !
+     */
+    
+    public  ServletRequestImpl createMessage() {
+      ServletRequestImpl req = new ServletRequestImpl();
+      ServletResponseImpl res = req.getResponse();
+      
+      getConnector().initRequest(req, res);
+      
+      req.getHttpRequest().method().setString("GET");
+      req.getHttpRequest().protocol().setString("HTTP/1.1");
+      
+      return req;
+    }
+    
+    /**
+     * Used internally for mapping. 
+     */
+    private ServletRequestImpl createMessage(ServletContextImpl deployCtx,
+                                            String ctxPath,
+                                            String reqPath) {
+      ServletRequestImpl req = createMessage();
+      req.setContextPath(ctxPath);
+      req.setContext(deployCtx);
+      req.setRequestURI(ctxPath + reqPath);
+      return req;
+    }
+    
+
+    /** 
+     * Set a global filter that will be used for context mapping.
+     * 
+     * The filter will get a request, with requestUri and hostname set.
+     *  
+     * It needs to compute the context path and set it as an attribute.
+     * 
+     * Advanced features may include on-demand loading of webapps, large scale
+     * virtual hosting, etc.
+     */
+    public void setContextMapper(Filter hostMapper2) {
+        this.hostMapper = hostMapper2;
+    }
+
+    public void endRequest(ServletRequestImpl req,
+                           ServletResponseImpl res) throws IOException {
+     res.outputBuffer.flush();
+     req.getConnector().finishResponse(res);
+    }
+    
+    public Connector getConnector() {
+        if (connector == null) {
+            connector = (Connector) getObjectManager().get(Connector.class);
+            setConnector(connector);
+        }
+        return connector;
+    }
+
+    public void setConnector(Connector c) {
+        connector = c;
+        connector.setTomcatLite(this);
+        getObjectManager().bind("Connector", connector);
+    }
+
+    
+    public void setDaemon(boolean d) {
+        getConnector();
+        if (connector != null) {
+            connector.setDaemon(d);
+        }
+    }
+
+    public void startConnector() throws IOException {
+        getConnector();
+        if (connector != null) {
+            connector.start();
+        }
+    }
+
+    public void stopConnector() throws Exception {
+        if (connector != null) {
+            connector.stop();
+        }
+    }
+
+    public void run() {
+        try {
+            execute();
+        } catch (ServletException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+    
+    public void execute() throws ServletException, IOException {
+        init();
+        start();
+        startConnector();
+    }
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/WebappContextMapper.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/WebappContextMapper.java
new file mode 100644 (file)
index 0000000..d9abbd8
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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.apache.coyote.servlet;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.mapper.MappingData;
+
+/** 
+ * This handles host and context mapping.
+ * 
+ * The default implementation for tomcat lite is very limitted - 
+ * no support for virtual hosts, no support for contexts deeper than 
+ * 1 level. The intention is to override this with more advanced mappers.
+ * 
+ * With 'ConfigurableHosts' interface it is possible for a smart 
+ * mapper to load/unload virtual hosts at runtime, maybe from a 
+ * database. It should be possible to use databases to store huge number 
+ * of hosts or webapps. 
+ * 
+ */
+public class WebappContextMapper implements Filter {
+
+  ServletContext rootContext;
+  Map<String, ServletContext> contexts = new HashMap();
+
+  public WebappContextMapper() {
+  }
+
+  public void addHost(String name, String[] aliases) {
+  }
+  
+  /**
+   * Add a new Context to an existing Host.
+   *
+   * @param hostName Virtual host name this context belongs to
+   * @param contextPath Context path
+   * @param context Context object
+   * @param welcomeResources Welcome files defined for this context
+   * @param resources Static resources of the context
+   */
+  public void addContext(String hostName, 
+                         ServletContext context)
+      throws ServletException
+  {
+    String path = context.getContextPath();
+    if (path.lastIndexOf("/") > 0) {
+      throw new ServletException("Base context mapper supports only one level");
+    }
+    if ("/".equals(path)) {
+      rootContext = context;
+    }
+    MessageBytes mb = MessageBytes.newInstance();
+    mb.setChars(path.toCharArray(), 0, path.length());
+    contexts.put(mb.toString(), context);
+  }
+
+
+  /**
+   * Remove a context from an existing host.
+   *
+   * @param hostName Virtual host name this context belongs to
+   * @param path Context path
+   */
+  public void removeContext(String hostName, String path) 
+      throws ServletException {
+    if ("/".equals(path)) {
+      rootContext = null;
+    }
+    contexts.remove(path);  
+  }
+
+  /**
+   * Map the specified URI.
+   */
+  private void mapContext(ServletRequestImpl req)
+      throws IOException, ServletException {
+    MessageBytes uriMB = req.getDecodedRequestURIMB();
+    MappingData mappingData = req.getMappingData(); 
+    uriMB.toChars();
+    CharChunk uri = uriMB.getCharChunk();
+
+    
+    if (uri.length() < 2 || contexts.size() == 0) {
+      mappingData.context = rootContext;
+      if (rootContext != null) {
+        mappingData.contextPath.setString(rootContext.getContextPath());
+      }
+      return;
+    }
+    
+    int nextSlash = uri.indexOf('/', 1);
+    if (nextSlash == -1) {
+      nextSlash = uri.length();
+    }
+    mappingData.contextPath.setChars(uri.getChars(), 0, nextSlash);
+    ServletContext servletContext = contexts.get(mappingData.contextPath.toString());
+
+    if (servletContext != null) {
+      mappingData.context = servletContext;
+    } else {
+      mappingData.context = rootContext;
+      if (rootContext != null) {
+        mappingData.contextPath.setString(rootContext.getContextPath());      
+      }
+    }
+  }
+
+  public void init(FilterConfig filterConfig) throws ServletException {
+  }
+    
+  public void doFilter(ServletRequest request, 
+                       ServletResponse response, 
+                       FilterChain chain) 
+      throws IOException, ServletException {
+    ServletRequestImpl req = (ServletRequestImpl)request;
+    mapContext(req);
+  }
+    
+  public void destroy() {
+  }
+}
\ No newline at end of file
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/WebappFilterMapper.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/WebappFilterMapper.java
new file mode 100644 (file)
index 0000000..305b245
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ * 
+ * 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.apache.coyote.servlet;
+
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.Servlet;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.tomcat.servlets.util.RequestUtil;
+
+/**
+ * First filter after the context and servlet are mapped. It will add 
+ * web.xml-defined filters. 
+ * 
+ * costin: This is another mapping - done in RequestDispatcher or initial 
+ * mapping.
+ * Also: StandardHostValve - sets attribute for error pages,
+ *   StandardWrapperValve - mapping per invocation
+ *
+ * @author Greg Murray
+ * @author Remy Maucherat
+ */
+public class WebappFilterMapper implements Filter {
+
+
+    // -------------------------------------------------------------- Constants
+
+
+    public static final int ERROR = 1;
+    public static final Integer ERROR_INTEGER = new Integer(ERROR);
+    public static final int FORWARD = 2;
+    public static final Integer FORWARD_INTEGER = new Integer(FORWARD);
+    public static final int INCLUDE = 4;
+    public static final Integer INCLUDE_INTEGER = new Integer(INCLUDE);
+    public static final int REQUEST = 8;
+    public static final Integer REQUEST_INTEGER = new Integer(REQUEST);
+
+    /**
+     * Request dispatcher state.
+     */
+    public static final String DISPATCHER_TYPE_ATTR = 
+        "org.apache.catalina.core.DISPATCHER_TYPE";
+
+    /**
+     * Request dispatcher path.
+     */
+    public static final String DISPATCHER_REQUEST_PATH_ATTR = 
+        "org.apache.catalina.core.DISPATCHER_REQUEST_PATH";
+
+
+    // ----------------------------------------------------------- Constructors
+    ServletContextImpl servletContext;
+
+    public WebappFilterMapper() {
+    }
+
+    public WebappFilterMapper(ServletContextImpl impl) {
+        servletContext = impl;
+    }
+
+    public void setServletContext(ServletContextImpl sc) {
+        servletContext = sc;
+    }
+
+    // --------------------------------------------------------- Public Methods
+
+    ArrayList filterMaps = new ArrayList();
+    
+    public void addMapping(String filterName, 
+                           String url, 
+                           String servletName, 
+                           String type[], boolean isMatchAfter) {
+        FilterMap map = new FilterMap();
+        map.setURLPattern(url);
+        map.setFilterName(filterName);
+        map.setServletName(servletName);
+        if (isMatchAfter) {
+            filterMaps.add(map);
+        } else {
+            filterMaps.add(0, map);
+        }
+    }
+
+    /**
+     * Construct and return a FilterChain implementation that will wrap the
+     * execution of the specified servlet instance.  If we should not execute
+     * a filter chain at all, return <code>null</code>.
+     *
+     * @param request The servlet request we are processing
+     * @param servlet The servlet instance to be wrapped
+     */
+    public FilterChainImpl createFilterChain(ServletRequest request, 
+                                             ServletConfigImpl wrapper, 
+                                             Servlet servlet) {
+
+        // If there is no servlet to execute, return null
+        if (servlet == null)
+            return (null);
+
+        // get the dispatcher type
+        int dispatcher = -1; 
+        if (request.getAttribute(DISPATCHER_TYPE_ATTR) != null) {
+            Integer dispatcherInt = 
+                (Integer) request.getAttribute(DISPATCHER_TYPE_ATTR);
+            dispatcher = dispatcherInt.intValue();
+        }
+        String requestPath = null;
+        Object attribute = request.getAttribute(DISPATCHER_REQUEST_PATH_ATTR);
+        
+        if (attribute != null){
+            requestPath = attribute.toString();
+        }
+        
+        HttpServletRequest hreq = null;
+        if (request instanceof HttpServletRequest) 
+            hreq = (HttpServletRequest)request;
+
+        // Create and initialize a filter chain object
+        FilterChainImpl filterChain = null;
+        if ((request instanceof ServletRequestImpl)) {
+            ServletRequestImpl req = (ServletRequestImpl) request;
+            filterChain = (FilterChainImpl) req.getFilterChain();
+            filterChain.release();
+        } else {
+            // Security: Do not recycle
+            filterChain = new FilterChainImpl();
+        }
+
+        filterChain.setServlet(wrapper, servlet);
+
+        // If there are no filter mappings, we are done
+        if ((filterMaps.size() == 0))
+            return (filterChain);
+
+        // Acquire the information we will need to match filter mappings
+        String servletName = wrapper.getServletName();
+
+        int n = 0;
+
+        // TODO(costin): optimize: separate in 2 lists, one for url-mapped, one for
+        // servlet-name. Maybe even separate list for dispatcher and 
+        // non-dispatcher
+        
+        // TODO(costin): optimize: set the FilterConfig in the FilterMap, to 
+        // avoid second hash lookup
+        
+        // Add the relevant path-mapped filters to this filter chain
+        for (int i = 0; i < filterMaps.size(); i++) {
+            FilterMap filterMap = (FilterMap)filterMaps.get(i);
+            if (!matchDispatcher(filterMap ,dispatcher)) {
+                continue;
+            }
+            if (!matchFiltersURL(filterMap, requestPath))
+                continue;
+            FilterConfigImpl filterConfig = 
+                servletContext.getFilter(filterMap.getFilterName());
+            if (filterConfig == null) {
+                // FIXME - log configuration problem
+                continue;
+            }
+            filterChain.addFilter(filterConfig);
+            n++;
+        }
+
+        // Add filters that match on servlet name second
+        for (int i = 0; i < filterMaps.size(); i++) {
+            FilterMap filterMap = (FilterMap)filterMaps.get(i);
+            if (!matchDispatcher(filterMap ,dispatcher)) {
+                continue;
+            }
+            if (!matchFiltersServlet(filterMap, servletName))
+                continue;
+            FilterConfigImpl filterConfig = 
+                servletContext.getFilter(filterMap.getFilterName());
+            if (filterConfig == null) {
+                ;       // FIXME - log configuration problem
+                continue;
+            }
+            filterChain.addFilter(filterConfig);
+            n++;
+        }
+
+        // Return the completed filter chain
+        return (filterChain);
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Return <code>true</code> if the context-relative request path
+     * matches the requirements of the specified filter mapping;
+     * otherwise, return <code>null</code>.
+     *
+     * @param filterMap Filter mapping being checked
+     * @param requestPath Context-relative request path of this request
+     */
+    private boolean matchFiltersURL(FilterMap filterMap, String requestPath) {
+
+        if (requestPath == null)
+            return (false);
+
+        // Match on context relative request path
+        String testPath = filterMap.getURLPattern();
+        if (testPath == null)
+            return (false);
+
+        // Case 1 - Exact Match
+        if (testPath.equals(requestPath))
+            return (true);
+
+        // Case 2 - Path Match ("/.../*")
+        if (testPath.equals("/*"))
+            return (true);
+        if (testPath.endsWith("/*")) {
+            if (testPath.regionMatches(0, requestPath, 0, 
+                                       testPath.length() - 2)) {
+                if (requestPath.length() == (testPath.length() - 2)) {
+                    return (true);
+                } else if ('/' == requestPath.charAt(testPath.length() - 2)) {
+                    return (true);
+                }
+            }
+            return (false);
+        }
+
+        // Case 3 - Extension Match
+        if (testPath.startsWith("*.")) {
+            int slash = requestPath.lastIndexOf('/');
+            int period = requestPath.lastIndexOf('.');
+            if ((slash >= 0) && (period > slash) 
+                && (period != requestPath.length() - 1)
+                && ((requestPath.length() - period) 
+                    == (testPath.length() - 1))) {
+                return (testPath.regionMatches(2, requestPath, period + 1,
+                                               testPath.length() - 2));
+            }
+        }
+
+        // Case 4 - "Default" Match
+        return (false); // NOTE - Not relevant for selecting filters
+
+    }
+
+
+    /**
+     * Return <code>true</code> if the specified servlet name matches
+     * the requirements of the specified filter mapping; otherwise
+     * return <code>false</code>.
+     *
+     * @param filterMap Filter mapping being checked
+     * @param servletName Servlet name being checked
+     */
+    private boolean matchFiltersServlet(FilterMap filterMap, 
+                                        String servletName) {
+
+        if (servletName == null) {
+            return (false);
+        } else {
+            if (servletName.equals(filterMap.getServletName())) {
+                return (true);
+            } else {
+                return false;
+            }
+        }
+
+    }
+
+
+    /**
+     * Convienience method which returns true if  the dispatcher type
+     * matches the dispatcher types specified in the FilterMap
+     */
+    private boolean matchDispatcher(FilterMap filterMap, int dispatcher) {
+        switch (dispatcher) {
+            case FORWARD : {
+                if (filterMap.getDispatcherMapping() == FilterMap.FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.FORWARD_ERROR ||
+                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE) {
+                        return true;
+                }
+                break;
+            }
+            case INCLUDE : {
+                if (filterMap.getDispatcherMapping() == FilterMap.INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR ||
+                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE) {
+                        return true;
+                }
+                break;
+            }
+            case REQUEST : {
+                if (filterMap.getDispatcherMapping() == FilterMap.REQUEST ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE) {
+                        return true;
+                }
+                break;
+            }
+            case ERROR : {
+                if (filterMap.getDispatcherMapping() == FilterMap.ERROR ||
+                    filterMap.getDispatcherMapping() == FilterMap.FORWARD_ERROR || 
+                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR || 
+                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD || 
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE ||
+                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE) {
+                        return true;
+                }
+                break;
+            }
+        }
+        return false;
+    }
+
+
+    // -------------------- Map elements -----------------------
+    
+    public static class FilterMap implements Serializable {
+
+
+        // ------------------------------------------------------------- Properties
+
+
+        /**
+         * The name of this filter to be executed when this mapping matches
+         * a particular request.
+         */
+        
+        public static final int ERROR = 1;
+        public static final int FORWARD = 2;
+        public static final int FORWARD_ERROR =3;  
+        public static final int INCLUDE = 4;
+        public static final int INCLUDE_ERROR  = 5;
+        public static final int INCLUDE_ERROR_FORWARD  =6;
+        public static final int INCLUDE_FORWARD  = 7;
+        public static final int REQUEST = 8;
+        public static final int REQUEST_ERROR = 9;
+        public static final int REQUEST_ERROR_FORWARD = 10;
+        public static final int REQUEST_ERROR_FORWARD_INCLUDE = 11;
+        public static final int REQUEST_ERROR_INCLUDE = 12;
+        public static final int REQUEST_FORWARD = 13;
+        public static final int REQUEST_INCLUDE = 14;
+        public static final int REQUEST_FORWARD_INCLUDE= 15;
+        
+        // represents nothing having been set. This will be seen 
+        // as equal to a REQUEST
+        private static final int NOT_SET = -1;
+        
+        private int dispatcherMapping=NOT_SET;
+        
+        private String filterName = null;    
+
+        /**
+         * The URL pattern this mapping matches.
+         */
+        private String urlPattern = null;
+
+        /**
+         * The servlet name this mapping matches.
+         */
+        private String servletName = null;
+
+
+
+        public String getFilterName() {
+            return (this.filterName);
+        }
+
+        public void setFilterName(String filterName) {
+            this.filterName = filterName;
+        }
+
+
+        public String getServletName() {
+            return (this.servletName);
+        }
+
+        public void setServletName(String servletName) {
+            this.servletName = servletName;
+        }
+
+
+        public String getURLPattern() {
+            return (this.urlPattern);
+        }
+
+        public void setURLPattern(String urlPattern) {
+            this.urlPattern = RequestUtil.URLDecode(urlPattern);
+        }
+        
+        /**
+         *
+         * This method will be used to set the current state of the FilterMap
+         * representing the state of when filters should be applied:
+         *
+         *        ERROR
+         *        FORWARD
+         *        FORWARD_ERROR
+         *        INCLUDE
+         *        INCLUDE_ERROR
+         *        INCLUDE_ERROR_FORWARD
+         *        REQUEST
+         *        REQUEST_ERROR
+         *        REQUEST_ERROR_INCLUDE
+         *        REQUEST_ERROR_FORWARD_INCLUDE
+         *        REQUEST_INCLUDE
+         *        REQUEST_FORWARD,
+         *        REQUEST_FORWARD_INCLUDE
+         *
+         */
+        public void setDispatcher(String dispatcherString) {
+            String dispatcher = dispatcherString.toUpperCase();
+            
+            if (dispatcher.equals("FORWARD")) {
+
+                // apply FORWARD to the global dispatcherMapping.
+                switch (dispatcherMapping) {
+                    case NOT_SET  :  dispatcherMapping = FORWARD; break;
+                    case ERROR : dispatcherMapping = FORWARD_ERROR; break;
+                    case INCLUDE  :  dispatcherMapping = INCLUDE_FORWARD; break;
+                    case INCLUDE_ERROR  :  dispatcherMapping = INCLUDE_ERROR_FORWARD; break;
+                    case REQUEST : dispatcherMapping = REQUEST_FORWARD; break;
+                    case REQUEST_ERROR : dispatcherMapping = REQUEST_ERROR_FORWARD; break;
+                    case REQUEST_ERROR_INCLUDE : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
+                    case REQUEST_INCLUDE : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break;
+                }
+            } else if (dispatcher.equals("INCLUDE")) {
+                // apply INCLUDE to the global dispatcherMapping.
+                switch (dispatcherMapping) {
+                    case NOT_SET  :  dispatcherMapping = INCLUDE; break;
+                    case ERROR : dispatcherMapping = INCLUDE_ERROR; break;
+                    case FORWARD  :  dispatcherMapping = INCLUDE_FORWARD; break;
+                    case FORWARD_ERROR  :  dispatcherMapping = INCLUDE_ERROR_FORWARD; break;
+                    case REQUEST : dispatcherMapping = REQUEST_INCLUDE; break;
+                    case REQUEST_ERROR : dispatcherMapping = REQUEST_ERROR_INCLUDE; break;
+                    case REQUEST_ERROR_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
+                    case REQUEST_FORWARD : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break;
+                }
+            } else if (dispatcher.equals("REQUEST")) {
+                // apply REQUEST to the global dispatcherMapping.
+                switch (dispatcherMapping) {
+                    case NOT_SET  :  dispatcherMapping = REQUEST; break;
+                    case ERROR : dispatcherMapping = REQUEST_ERROR; break;
+                    case FORWARD  :  dispatcherMapping = REQUEST_FORWARD; break;
+                    case FORWARD_ERROR  :  dispatcherMapping = REQUEST_ERROR_FORWARD; break;
+                    case INCLUDE  :  dispatcherMapping = REQUEST_INCLUDE; break;
+                    case INCLUDE_ERROR  :  dispatcherMapping = REQUEST_ERROR_INCLUDE; break;
+                    case INCLUDE_FORWARD : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break;
+                    case INCLUDE_ERROR_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
+                }
+            }  else if (dispatcher.equals("ERROR")) {
+                // apply ERROR to the global dispatcherMapping.
+                switch (dispatcherMapping) {
+                    case NOT_SET  :  dispatcherMapping = ERROR; break;
+                    case FORWARD  :  dispatcherMapping = FORWARD_ERROR; break;
+                    case INCLUDE  :  dispatcherMapping = INCLUDE_ERROR; break;
+                    case INCLUDE_FORWARD : dispatcherMapping = INCLUDE_ERROR_FORWARD; break;
+                    case REQUEST : dispatcherMapping = REQUEST_ERROR; break;
+                    case REQUEST_INCLUDE : dispatcherMapping = REQUEST_ERROR_INCLUDE; break;
+                    case REQUEST_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD; break;
+                    case REQUEST_FORWARD_INCLUDE : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
+                }
+            }
+        }
+        
+        public int getDispatcherMapping() {
+            // per the SRV.6.2.5 absence of any dispatcher elements is
+            // equivelant to a REQUEST value
+            if (dispatcherMapping == NOT_SET) return REQUEST;
+            else return dispatcherMapping; 
+        }
+
+    }
+
+
+    public void init(FilterConfig filterConfig) throws ServletException {
+    }
+
+
+    public void doFilter(ServletRequest request, ServletResponse response, 
+                         FilterChain chain) 
+            throws IOException, ServletException {
+    }
+
+
+    public void destroy() {
+    }
+
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/WebappServletMapper.java b/modules/tomcat-lite/java/org/apache/coyote/servlet/WebappServletMapper.java
new file mode 100644 (file)
index 0000000..8e2f307
--- /dev/null
@@ -0,0 +1,883 @@
+/*
+ *  Copyright 1999-2004 The Apache Software Foundation
+ *
+ *  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.apache.coyote.servlet;
+
+import java.io.File;
+import java.io.IOException;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import org.apache.tomcat.util.buf.Ascii;
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.mapper.MappingData;
+
+/**
+ * Mapper, which implements the servlet API mapping rules (which are derived
+ * from the HTTP rules).
+ * 
+ * Based on catalina mapper - but simplified. All host and context mappings
+ * is done in HostMapper - this is just dealing with web.xml.
+ * 
+ * For corner cases ( very large number of rules, dynamic rules, etc ) you 
+ * can override the mapper for a context with a class extending this.
+ * 
+ * TODO: remove, use coyote-level mapper or user-space
+ */
+public class WebappServletMapper implements Filter {
+
+    /**
+     * Context associated with this wrapper, used for wrapper mapping.
+     */
+    public ContextMapElement contextMapElement = new ContextMapElement();
+
+
+    // --------------------------------------------------------- Public Methods
+    public WebappServletMapper() {
+    }
+    
+    public void setServletContext(ServletContextImpl impl) {
+        contextMapElement.object = impl;
+        contextMapElement.name = impl.getContextPath();        
+    }
+
+
+   /** Set context, used for wrapper mapping (request dispatcher).
+     *
+     * @param welcomeResources Welcome files defined for this context
+     * @param resources Static resources of the context
+     */
+    public void setContext(String path, String[] welcomeResources,
+                           File resources) {
+        contextMapElement.name = path;
+        contextMapElement.welcomeResources = welcomeResources;
+        contextMapElement.resources = resources;
+    }
+
+
+    /**
+     * Add a wrapper to the context associated with this wrapper.
+     *
+     * @param path Wrapper mapping
+     * @param wrapper The Wrapper object
+     */
+    public void addWrapper(String path, Object wrapper) {
+        addWrapper(contextMapElement, path, wrapper);
+    }
+
+
+    public void addWrapper(String path, Object wrapper, boolean jspWildCard) {
+        addWrapper(contextMapElement, path, wrapper, jspWildCard);
+    }
+
+
+    public void addWrapper(ContextMapElement context, String path, Object wrapper) {
+        addWrapper(context, path, wrapper, false);
+    }
+
+
+    /**
+     * Adds a wrapper to the given context.
+     *
+     * @param context The context to which to add the wrapper
+     * @param path Wrapper mapping
+     * @param wrapper The Wrapper object
+     * @param jspWildCard true if the wrapper corresponds to the JspServlet
+     * and the mapping path contains a wildcard; false otherwise
+     */
+    protected void addWrapper(ContextMapElement context, String path, Object wrapper,
+                              boolean jspWildCard) {
+
+        synchronized (context) {
+            WrapperMapElement newWrapper = new WrapperMapElement();
+            newWrapper.object = wrapper;
+            newWrapper.jspWildCard = jspWildCard;
+            if (path.endsWith("/*")) {
+                // Wildcard wrapper
+                newWrapper.name = path.substring(0, path.length() - 2);
+                WrapperMapElement[] oldWrappers = context.wildcardWrappers;
+                WrapperMapElement[] newWrappers =
+                    new WrapperMapElement[oldWrappers.length + 1];
+                if (insertMap(oldWrappers, newWrappers, newWrapper)) {
+                    context.wildcardWrappers = newWrappers;
+                    int slashCount = slashCount(newWrapper.name);
+                    if (slashCount > context.nesting) {
+                        context.nesting = slashCount;
+                    }
+                }
+            } else if (path.startsWith("*.")) {
+                // Extension wrapper
+                newWrapper.name = path.substring(2);
+                WrapperMapElement[] oldWrappers = context.extensionWrappers;
+                WrapperMapElement[] newWrappers =
+                    new WrapperMapElement[oldWrappers.length + 1];
+                if (insertMap(oldWrappers, newWrappers, newWrapper)) {
+                    context.extensionWrappers = newWrappers;
+                }
+            } else if (path.equals("/")) {
+                // Default wrapper
+                newWrapper.name = "";
+                context.defaultWrapper = newWrapper;
+            } else {
+                // Exact wrapper
+                newWrapper.name = path;
+                WrapperMapElement[] oldWrappers = context.exactWrappers;
+                WrapperMapElement[] newWrappers =
+                    new WrapperMapElement[oldWrappers.length + 1];
+                if (insertMap(oldWrappers, newWrappers, newWrapper)) {
+                    context.exactWrappers = newWrappers;
+                }
+            }
+        }
+    }
+
+
+    /**
+     * Remove a wrapper from the context associated with this wrapper.
+     *
+     * @param path Wrapper mapping
+     */
+    public void removeWrapper(String path) {
+        removeWrapper(contextMapElement, path);
+    }
+
+
+    protected void removeWrapper(ContextMapElement context, String path) {
+        synchronized (context) {
+            if (path.endsWith("/*")) {
+                // Wildcard wrapper
+                String name = path.substring(0, path.length() - 2);
+                WrapperMapElement[] oldWrappers = context.wildcardWrappers;
+                WrapperMapElement[] newWrappers =
+                    new WrapperMapElement[oldWrappers.length - 1];
+                if (removeMap(oldWrappers, newWrappers, name)) {
+                    // Recalculate nesting
+                    context.nesting = 0;
+                    for (int i = 0; i < newWrappers.length; i++) {
+                        int slashCount = slashCount(newWrappers[i].name);
+                        if (slashCount > context.nesting) {
+                            context.nesting = slashCount;
+                        }
+                    }
+                    context.wildcardWrappers = newWrappers;
+                }
+            } else if (path.startsWith("*.")) {
+                // Extension wrapper
+                String name = path.substring(2);
+                WrapperMapElement[] oldWrappers = context.extensionWrappers;
+                WrapperMapElement[] newWrappers =
+                    new WrapperMapElement[oldWrappers.length - 1];
+                if (removeMap(oldWrappers, newWrappers, name)) {
+                    context.extensionWrappers = newWrappers;
+                }
+            } else if (path.equals("/")) {
+                // Default wrapper
+                context.defaultWrapper = null;
+            } else {
+                // Exact wrapper
+                String name = path;
+                WrapperMapElement[] oldWrappers = context.exactWrappers;
+                WrapperMapElement[] newWrappers =
+                    new WrapperMapElement[oldWrappers.length - 1];
+                if (removeMap(oldWrappers, newWrappers, name)) {
+                    context.exactWrappers = newWrappers;
+                }
+            }
+        }
+    }
+
+    /**
+     * Map the specified URI relative to the context,
+     * mutating the given mapping data.
+     *
+     * @param uri URI
+     * @param mappingData This structure will contain the result of the mapping
+     *                    operation
+     */
+    public void map(MessageBytes uri, MappingData mappingData)
+        throws Exception {
+
+        uri.toChars();
+        CharChunk uricc = uri.getCharChunk();
+        //uricc.setLimit(-1);
+        internalMapWrapper(contextMapElement, uricc, mappingData);
+
+    }
+
+
+    // -------------------------------------------------------- Private Methods
+
+
+    /**
+     * Wrapper mapping.
+     */
+    private final void internalMapWrapper(ContextMapElement context,
+                                          CharChunk path,
+                                          MappingData mappingData)
+        throws Exception {
+
+        int pathOffset = path.getOffset();
+        int pathEnd = path.getEnd();
+        int servletPath = pathOffset;
+        boolean noServletPath = false;
+
+        int length = context.name.length();
+        if (length == 1) length--;
+        if (length != (pathEnd - pathOffset)) {
+            servletPath = pathOffset + length;
+        } else {
+            noServletPath = true;
+            // What is this doing ??? 
+            path.append('/');
+            pathOffset = path.getOffset();
+            pathEnd = path.getEnd();
+            servletPath = pathOffset+length;
+        }
+
+        path.setOffset(servletPath);
+
+        // Rule 1 -- Exact Match
+        WrapperMapElement[] exactWrappers = context.exactWrappers;
+        internalMapExactWrapper(exactWrappers, path, mappingData);
+
+        // Rule 2 -- Prefix Match
+        boolean checkJspWelcomeFiles = false;
+        WrapperMapElement[] wildcardWrappers = context.wildcardWrappers;
+        if (mappingData.wrapper == null) {
+            internalMapWildcardWrapper(wildcardWrappers, context.nesting, 
+                                       path, mappingData);
+            if (mappingData.wrapper != null && mappingData.jspWildCard) {
+                char[] buf = path.getBuffer();
+                if (buf[pathEnd - 1] == '/') {
+                    /*
+                     * Path ending in '/' was mapped to JSP servlet based on
+                     * wildcard match (e.g., as specified in url-pattern of a
+                     * jsp-property-group.
+                     * Force the context's welcome files, which are interpreted
+                     * as JSP files (since they match the url-pattern), to be
+                     * considered. See Bugzilla 27664.
+                     */ 
+                    mappingData.wrapper = null;
+                    checkJspWelcomeFiles = true;
+                } else {
+                    // See Bugzilla 27704
+                    mappingData.wrapperPath.setChars(buf, path.getStart(),
+                                                     path.getLength());
+                    mappingData.pathInfo.recycle();
+                }
+            }
+        }
+
+        if(mappingData.wrapper == null && noServletPath) {
+            // The path is empty, redirect to "/"
+            mappingData.redirectPath.setChars
+                (path.getBuffer(), pathOffset, pathEnd);
+            path.setEnd(pathEnd - 1);
+            return;
+        }
+
+        // Rule 3 -- Extension Match
+        WrapperMapElement[] extensionWrappers = context.extensionWrappers;
+        if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
+            internalMapExtensionWrapper(extensionWrappers, path, mappingData);
+        }
+
+        File file = null;
+        // Rule 4 -- Welcome resources processing for servlets
+        if (mappingData.wrapper == null) {
+            boolean checkWelcomeFiles = checkJspWelcomeFiles;
+            if (!checkWelcomeFiles) {
+                char[] buf = path.getBuffer();
+                checkWelcomeFiles = (buf[pathEnd - 1] == '/');
+            }
+            if (checkWelcomeFiles) {
+                for (int i = 0; (i < context.welcomeResources.length)
+                         && (mappingData.wrapper == null); i++) {
+                    path.setOffset(pathOffset);
+                    path.setEnd(pathEnd);
+                    path.append(context.welcomeResources[i], 0,
+                                context.welcomeResources[i].length());
+                    path.setOffset(servletPath);
+
+                    // Rule 4a -- Welcome resources processing for exact macth
+                    internalMapExactWrapper(exactWrappers, path, mappingData);
+
+                    // Rule 4b -- Welcome resources processing for prefix match
+                    if (mappingData.wrapper == null) {
+                        internalMapWildcardWrapper
+                            (wildcardWrappers, context.nesting, 
+                             path, mappingData);
+                    }
+
+                    // Rule 4c -- Welcome resources processing
+                    //            for physical folder
+                    if (mappingData.wrapper == null
+                        && context.resources != null) {
+                        // Default servlet: check if it's file or dir to apply
+                        // welcome files rules. 
+                        // TODO: Save the File in attributes, 
+                        // to avoid duplication in DefaultServlet.
+                        
+                        String pathStr = path.toString();
+                        file = new File(context.resources, pathStr);
+                        if (file.exists() && !(file.isDirectory()) ) {
+                            
+                            internalMapExtensionWrapper(extensionWrappers,
+                                                        path, mappingData);
+                            if (mappingData.wrapper == null
+                                && context.defaultWrapper != null) {
+                                mappingData.wrapper =
+                                    context.defaultWrapper.object;
+                                mappingData.requestPath.setChars
+                                    (path.getBuffer(), path.getStart(), 
+                                     path.getLength());
+                                mappingData.wrapperPath.setChars
+                                    (path.getBuffer(), path.getStart(), 
+                                     path.getLength());
+                                mappingData.requestPath.setString(pathStr);
+                                mappingData.wrapperPath.setString(pathStr);
+                            }
+                        }
+                    }
+                }
+
+                path.setOffset(servletPath);
+                path.setEnd(pathEnd);
+            }
+                                        
+        }
+
+
+        // Rule 7 -- Default servlet
+        if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
+            if (context.defaultWrapper != null) {
+                mappingData.wrapper = context.defaultWrapper.object;
+                mappingData.requestPath.setChars
+                    (path.getBuffer(), path.getStart(), path.getLength());
+                mappingData.wrapperPath.setChars
+                    (path.getBuffer(), path.getStart(), path.getLength());
+            }
+            // Redirection to a folder
+            char[] buf = path.getBuffer();
+            if (context.resources != null && buf[pathEnd -1 ] != '/') {
+                String pathStr = path.toString();
+                file = new File( context.resources, pathStr);
+                if (file.exists() && file.isDirectory()) {
+                    // Note: this mutates the path: do not do any processing 
+                    // after this (since we set the redirectPath, there 
+                    // shouldn't be any)
+                    path.setOffset(pathOffset);
+                    path.append('/');
+                    mappingData.redirectPath.setChars
+                        (path.getBuffer(), path.getStart(), path.getLength());
+                } else {
+                    mappingData.requestPath.setString(pathStr);
+                    mappingData.wrapperPath.setString(pathStr);
+                }
+            }
+        }
+
+        path.setOffset(pathOffset);
+        path.setEnd(pathEnd);
+    }
+
+
+    /**
+     * Exact mapping.
+     */
+    private final void internalMapExactWrapper
+        (WrapperMapElement[] wrappers, CharChunk path, MappingData mappingData) {
+        int pos = find(wrappers, path);
+        if ((pos != -1) && (path.equals(wrappers[pos].name))) {
+            mappingData.requestPath.setString(wrappers[pos].name);
+            mappingData.wrapperPath.setString(wrappers[pos].name);
+            mappingData.wrapper = wrappers[pos].object;
+        }
+    }
+
+
+    /**
+     * Wildcard mapping.
+     */
+    private final void internalMapWildcardWrapper
+        (WrapperMapElement[] wrappers, int nesting, CharChunk path, 
+         MappingData mappingData) {
+
+        int pathEnd = path.getEnd();
+        int pathOffset = path.getOffset();
+
+        int lastSlash = -1;
+        int length = -1;
+        int pos = find(wrappers, path);
+        if (pos != -1) {
+            boolean found = false;
+            while (pos >= 0) {
+                if (path.startsWith(wrappers[pos].name)) {
+                    length = wrappers[pos].name.length();
+                    if (path.getLength() == length) {
+                        found = true;
+                        break;
+                    } else if (path.startsWithIgnoreCase("/", length)) {
+                        found = true;
+                        break;
+                    }
+                }
+                if (lastSlash == -1) {
+                    lastSlash = nthSlash(path, nesting + 1);
+                } else {
+                    lastSlash = lastSlash(path);
+                }
+                path.setEnd(lastSlash);
+                pos = find(wrappers, path);
+            }
+            path.setEnd(pathEnd);
+            if (found) {
+                mappingData.wrapperPath.setString(wrappers[pos].name);
+                if (path.getLength() > length) {
+                    mappingData.pathInfo.setChars
+                        (path.getBuffer(),
+                         path.getOffset() + length,
+                         path.getLength() - length);
+                }
+                mappingData.requestPath.setChars
+                    (path.getBuffer(), path.getOffset(), path.getLength());
+                mappingData.wrapper = wrappers[pos].object;
+                mappingData.jspWildCard = wrappers[pos].jspWildCard;
+            }
+        }
+    }
+
+
+    /**
+     * Extension mappings.
+     */
+    private final void internalMapExtensionWrapper
+        (WrapperMapElement[] wrappers, CharChunk path, MappingData mappingData) {
+        char[] buf = path.getBuffer();
+        int pathEnd = path.getEnd();
+        int servletPath = path.getOffset();
+        int slash = -1;
+        for (int i = pathEnd - 1; i >= servletPath; i--) {
+            if (buf[i] == '/') {
+                slash = i;
+                break;
+            }
+        }
+        if (slash == -1 ) slash = 0;
+        if (slash >= 0) {
+            int period = -1;
+            for (int i = pathEnd - 1; i > slash; i--) {
+                if (buf[i] == '.') {
+                    period = i;
+                    break;
+                }
+            }
+            if (period >= 0) {
+                path.setOffset(period + 1);
+                path.setEnd(pathEnd);
+                int pos = find(wrappers, path);
+                if ((pos != -1)
+                    && (path.equals(wrappers[pos].name))) {
+                    mappingData.wrapperPath.setChars
+                        (buf, servletPath, pathEnd - servletPath);
+                    mappingData.requestPath.setChars
+                        (buf, servletPath, pathEnd - servletPath);
+                    mappingData.wrapper = wrappers[pos].object;
+                }
+                path.setOffset(servletPath);
+                path.setEnd(pathEnd);
+            }
+        }
+    }
+
+
+    /**
+     * Find a map elemnt given its name in a sorted array of map elements.
+     * This will return the index for the closest inferior or equal item in the
+     * given array.
+     */
+    public static final int find(MapElement[] map, CharChunk name) {
+        return find(map, name, name.getStart(), name.getEnd());
+    }
+
+
+    /**
+     * Find a map elemnt given its name in a sorted array of map elements.
+     * This will return the index for the closest inferior or equal item in the
+     * given array.
+     */
+    private static final int find(MapElement[] map, CharChunk name,
+                                  int start, int end) {
+
+        int a = 0;
+        int b = map.length - 1;
+
+        // Special cases: -1 and 0
+        if (b == -1) {
+            return -1;
+        }
+        
+        if (compare(name, start, end, map[0].name) < 0 ) {
+            return -1;
+        }         
+        if (b == 0) {
+            return 0;
+        }
+
+        int i = 0;
+        while (true) {
+            i = (b + a) / 2;
+            int result = compare(name, start, end, map[i].name);
+            if (result == 1) {
+                a = i;
+            } else if (result == 0) {
+                return i;
+            } else {
+                b = i;
+            }
+            if ((b - a) == 1) {
+                int result2 = compare(name, start, end, map[b].name);
+                if (result2 < 0) {
+                    return a;
+                } else {
+                    return b;
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Find a map elemnt given its name in a sorted array of map elements.
+     * This will return the index for the closest inferior or equal item in the
+     * given array.
+     */
+    private static final int findIgnoreCase(MapElement[] map, CharChunk name) {
+        return findIgnoreCase(map, name, name.getStart(), name.getEnd());
+    }
+
+
+    /**
+     * Find a map elemnt given its name in a sorted array of map elements.
+     * This will return the index for the closest inferior or equal item in the
+     * given array.
+     */
+    private static final int findIgnoreCase(MapElement[] map, CharChunk name,
+                                  int start, int end) {
+
+        int a = 0;
+        int b = map.length - 1;
+
+        // Special cases: -1 and 0
+        if (b == -1) {
+            return -1;
+        }
+        if (compareIgnoreCase(name, start, end, map[0].name) < 0 ) {
+            return -1;
+        }         
+        if (b == 0) {
+            return 0;
+        }
+
+        int i = 0;
+        while (true) {
+            i = (b + a) / 2;
+            int result = compareIgnoreCase(name, start, end, map[i].name);
+            if (result == 1) {
+                a = i;
+            } else if (result == 0) {
+                return i;
+            } else {
+                b = i;
+            }
+            if ((b - a) == 1) {
+                int result2 = compareIgnoreCase(name, start, end, map[b].name);
+                if (result2 < 0) {
+                    return a;
+                } else {
+                    return b;
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Find a map elemnt given its name in a sorted array of map elements.
+     * This will return the index for the closest inferior or equal item in the
+     * given array.
+     */
+    public static final int find(MapElement[] map, String name) {
+
+        int a = 0;
+        int b = map.length - 1;
+
+        // Special cases: -1 and 0
+        if (b == -1) {
+            return -1;
+        }
+        
+        if (name.compareTo(map[0].name) < 0) {
+            return -1;
+        } 
+        if (b == 0) {
+            return 0;
+        }
+
+        int i = 0;
+        while (true) {
+            i = (b + a) / 2;
+            int result = name.compareTo(map[i].name);
+            if (result > 0) {
+                a = i;
+            } else if (result == 0) {
+                return i;
+            } else {
+                b = i;
+            }
+            if ((b - a) == 1) {
+                int result2 = name.compareTo(map[b].name);
+                if (result2 < 0) {
+                    return a;
+                } else {
+                    return b;
+                }
+            }
+        }
+
+    }
+
+
+    /**
+     * Compare given char chunk with String.
+     * Return -1, 0 or +1 if inferior, equal, or superior to the String.
+     */
+    private static final int compare(CharChunk name, int start, int end,
+                                     String compareTo) {
+        int result = 0;
+        char[] c = name.getBuffer();
+        int len = compareTo.length();
+        if ((end - start) < len) {
+            len = end - start;
+        }
+        for (int i = 0; (i < len) && (result == 0); i++) {
+            if (c[i + start] > compareTo.charAt(i)) {
+                result = 1;
+            } else if (c[i + start] < compareTo.charAt(i)) {
+                result = -1;
+            }
+        }
+        if (result == 0) {
+            if (compareTo.length() > (end - start)) {
+                result = -1;
+            } else if (compareTo.length() < (end - start)) {
+                result = 1;
+            }
+        }
+        return result;
+    }
+
+
+    /**
+     * Compare given char chunk with String ignoring case.
+     * Return -1, 0 or +1 if inferior, equal, or superior to the String.
+     */
+    private static final int compareIgnoreCase(CharChunk name, int start, int end,
+                                     String compareTo) {
+        int result = 0;
+        char[] c = name.getBuffer();
+        int len = compareTo.length();
+        if ((end - start) < len) {
+            len = end - start;
+        }
+        for (int i = 0; (i < len) && (result == 0); i++) {
+            if (Ascii.toLower(c[i + start]) > Ascii.toLower(compareTo.charAt(i))) {
+                result = 1;
+            } else if (Ascii.toLower(c[i + start]) < Ascii.toLower(compareTo.charAt(i))) {
+                result = -1;
+            }
+        }
+        if (result == 0) {
+            if (compareTo.length() > (end - start)) {
+                result = -1;
+            } else if (compareTo.length() < (end - start)) {
+                result = 1;
+            }
+        }
+        return result;
+    }
+
+
+    /**
+     * Find the position of the last slash in the given char chunk.
+     */
+    public static final int lastSlash(CharChunk name) {
+
+        char[] c = name.getBuffer();
+        int end = name.getEnd();
+        int start = name.getStart();
+        int pos = end;
+
+        while (pos > start) {
+            if (c[--pos] == '/') {
+                break;
+            }
+        }
+
+        return (pos);
+
+    }
+
+
+    /**
+     * Find the position of the nth slash, in the given char chunk.
+     */
+    public static final int nthSlash(CharChunk name, int n) {
+
+        char[] c = name.getBuffer();
+        int end = name.getEnd();
+        int start = name.getStart();
+        int pos = start;
+        int count = 0;
+
+        while (pos < end) {
+            if ((c[pos++] == '/') && ((++count) == n)) {
+                pos--;
+                break;
+            }
+        }
+
+        return (pos);
+
+    }
+
+
+    /**
+     * Return the slash count in a given string.
+     */
+    public static final int slashCount(String name) {
+        int pos = -1;
+        int count = 0;
+        while ((pos = name.indexOf('/', pos + 1)) != -1) {
+            count++;
+        }
+        return count;
+    }
+
+
+    /**
+     * Insert into the right place in a sorted MapElement array, and prevent
+     * duplicates.
+     */
+    public static final boolean insertMap
+        (MapElement[] oldMap, MapElement[] newMap, MapElement newElement) {
+        int pos = find(oldMap, newElement.name);
+        if ((pos != -1) && (newElement.name.equals(oldMap[pos].name))) {
+            return false;
+        }
+        System.arraycopy(oldMap, 0, newMap, 0, pos + 1);
+        newMap[pos + 1] = newElement;
+        System.arraycopy
+            (oldMap, pos + 1, newMap, pos + 2, oldMap.length - pos - 1);
+        return true;
+    }
+
+
+    /**
+     * Insert into the right place in a sorted MapElement array.
+     */
+    public static final boolean removeMap
+        (MapElement[] oldMap, MapElement[] newMap, String name) {
+        int pos = find(oldMap, name);
+        if ((pos != -1) && (name.equals(oldMap[pos].name))) {
+            System.arraycopy(oldMap, 0, newMap, 0, pos);
+            System.arraycopy(oldMap, pos + 1, newMap, pos,
+                             oldMap.length - pos - 1);
+            return true;
+        }
+        return false;
+    }
+
+
+    // ------------------------------------------------- MapElement Inner Class
+
+
+    protected static abstract class MapElement {
+        /** hostname or path  
+         */
+        public String name = null;
+        public Object object = null;
+
+        public String toString() {
+            return "MapElement: \"" + name +"\"";
+        }
+    }
+
+
+    // ---------------------------------------------------- Context Inner Class
+
+
+    public static final class ContextMapElement
+        extends MapElement {
+
+        public String[] welcomeResources = new String[0];
+        public File resources = null;
+        public WrapperMapElement defaultWrapper = null;
+        public WrapperMapElement[] exactWrappers = new WrapperMapElement[0];
+        public WrapperMapElement[] wildcardWrappers = new WrapperMapElement[0];
+        public WrapperMapElement[] extensionWrappers = new WrapperMapElement[0];
+        public int nesting = 0;
+
+        public String toString() {
+            return "ContextMapElement {" +
+            "name: \"" + name +
+            "\"\nnesting: \"" + nesting +
+            "\"\n}";
+        }
+    }
+
+
+    // ---------------------------------------------------- Wrapper Inner Class
+
+
+    public static class WrapperMapElement
+        extends MapElement {
+        public boolean jspWildCard = false;
+    }
+
+
+    public void destroy() {
+    }
+
+
+    public void doFilter(ServletRequest request, ServletResponse response,
+                         FilterChain chain) throws IOException,
+        ServletException {
+    }
+
+
+    public void init(FilterConfig filterConfig) throws ServletException {
+    }
+
+   
+}
diff --git a/modules/tomcat-lite/java/org/apache/coyote/servlet/config.properties b/modules/tomcat-lite/java/org/apache/coyote/servlet/config.properties
new file mode 100644 (file)
index 0000000..0a5d658
--- /dev/null
@@ -0,0 +1,34 @@
+# Support for PropertiesSpi - the 'dummy' framework used for tomcat-lite
+# If tomcat is used with a proper framework, you need to bind and configure 
+# those objects in the framework. 
+
+Main.(class)=org.apache.coyote.servlet.TomcatLite
+
+Jmx.(class)=org.apache.tomcat.integration.jmx.JmxObjectManagerSpi
+
+# --- Class names for required plugin interfaces --- 
+
+org.apache.coyote.servlet.WebappServletMapper.(class)=org.apache.coyote.servlet.WebappServletMapper
+org.apache.coyote.servlet.WebappFilterMapper.(class)=org.apache.coyote.servlet.WebappFilterMapper
+
+# Sessions
+org.apache.tomcat.servlets.session.UserSessionManager.(class)=org.apache.tomcat.servlets.session.SimpleSessionManager
+
+# Loader for web.xml - you can have your own custom class using a more efficient
+# or hardcoded.
+org.apache.coyote.servlet.ContextPreinitListener.(class)=org.apache.coyote.servlet.webxml.TomcatLiteWebXmlConfig
+
+# Connector class
+org.apache.coyote.servlet.Connector.(class)=org.apache.coyote.servlet.CoyoteConnector
+
+# JMX 
+jmx-connector.(class)=org.apache.tomcat.integration.jmx.JmxObjectManagerSpi
+
+# --- Other required settings ---
+
+# Customize default and *.jsp mappings
+default-servlet.(class)=org.apache.tomcat.servlets.file.WebdavServlet
+jspwildcard-servlet.(class)=org.apache.tomcat.servlets.jsp.WildcardTemplateServlet
+filetemplate-servlet.(class)=org.apache.tomcat.servlets.jsp.JspFileTemplateServlet
+
+
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/BodyReader.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/BodyReader.java
deleted file mode 100644 (file)
index e8f8a6b..0000000
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.tomcat.lite;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Reader;
-import java.util.HashMap;
-
-import org.apache.tomcat.util.buf.B2CConverter;
-import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.buf.CharChunk;
-
-/**
- * Refactored from catalina.connector.InputBuffer. Renamed to avoid conflict
- * with coyote class.
- * 
- */
-
-/**
- * The buffer used by Tomcat request. This is a derivative of the Tomcat 3.3
- * OutputBuffer, adapted to handle input instead of output. This allows 
- * complete recycling of the facade objects (the ServletInputStream and the
- * BufferedReader).
- *
- * @author Remy Maucherat
- */
-public class BodyReader extends Reader
-    implements ByteChunk.ByteInputChannel, CharChunk.CharInputChannel,
-               CharChunk.CharOutputChannel {
-
-
-    // -------------------------------------------------------------- Constants
-
-
-    public static final String DEFAULT_ENCODING = 
-        org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
-    public static final int DEFAULT_BUFFER_SIZE = 8*1024;
-
-    // The buffer can be used for byte[] and char[] reading
-    // ( this is needed to support ServletInputStream and BufferedReader )
-    public final int INITIAL_STATE = 0;
-    public final int CHAR_STATE = 1;
-    public final int BYTE_STATE = 2;
-
-
-    // ----------------------------------------------------- Instance Variables
-
-
-    /**
-     * The byte buffer. More data may be added to it while reading.
-     */
-    private ByteChunk bb;
-
-
-    /**
-     * The chunk buffer, will be filled in from the bb.
-     */
-    private CharChunk cb;
-
-
-    /**
-     * State of the output buffer.
-     */
-    private int state = 0;
-
-
-    /**
-     * Number of bytes read.
-     */
-    private int bytesRead = 0;
-
-
-    /**
-     * Number of chars read.
-     */
-    private int charsRead = 0;
-
-
-    /**
-     * Flag which indicates if the input buffer is closed.
-     */
-    private boolean closed = false;
-
-    /**
-     * Encoding to use.
-     */
-    private String enc;
-
-
-    /**
-     * Encoder is set.
-     */
-    private boolean gotEnc = false;
-
-
-    /**
-     * Cached encoders.
-     */
-    protected HashMap<String, B2CConverter> encoders = 
-      new HashMap<String, B2CConverter>();
-
-
-    /**
-     * Current byte to char converter.
-     */
-    protected B2CConverter conv;
-
-
-    /**
-     * Associated Coyote request.
-     */
-    private ServletRequestImpl coyoteRequest;
-    Connector connector;
-
-    /**
-     * Buffer position.
-     */
-    private int markPos = -1;
-
-
-    /**
-     * Buffer size.
-     */
-    private int size = -1;
-
-
-    // ----------------------------------------------------------- Constructors
-
-
-    /**
-     * Default constructor. Allocate the buffer with the default buffer size.
-     */
-    public BodyReader() {
-        this(DEFAULT_BUFFER_SIZE);
-    }
-
-
-    /**
-     * Alternate constructor which allows specifying the initial buffer size.
-     * 
-     * @param size Buffer size to use
-     */
-    public BodyReader(int size) {
-        this.size = size;
-        bb = new ByteChunk(size);
-        bb.setLimit(size);
-        bb.setByteInputChannel(this);
-        cb = new CharChunk(size);
-        cb.setLimit(size);
-        cb.setOptimizedWrite(false);
-        cb.setCharInputChannel(this);
-        cb.setCharOutputChannel(this);
-    }
-
-
-    // ------------------------------------------------------------- Properties
-
-
-    /**
-     * Associated Coyote request.
-     * 
-     * @param coyoteRequest Associated Coyote request
-     */
-    public void setConnector(Connector c, ServletRequestImpl coyoteRequest) {
-        this.connector = c;
-        this.coyoteRequest = coyoteRequest;
-    }
-
-
-
-    // --------------------------------------------------------- Public Methods
-
-
-    /**
-     * Recycle the output buffer.
-     */
-    public void recycle() {
-        
-        state = INITIAL_STATE;
-        bytesRead = 0;
-        charsRead = 0;
-        
-        // If usage of mark made the buffer too big, reallocate it
-        if (cb.getChars().length > size) {
-            cb = new CharChunk(size);
-            cb.setLimit(size);
-            cb.setCharInputChannel(this);
-            cb.setCharOutputChannel(this);
-        } else {
-            cb.recycle();
-        }
-        markPos = -1;
-        bb.recycle(); 
-        closed = false;
-        
-        if (conv != null) {
-            conv.recycle();
-        }
-        
-        gotEnc = false;
-        enc = null;
-        
-    }
-
-
-    /**
-     * Close the input buffer.
-     * 
-     * @throws IOException An underlying IOException occurred
-     */
-    public void close()
-        throws IOException {
-        closed = true;
-    }
-
-
-    public int available()
-        throws IOException {
-        if (state == BYTE_STATE) {
-            return bb.getLength();
-        } else if (state == CHAR_STATE) {
-            return cb.getLength();
-        } else {
-            return 0;
-        }
-    }
-
-
-    // ------------------------------------------------- Bytes Handling Methods
-
-
-    /** 
-     * Reads new bytes in the byte chunk.
-     * 
-     * @param cbuf Byte buffer to be written to the response
-     * @param off Offset
-     * @param len Length
-     * 
-     * @throws IOException An underlying IOException occurred
-     */
-    public int realReadBytes(byte cbuf[], int off, int len)
-       throws IOException {
-
-        if (closed)
-            return -1;
-        if (coyoteRequest == null)
-            return -1;
-
-        state = BYTE_STATE;
-
-        int result = connector.doRead(coyoteRequest, bb);
-
-        return result;
-
-    }
-
-
-    public int readByte()
-        throws IOException {
-        return bb.substract();
-    }
-
-
-    public int read(byte[] b, int off, int len)
-        throws IOException {
-        return bb.substract(b, off, len);
-    }
-
-
-    // ------------------------------------------------- Chars Handling Methods
-
-
-    /**
-     * Since the converter will use append, it is possible to get chars to
-     * be removed from the buffer for "writing". Since the chars have already
-     * been read before, they are ignored. If a mark was set, then the
-     * mark is lost.
-     */
-    public void realWriteChars(char c[], int off, int len) 
-        throws IOException {
-        markPos = -1;
-    }
-
-
-    public void setEncoding(String s) {
-        enc = s;
-    }
-
-    /** 
-     * Called when a read(char[]) operation is lacking data. It will read
-     * bytes.
-     */
-    public int realReadChars(char cbuf[], int off, int len)
-        throws IOException {
-
-        if (!gotEnc)
-            setConverter();
-
-        if (bb.getLength() <= 0) {
-            int nRead = realReadBytes(bb.getBytes(), 0, bb.getBytes().length);
-            if (nRead < 0) {
-                return -1;
-            }
-        }
-
-        if (markPos == -1) {
-            cb.setOffset(0);
-            cb.setEnd(0);
-        }
-
-        conv.convert(bb, cb, -1);
-        bb.setOffset(bb.getEnd());
-        state = CHAR_STATE;
-
-        return cb.getLength();
-
-    }
-
-
-    public int read()
-        throws IOException {
-        return cb.substract();
-    }
-
-
-    public int read(char[] cbuf)
-        throws IOException {
-        return read(cbuf, 0, cbuf.length);
-    }
-
-
-    public int read(char[] cbuf, int off, int len)
-        throws IOException {
-        return cb.substract(cbuf, off, len);
-    }
-
-
-    public long skip(long n)
-        throws IOException {
-
-        if (n < 0) {
-            throw new IllegalArgumentException();
-        }
-
-        long nRead = 0;
-        while (nRead < n) {
-            if (cb.getLength() >= n) {
-                cb.setOffset(cb.getStart() + (int) n);
-                nRead = n;
-            } else {
-                nRead += cb.getLength();
-                cb.setOffset(cb.getEnd());
-                int toRead = 0;
-                if (cb.getChars().length < (n - nRead)) {
-                    toRead = cb.getChars().length;
-                } else {
-                    toRead = (int) (n - nRead);
-                }
-                int nb = realReadChars(cb.getChars(), 0, toRead);
-                if (nb < 0)
-                    break;
-            }
-        }
-
-        return nRead;
-
-    }
-
-
-    public boolean ready()
-        throws IOException {
-        return (cb.getLength() > 0);
-    }
-
-
-    public boolean markSupported() {
-        return true;
-    }
-
-
-    public void mark(int readAheadLimit)
-        throws IOException {
-        if (cb.getLength() <= 0) {
-            cb.setOffset(0);
-            cb.setEnd(0);
-        } else {
-            if ((cb.getBuffer().length > (2 * size)) 
-                && (cb.getLength()) < (cb.getStart())) {
-                System.arraycopy(cb.getBuffer(), cb.getStart(), 
-                                 cb.getBuffer(), 0, cb.getLength());
-                cb.setEnd(cb.getLength());
-                cb.setOffset(0);
-            }
-        }
-        int offset = readAheadLimit;
-        if (offset < size) {
-            offset = size;
-        }
-        cb.setLimit(cb.getStart() + offset);
-        markPos = cb.getStart();
-    }
-
-
-    public void reset()
-        throws IOException {
-        if (state == CHAR_STATE) {
-            if (markPos < 0) {
-                cb.recycle();
-                markPos = -1;
-                throw new IOException();
-            } else {
-                cb.setOffset(markPos);
-            }
-        } else {
-            bb.recycle();
-        }
-    }
-
-
-    protected void setConverter()
-        throws IOException {
-        if (coyoteRequest != null)
-            enc = coyoteRequest.getCharacterEncoding();
-
-        gotEnc = true;
-        if (enc == null)
-            enc = DEFAULT_ENCODING;
-        conv = (B2CConverter) encoders.get(enc);
-        if (conv == null) {
-          conv = new B2CConverter(enc);
-          encoders.put(enc, conv);
-        }
-    }
-    
-    public class MRInputStream extends InputStream {
-        public long skip(long n)
-                throws IOException {
-            return BodyReader.this.skip(n);
-        }
-
-        public void mark(int readAheadLimit)
-        {
-            try {
-                BodyReader.this.mark(readAheadLimit);
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-        }
-
-
-        public void reset()
-        throws IOException {
-            BodyReader.this.reset();
-        }
-
-
-
-        public int read()
-        throws IOException {    
-            return BodyReader.this.readByte();
-        }
-
-        public int available() throws IOException {
-            return BodyReader.this.available();
-        }
-
-        public int read(final byte[] b) throws IOException {
-            return BodyReader.this.read(b, 0, b.length);
-        }
-
-
-        public int read(final byte[] b, final int off, final int len)
-        throws IOException {
-
-            return BodyReader.this.read(b, off, len);
-        }
-
-
-        /** 
-         * Close the stream
-         * Since we re-cycle, we can't allow the call to super.close()
-         * which would permantely disable us.
-         */
-        public void close() throws IOException {
-            BodyReader.this.close();
-        }
-    }
-    
-    MRInputStream is = new MRInputStream();
-    
-    public InputStream asInputStream() {
-        return is;
-    }
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/BodyWriter.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/BodyWriter.java
deleted file mode 100644 (file)
index 5e09ae7..0000000
+++ /dev/null
@@ -1,671 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You 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.apache.tomcat.lite;
-
-import java.io.IOException;
-import java.io.Writer;
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
-import java.util.HashMap;
-
-import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.buf.C2BConverter;
-import org.apache.tomcat.util.buf.CharChunk;
-
-/**
- * Implement buffering and character translation acording to the
- * servlet spec.
- *
- * This class handles both chars and bytes.
- *
- * It is tightly integrated with servlet response, sending headers
- * and updating the commit state.
- *
- * TODO: add 'extension' interface that allows direct access to
- * the async connector non-copy non-blocking queue. Same for the
- * OutputStream. Maybe switch the buffer to the brigade.
- *
- * @author Costin Manolache
- */
-public class BodyWriter extends Writer {
-
-    // used in getWriter, until a method is added to res.
-    protected static final int WRITER_NOTE = 3;
-
-
-    private ByteChunk.ByteOutputChannel byteFlusher =
-        new ByteChunk.ByteOutputChannel() {
-
-        @Override
-        public void realWriteBytes(byte[] cbuf, int off, int len)
-                throws IOException {
-            BodyWriter.this.realWriteBytes(cbuf, off, len);
-        }
-    };
-
-    private CharChunk.CharOutputChannel charFlusher =
-        new CharChunk.CharOutputChannel() {
-        @Override
-        public void realWriteChars(char[] cbuf, int off, int len)
-                throws IOException {
-            BodyWriter.this.realWriteChars(cbuf, off, len);
-        }
-    };
-
-
-    public static final String DEFAULT_ENCODING =
-        org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING;
-    public static final int DEFAULT_BUFFER_SIZE = 8*1024;
-
-
-    // The buffer can be used for byte[] and char[] writing
-    // ( this is needed to support ServletOutputStream and for
-    // efficient implementations of templating systems )
-    public final int CHAR_STATE = 1;
-    public final int BYTE_STATE = 2;
-
-    boolean headersSent = false;
-    // ----------------------------------------------------- Instance Variables
-    ServletResponseImpl res;
-
-    /**
-     * The byte buffer.
-     */
-    protected ByteChunk bb;
-
-
-    /**
-     * The chunk buffer.
-     */
-    protected CharChunk cb;
-
-
-    /**
-     * State of the output buffer.
-     */
-    protected int state = 0;
-
-
-    /**
-     * Number of bytes written.
-     */
-    protected int bytesWritten = 0;
-
-
-    /**
-     * Number of chars written.
-     */
-    protected int charsWritten = 0;
-
-
-    /**
-     * Flag which indicates if the output buffer is closed.
-     */
-    protected boolean closed = false;
-
-
-    /**
-     * Do a flush on the next operation.
-     */
-    protected boolean doFlush = false;
-
-
-    /**
-     * Byte chunk used to output bytes. This is just used to wrap the byte[]
-     * to match the coyote OutputBuffer interface
-     */
-    protected ByteChunk outputChunk = new ByteChunk();
-
-
-    /**
-     * Encoding to use.
-     * TODO: isn't it redundant ? enc, gotEnc, conv plus the enc in the bb
-     */
-    protected String enc;
-
-
-    /**
-     * Encoder is set.
-     */
-    protected boolean gotEnc = false;
-
-
-    /**
-     * List of encoders. The writer is reused - the encoder mapping
-     * avoids creating expensive objects. In future it'll contain nio.Charsets
-     */
-    protected HashMap encoders = new HashMap();
-
-
-    /**
-     * Current char to byte converter. TODO: replace with Charset
-     */
-    protected C2BConverter conv;
-
-    /**
-     * Suspended flag. All output bytes will be swallowed if this is true.
-     */
-    protected boolean suspended = false;
-
-    private Connector connector;
-
-
-    // ----------------------------------------------------------- Constructors
-
-
-    /**
-     * Default constructor. Allocate the buffer with the default buffer size.
-     */
-    public BodyWriter() {
-
-        this(DEFAULT_BUFFER_SIZE);
-
-    }
-
-
-    /**
-     * Alternate constructor which allows specifying the initial buffer size.
-     *
-     * @param size Buffer size to use
-     */
-    public BodyWriter(int size) {
-
-        bb = new ByteChunk(size);
-        bb.setLimit(size);
-        bb.setByteOutputChannel(byteFlusher);
-        cb = new CharChunk(size);
-        cb.setCharOutputChannel(charFlusher);
-        cb.setLimit(size);
-
-    }
-
-    public void setConnector(Connector c, ServletResponseImpl res) {
-        this.res = res;
-        this.connector = c;
-    }
-
-
-    // ------------------------------------------------------------- Properties
-
-
-    /**
-     * Is the response output suspended ?
-     *
-     * @return suspended flag value
-     */
-    public boolean isSuspended() {
-        return this.suspended;
-    }
-
-
-    /**
-     * Set the suspended flag.
-     *
-     * @param suspended New suspended flag value
-     */
-    public void setSuspended(boolean suspended) {
-        this.suspended = suspended;
-    }
-
-
-    // --------------------------------------------------------- Public Methods
-
-
-    /**
-     * Recycle the output buffer.
-     */
-    public void recycle() {
-
-        state = BYTE_STATE;
-        headersSent = false;
-        bytesWritten = 0;
-        charsWritten = 0;
-
-        cb.recycle();
-        bb.recycle();
-        closed = false;
-        suspended = false;
-
-        if (conv!= null) {
-            conv.recycle();
-        }
-
-        gotEnc = false;
-        enc = null;
-
-    }
-
-
-    /**
-     * Close the output buffer. This tries to calculate the response size if
-     * the response has not been committed yet.
-     *
-     * @throws IOException An underlying IOException occurred
-     */
-    public void close()
-        throws IOException {
-
-        if (closed)
-            return;
-        if (suspended)
-            return;
-
-        if (state == CHAR_STATE) {
-            cb.flushBuffer();
-            state = BYTE_STATE;
-        }
-        connector.beforeClose(res, bb.getLength());
-
-        doFlush(false);
-        closed = true;
-
-        connector.finishResponse(res);
-    }
-
-
-    /**
-     * Flush bytes or chars contained in the buffer.
-     *
-     * @throws IOException An underlying IOException occurred
-     */
-    public void flush()
-        throws IOException {
-        doFlush(true);
-    }
-
-    /**
-     * Flush bytes or chars contained in the buffer.
-     *
-     * @throws IOException An underlying IOException occurred
-     */
-    protected void doFlush(boolean realFlush)
-        throws IOException {
-
-        if (suspended)
-            return;
-
-        doFlush = true;
-        if (!headersSent) {
-            // If the buffers are empty, commit the response header
-            connector.sendHeaders(res);
-            headersSent = true;
-        }
-        if (state == CHAR_STATE) {
-            cb.flushBuffer();
-            state = BYTE_STATE;
-        }
-        if (state == BYTE_STATE) {
-            bb.flushBuffer();
-        }
-        doFlush = false;
-
-        if (realFlush) {
-            connector.realFlush(res);
-        }
-
-    }
-
-
-    // ------------------------------------------------- Bytes Handling Methods
-
-
-    /**
-     * Sends the buffer data to the client output, checking the
-     * state of Response and calling the right interceptors.
-     *
-     * @param buf Byte buffer to be written to the response
-     * @param off Offset
-     * @param cnt Length
-     *
-     * @throws IOException An underlying IOException occurred
-     */
-    private void realWriteBytes(byte buf[], int off, int cnt)
-        throws IOException {
-
-        if (closed)
-            return;
-
-        // If we really have something to write
-        if (cnt > 0) {
-            // real write to the adapter
-            outputChunk.setBytes(buf, off, cnt);
-            try {
-                connector.doWrite(res, outputChunk);
-            } catch (IOException e) {
-                // An IOException on a write is almost always due to
-                // the remote client aborting the request.  Wrap this
-                // so that it can be handled better by the error dispatcher.
-                throw new ClientAbortException(e);
-            }
-        }
-
-    }
-
-
-    public void write(byte b[], int off, int len) throws IOException {
-
-        if (suspended)
-            return;
-
-        if (state == CHAR_STATE)
-            cb.flushBuffer();
-        state = BYTE_STATE;
-        writeBytes(b, off, len);
-
-    }
-
-
-    private void writeBytes(byte b[], int off, int len)
-        throws IOException {
-
-        if (closed)
-            return;
-
-        bb.append(b, off, len);
-        bytesWritten += len;
-
-        // if called from within flush(), then immediately flush
-        // remaining bytes
-        if (doFlush) {
-            bb.flushBuffer();
-        }
-
-    }
-
-
-    public void writeByte(int b)
-        throws IOException {
-
-        if (suspended)
-            return;
-
-        if (state == CHAR_STATE)
-            cb.flushBuffer();
-        state = BYTE_STATE;
-
-        bb.append( (byte)b );
-        bytesWritten++;
-
-    }
-
-
-    // ------------------------------------------------- Chars Handling Methods
-
-
-    public void write(int c)
-        throws IOException {
-
-        if (suspended)
-            return;
-
-        state = CHAR_STATE;
-
-        cb.append((char) c);
-        charsWritten++;
-
-    }
-
-
-    public void write(char c[])
-        throws IOException {
-
-        if (suspended)
-            return;
-
-        write(c, 0, c.length);
-
-    }
-
-
-    public void write(char c[], int off, int len)
-        throws IOException {
-
-        if (suspended)
-            return;
-
-        state = CHAR_STATE;
-
-        cb.append(c, off, len);
-        charsWritten += len;
-
-    }
-
-
-    public void write(StringBuilder sb)
-        throws IOException {
-
-        if (suspended)
-            return;
-
-        state = CHAR_STATE;
-
-        int len = sb.length();
-        charsWritten += len;
-        cb.append(sb);
-
-    }
-
-
-    /**
-     * Append a string to the buffer
-     */
-    public void write(String s, int off, int len)
-        throws IOException {
-
-        if (suspended)
-            return;
-
-        state=CHAR_STATE;
-
-        charsWritten += len;
-        if (s==null)
-            s="null";
-        cb.append( s, off, len );
-
-    }
-
-
-    public void write(String s)
-        throws IOException {
-
-        if (suspended)
-            return;
-
-        state = CHAR_STATE;
-        if (s==null)
-            s="null";
-        write(s, 0, s.length());
-
-    }
-
-    public void println() throws IOException {
-        write("\n");
-    }
-
-    public void println(String s) throws IOException {
-        write(s);
-        write("\n");
-    }
-
-    public void print(String s) throws IOException {
-        write(s);
-    }
-
-    public void flushChars()
-        throws IOException {
-
-        cb.flushBuffer();
-        state = BYTE_STATE;
-
-    }
-
-
-    public boolean flushCharsNeeded() {
-        return state == CHAR_STATE;
-    }
-
-
-    public void setEncoding(String s) {
-        enc = s;
-    }
-
-
-    private void realWriteChars(char c[], int off, int len)
-        throws IOException {
-
-        if (!gotEnc)
-            setConverter();
-
-        conv.convert(c, off, len);
-        conv.flushBuffer();     // ???
-
-    }
-
-
-    public void checkConverter()
-        throws IOException {
-
-        if (!gotEnc)
-            setConverter();
-
-    }
-
-
-    protected void setConverter()
-        throws IOException {
-
-        enc = res.getCharacterEncoding();
-
-        gotEnc = true;
-        if (enc == null)
-            enc = DEFAULT_ENCODING;
-        conv = (C2BConverter) encoders.get(enc);
-        if (conv == null) {
-
-            if (System.getSecurityManager() != null){
-                try{
-                    conv = (C2BConverter)AccessController.doPrivileged(
-                            new PrivilegedExceptionAction(){
-
-                                public Object run() throws IOException{
-                                    return new C2BConverter(bb, enc);
-                                }
-
-                            }
-                    );
-                }catch(PrivilegedActionException ex){
-                    Exception e = ex.getException();
-                    if (e instanceof IOException)
-                        throw (IOException)e;
-                }
-            } else {
-                conv = new C2BConverter(bb, enc);
-            }
-
-            encoders.put(enc, conv);
-
-        }
-    }
-
-
-    // --------------------  BufferedOutputStream compatibility
-
-
-    /**
-     * Real write - this buffer will be sent to the client
-     */
-    public void flushBytes()
-        throws IOException {
-
-        bb.flushBuffer();
-
-    }
-
-
-    public int getBytesWritten() {
-        return bytesWritten;
-    }
-
-
-    public int getCharsWritten() {
-        return charsWritten;
-    }
-
-
-    public int getContentWritten() {
-        return bytesWritten + charsWritten;
-    }
-
-
-    /**
-     * True if this buffer hasn't been used ( since recycle() ) -
-     * i.e. no chars or bytes have been added to the buffer.
-     */
-    public boolean isNew() {
-        return (bytesWritten == 0) && (charsWritten == 0);
-    }
-
-
-    public void setBufferSize(int size) {
-        if (size > bb.getLimit()) {// ??????
-            bb.setLimit(size);
-        }
-    }
-
-
-    public void reset() {
-
-        //count=0;
-        bb.recycle();
-        bytesWritten = 0;
-        cb.recycle();
-        charsWritten = 0;
-        gotEnc = false;
-        enc = null;
-        state = BYTE_STATE;
-    }
-
-
-    public int getBufferSize() {
-        return bb.getLimit();
-    }
-
-    public ByteChunk getByteBuffer() {
-      return outputChunk;
-    }
-
-}
-//{
-//    public abstract int getBytesWritten();
-//    public abstract int getCharsWritten();
-//    public abstract void recycle();
-//    public abstract void setSuspended(boolean suspended);
-//    public abstract boolean isSuspended();
-//
-//    public abstract void reset();
-//    public abstract int getBufferSize();
-//    public abstract void setBufferSize(int n);
-//    public abstract void checkConverter() throws IOException;
-//    public boolean isNew() {
-//        return getBytesWritten() == 0 && getCharsWritten() == 0;
-//    }
-//    public abstract void write(byte[] b, int off, int len) throws IOException;
-//    public abstract void writeByte(int b) throws IOException;
-//
-//}
\ No newline at end of file
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/CharsetMapperDefault.properties b/modules/tomcat-lite/java/org/apache/tomcat/lite/CharsetMapperDefault.properties
deleted file mode 100644 (file)
index c73a8fc..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-en=ISO-8859-1
-fr=ISO-8859-1
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ClientAbortException.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ClientAbortException.java
deleted file mode 100644 (file)
index ab395a3..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.tomcat.lite;
-
-import java.io.IOException;
-
-/**
- * Wrap an IOException identifying it as being caused by an abort
- * of a request by a remote client.
- *
- * @author Glenn L. Nielsen
- * @version $Revision: 304063 $ $Date: 2005-08-18 06:25:18 -0700 (Thu, 18 Aug 2005) $
- */
-
-public final class ClientAbortException extends IOException {
-
-
-    //------------------------------------------------------------ Constructors
-
-
-    /**
-     * Construct a new ClientAbortException with no other information.
-     */
-    public ClientAbortException() {
-
-        this(null, null);
-
-    }
-
-
-    /**
-     * Construct a new ClientAbortException for the specified message.
-     *
-     * @param message Message describing this exception
-     */
-    public ClientAbortException(String message) {
-
-        this(message, null);
-
-    }
-
-
-    /**
-     * Construct a new ClientAbortException for the specified throwable.
-     *
-     * @param throwable Throwable that caused this exception
-     */
-    public ClientAbortException(Throwable throwable) {
-
-        this(null, throwable);
-
-    }
-
-
-    /**
-     * Construct a new ClientAbortException for the specified message
-     * and throwable.
-     *
-     * @param message Message describing this exception
-     * @param throwable Throwable that caused this exception
-     */
-    public ClientAbortException(String message, Throwable throwable) {
-
-        super();
-        this.message = message;
-        this.throwable = throwable;
-
-    }
-
-
-    //------------------------------------------------------ Instance Variables
-
-
-    /**
-     * The error message passed to our constructor (if any)
-     */
-    protected String message = null;
-
-
-    /**
-     * The underlying exception or error passed to our constructor (if any)
-     */
-    protected Throwable throwable = null;
-
-
-    //---------------------------------------------------------- Public Methods
-
-
-    /**
-     * Returns the message associated with this exception, if any.
-     */
-    public String getMessage() {
-
-        return (message);
-
-    }
-
-
-    /**
-     * Returns the cause that caused this exception, if any.
-     */
-    public Throwable getCause() {
-        
-        return (throwable);
-        
-    }
-
-    
-    /**
-     * Return a formatted string that describes this exception.
-     */
-    public String toString() {
-
-        StringBuilder sb = new StringBuilder("ClientAbortException:  ");
-        if (message != null) {
-            sb.append(message);
-            if (throwable != null) {
-                sb.append(":  ");
-            }
-        }
-        if (throwable != null) {
-            sb.append(throwable.toString());
-        }
-        return (sb.toString());
-
-    }
-
-
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/Connector.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/Connector.java
deleted file mode 100644 (file)
index b5a4fdf..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You 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.apache.tomcat.lite;
-
-import java.io.IOException;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.tomcat.integration.ObjectManager;
-import org.apache.tomcat.util.buf.ByteChunk;
-
-/**
- * What we need to plugin a connector.
- * 
- * Currently we have lots of deps on coyote Request, but I plan to
- * change this and allow other HTTP implementations - like MINA, the
- * experimental async connector, etc. Most important will be 
- * different support for IO - i.e. a more non-blocking mode.
- * We'll probably keep MessageBytes as wrappers for request/res
- * properties. 
- * 
- * This interface has no dep on coyote.
- *  
- */
-public interface Connector {
-
-    public void setDaemon(boolean b);
-    
-    public void start() throws IOException;
-    
-    public void stop() throws Exception;
-    
-    /**
-     * Called during close() - either on explicit output close, or 
-     * after the request is completed. 
-     * 
-     * @throws IOException
-     */
-    public abstract void finishResponse(HttpServletResponse res) throws IOException;
-   
-    /**
-     * Called before flushing the output during close.
-     * Content-Length may be updated.
-     * @param len 
-     * 
-     * @throws IOException
-     */
-    public abstract void beforeClose(HttpServletResponse res, int len) throws IOException;
-    
-    /** 
-     * Called when the first flush() is called.
-     * @throws IOException
-     */
-    public abstract void sendHeaders(HttpServletResponse res) throws IOException;
-    
-    /**
-     * Send data to the client.
-     * @throws IOException
-     */
-    public abstract void realFlush(HttpServletResponse res) throws IOException;
-
-    /**
-     * Write to the connector underlying buffer.
-     * The chunk will be reused (currently).
-     */
-    public abstract void doWrite(HttpServletResponse res, ByteChunk outputChunk2) throws IOException;
-
-    
-    //public void finishResponse(HttpServletResponse res) throws IOException;
-    
-    public void acknowledge(HttpServletResponse res) throws IOException;
-
-    public void reset(HttpServletResponse res);
-    
-    public void recycle(HttpServletRequest req, HttpServletResponse res);
-
-    void initRequest(HttpServletRequest req, HttpServletResponse res);
-
-    public void setTomcatLite(TomcatLite tomcatLite);
-
-    public void setObjectManager(ObjectManager objectManager);
-    
-    public String getRemoteHost(HttpServletRequest req);
-    
-    public String getRemoteAddr(HttpServletRequest req);
-    
-    public int doRead(ServletRequestImpl coyoteRequest, ByteChunk bb) throws IOException;
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ContextPreinitListener.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ContextPreinitListener.java
deleted file mode 100644 (file)
index 663266e..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You 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.apache.tomcat.lite;
-
-import javax.servlet.ServletContext;
-
-/**
- * Tomcat-lite specific interface ( could be moved to addons ).
- * This class will be called before initialization - implementations
- * can add servlets, filters, etc. In particular web.xml parsing
- * is done implementing this interface. 
- * 
- * On a small server you could remove web.xml support to reduce 
- * footprint, and either hardcode this class or use properties.
- * Same if you already use a framework and you inject settings
- * or use framework's registry (OSGI).
- * 
- * @author Costin Manolache
- */
-public interface ContextPreinitListener {
-
-    public void preInit(ServletContext ctx);
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/FilterChainImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/FilterChainImpl.java
deleted file mode 100644 (file)
index 7d3569b..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright 2009 The Apache Software Foundation.
- * 
- * 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.apache.tomcat.lite;
-
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.Servlet;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-/**
- * Wraps the list of filters for the current request. One instance 
- * associated with each RequestImpl, reused. 
- * 
- * Populated by the mapper ( WebappFilterMapper for example ), which
- * determines the filters for the current request.
- * 
- * Not thread safe.
- */
-public final class FilterChainImpl implements FilterChain {
-    private List<FilterConfigImpl> filters =  new ArrayList<FilterConfigImpl>();
-
-
-    /**
-     * The int which is used to maintain the current position 
-     * in the filter chain.
-     */
-    private int pos = 0;
-
-    /**
-     * The servlet instance to be executed by this chain.
-     */
-    private Servlet servlet = null;
-
-
-    private ServletConfigImpl wrapper;
-
-
-    public FilterChainImpl() {
-        super();
-    }
-
-
-    /**
-     * Invoke the next filter in this chain, passing the specified request
-     * and response.  If there are no more filters in this chain, invoke
-     * the <code>service()</code> method of the servlet itself.
-     *
-     * @param request The servlet request we are processing
-     * @param response The servlet response we are creating
-     *
-     * @exception IOException if an input/output error occurs
-     * @exception ServletException if a servlet exception occurs
-     */
-    public void doFilter(ServletRequest request, ServletResponse response)
-        throws IOException, ServletException {
-
-
-        // Call the next filter if there is one
-        if (pos < filters.size()) {
-            FilterConfigImpl filterConfig = filters.get(pos++);
-            Filter filter = null;
-            try {
-                filter = filterConfig.getFilter();
-                filter.doFilter(request, response, this);
-            } catch (IOException e) {
-                throw e;
-            } catch (ServletException e) {
-                throw e;
-            } catch (RuntimeException e) {
-                throw e;
-            } catch (Throwable e) {
-                e.printStackTrace();
-                throw new ServletException("Throwable", e);
-            }
-            return;
-        }
-
-        // We fell off the end of the chain -- call the servlet instance
-        try {
-            if (servlet != null) 
-                servlet.service(request, response);
-        } catch (IOException e) {
-            throw e;
-        } catch (ServletException e) {
-            throw e;
-        } catch (RuntimeException e) {
-            throw e;
-        } catch (Throwable e) {
-            throw new ServletException("Throwable", e);
-        }
-    }
-
-
-    // -------------------------------------------------------- Package Methods
-
-
-
-    /**
-     * Add a filter to the set of filters that will be executed in this chain.
-     *
-     * @param filterConfig The FilterConfig for the servlet to be executed
-     */
-    public void addFilter(FilterConfigImpl filterConfig) {
-        filters.add(filterConfig);
-    }
-
-
-    /**
-     * Release references to the filters and wrapper executed by this chain.
-     */
-    public void release() {
-        filters.clear();
-        pos = 0;
-        servlet = null;
-    }
-
-
-    /**
-     * Set the servlet that will be executed at the end of this chain.
-     * Set by the mapper filter 
-     */
-    public void setServlet(ServletConfigImpl wrapper, Servlet servlet) {
-        this.wrapper = wrapper;
-        this.servlet = servlet;
-    }
-
-    // ------ Getters for information ------------ 
-    
-    public int getSize() {
-        return filters.size();
-    }
-    
-    public FilterConfigImpl getFilter(int i) {
-        return filters.get(i);
-    }
-    
-    public Servlet getServlet() {
-        return servlet;
-    }
-    
-    public ServletConfigImpl getServletConfig() {
-        return wrapper;
-    }
-    
-    public int getPos() {
-        return pos;
-    }
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/FilterConfigImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/FilterConfigImpl.java
deleted file mode 100644 (file)
index b3b5951..0000000
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- *
- * 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.apache.tomcat.lite;
-
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import javax.servlet.DispatcherType;
-import javax.servlet.Filter;
-import javax.servlet.FilterConfig;
-import javax.servlet.FilterRegistration;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.FilterRegistration.Dynamic;
-
-import org.apache.tomcat.servlets.util.Enumerator;
-
-
-/**
- * A Filter is configured in web.xml by:
- *  - name - used in mappings
- *  - className - used to instantiate the filter
- *  - init params
- *  - other things not used in the servlet container ( icon, descr, etc )
- *
- * Alternatively, in API mode you can pass the actual filter.
- *
- * @see ServletConfigImpl
- */
-public final class FilterConfigImpl implements FilterConfig, FilterRegistration {
-
-    DynamicFilterRegistration dynamic = new DynamicFilterRegistration();
-
-    public FilterConfigImpl(ServletContextImpl context) {
-        this.ctx = context;
-    }
-
-    boolean asyncSupported;
-
-    private ServletContextImpl ctx = null;
-
-    /**
-     * The application Filter we are configured for.
-     */
-    private transient Filter filter = null;
-
-    String descryption;
-
-    private String filterName;
-
-    private String filterClassName;
-
-    Map<String, String> initParams;
-
-    private Class<? extends Filter> filterClass;
-
-    public void setData(String filterName, String filterClass,
-                        Map<String, String> params) {
-        this.filterName = filterName;
-        this.filterClassName = filterClass;
-        this.initParams = params;
-    }
-
-    public void setFilter(Filter f) {
-        filter = f;
-    }
-
-    public String getFilterName() {
-        return filterName;
-    }
-
-    public void setFilterClass(Class<? extends Filter> filterClass2) {
-        this.filterClass = filterClass2;
-    }
-
-
-    public String getInitParameter(String name) {
-        if (initParams == null) return null;
-        return initParams.get(name);
-    }
-
-    /**
-     * Return an <code>Enumeration</code> of the names of the initialization
-     * parameters for this Filter.
-     */
-    public Enumeration getInitParameterNames() {
-        if (initParams == null)
-            return (new Enumerator(new ArrayList()));
-        else
-            return (new Enumerator(initParams.keySet()));
-    }
-
-
-    /**
-     * Return the ServletContext of our associated web application.
-     */
-    public ServletContext getServletContext() {
-        return ctx;
-    }
-
-    /**
-     * Return the application Filter we are configured for.
-     */
-    public Filter createFilter() throws ClassCastException, ClassNotFoundException,
-        IllegalAccessException, InstantiationException, ServletException {
-
-        // Return the existing filter instance, if any
-        if (filter != null)
-            return filter;
-
-        ClassLoader classLoader = ctx.getClassLoader();
-
-        ClassLoader oldCtxClassLoader =
-            Thread.currentThread().getContextClassLoader();
-        if (classLoader != oldCtxClassLoader) {
-            Thread.currentThread().setContextClassLoader(classLoader);
-        }
-        try {
-            if (filterClass == null) {
-                filterClass = (Class<? extends Filter>) classLoader.loadClass(filterClassName);
-            }
-            this.filter = (Filter) filterClass.newInstance();
-        } finally {
-            if (classLoader != oldCtxClassLoader) {
-                Thread.currentThread().setContextClassLoader(oldCtxClassLoader);
-            }
-        }
-
-        // TODO: resource injection
-
-        return filter;
-    }
-
-    public Filter getFilter() throws ClassCastException, ClassNotFoundException, IllegalAccessException, InstantiationException, ServletException {
-        Filter filter = createFilter();
-        filter.init(this);
-        return (this.filter);
-    }
-
-
-    /**
-     * Release the Filter instance associated with this FilterConfig,
-     * if there is one.
-     */
-    public void release() {
-        if (this.filter != null){
-            filter.destroy();
-        }
-        this.filter = null;
-     }
-
-
-   @Override
-    public void addMappingForServletNames(EnumSet<DispatcherType> dispatcherTypes,
-                                          boolean isMatchAfter,
-                                          String... servletNames) {
-        if (ctx.startDone) {
-            // Use the context method instead of the servlet API to
-            // add mappings after context init.
-            throw new IllegalStateException();
-        }
-        ArrayList<String> dispatchers = new ArrayList<String>();
-        for (DispatcherType dt: dispatcherTypes) {
-            dispatchers.add(dt.name());
-        }
-        for (String servletName: servletNames) {
-            ctx.getFilterMapper().addMapping(getFilterName(),
-                    null, servletName, (String[]) dispatchers.toArray(), isMatchAfter);
-        }
-    }
-
-
-   @Override
-    public void addMappingForUrlPatterns(EnumSet<DispatcherType> dispatcherTypes,
-                                         boolean isMatchAfter,
-                                         String... urlPatterns) {
-        if (ctx.startDone) {
-            // Use the context method instead of the servlet API to
-            // add mappings after context init.
-            throw new IllegalStateException();
-        }
-        ArrayList<String> dispatchers = new ArrayList<String>();
-        for (DispatcherType dt: dispatcherTypes) {
-            dispatchers.add(dt.name());
-        }
-        for (String url: urlPatterns) {
-            ctx.getFilterMapper().addMapping(getFilterName(),
-                    url, null, (String[]) dispatchers.toArray(), isMatchAfter);
-        }
-    }
-
-
-   @Override
-    public boolean setInitParameter(String name, String value)
-            throws IllegalArgumentException, IllegalStateException {
-        return ServletContextImpl.setInitParameter(ctx, initParams,
-                name, value);
-    }
-
-
-   @Override
-    public Set<String> setInitParameters(Map<String, String> initParameters)
-    throws IllegalArgumentException, IllegalStateException {
-        return ServletContextImpl.setInitParameters(ctx, initParams,
-                initParameters);
-    }
-
-    public Dynamic getDynamic() {
-        return dynamic;
-    }
-
-    public class DynamicFilterRegistration implements Dynamic {
-
-
-       @Override
-        public void addMappingForServletNames(EnumSet<DispatcherType> dispatcherTypes,
-                                              boolean isMatchAfter,
-                                              String... servletNames) {
-            FilterConfigImpl.this.addMappingForServletNames(dispatcherTypes, isMatchAfter, servletNames);
-        }
-
-
-       @Override
-        public void addMappingForUrlPatterns(EnumSet<DispatcherType> dispatcherTypes,
-                                             boolean isMatchAfter,
-                                             String... urlPatterns) {
-            FilterConfigImpl.this.addMappingForUrlPatterns(dispatcherTypes, isMatchAfter, urlPatterns);
-        }
-
-
-       @Override
-        public boolean setInitParameter(String name, String value)
-                throws IllegalArgumentException, IllegalStateException {
-            return ServletContextImpl.setInitParameter(ctx, initParams,
-                    name, value);
-        }
-
-
-       @Override
-        public Set<String> setInitParameters(Map<String, String> initParameters)
-                throws IllegalArgumentException, IllegalStateException {
-            return ServletContextImpl.setInitParameters(ctx, initParams,
-                    initParameters);
-        }
-
-
-       @Override
-        public void setAsyncSupported(boolean isAsyncSupported)
-                throws IllegalStateException {
-            asyncSupported = isAsyncSupported;
-        }
-
-
-        public void setDescription(String description)
-                throws IllegalStateException {
-            FilterConfigImpl.this.descryption = description;
-        }
-
-       @Override
-        public Collection<String> getUrlPatternMappings() {
-            // implement me
-            return null;
-        }
-
-       @Override
-        public Collection<String> getServletNameMappings() {
-            // implement me
-            return null;
-        }
-
-       @Override
-        public Map<String, String> getInitParameters() {
-            // implement me
-            return null;
-        }
-
-       @Override
-        public String getInitParameter(String name) {
-            if (initParams == null) return null;
-            return initParams.get(name);
-        }
-
-       @Override
-        public String getClassName() {
-            // implement me
-            return null;
-        }
-
-       @Override
-        public String getName() {
-            // implement me
-            return null;
-        }
-    }
-
-   @Override
-    public Collection<String> getUrlPatternMappings() {
-        // implement me
-        return null;
-    }
-
-   @Override
-    public Collection<String> getServletNameMappings() {
-        // implement me
-        return null;
-    }
-
-   @Override
-    public Map<String, String> getInitParameters() {
-        // implement me
-        return null;
-    }
-
-   @Override
-    public String getClassName() {
-        // implement me
-        return null;
-    }
-
-   @Override
-    public String getName() {
-        // implement me
-        return null;
-    }
-
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/Locale2Charset.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/Locale2Charset.java
deleted file mode 100644 (file)
index 0a9d73a..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- * 
- * 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.apache.tomcat.lite;
-
-
-import java.io.InputStream;
-import java.util.Locale;
-import java.util.Properties;
-
-
-
-/**
- * One instance per Context. Holds the 
- * 
- * Utility class that attempts to map from a Locale to the corresponding
- * character set to be used for interpreting input text (or generating
- * output text) when the Content-Type header does not include one.  You
- * can customize the behavior of this class by modifying the mapping data
- * it loads, or by subclassing it (to change the algorithm) and then using
- * your own version for a particular web application.
- *
- * @author Craig R. McClanahan
- */
-public class Locale2Charset {
-
-
-    // ---------------------------------------------------- Manifest Constants
-
-
-    /**
-     * Default properties resource name.
-     */
-    public static final String DEFAULT_RESOURCE =
-      "/org/apache/tomcat/lite/CharsetMapperDefault.properties";
-
-    
-
-    // ---------------------------------------------------------- Constructors
-
-
-    /**
-     * Construct a new CharsetMapper using the default properties resource.
-     */
-    public Locale2Charset() {
-      String name = DEFAULT_RESOURCE;
-      if (defaultMap == null) { // once !
-        try {
-          defaultMap = new Properties();
-          InputStream stream =
-            this.getClass().getResourceAsStream(name);
-          defaultMap.load(stream);
-          stream.close();
-        } catch (Throwable t) {
-          throw new IllegalArgumentException(t.toString());
-        }
-      }
-      map = defaultMap;
-    }
-
-
-    // ---------------------------------------------------- Instance Variables
-
-
-    private static Properties defaultMap; // shared for all apps
-    
-    /**
-     * The mapping properties that have been initialized from the specified or
-     * default properties resource.
-     */
-    private Properties map;
-
-
-    // ------------------------------------------------------- Public Methods
-
-
-    /**
-     * Calculate the name of a character set to be assumed, given the specified
-     * Locale and the absence of a character set specified as part of the
-     * content type header.
-     *
-     * @param locale The locale for which to calculate a character set
-     */
-    public String getCharset(Locale locale) {
-        // Match full language_country_variant first, then language_country, 
-        // then language only
-        String charset = map.getProperty(locale.toString());
-        if (charset == null) {
-            charset = map.getProperty(locale.getLanguage() + "_" 
-                    + locale.getCountry());
-            if (charset == null) {
-                charset = map.getProperty(locale.getLanguage());
-            }
-        }
-        return (charset);
-    }
-
-    
-    /**
-     * The deployment descriptor can have a
-     * locale-encoding-mapping-list element which describes the
-     * webapp's desired mapping from locale to charset.  This method
-     * gets called when processing the web.xml file for a context
-     *
-     * @param locale The locale for a character set
-     * @param charset The charset to be associated with the locale
-     */
-    public void addCharsetMapping(String locale, String charset) {
-      if (map == defaultMap) { 
-        // new copy, don't modify original
-        map = new Properties(defaultMap);
-      }
-      map.put(locale, charset);
-    }
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ParameterMap.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ParameterMap.java
deleted file mode 100644 (file)
index 045ecfb..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- * 
- * 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.apache.tomcat.lite;
-
-
-import java.util.HashMap;
-import java.util.Map;
-
-
-/**
- * Extended implementation of <strong>HashMap</strong> that includes a
- * <code>locked</code> property.  This class can be used to safely expose
- * Catalina internal parameter map objects to user classes without having
- * to clone them in order to avoid modifications.  When first created, a
- * <code>ParmaeterMap</code> instance is not locked.
- *
- * @author Craig R. McClanahan
- * @version $Revision$ $Date$
- */
-
-public final class ParameterMap extends HashMap {
-
-
-    // ----------------------------------------------------------- Constructors
-
-
-    /**
-     * Construct a new, empty map with the default initial capacity and
-     * load factor.
-     */
-    public ParameterMap() {
-
-        super();
-
-    }
-
-
-    /**
-     * Construct a new, empty map with the specified initial capacity and
-     * default load factor.
-     *
-     * @param initialCapacity The initial capacity of this map
-     */
-    public ParameterMap(int initialCapacity) {
-
-        super(initialCapacity);
-
-    }
-
-
-    /**
-     * Construct a new, empty map with the specified initial capacity and
-     * load factor.
-     *
-     * @param initialCapacity The initial capacity of this map
-     * @param loadFactor The load factor of this map
-     */
-    public ParameterMap(int initialCapacity, float loadFactor) {
-
-        super(initialCapacity, loadFactor);
-
-    }
-
-
-    /**
-     * Construct a new map with the same mappings as the given map.
-     *
-     * @param map Map whose contents are dupliated in the new map
-     */
-    public ParameterMap(Map map) {
-
-        super(map);
-
-    }
-
-
-    // ------------------------------------------------------------- Properties
-
-
-    /**
-     * The current lock state of this parameter map.
-     */
-    private boolean locked = false;
-
-
-    /**
-     * Return the locked state of this parameter map.
-     */
-    public boolean isLocked() {
-
-        return (this.locked);
-
-    }
-
-
-    /**
-     * Set the locked state of this parameter map.
-     *
-     * @param locked The new locked state
-     */
-    public void setLocked(boolean locked) {
-
-        this.locked = locked;
-
-    }
-
-
-    // --------------------------------------------------------- Public Methods
-
-
-
-    /**
-     * Remove all mappings from this map.
-     *
-     * @exception IllegalStateException if this map is currently locked
-     */
-    public void clear() {
-
-        if (locked)
-            throw new IllegalStateException
-                ("parameterMap.locked");
-        super.clear();
-
-    }
-
-
-    /**
-     * Associate the specified value with the specified key in this map.  If
-     * the map previously contained a mapping for this key, the old value is
-     * replaced.
-     *
-     * @param key Key with which the specified value is to be associated
-     * @param value Value to be associated with the specified key
-     *
-     * @return The previous value associated with the specified key, or
-     *  <code>null</code> if there was no mapping for key
-     *
-     * @exception IllegalStateException if this map is currently locked
-     */
-    public Object put(Object key, Object value) {
-
-        if (locked)
-            throw new IllegalStateException
-                ("parameterMap.locked");
-        return (super.put(key, value));
-
-    }
-
-
-    /**
-     * Copy all of the mappings from the specified map to this one.  These
-     * mappings replace any mappings that this map had for any of the keys
-     * currently in the specified Map.
-     *
-     * @param map Mappings to be stored into this map
-     *
-     * @exception IllegalStateException if this map is currently locked
-     */
-    public void putAll(Map map) {
-
-        if (locked)
-            throw new IllegalStateException
-                ("parameterMap.locked");
-        super.putAll(map);
-
-    }
-
-
-    /**
-     * Remove the mapping for this key from the map if present.
-     *
-     * @param key Key whose mapping is to be removed from the map
-     *
-     * @return The previous value associated with the specified key, or
-     *  <code>null</code> if there was no mapping for that key
-     *
-     * @exception IllegalStateException if this map is currently locked
-     */
-    public Object remove(Object key) {
-
-        if (locked)
-            throw new IllegalStateException
-                ("parameterMap.locked");
-        return (super.remove(key));
-
-    }
-
-
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/RequestDispatcherImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/RequestDispatcherImpl.java
deleted file mode 100644 (file)
index 6ec2397..0000000
+++ /dev/null
@@ -1,853 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.tomcat.lite;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.Servlet;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletRequestWrapper;
-import javax.servlet.ServletResponse;
-import javax.servlet.ServletResponseWrapper;
-import javax.servlet.UnavailableException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.tomcat.util.buf.CharChunk;
-import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.http.mapper.MappingData;
-
-/**
- *
- */
-public final class RequestDispatcherImpl implements RequestDispatcher {
-    /**
-     * The request attribute under which the original servlet path is stored
-     * on an forwarded dispatcher request.
-     */
-    public static final String FORWARD_SERVLET_PATH_ATTR =
-        "javax.servlet.forward.servlet_path";
-
-
-    /**
-     * The request attribute under which the original query string is stored
-     * on an forwarded dispatcher request.
-     */
-    public static final String FORWARD_QUERY_STRING_ATTR =
-        "javax.servlet.forward.query_string";
-
-    /**
-     * The request attribute under which the original request URI is stored
-     * on an forwarded dispatcher request.
-     */
-    public static final String FORWARD_REQUEST_URI_ATTR =
-        "javax.servlet.forward.request_uri";
-    
-    
-    /**
-     * The request attribute under which the original context path is stored
-     * on an forwarded dispatcher request.
-     */
-    public static final String FORWARD_CONTEXT_PATH_ATTR =
-        "javax.servlet.forward.context_path";
-
-
-    /**
-     * The request attribute under which the original path info is stored
-     * on an forwarded dispatcher request.
-     */
-    public static final String FORWARD_PATH_INFO_ATTR =
-        "javax.servlet.forward.path_info";
-
-    /**
-     * The request attribute under which we store the servlet name on a
-     * named dispatcher request.
-     */
-    public static final String NAMED_DISPATCHER_ATTR =
-        "org.apache.catalina.NAMED";
-
-    /**
-     * The request attribute under which the request URI of the included
-     * servlet is stored on an included dispatcher request.
-     */
-    public static final String INCLUDE_REQUEST_URI_ATTR =
-        "javax.servlet.include.request_uri";
-
-
-    /**
-     * The request attribute under which the context path of the included
-     * servlet is stored on an included dispatcher request.
-     */
-    public static final String INCLUDE_CONTEXT_PATH_ATTR =
-        "javax.servlet.include.context_path";
-
-
-    /**
-     * The request attribute under which the path info of the included
-     * servlet is stored on an included dispatcher request.
-     */
-    public static final String INCLUDE_PATH_INFO_ATTR =
-        "javax.servlet.include.path_info";
-
-
-    /**
-     * The request attribute under which the servlet path of the included
-     * servlet is stored on an included dispatcher request.
-     */
-    public static final String INCLUDE_SERVLET_PATH_ATTR =
-        "javax.servlet.include.servlet_path";
-
-
-    /**
-     * The request attribute under which the query string of the included
-     * servlet is stored on an included dispatcher request.
-     */
-    public static final String INCLUDE_QUERY_STRING_ATTR =
-        "javax.servlet.include.query_string";
-
-    /**
-     * The request attribute under which we expose the value of the
-     * <code>&lt;jsp-file&gt;</code> value associated with this servlet,
-     * if any.
-     */
-    public static final String JSP_FILE_ATTR =
-        "org.apache.catalina.jsp_file";
-
-
-    // ----------------------------------------------------- Instance Variables
-
-    private static Logger log = Logger.getLogger(RequestDispatcherImpl.class.getName());
-
-    private ServletContextImpl ctx = null;
-
-    /**
-     * The servlet name for a named dispatcher.
-     */
-    private String name = null;
-
-    // Path for a path dispatcher
-    private String path;
-
-    /**
-     * MappingData object - per thread for buffering.
-     */
-    private transient ThreadLocal localMappingData = new ThreadLocal();
-
-    /*
-      OrigRequest(ServletRequestImpl) -> include/forward * -> this include
-      
-      On the path: user-defined RequestWrapper or our ServletRequestWrapper
-
-      include() is called with a RequestWrapper(->...->origRequest) or origRequest
-      
-      Based on params, etc -> we wrap the req / response in ServletRequestWrapper,
-       call filters+servlet. Inside, the req can be wrapped again in 
-       userReqWrapper, and other include called. 
-       
-      
-     */
-    
-    /**
-     * The outermost request that will be passed on to the invoked servlet.
-     */
-    private ServletRequest outerRequest = null;
-
-    /**
-     * The outermost response that will be passed on to the invoked servlet.
-     */
-    private ServletResponse outerResponse = null;
-
-    /**
-     * The request wrapper we have created and installed (if any).
-     */
-    private ServletRequest wrapRequest = null;
-
-    /**
-     * The response wrapper we have created and installed (if any).
-     */
-    private ServletResponse wrapResponse = null;
-
-    // Parameters used when constructing the dispatcvher 
-    /**
-     * The extra path information for this RequestDispatcher.
-     */
-    private String pathInfo = null;
-    /**
-     * The query string parameters for this RequestDispatcher.
-     */
-    private String queryString = null;
-    /**
-     * The request URI for this RequestDispatcher.
-     */
-    private String requestURI = null;
-    /**
-     * The servlet path for this RequestDispatcher.
-     */
-    private String servletPath = null;
-
-    //
-    private String origServletPath = null;
-    
-    /**
-     * The Wrapper associated with the resource that will be forwarded to
-     * or included.
-     */
-    private ServletConfigImpl wrapper = null;
-    
-    private Servlet servlet; 
-
-    /** Named dispatcher 
-     */
-    public RequestDispatcherImpl(ServletConfigImpl wrapper, String name) {
-        this.wrapper = wrapper;
-        this.name = name;
-        this.ctx = (ServletContextImpl) wrapper.getServletContext();
-
-    }
-    
-    public RequestDispatcherImpl(ServletContextImpl ctx, String path) {
-        this.path = path;
-        this.ctx = ctx;
-    }
-   
-
-
-    /**
-     * Forward this request and response to another resource for processing.
-     * Any runtime exception, IOException, or ServletException thrown by the
-     * called servlet will be propogated to the caller.
-     *
-     * @param request The servlet request to be forwarded
-     * @param response The servlet response to be forwarded
-     *
-     * @exception IOException if an input/output error occurs
-     * @exception ServletException if a servlet exception occurs
-     */
-    public void forward(ServletRequest request, ServletResponse response)
-        throws ServletException, IOException
-    {
-        // Reset any output that has been buffered, but keep headers/cookies
-        if (response.isCommitted()) {
-            throw new IllegalStateException("forward(): response.isComitted()");
-        }
-        
-        try {
-            response.resetBuffer();
-        } catch (IllegalStateException e) {
-            throw e;
-        }
-
-        // Set up to handle the specified request and response
-        setup(request, response, false);
-
-        // Identify the HTTP-specific request and response objects (if any)
-        HttpServletRequest hrequest = (HttpServletRequest) request;
-
-        ServletRequestWrapperImpl wrequest =
-            (ServletRequestWrapperImpl) wrapRequest();
-
-        
-        if (name != null) {
-            wrequest.setRequestURI(hrequest.getRequestURI());
-            wrequest.setContextPath(hrequest.getContextPath());
-            wrequest.setServletPath(hrequest.getServletPath());
-            wrequest.setPathInfo(hrequest.getPathInfo());
-            wrequest.setQueryString(hrequest.getQueryString());
-
-            
-        } else { // path based
-            mapPath();
-            if (wrapper == null) {
-                throw new ServletException("Forward not found " + 
-                        path);
-            }
-            String contextPath = ctx.getContextPath();
-            if (hrequest.getAttribute(FORWARD_REQUEST_URI_ATTR) == null) {
-                wrequest.setAttribute(FORWARD_REQUEST_URI_ATTR,
-                                      hrequest.getRequestURI());
-                wrequest.setAttribute(FORWARD_CONTEXT_PATH_ATTR,
-                                      hrequest.getContextPath());
-                wrequest.setAttribute(FORWARD_SERVLET_PATH_ATTR,
-                                      hrequest.getServletPath());
-                wrequest.setAttribute(FORWARD_PATH_INFO_ATTR,
-                                      hrequest.getPathInfo());
-                wrequest.setAttribute(FORWARD_QUERY_STRING_ATTR,
-                                      hrequest.getQueryString());
-            }
-            wrequest.setContextPath(contextPath);
-            wrequest.setRequestURI(requestURI);
-            wrequest.setServletPath(servletPath);
-            wrequest.setPathInfo(pathInfo);
-            if (queryString != null) {
-                wrequest.setQueryString(queryString);
-                wrequest.setQueryParams(queryString);
-            }
-        }
-        processRequest(outerRequest, outerResponse);
-
-        wrequest.recycle();
-        unwrapRequest();
-
-        // This is not a real close in order to support error processing
-//        if ( log.isDebugEnabled() )
-//            log.debug(" Disabling the response for futher output");
-
-        if  (response instanceof ServletResponseImpl) {
-            ((ServletResponseImpl) response).flushBuffer();
-            ((ServletResponseImpl) response).setSuspended(true);
-        } else {
-            // Servlet SRV.6.2.2. The Resquest/Response may have been wrapped
-            // and may no longer be instance of RequestFacade 
-            if (log.isLoggable(Level.FINE)){
-                log.fine( " The Response is vehiculed using a wrapper: " 
-                           + response.getClass().getName() );
-            }
-
-            // Close anyway
-            try {
-                PrintWriter writer = response.getWriter();
-                writer.close();
-            } catch (IllegalStateException e) {
-                try {
-                    ServletOutputStream stream = response.getOutputStream();
-                    stream.close();
-                } catch (IllegalStateException f) {
-                    ;
-                } catch (IOException f) {
-                    ;
-                }
-            } catch (IOException e) {
-                ;
-            }
-        }
-    }
-
-    
-    
-    /**
-     * Include the response from another resource in the current response.
-     * Any runtime exception, IOException, or ServletException thrown by the
-     * called servlet will be propogated to the caller.
-     *
-     * @param request The servlet request that is including this one
-     * @param response The servlet response to be appended to
-     *
-     * @exception IOException if an input/output error occurs
-     * @exception ServletException if a servlet exception occurs
-     */
-    public void include(ServletRequest request, ServletResponse response)
-        throws ServletException, IOException
-    {
-
-        // Set up to handle the specified request and response
-        setup(request, response, true);
-
-        // Create a wrapped response to use for this request
-        // this actually gets inserted somewhere in the chain - it's not 
-        // the last one, but first non-user response
-        wrapResponse();
-        ServletRequestWrapperImpl wrequest =
-            (ServletRequestWrapperImpl) wrapRequest();
-
-
-        // Handle an HTTP named dispatcher include
-        if (name != null) {
-            wrequest.setAttribute(NAMED_DISPATCHER_ATTR, name);
-            if (servletPath != null) wrequest.setServletPath(servletPath);
-            wrequest.setAttribute(WebappFilterMapper.DISPATCHER_TYPE_ATTR,
-                                  new Integer(WebappFilterMapper.INCLUDE));
-            wrequest.setAttribute(WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR, 
-                                  origServletPath);
-        } else {
-            mapPath();
-            String contextPath = ctx.getContextPath();
-            if (requestURI != null)
-                wrequest.setAttribute(INCLUDE_REQUEST_URI_ATTR,
-                                      requestURI);
-            if (contextPath != null)
-                wrequest.setAttribute(INCLUDE_CONTEXT_PATH_ATTR,
-                                      contextPath);
-            if (servletPath != null)
-                wrequest.setAttribute(INCLUDE_SERVLET_PATH_ATTR,
-                                      servletPath);
-            if (pathInfo != null)
-                wrequest.setAttribute(INCLUDE_PATH_INFO_ATTR,
-                                      pathInfo);
-            if (queryString != null) {
-                wrequest.setAttribute(INCLUDE_QUERY_STRING_ATTR,
-                                      queryString);
-                wrequest.setQueryParams(queryString);
-            }
-            
-            wrequest.setAttribute(WebappFilterMapper.DISPATCHER_TYPE_ATTR,
-                                  new Integer(WebappFilterMapper.INCLUDE));
-            wrequest.setAttribute(WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR, 
-                                  origServletPath);
-        }
-
-        invoke(outerRequest, outerResponse);
-
-        wrequest.recycle();
-        unwrapRequest();
-        unwrapResponse();
-    }
-
-
-    // -------------------------------------------------------- Private Methods
-
-    public void mapPath() {
-        if (path == null || servletPath != null) return;
-        
-        // Retrieve the thread local URI, used for mapping
-        // TODO: recycle RequestDispatcher stack and associated objects
-        // instead of this object
-        
-        // Retrieve the thread local mapping data
-        MappingData mappingData = (MappingData) localMappingData.get();
-        if (mappingData == null) {
-            mappingData = new MappingData();
-            localMappingData.set(mappingData);
-        }
-
-        // Get query string
-        int pos = path.indexOf('?');
-        if (pos >= 0) {
-            queryString = path.substring(pos + 1);
-        } else {
-            pos = path.length();
-        }
-        // Map the URI
-        MessageBytes uriMB = MessageBytes.newInstance();
-        CharChunk charBuffer = new CharChunk();
-        //mappingData.localURIBytes;
-        uriMB.recycle();
-        //CharChunk uriCC = uriMB.getCharChunk();
-        try {
-            /*
-             * Ignore any trailing path params (separated by ';') for mapping
-             * purposes.
-             * This is sometimes broken - path params can be on any path 
-             * component, not just last.
-             */
-            int semicolon = path.indexOf(';');
-            if (pos >= 0 && semicolon > pos) {
-                semicolon = -1;
-            }
-            if (ctx.getContextPath().length() > 1 ) {
-                charBuffer.append(ctx.getContextPath());
-            }
-            charBuffer.append(path, 0, 
-                semicolon > 0 ? semicolon : pos);
-
-            // Wrap the buffer 
-            uriMB.setChars(charBuffer.getBuffer(),
-                    charBuffer.getOffset(),
-                    charBuffer.getLength());
-
-            // TODO: make charBuffer part of request or something
-            ctx.getMapper().map(uriMB, mappingData);
-            
-            // at least default wrapper must be returned
-            
-            /*
-             * Append any trailing path params (separated by ';') that were
-             * ignored for mapping purposes, so that they're reflected in the
-             * RequestDispatcher's requestURI
-             */
-            if (semicolon > 0) {
-                // I don't think this will be used in future
-                charBuffer.append(path, 
-                    semicolon, pos - semicolon);
-            }
-        } catch (Exception e) {
-            log.log(Level.SEVERE, "getRequestDispatcher()", e);
-        }
-
-        wrapper = (ServletConfigImpl) mappingData.wrapper;
-        servletPath = mappingData.wrapperPath.toString();
-        pathInfo = mappingData.pathInfo.toString();
-
-        mappingData.recycle();
-
-    }
-    
-
-    /**
-     * Prepare the request based on the filter configuration.
-     * @param request The servlet request we are processing
-     * @param response The servlet response we are creating
-     *
-     * @exception IOException if an input/output error occurs
-     * @exception ServletException if a servlet error occurs
-     */
-    private void processRequest(ServletRequest request, 
-                                ServletResponse response)
-            throws IOException, ServletException {
-        Integer disInt = 
-            (Integer) request.getAttribute(WebappFilterMapper.DISPATCHER_TYPE_ATTR);
-        if (disInt != null) {
-            if (disInt.intValue() != WebappFilterMapper.ERROR) {
-                outerRequest.setAttribute
-                    (WebappFilterMapper.DISPATCHER_REQUEST_PATH_ATTR,
-                     origServletPath);
-                outerRequest.setAttribute
-                    (WebappFilterMapper.DISPATCHER_TYPE_ATTR,
-                     new Integer(WebappFilterMapper.FORWARD));
-            }
-            invoke(outerRequest, response);
-        }
-
-    }
-    
-    
-    
-
-    /**
-     * Ask the resource represented by this RequestDispatcher to process
-     * the associated request, and create (or append to) the associated
-     * response.
-     * <p>
-     * <strong>IMPLEMENTATION NOTE</strong>: This implementation assumes
-     * that no filters are applied to a forwarded or included resource,
-     * because they were already done for the original request.
-     *
-     * @param request The servlet request we are processing
-     * @param response The servlet response we are creating
-     *
-     * @exception IOException if an input/output error occurs
-     * @exception ServletException if a servlet error occurs
-     */
-    private void invoke(ServletRequest request, ServletResponse response)
-            throws IOException, ServletException {
-
-        // Checking to see if the context classloader is the current context
-        // classloader. If it's not, we're saving it, and setting the context
-        // classloader to the Context classloader
-        ClassLoader oldCCL = Thread.currentThread().getContextClassLoader();
-        ClassLoader contextClassLoader = ctx.getClassLoader();
-
-        if (oldCCL != contextClassLoader) {
-            Thread.currentThread().setContextClassLoader(contextClassLoader);
-        } else {
-            oldCCL = null;
-        }
-
-        // Initialize local variables we may need
-        HttpServletResponse hresponse = (HttpServletResponse) response;
-        IOException ioException = null;
-        ServletException servletException = null;
-        RuntimeException runtimeException = null;
-        
-        servletException = allocateServlet(hresponse, servletException);
-                
-        // Get the FilterChain Here
-        WebappFilterMapper factory = 
-            ((ServletContextImpl)wrapper.getServletContext()).getFilterMapper();
-        
-        FilterChainImpl filterChain = factory.createFilterChain(request,
-                                                                wrapper,
-                                                                servlet);
-
-        // Call the service() method for the allocated servlet instance
-        try {
-            String jspFile = wrapper.getJspFile();
-            if (jspFile != null)
-                request.setAttribute(JSP_FILE_ATTR, jspFile);
-            else
-                request.removeAttribute(JSP_FILE_ATTR);
-            // for includes/forwards
-            if ((servlet != null) && (filterChain != null)) {
-               filterChain.doFilter(request, response);
-             }
-        } catch (IOException e) {
-            ctx.getLogger().log(Level.WARNING, "RequestDispatcherImpl error " + 
-                    wrapper.getServletName(), e);
-            ioException = e;
-        } catch (UnavailableException e) {
-            ctx.getLogger().log(Level.WARNING, "RequestDispatcherImpl error " + 
-                    wrapper.getServletName(), e);
-            servletException = e;
-            wrapper.unavailable(e);
-        } catch (ServletException e) {
-            servletException = e;
-        } catch (RuntimeException e) {
-            ctx.getLogger().log(Level.WARNING, "RequestDispatcherImpl error " + 
-                    wrapper.getServletName(), e);
-            runtimeException = e;
-        }
-        request.removeAttribute(JSP_FILE_ATTR);
-
-        // Release the filter chain (if any) for this request
-        if (filterChain != null)
-            filterChain.release();
-
-        servletException = servletDealocate(servletException);
-
-        // Reset the old context class loader
-        if (oldCCL != null)
-            Thread.currentThread().setContextClassLoader(oldCCL);
-        
-        // Unwrap request/response if needed
-        unwrapRequest();
-        unwrapResponse();
-
-        // Rethrow an exception if one was thrown by the invoked servlet
-        if (ioException != null)
-            throw ioException;
-        if (servletException != null)
-            throw servletException;
-        if (runtimeException != null)
-            throw runtimeException;
-
-    }
-
-    private ServletException servletDealocate(ServletException servletException)
-    {
-        if (servlet != null) {
-            wrapper.deallocate(servlet);
-        }
-        return servletException;
-    }
-
-    private ServletException allocateServlet(HttpServletResponse hresponse,
-                                             ServletException servletException)
-        throws IOException
-    {
-        boolean unavailable = false;
-
-        // Check for the servlet being marked unavailable
-        if (wrapper.isUnavailable()) {
-            ctx.getLogger().log(Level.WARNING, "isUnavailable() " + wrapper.getServletName());
-            long available = wrapper.getAvailable();
-            if ((available > 0L) && (available < Long.MAX_VALUE))
-                hresponse.setDateHeader("Retry-After", available);
-            hresponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, 
-                    "Unavailable"); // No need to include internal info: wrapper.getServletName();
-            unavailable = true;
-        }
-
-        // Allocate a servlet instance to process this request
-        try {
-            if (!unavailable) {
-                servlet = wrapper.allocate();
-            }
-        } catch (ServletException e) {
-            ctx.getLogger().log(Level.WARNING, "RequestDispatcher: allocate " + 
-                             wrapper.toString());
-            servletException = e;
-            servlet = null;
-        } catch (Throwable e) {
-            ctx.getLogger().log(Level.WARNING, "allocate() error " + wrapper.getServletName(), e);
-            servletException = new ServletException
-                ("Allocate error " + wrapper.getServletName(), e);
-            servlet = null;
-        }
-        return servletException;
-    }
-
-
-    /**
-     * Set up to handle the specified request and response
-     *
-     * @param request The servlet request specified by the caller
-     * @param response The servlet response specified by the caller
-     * @param including Are we performing an include() as opposed to
-     *  a forward()?
-     */
-    private void setup(ServletRequest request, ServletResponse response,
-                       boolean including) {
-
-        this.outerRequest = request;
-        this.outerResponse = response;
-    }
-
-
-    /**
-     * Unwrap the request if we have wrapped it. Not sure how it could end
-     * up in the middle. 
-     */
-    private void unwrapRequest() {
-        if (wrapRequest == null)
-            return;
-
-        ServletRequest previous = null;
-        ServletRequest current = outerRequest;
-        while (current != null) {
-            // If we run into the container request we are done
-            if (current instanceof ServletRequestImpl)
-                break;
-
-            // Remove the current request if it is our wrapper
-            if (current == wrapRequest) {
-                ServletRequest next =
-                  ((ServletRequestWrapper) current).getRequest();
-                if (previous == null)
-                    outerRequest = next;
-                else
-                    ((ServletRequestWrapper) previous).setRequest(next);
-                break;
-            }
-
-            // Advance to the next request in the chain
-            previous = current;
-            current = ((ServletRequestWrapper) current).getRequest();
-        }
-    }
-
-
-    /**
-     * Unwrap the response if we have wrapped it.
-     */
-    private void unwrapResponse() {
-        if (wrapResponse == null)
-            return;
-
-        ServletResponse previous = null;
-        ServletResponse current = outerResponse;
-        while (current != null) {
-            // If we run into the container response we are done
-            if (current instanceof ServletResponseImpl)
-                break;
-
-            // Remove the current response if it is our wrapper
-            if (current == wrapResponse) {
-                ServletResponse next =
-                  ((ServletResponseWrapper) current).getResponse();
-                if (previous == null)
-                    outerResponse = next;
-                else
-                    ((ServletResponseWrapper) previous).setResponse(next);
-                break;
-            }
-            // Advance to the next response in the chain
-            previous = current;
-            current = ((ServletResponseWrapper) current).getResponse();
-        }
-    }
-
-
-    /**
-     * Create and return a request wrapper that has been inserted in the
-     * appropriate spot in the request chain.
-     */
-    private ServletRequest wrapRequest() {
-        // Locate the request we should insert in front of
-        ServletRequest previous = null;
-        ServletRequest current = outerRequest;
-        while (current != null) {
-            if (!(current instanceof ServletRequestWrapper))
-                break;
-            if (current instanceof ServletRequestWrapperImpl)
-                break;
-            if (current instanceof ServletRequestImpl)
-                break;
-            // user-specified
-            previous = current;
-            current = ((ServletRequestWrapper) current).getRequest();
-        }
-        // now previous will be a user-specified wrapper, 
-        // and current one of our own wrappers ( deeper in stack )
-        // ... current USER_previous USER USER
-        // previous is null if the top request is ours.
-
-        // Instantiate a new wrapper at this point and insert it in the chain
-        ServletRequest wrapper = null;
-        
-        // Compute a crossContext flag
-        boolean crossContext = isCrossContext();
-        wrapper = 
-            new ServletRequestWrapperImpl((HttpServletRequest) current, 
-                                          ctx, crossContext);
-
-        if (previous == null) {
-            // outer becomes the wrapper, includes orig wrapper inside
-            outerRequest = wrapper;
-        } else {
-            // outer remains user-specified sersvlet, delegating to 
-            // our wrapper, which delegates to real request or our wrapper.
-            ((ServletRequestWrapper) previous).setRequest(wrapper);
-        }
-        wrapRequest = wrapper;
-        return (wrapper);
-    }
-
-    private boolean isCrossContext() {
-        boolean crossContext = false;
-        if ((outerRequest instanceof ServletRequestWrapperImpl) ||
-                (outerRequest instanceof ServletRequestImpl) ||
-                (outerRequest instanceof HttpServletRequest)) {
-            HttpServletRequest houterRequest = 
-                (HttpServletRequest) outerRequest;
-            Object contextPath = 
-                houterRequest.getAttribute(INCLUDE_CONTEXT_PATH_ATTR);
-            if (contextPath == null) {
-                // Forward
-                contextPath = houterRequest.getContextPath();
-            }
-            crossContext = !(ctx.getContextPath().equals(contextPath));
-        }
-        return crossContext;
-    }
-
-
-    /**
-     * Create and return a response wrapper that has been inserted in the
-     * appropriate spot in the response chain.
-     * 
-     * Side effect: updates outerResponse, wrapResponse.
-     * The chain is updated with a wrapper below lowest user wrapper
-     */
-    private ServletResponse wrapResponse() {
-        // Locate the response we should insert in front of
-        ServletResponse previous = null;
-        ServletResponse current = outerResponse;
-        while (current != null) {
-            if (!(current instanceof ServletResponseWrapper))
-                break;
-            if (current instanceof ServletResponseImpl)
-                break;
-            previous = current;
-            current = ((ServletResponseWrapper) current).getResponse();
-        }
-
-        // Instantiate a new wrapper at this point and insert it in the chain
-        ServletResponse wrapper = 
-             new ServletResponseIncludeWrapper(current);
-            
-        if (previous == null) {
-            // outer is ours, we can wrap on top
-            outerResponse = wrapper;
-        } else {
-            // outer is user-specified, leave it alone. 
-            // we insert ourself below the lowest user-specified response
-            ((ServletResponseWrapper) previous).setResponse(wrapper);
-        }
-        wrapResponse = wrapper;
-        return (wrapper);
-
-    }
-
-
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletConfigImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletConfigImpl.java
deleted file mode 100644 (file)
index dee9826..0000000
+++ /dev/null
@@ -1,990 +0,0 @@
-/*
- * Copyright 1999-2002,2004 The Apache Software Foundation.
- *
- * 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.apache.tomcat.lite;
-
-import java.io.PrintStream;
-import java.lang.reflect.Method;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.Stack;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-
-import javax.servlet.MultipartConfigElement;
-import javax.servlet.Servlet;
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRegistration;
-import javax.servlet.ServletSecurityElement;
-import javax.servlet.SingleThreadModel;
-import javax.servlet.UnavailableException;
-
-import org.apache.tomcat.addons.UserTemplateClassMapper;
-import org.apache.tomcat.servlets.util.Enumerator;
-import org.apache.tomcat.util.IntrospectionUtils;
-
-/**
- * Based on Wrapper.
- *
- * Standard implementation of the <b>Wrapper</b> interface that represents
- * an individual servlet definition.  No child Containers are allowed, and
- * the parent Container must be a Context.
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
- */
-@SuppressWarnings("deprecation")
-public class ServletConfigImpl implements ServletConfig, ServletRegistration {
-
-    ServletDynamicRegistration dynamic = new ServletDynamicRegistration();
-
-    protected boolean asyncSupported;
-
-    private static Logger log=
-        Logger.getLogger(ServletConfigImpl.class.getName());
-
-    private static final String[] DEFAULT_SERVLET_METHODS = new String[] {
-                                                    "GET", "HEAD", "POST" };
-
-    // TODO: refactor all 'stm' to separate class (not implemented)
-    //    public static final String SINGLE_THREADED_PROXY =
-    //             "org.apache.tomcat.servlets.jsp.SingleThreadedProxyServlet";
-
-    protected String description;
-    protected Map<String, String> initParams = new HashMap<String, String>();
-    protected String servletName;
-    protected String servletClassName;
-    protected String jspFile;
-    protected int loadOnStartup = -1;
-    protected String runAs;
-    protected Map securityRoleRef = new HashMap(); // roleName -> [roleLink]
-
-    /**
-     * The date and time at which this servlet will become available (in
-     * milliseconds since the epoch), or zero if the servlet is available.
-     * If this value equals Long.MAX_VALUE, the unavailability of this
-     * servlet is considered permanent.
-     */
-    private transient long available = 0L;
-
-    private ServletContextImpl ctx;
-
-    /**
-     * The (single) initialized instance of this servlet.
-     */
-    private transient Servlet instance = null;
-
-    /**
-     * Are we unloading our servlet instance at the moment?
-     */
-    private transient boolean unloading = false;
-
-    private Class servletClass = null;
-
-    // Support for SingleThreaded
-    /**
-     * The count of allocations that are currently active (even if they
-     * are for the same instance, as will be true on a non-STM servlet).
-     */
-    private transient int countAllocated = 0;
-
-    private transient boolean singleThreadModel = false;
-    /**
-     * Stack containing the STM instances.
-     */
-    private transient Stack instancePool = null;
-
-
-    // Statistics
-    private transient long loadTime=0;
-    private transient int classLoadTime=0;
-
-    // ------------------------------------------------------------- Properties
-    public ServletConfigImpl(ServletContextImpl ctx, String name,
-                             String classname) {
-        this.servletName = name;
-        this.servletClassName = classname;
-        this.ctx = ctx;
-        ctx.facade.notifyAdd(this);
-    }
-
-    /**
-     * Return the available date/time for this servlet, in milliseconds since
-     * the epoch.  If this date/time is Long.MAX_VALUE, it is considered to mean
-     * that unavailability is permanent and any request for this servlet will return
-     * an SC_NOT_FOUND error.  If this date/time is in the future, any request for
-     * this servlet will return an SC_SERVICE_UNAVAILABLE error.  If it is zero,
-     * the servlet is currently available.
-     */
-    public long getAvailable() {
-        return (this.available);
-    }
-
-
-    /**
-     * Set the available date/time for this servlet, in milliseconds since the
-     * epoch.  If this date/time is Long.MAX_VALUE, it is considered to mean
-     * that unavailability is permanent and any request for this servlet will return
-     * an SC_NOT_FOUND error. If this date/time is in the future, any request for
-     * this servlet will return an SC_SERVICE_UNAVAILABLE error.
-     *
-     * @param available The new available date/time
-     */
-    public void setAvailable(long available) {
-
-        long oldAvailable = this.available;
-        if (available > System.currentTimeMillis())
-            this.available = available;
-        else
-            this.available = 0L;
-
-    }
-
-
-    /**
-     * Return the number of active allocations of this servlet, even if they
-     * are all for the same instance (as will be true for servlets that do
-     * not implement <code>SingleThreadModel</code>.
-     */
-    public int getCountAllocated() {
-        return (this.countAllocated);
-    }
-
-    /**
-     * Return the jsp-file setting for this servlet.
-     */
-    public String getJspFile() {
-        return jspFile;
-    }
-
-    public void setJspFile(String s) {
-      this.jspFile = s;
-    }
-
-    /**
-     * Return the load-on-startup order value (negative value means
-     * load on first call).
-     */
-    public int getLoadOnStartup() {
-        return loadOnStartup;
-    }
-
-    /**
-     * Return the fully qualified servlet class name for this servlet.
-     */
-    public String getServletClass() {
-        return servletClassName;
-    }
-
-    /**
-     * Is this servlet currently unavailable?
-     */
-    public boolean isUnavailable() {
-        if (available == 0L)
-            return (false);
-        else if (available <= System.currentTimeMillis()) {
-            available = 0L;
-            return (false);
-        } else
-            return (true);
-
-    }
-
-
-    /**
-     * Gets the names of the methods supported by the underlying servlet.
-     *
-     * This is the same set of methods included in the Allow response header
-     * in response to an OPTIONS request method processed by the underlying
-     * servlet.
-     *
-     * @return Array of names of the methods supported by the underlying
-     * servlet
-     */
-    public String[] getServletMethods() throws ServletException {
-
-        Class servletClazz = loadServlet().getClass();
-        if (!javax.servlet.http.HttpServlet.class.isAssignableFrom(
-                                                        servletClazz)) {
-            return DEFAULT_SERVLET_METHODS;
-        }
-
-        HashSet allow = new HashSet();
-        allow.add("TRACE");
-        allow.add("OPTIONS");
-
-        Method[] methods = getAllDeclaredMethods(servletClazz);
-        for (int i=0; methods != null && i<methods.length; i++) {
-            Method m = methods[i];
-
-            if (m.getName().equals("doGet")) {
-                allow.add("GET");
-                allow.add("HEAD");
-            } else if (m.getName().equals("doPost")) {
-                allow.add("POST");
-            } else if (m.getName().equals("doPut")) {
-                allow.add("PUT");
-            } else if (m.getName().equals("doDelete")) {
-                allow.add("DELETE");
-            }
-        }
-
-        String[] methodNames = new String[allow.size()];
-        return (String[]) allow.toArray(methodNames);
-
-    }
-
-
-    // --------------------------------------------------------- Public Methods
-
-
-    /**
-     * Extract the root cause from a servlet exception.
-     *
-     * @param e The servlet exception
-     */
-    public static Throwable getRootCause(ServletException e) {
-        Throwable rootCause = e;
-        Throwable rootCauseCheck = null;
-        // Extra aggressive rootCause finding
-        do {
-            try {
-                rootCauseCheck = (Throwable)IntrospectionUtils.getProperty
-                                            (rootCause, "rootCause");
-                if (rootCauseCheck!=null)
-                    rootCause = rootCauseCheck;
-
-            } catch (ClassCastException ex) {
-                rootCauseCheck = null;
-            }
-        } while (rootCauseCheck != null);
-        return rootCause;
-    }
-
-    /**
-     *  MUST be called before service()
-     *  This method should be called to get the servlet. After
-     *  service(), dealocate should be called. This deals with STM and
-     *  update use counters.
-     *
-     *  Normally called from RequestDispatcher and TomcatLite.
-     */
-    public Servlet allocate() throws ServletException {
-        // If we are currently unloading this servlet, throw an exception
-        if (unloading)
-            throw new ServletException
-              ("allocate() while unloading " + getServletName());
-
-        Servlet servlet = null;
-        if (instance == null && !singleThreadModel) {
-            // never loaded.
-            synchronized (this) {
-                if (instance == null && !singleThreadModel) {
-                    try {
-                        servlet = loadServlet();
-                    } catch (ServletException e) {
-                        throw e;
-                    } catch (Throwable e) {
-                        throw new ServletException("loadServlet()", e);
-                    }
-                    if (servlet != null && !singleThreadModel) {
-                        setServlet(servlet);
-                    }
-                }
-            }
-        }
-
-        // If not SingleThreadedModel, return the same instance every time
-        if (instance != null) {
-            countAllocated++;
-            return (instance);
-        }
-
-        // Simpler policy for ST: unbound number of servlets ( can grow to
-        // one per thread )
-
-        synchronized (instancePool) {
-            if (instancePool.isEmpty()) {
-                try {
-                    if (servlet != null) {
-                        // this is the first invocation
-                        countAllocated++;
-                        return servlet;
-                    }
-                    countAllocated++;
-                    Servlet newServlet = loadServlet();
-                    log.fine("New STM servet " + newServlet + " " +
-                            countAllocated);
-                    return newServlet;
-                } catch (ServletException e) {
-                    throw e;
-                } catch (Throwable e) {
-                    throw new ServletException("allocate " + getServletName(),
-                            e);
-                }
-            }
-            log.fine("Get from pool " + instancePool.size() +  " " +
-                    countAllocated);
-            Servlet s = (Servlet) instancePool.pop();
-            countAllocated++;
-            log.fine("After get " + instancePool.size() + " " + s  +
-                    " " + countAllocated);
-            return s;
-        }
-    }
-
-
-    /**
-     * MUST be called after service().
-     */
-    public void deallocate(Servlet servlet) {
-        // If not SingleThreadModel, no action is required
-        if (!singleThreadModel) {
-            countAllocated--;
-            return;
-        }
-
-        // Unlock and free this instance
-        synchronized (instancePool) {
-            countAllocated--;
-            if (instancePool.contains(servlet)) {
-                System.err.println("Aleady in pool " + servlet + " "
-                        + instancePool.size()+ " " + countAllocated);
-                return;
-            }
-            System.err.println("return  pool " + servlet +  " " +
-                    instancePool.size() + " " + countAllocated);
-            instancePool.push(servlet);
-        }
-    }
-
-    public Servlet newInstance() throws ServletException {
-        String actualClass = servletClassName;
-
-        if (instance != null) {
-            return instance;
-        }
-        if (actualClass == null) {
-            // No explicit name. Try to use the framework
-            if (jspFile != null) {
-
-                // Named JSPs can be handled by a servlet or by the mapper.
-                Servlet res = (Servlet) ctx.getObjectManager().get("filetemplate-servlet");
-                if (res != null) {
-                    servletClass = res.getClass();
-                    actualClass = servletClass.getName();
-                    initParams.put("jsp-file", jspFile);
-                    return res;
-                } else {
-                    UserTemplateClassMapper mapper =
-                        (UserTemplateClassMapper) ctx.getObjectManager().get(
-                                UserTemplateClassMapper.class);
-                    if (mapper != null) {
-                        return mapper.loadProxy(jspFile, ctx, this);
-                    }
-                }
-            }
-            if (actualClass == null) {
-                // Covers 'default-" and "jspwildcard-" servlets as well
-                Servlet res = (Servlet) ctx.getObjectManager().get( servletName +
-                        "-servlet");
-                if (res != null) {
-                    servletClass = res.getClass();
-                    actualClass = servletClass.getName();
-                    return res;
-                }
-            }
-
-            //ctx.getObjectManager().getObject(c);
-            //ctx.getObjectManager().getObject(servletName);
-        }
-
-
-        if (servletClass == null) {
-            // set classClass
-            loadClass(actualClass);
-        }
-
-
-        // jsp-file case. Load the JspProxyServlet instead, with the
-        // right params. Note the JspProxyServlet is _not_ jasper,
-        // nor 'jsp' servlet - it is just a proxy with no special
-        // params. It calls the jsp servlet and jasper to generate the
-        // real class.
-
-        // this is quite different from catalina, where an ugly kludge was
-        // used to use the same jsp servlet in 2 roles
-
-        // the jsp proxy is replaced by the web.xml processor
-
-        if (servletClass == null) {
-            unavailable(null);
-            throw new UnavailableException("ClassNotFound: " + actualClass);
-        }
-
-        // Instantiate and initialize an instance of the servlet class itself
-        try {
-            return (Servlet) servletClass.newInstance();
-        } catch (ClassCastException e) {
-            unavailable(null);
-            throw new UnavailableException("ClassCast: (Servlet)" +
-                    actualClass);
-        } catch (Throwable e) {
-            unavailable(null);
-
-            // Added extra log statement for Bugzilla 36630:
-            // http://issues.apache.org/bugzilla/show_bug.cgi?id=36630
-            if(log.isLoggable(Level.FINE)) {
-                log.log(Level.FINE, "newInstance() error: servlet-name: " +
-                        getServletName() +
-                        " servlet-class: " + actualClass, e);
-            }
-
-            // Restore the context ClassLoader
-            throw new ServletException("newInstance() error " + getServletName() +
-                    " " + actualClass, e);
-        }
-    }
-
-    /**
-     * Load and initialize an instance of this servlet, if there is not already
-     * at least one initialized instance.  This can be used, for example, to
-     * load servlets that are marked in the deployment descriptor to be loaded
-     * at server startup time.
-     */
-    public synchronized Servlet loadServlet() throws ServletException {
-        // Nothing to do if we already have an instance or an instance pool
-        if (!singleThreadModel && (instance != null))
-            return instance;
-
-        long t1=System.currentTimeMillis();
-
-        Servlet servlet = newInstance();
-
-        classLoadTime=(int) (System.currentTimeMillis() -t1);
-
-        // Call the initialization method of this servlet
-        try {
-            servlet.init(this);
-        } catch (UnavailableException f) {
-            unavailable(f);
-            throw f;
-        } catch (ServletException f) {
-            throw f;
-        } catch (Throwable f) {
-            getServletContext().log("StandardWrapper.Throwable", f );
-            throw new ServletException("Servlet.init()", f);
-        }
-
-        // Register our newly initialized instance
-        singleThreadModel = servlet instanceof SingleThreadModel;
-        if (singleThreadModel) {
-            if (instancePool == null)
-                instancePool = new Stack();
-        }
-        loadTime=System.currentTimeMillis() -t1;
-
-        return servlet;
-    }
-
-
-    private void loadClass(String actualClass) throws ServletException {
-        // Complain if no servlet class has been specified
-        if (actualClass == null) {
-            unavailable(null);
-            throw new ServletException("servlet-class missing " +
-                    getServletName());
-        }
-
-        ClassLoader classLoader = ctx.getClassLoader();
-        if (classLoader == null )
-            classLoader = this.getClass().getClassLoader();
-
-        // Load the specified servlet class from the appropriate class loader
-        try {
-            servletClass = classLoader.loadClass(actualClass);
-        } catch (ClassNotFoundException e) {
-            servletClass = null;
-        }
-    }
-
-    /**
-     * Return a String representation of this component.
-     */
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        if (ctx != null) {
-            sb.append(ctx.toString());
-            sb.append(".");
-        }
-        sb.append("Servlet[");
-        sb.append(getServletName()).append(" ");
-        sb.append(servletClassName);
-        if (jspFile != null) {
-            sb.append(" jsp=").append(jspFile);
-        }
-        sb.append("]");
-        return (sb.toString());
-    }
-
-
-    /**
-     * Process an UnavailableException, marking this servlet as unavailable
-     * for the specified amount of time.
-     *
-     * @param unavailable The exception that occurred, or <code>null</code>
-     *  to mark this servlet as permanently unavailable
-     */
-    public void unavailable(UnavailableException unavailable) {
-        getServletContext().log("UnavailableException:" + getServletName());
-        if (unavailable == null)
-            setAvailable(Long.MAX_VALUE);
-        else if (unavailable.isPermanent())
-            setAvailable(Long.MAX_VALUE);
-        else {
-            int unavailableSeconds = unavailable.getUnavailableSeconds();
-            if (unavailableSeconds <= 0)
-                unavailableSeconds = 60;        // Arbitrary default
-            setAvailable(System.currentTimeMillis() +
-                         (unavailableSeconds * 1000L));
-        }
-
-    }
-
-
-    /**
-     * Unload all initialized instances of this servlet, after calling the
-     * <code>destroy()</code> method for each instance.  This can be used,
-     * for example, prior to shutting down the entire servlet engine, or
-     * prior to reloading all of the classes from the Loader associated with
-     * our Loader's repository.
-     *
-     * @exception ServletException if an exception is thrown by the
-     *  destroy() method
-     */
-    public synchronized void unload() throws ServletException {
-        setAvailable(Long.MAX_VALUE);
-
-        // Nothing to do if we have never loaded the instance
-        if (!singleThreadModel && (instance == null))
-            return;
-        unloading = true;
-
-        // Loaf a while if the current instance is allocated
-        // (possibly more than once if non-STM)
-        if (countAllocated > 0) {
-            int nRetries = 0;
-            long delay = ctx.getUnloadDelay() / 20;
-            while ((nRetries < 21) && (countAllocated > 0)) {
-                if ((nRetries % 10) == 0) {
-                    log.info("Servlet.unload() timeout " +
-                            countAllocated);
-                }
-                try {
-                    Thread.sleep(delay);
-                } catch (InterruptedException e) {
-                    ;
-                }
-                nRetries++;
-            }
-        }
-
-        ClassLoader oldCtxClassLoader =
-            Thread.currentThread().getContextClassLoader();
-        if (instance != null) {
-            ClassLoader classLoader = instance.getClass().getClassLoader();
-
-            PrintStream out = System.out;
-            // Call the servlet destroy() method
-            try {
-                Thread.currentThread().setContextClassLoader(classLoader);
-                instance.destroy();
-            } catch (Throwable t) {
-                instance = null;
-                //instancePool = null;
-                unloading = false;
-                throw new ServletException("Servlet.destroy() " +
-                        getServletName(), t);
-            } finally {
-                // restore the context ClassLoader
-                Thread.currentThread().setContextClassLoader(oldCtxClassLoader);
-            }
-
-            // Deregister the destroyed instance
-            instance = null;
-        }
-        if (singleThreadModel && (instancePool != null)) {
-            try {
-                ClassLoader classLoader = ctx.getClassLoader();
-                Thread.currentThread().setContextClassLoader(classLoader);
-                while (!instancePool.isEmpty()) {
-                    ((Servlet) instancePool.pop()).destroy();
-                }
-            } catch (Throwable t) {
-                instancePool = null;
-                unloading = false;
-                throw new ServletException("Servlet.destroy() " + getServletName(), t);
-            } finally {
-                // restore the context ClassLoader
-                Thread.currentThread().setContextClassLoader
-                    (oldCtxClassLoader);
-            }
-            instancePool = null;
-        }
-
-        singleThreadModel = false;
-
-        unloading = false;
-    }
-
-
-    /**
-     * Return the initialization parameter value for the specified name,
-     * if any; otherwise return <code>null</code>.
-     *
-     * @param name Name of the initialization parameter to retrieve
-     */
-    public String getInitParameter(String name) {
-        return initParams.get(name);
-    }
-
-
-    /**
-     * Return the set of initialization parameter names defined for this
-     * servlet.  If none are defined, an empty Enumeration is returned.
-     */
-    public Enumeration getInitParameterNames() {
-        synchronized (initParams) {
-            return (new Enumerator(initParams.keySet()));
-        }
-    }
-
-
-    /**
-     * Return the servlet context with which this servlet is associated.
-     */
-    public ServletContext getServletContext() {
-        return ctx;
-    }
-
-
-    /**
-     * Return the name of this servlet.
-     */
-    public String getServletName() {
-        return servletName;
-    }
-
-//    public long getProcessingTime() {
-//        return swValve.getProcessingTime();
-//    }
-//
-//    public void setProcessingTime(long processingTime) {
-//        swValve.setProcessingTime(processingTime);
-//    }
-//
-//    public long getMaxTime() {
-//        return swValve.getMaxTime();
-//    }
-//
-//    public void setMaxTime(long maxTime) {
-//        swValve.setMaxTime(maxTime);
-//    }
-//
-//    public long getMinTime() {
-//        return swValve.getMinTime();
-//    }
-//
-//    public void setMinTime(long minTime) {
-//        swValve.setMinTime(minTime);
-//    }
-//
-//    public int getRequestCount() {
-//        return swValve.getRequestCount();
-//    }
-//
-//    public void setRequestCount(int requestCount) {
-//        swValve.setRequestCount(requestCount);
-//    }
-//
-//    public int getErrorCount() {
-//        return swValve.getErrorCount();
-//    }
-//
-//    public void setErrorCount(int errorCount) {
-//           swValve.setErrorCount(errorCount);
-//    }
-//
-//    /**
-//     * Increment the error count used for monitoring.
-//     */
-//    public void incrementErrorCount(){
-//        swValve.setErrorCount(swValve.getErrorCount() + 1);
-//    }
-//
-//    public long getLoadTime() {
-//        return loadTime;
-//    }
-//
-//    public void setLoadTime(long loadTime) {
-//        this.loadTime = loadTime;
-//    }
-//
-//    public int getClassLoadTime() {
-//        return classLoadTime;
-//    }
-
-    // -------------------------------------------------------- Package Methods
-
-
-    // -------------------------------------------------------- Private Methods
-
-    private Method[] getAllDeclaredMethods(Class c) {
-
-        if (c.equals(javax.servlet.http.HttpServlet.class)) {
-            return null;
-        }
-
-        Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
-
-        Method[] thisMethods = c.getDeclaredMethods();
-        if (thisMethods == null) {
-            return parentMethods;
-        }
-
-        if ((parentMethods != null) && (parentMethods.length > 0)) {
-            Method[] allMethods =
-                new Method[parentMethods.length + thisMethods.length];
-        System.arraycopy(parentMethods, 0, allMethods, 0,
-                             parentMethods.length);
-        System.arraycopy(thisMethods, 0, allMethods, parentMethods.length,
-                             thisMethods.length);
-
-        thisMethods = allMethods;
-    }
-
-    return thisMethods;
-    }
-
-    /** Specify the instance. Avoids the class lookup, disables unloading.
-     *  Use for embedded case, or to control the allocation.
-     *
-     * @param servlet
-     */
-    public void setServlet(Servlet servlet) {
-        instance = servlet;
-        ctx.getObjectManager().bind("Servlet:" +
-                ctx.getContextPath() + ":" + getServletName(),
-                this);
-    }
-
-    public String getSecurityRoleRef(String role) {
-        return (String)securityRoleRef.get(role);
-    }
-
-    public void setSecurityRoleRef(Map securityRoles) {
-      this.securityRoleRef = securityRoles;
-    }
-
-    public void setConfig(Map initParams) {
-      this.initParams = initParams;
-    }
-
-    public void setLoadOnStartup(int loadOnStartup) {
-      this.loadOnStartup = loadOnStartup;
-    }
-
-   @Override
-    public Set<String> addMapping(String... urlPatterns) {
-        if (ctx.startDone) {
-            // Use the context method instead of the servlet API to
-            // add mappings after context init.
-            throw new IllegalStateException();
-        }
-        Set<String> failed = new HashSet<String>();
-        for (String url: urlPatterns) {
-            if (url == null) {
-                throw new IllegalArgumentException();
-            }
-            if (ctx.contextConfig.servletMapping.get(url) != null) {
-                failed.add(url);
-            } else {
-                ctx.contextConfig.servletMapping.put(url, getServletName());
-                ctx.addMapping(url, this);
-            }
-        }
-        return failed;
-    }
-
-
-   @Override
-    public boolean setInitParameter(String name, String value)
-            throws IllegalArgumentException, IllegalStateException {
-        return ServletContextImpl.setInitParameter(ctx, initParams,
-                name, value);
-    }
-
-
-   @Override
-    public Set<String> setInitParameters(Map<String, String> initParameters)
-            throws IllegalArgumentException, IllegalStateException {
-        return ServletContextImpl.setInitParameters(ctx, initParams,
-                initParameters);
-    }
-
-    public Dynamic getDynamic() {
-        return dynamic;
-    }
-
-    class ServletDynamicRegistration implements Dynamic {
-
-
-        @Override
-        public void setAsyncSupported(boolean isAsyncSupported)
-                throws IllegalStateException {
-            asyncSupported = isAsyncSupported;
-        }
-
-
-        public void setDescription(String description)
-                throws IllegalStateException {
-            ServletConfigImpl.this.description = description;
-        }
-
-        @Override
-        public Set<String> setServletSecurity(ServletSecurityElement constraint) {
-            //implement me
-            return null;
-        }
-
-        @Override
-        public void setLoadOnStartup(int loadOnStartup) {
-            //implement me - here to compile
-        }
-
-        @Override
-        public void setMultipartConfig(MultipartConfigElement multipartConfig) {
-            //implement me - here to compile
-        }
-
-        @Override
-        public void setRunAsRole(String roleName) {
-            //implement me - here to compile
-        }
-
-        @Override
-        public String getRunAsRole() {
-            //implement me - here to compile
-            return null;
-        }
-
-        @Override
-        public Collection<String> getMappings() {
-            //implement me
-            return null;
-        }
-
-        @Override
-        public Set<String> addMapping(String... urlPatterns) {
-            //implement me
-            return null;
-        }
-
-        @Override
-        public Map<String, String> getInitParameters() {
-            // implement me
-            return null;
-        }
-
-        @Override
-        public Set<String> setInitParameters(Map<String, String> initParameters)
-                throws IllegalArgumentException, IllegalStateException {
-            // implement me
-            return null;
-        }
-
-        @Override
-        public String getClassName() {
-            // implement me
-            return null;
-        }
-
-        @Override
-        public String getName() {
-            // implement me
-            return null;
-        }
-
-        @Override
-        public String getInitParameter(String name) {
-            // implement me
-            return null;
-        }
-
-        @Override
-        public boolean setInitParameter(String name, String value)
-                throws IllegalArgumentException, IllegalStateException {
-            // implement me
-            return false;
-        }
-
-    }
-
-   @Override
-    public Collection<String> getMappings() {
-        //implement me
-        return null;
-    }
-
-    public void setServletClass(Class<? extends Servlet> servletClass2) {
-        servletClass = servletClass2;
-    }
-
-
-   @Override
-    public String getRunAsRole() {
-        //implement me
-        return null;
-    }
-
-
-   @Override
-    public Map<String, String> getInitParameters() {
-        // implement me
-        return null;
-    }
-
-   @Override
-    public String getClassName() {
-        // implement me
-        return null;
-    }
-
-   @Override
-    public String getName() {
-        // implement me
-        return null;
-    }
-
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletContextImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletContextImpl.java
deleted file mode 100644 (file)
index 7157cde..0000000
+++ /dev/null
@@ -1,1628 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.tomcat.lite;
-
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FilenameFilter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.Enumeration;
-import java.util.EventListener;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import javax.servlet.DispatcherType;
-import javax.servlet.Filter;
-import javax.servlet.FilterRegistration;
-import javax.servlet.RequestDispatcher;
-import javax.servlet.Servlet;
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextAttributeEvent;
-import javax.servlet.ServletContextAttributeListener;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRegistration;
-import javax.servlet.SessionCookieConfig;
-import javax.servlet.SessionTrackingMode;
-import javax.servlet.FilterRegistration.Dynamic;
-import javax.servlet.descriptor.JspConfigDescriptor;
-
-import org.apache.tomcat.addons.UserSessionManager;
-import org.apache.tomcat.integration.ObjectManager;
-import org.apache.tomcat.lite.webxml.ServletContextConfig;
-import org.apache.tomcat.lite.webxml.ServletContextConfig.FilterData;
-import org.apache.tomcat.lite.webxml.ServletContextConfig.FilterMappingData;
-import org.apache.tomcat.lite.webxml.ServletContextConfig.ServletData;
-import org.apache.tomcat.servlets.util.Enumerator;
-import org.apache.tomcat.servlets.util.RequestUtil;
-import org.apache.tomcat.servlets.util.UrlUtils;
-import org.apache.tomcat.util.http.MimeMap;
-
-
-/**
- * Context - initialized from web.xml or using APIs.
- *
- * Initialization order:
- *
- *  - add all listeners
- *  - add all filters
- *  - add all servlets
- *
- *  - session parameters
- *  -
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
- * @version $Revision$ $Date$
- */
-
-public class ServletContextImpl implements ServletContext {
-
-    /**
-     * Empty collection to serve as the basis for empty enumerations.
-     */
-    private transient static final ArrayList empty = new ArrayList();
-
-    transient Logger log;
-
-    /**
-     * Base path - the directory root of the webapp
-     */
-    protected String basePath = null;
-
-    protected String contextPath;
-
-    // All config from web.xml
-    protected ServletContextConfig contextConfig = new ServletContextConfig();
-
-    MimeMap contentTypes = new MimeMap();
-
-    /**
-     * The context attributes for this context.
-     */
-    protected transient Map<String, Object> attributes = new HashMap<String, Object>();
-
-    /**
-     * List of read only attributes for this context.
-     * In catalina - used to protect workdir att. We trust the app, so no need
-     * for extra complexity.
-     */
-    //protected transient HashMap readOnlyAttributes = new HashMap();
-
-    protected transient ArrayList<EventListener> lifecycleListeners = new ArrayList();
-
-    protected UserSessionManager manager;
-
-    HashMap<String, FilterConfigImpl> filters = new HashMap<String, FilterConfigImpl>();
-
-    HashMap<String, ServletConfigImpl> servlets = new HashMap<String, ServletConfigImpl>();
-
-    ArrayList<String> securityRoles = new ArrayList<String>();
-
-    /** Mapper for filters.
-     */
-    protected WebappFilterMapper webappFilterMapper;
-
-    /** Internal mapper for request dispatcher, must have all
-     *  context mappings.
-     */
-    protected WebappServletMapper mapper;
-
-    transient Locale2Charset charsetMapper = new Locale2Charset();
-
-    transient TomcatLite facade;
-
-    ObjectManager om;
-
-    private String hostname;
-
-
-    boolean initDone = false;
-
-    boolean startDone = false;
-
-    // ------------------------------------------------- ServletContext Methods
-    public ServletContextImpl() {
-    }
-
-    public void setTomcat(TomcatLite facade) {
-        this.facade = facade;
-    }
-
-    /**
-     * Registry/framework interface associated with the context.
-     * Also available as a context attribute.
-     * @return
-     */
-    public ObjectManager getObjectManager() {
-        if (om == null) {
-            om = facade.getObjectManager();
-        }
-        return om;
-    }
-
-    public void setObjectManager(ObjectManager om) {
-        this.om = om;
-    }
-
-    public Locale2Charset getCharsetMapper() {
-        return charsetMapper;
-    }
-
-    /**
-     * Set the context path, starting with "/" - "/" for ROOT
-     * @param path
-     */
-    public void setContextPath(String path) {
-        this.contextPath = path;
-        log = Logger.getLogger("webapp" + path.replace('/', '.'));
-    }
-
-    public void setHostname(String hostname) {
-        this.hostname = hostname;
-    }
-
-    public String getHostname() {
-        return hostname;
-    }
-
-    /** The directory where this app is based. May be null.
-     *
-     * @param basePath
-     */
-    public void setBasePath(String basePath) {
-        this.basePath = basePath;
-    }
-
-    public ServletContextConfig getContextConfig() {
-        return contextConfig;
-    }
-
-    /** The directory where this app is based.
-     *
-     * @param basePath
-     */
-    public String getBasePath() {
-        return basePath;
-    }
-
-    public String getEncodedPath() {
-        return null;
-    }
-
-
-    public boolean getCookies() {
-        return false;
-    }
-
-
-    public ServletContext getServletContext() {
-        return this;
-    }
-
-    public List<EventListener> getListeners() {
-        return lifecycleListeners;
-    }
-
-    public void addListener(Class <? extends EventListener> listenerClass) {
-        // implement me
-    }
-
-    public void addListener(String className) {
-        // implement me
-    }
-
-    public <T extends EventListener> void addListener(T t) {
-      lifecycleListeners.add(t);
-    }
-
-
-    public void removeListener(EventListener listener) {
-      lifecycleListeners.remove(listener);
-    }
-
-
-
-    public Logger getLogger() {
-        return log;
-    }
-
-    public long getUnloadDelay() {
-        return 0;
-    }
-
-    public ServletConfigImpl getServletConfig(String jsp_servlet_name) {
-        return (ServletConfigImpl)servlets.get(jsp_servlet_name);
-    }
-
-    public Map getServletConfigs() {
-        return servlets;
-    }
-
-    /**
-     *  Add a servlet to the context.
-     *  Called from processWebAppData()
-     *
-     * @param servletConfig
-     */
-    public void addServletConfig(ServletConfigImpl servletConfig) {
-        servlets.put(servletConfig.getServletName(), servletConfig);
-    }
-
-    public boolean getPrivileged() {
-        return false;
-    }
-
-
-    public Map getFilters() {
-        return filters;
-    }
-
-
-    protected boolean getCrossContext() {
-        return true;
-    }
-
-    public void addMimeType(String ext, String type) {
-        contentTypes.addContentType(ext, type);
-    }
-
-    public WebappServletMapper getMapper() {
-        if (mapper == null) {
-            Object customMapper = getObjectManager().get(WebappServletMapper.class);
-            if (customMapper == null) {
-                mapper = new WebappServletMapper();
-            } else {
-                mapper = (WebappServletMapper) customMapper;
-            }
-            mapper.setServletContext(this);
-        }
-
-        return mapper;
-    }
-
-    public WebappFilterMapper getFilterMapper() {
-        if (webappFilterMapper == null) {
-            Object customMapper = getObjectManager().get(WebappFilterMapper.class);
-            if (customMapper == null) {
-                webappFilterMapper = new WebappFilterMapper();
-            } else {
-                webappFilterMapper = (WebappFilterMapper) customMapper;
-            }
-            webappFilterMapper.setServletContext(this);
-        }
-
-        return webappFilterMapper ;
-    }
-
-    public FilterConfigImpl getFilter(String name) {
-        return (FilterConfigImpl)filters.get(name);
-    }
-
-    /**
-     * Return the value of the specified context attribute, if any;
-     * otherwise return <code>null</code>.
-     *
-     * @param name Name of the context attribute to return
-     */
-    public Object getAttribute(String name) {
-        if ("ObjectManager".equals(name)) {
-            return om;
-        }
-        if ("context-listeners".equals(name)) {
-            return lifecycleListeners;
-        }
-        return (attributes.get(name));
-    }
-
-    /**
-     * Return an enumeration of the names of the context attributes
-     * associated with this context.
-     */
-    public Enumeration getAttributeNames() {
-        return new Enumerator(attributes.keySet(), true);
-    }
-
-
-    public void addSecurityRole(String role) {
-        securityRoles.add(role);
-    }
-
-    public List getSecurityRoles() {
-        return securityRoles;
-    }
-
-    /**
-     * Return a <code>ServletContext</code> object that corresponds to a
-     * specified URI on the server.  This method allows servlets to gain
-     * access to the context for various parts of the server, and as needed
-     * obtain <code>RequestDispatcher</code> objects or resources from the
-     * context.  The given path must be absolute (beginning with a "/"),
-     * and is interpreted based on our virtual host's document root.
-     *
-     * @param uri Absolute URI of a resource on the server
-     */
-    public ServletContext getContext(String uri) {
-        // TODO: support real uri ( http://host/path )
-        // Validate the format of the specified argument
-        if ((uri == null) || (!uri.startsWith("/")))
-            return (null);
-
-        ServletContextImpl child = null;
-        try {
-            child = facade.getContext(this, uri);
-        } catch (IOException e) {
-        } catch (ServletException e) {
-        }
-
-        if (child == null)
-            return (null);
-
-        if (this.getCrossContext()) {
-            // If crossContext is enabled, can always return the context
-            return child.getServletContext();
-        } else if (child == this) {
-            // Can still return the current context
-            return this.getServletContext();
-        } else {
-            // Nothing to return
-            return (null);
-        }
-    }
-
-
-    /**
-     * Return the main path associated with this context.
-     */
-    public String getContextPath() {
-        return contextPath;
-    }
-
-
-    /**
-     * Return the value of the specified initialization parameter, or
-     * <code>null</code> if this parameter does not exist.
-     *
-     * @param name Name of the initialization parameter to retrieve
-     */
-    public String getInitParameter(final String name) {
-        return ((String) contextConfig.contextParam.get(name));
-    }
-
-
-    /**
-     * Return the names of the context's initialization parameters, or an
-     * empty enumeration if the context has no initialization parameters.
-     */
-    public Enumeration getInitParameterNames() {
-        return (new Enumerator(contextConfig.contextParam.keySet()));
-    }
-
-    public void setContextParams(Map newParams) {
-      contextConfig.contextParam = (HashMap) newParams;
-    }
-
-    /**
-     * Return the major version of the Java Servlet API that we implement.
-     */
-    public int getMajorVersion() {
-        return 2;
-    }
-
-
-    /**
-     * Return the minor version of the Java Servlet API that we implement.
-     */
-    public int getMinorVersion() {
-        return 4;
-    }
-
-
-    /**
-     * Return the MIME type of the specified file, or <code>null</code> if
-     * the MIME type cannot be determined.
-     *
-     * @param file Filename for which to identify a MIME type
-     */
-    public String getMimeType(String file) {
-        return contentTypes.getMimeType(file);
-    }
-
-    /**
-     * Return the real path for a given virtual path, if possible; otherwise
-     * return <code>null</code>.
-     *
-     * @param path The path to the desired resource
-     */
-    public String getRealPath(String path) {
-        if (path == null) {
-            return null;
-        }
-
-        File file = new File(basePath, path);
-        return (file.getAbsolutePath());
-    }
-
-    /**
-     * Return a <code>RequestDispatcher</code> object that acts as a
-     * wrapper for the named servlet.
-     *
-     * @param name Name of the servlet for which a dispatcher is requested
-     */
-    public RequestDispatcher getNamedDispatcher(String name) {
-        if (name == null) return null;
-        ServletConfigImpl wrapper =
-            (ServletConfigImpl) this.getServletConfig(name);
-        if (wrapper == null) return null;
-
-        return new RequestDispatcherImpl(wrapper, name);
-    }
-
-
-    /**
-     * Return a <code>RequestDispatcher</code> instance that acts as a
-     * wrapper for the resource at the given path.  The path must begin
-     * with a "/" and is interpreted as relative to the current context root.
-     *
-     * @param path The path to the desired resource.
-     */
-    public RequestDispatcher getRequestDispatcher(String path) {
-        if (path == null) return null;
-
-        if (!path.startsWith("/"))
-            throw new IllegalArgumentException(path);
-
-        path = UrlUtils.normalize(path);
-        if (path == null)  return (null);
-
-
-        return new RequestDispatcherImpl(this, path);
-    }
-
-    public RequestDispatcher getRequestDispatcher(String path,
-                                                  int type,
-                                                  String dispatcherPath) {
-        RequestDispatcher dispatcher = getRequestDispatcher(path);
-        //((RequestDispatcherImpl)dispatcher);
-        return dispatcher;
-    }
-
-    ThreadLocal requestDispatcherStack = new ThreadLocal();
-
-    protected ClassLoader classLoader;
-
-//    protected RequestDispatcherImpl getRequestDispatcher() {
-//        ArrayList/*<RequestDispatcherImpl>*/ list =
-//            (ArrayList)requestDispatcherStack.get();
-//        if (list == null) {
-//            list = new ArrayList();
-//            requestDispatcherStack.set(list);
-//        }
-//
-//
-//        return null;
-//    }
-
-    public void resetDispatcherStack() {
-
-    }
-
-    /**
-     * Return the URL to the resource that is mapped to a specified path.
-     * The path must begin with a "/" and is interpreted as relative to the
-     * current context root.
-     *
-     * @param path The path to the desired resource
-     *
-     * @exception MalformedURLException if the path is not given
-     *  in the correct form
-     */
-    public URL getResource(String path)
-        throws MalformedURLException {
-
-        if (path == null || !path.startsWith("/")) {
-            throw new MalformedURLException("getResource() " + path);
-        }
-
-        path = UrlUtils.normalize(path);
-        if (path == null)
-            return (null);
-
-        String libPath = "/WEB-INF/lib/";
-        if ((path.startsWith(libPath)) && (path.endsWith(".jar"))) {
-            File jarFile = null;
-            jarFile = new File(basePath, path);
-            if (jarFile.exists()) {
-                return jarFile.toURL();
-            } else {
-                return null;
-            }
-        } else {
-            File resFile = new File(basePath + path);
-            if (resFile.exists()) {
-                return resFile.toURL();
-            }
-        }
-
-        return (null);
-
-    }
-
-    /**
-     * Return the requested resource as an <code>InputStream</code>.  The
-     * path must be specified according to the rules described under
-     * <code>getResource</code>.  If no such resource can be identified,
-     * return <code>null</code>.
-     *
-     * @param path The path to the desired resource.
-     */
-    public InputStream getResourceAsStream(String path) {
-
-        path = UrlUtils.normalize(path);
-        if (path == null)
-            return (null);
-
-        File resFile = new File(basePath + path);
-        if (!resFile.exists())
-            return null;
-
-        try {
-            return new FileInputStream(resFile);
-        } catch (FileNotFoundException e) {
-            return null;
-        }
-
-    }
-
-
-    /**
-     * Return a Set containing the resource paths of resources member of the
-     * specified collection. Each path will be a String starting with
-     * a "/" character. The returned set is immutable.
-     *
-     * @param path Collection path
-     */
-    public Set getResourcePaths(String path) {
-
-        // Validate the path argument
-        if (path == null) {
-            return null;
-        }
-        if (!path.startsWith("/")) {
-            throw new IllegalArgumentException("getResourcePaths() " + path);
-        }
-
-        path = UrlUtils.normalize(path);
-        if (path == null)
-            return (null);
-
-        File f = new File(basePath + path);
-        File[] files = f.listFiles();
-        if (files == null) return null;
-        if (!path.endsWith("/")) {
-          path = path + "/";
-        }
-
-        HashSet result = new HashSet();
-        for (int i=0; i < files.length; i++) {
-            if (files[i].isDirectory() ) {
-                result.add(path + files[i].getName() + "/");
-            } else {
-                result.add(path + files[i].getName());
-            }
-        }
-        return result;
-    }
-
-
-
-    /**
-     * Return the name and version of the servlet container.
-     */
-    public String getServerInfo() {
-        return "Apache Tomcat Lite";
-    }
-
-    /**
-     * @deprecated As of Java Servlet API 2.1, with no direct replacement.
-     */
-    public Servlet getServlet(String name) {
-        return (null);
-    }
-
-
-    /**
-     * Return the display name of this web application.
-     */
-    public String getServletContextName() {
-        return contextConfig.displayName;
-    }
-
-
-    /**
-     * @deprecated As of Java Servlet API 2.1, with no direct replacement.
-     */
-    public Enumeration getServletNames() {
-        return (new Enumerator(empty));
-    }
-
-
-    /**
-     * @deprecated As of Java Servlet API 2.1, with no direct replacement.
-     */
-    public Enumeration getServlets() {
-        return (new Enumerator(empty));
-    }
-
-
-    /**
-     * Writes the specified message to a servlet log file.
-     *
-     * @param message Message to be written
-     */
-    public void log(String message) {
-        this.getLogger().info(message);
-    }
-
-
-    /**
-     * Writes the specified exception and message to a servlet log file.
-     *
-     * @param exception Exception to be reported
-     * @param message Message to be written
-     *
-     * @deprecated As of Java Servlet API 2.1, use
-     *  <code>log(String, Throwable)</code> instead
-     */
-    public void log(Exception exception, String message) {
-        this.getLogger().log(Level.INFO, message, exception);
-    }
-
-
-    /**
-     * Writes the specified message and exception to a servlet log file.
-     *
-     * @param message Message to be written
-     * @param throwable Exception to be reported
-     */
-    public void log(String message, Throwable throwable) {
-        this.getLogger().log(Level.INFO, message, throwable);
-    }
-
-    /**
-     * Remove the context attribute with the specified name, if any.
-     *
-     * @param name Name of the context attribute to be removed
-     */
-    public void removeAttribute(String name) {
-
-        Object value = null;
-        boolean found = false;
-
-        // Remove the specified attribute
-        // Check for read only attribute
-        found = attributes.containsKey(name);
-        if (found) {
-            value = attributes.get(name);
-            attributes.remove(name);
-        } else {
-            return;
-        }
-
-        // Notify interested application event listeners
-        List listeners = this.getListeners();
-        if (listeners.size() == 0)
-            return;
-        ServletContextAttributeEvent event = null;
-        for (int i = 0; i < listeners.size(); i++) {
-            if (!(listeners.get(i) instanceof ServletContextAttributeListener))
-                continue;
-            ServletContextAttributeListener listener =
-                (ServletContextAttributeListener) listeners.get(i);
-            try {
-                if (event == null) {
-                    event = new ServletContextAttributeEvent(this.getServletContext(),
-                            name, value);
-
-                }
-                listener.attributeRemoved(event);
-            } catch (Throwable t) {
-                // FIXME - should we do anything besides log these?
-                log("ServletContextAttributeListener", t);
-            }
-        }
-    }
-
-
-    /**
-     * Bind the specified value with the specified context attribute name,
-     * replacing any existing value for that name.
-     *
-     * @param name Attribute name to be bound
-     * @param value New attribute value to be bound
-     */
-    public void setAttribute(String name, Object value) {
-        // Name cannot be null
-        if (name == null)
-            throw new IllegalArgumentException
-                ("name == null");
-
-        // Null value is the same as removeAttribute()
-        if (value == null) {
-            removeAttribute(name);
-            return;
-        }
-
-        Object oldValue = null;
-        boolean replaced = false;
-
-        // Add or replace the specified attribute
-        synchronized (attributes) {
-            // Check for read only attribute
-            oldValue = attributes.get(name);
-            if (oldValue != null)
-                replaced = true;
-            attributes.put(name, value);
-        }
-
-        // Notify interested application event listeners
-        List listeners = this.getListeners();
-        if (listeners.size() == 0)
-            return;
-        ServletContextAttributeEvent event = null;
-        for (int i = 0; i < listeners.size(); i++) {
-            if (!(listeners.get(i) instanceof ServletContextAttributeListener))
-                continue;
-            ServletContextAttributeListener listener =
-                (ServletContextAttributeListener) listeners.get(i);
-            try {
-                if (event == null) {
-                    if (replaced)
-                        event =
-                            new ServletContextAttributeEvent(this.getServletContext(),
-                                                             name, oldValue);
-                    else
-                        event =
-                            new ServletContextAttributeEvent(this.getServletContext(),
-                                                             name, value);
-
-                }
-                if (replaced) {
-                    listener.attributeReplaced(event);
-                } else {
-                    listener.attributeAdded(event);
-                }
-            } catch (Throwable t) {
-                // FIXME - should we do anything besides log these?
-                log("ServletContextAttributeListener error", t);
-            }
-        }
-
-    }
-
-    /**
-     * Clear all application-created attributes.
-     */
-    void clearAttributes() {
-        // Create list of attributes to be removed
-        ArrayList list = new ArrayList();
-        synchronized (attributes) {
-            Iterator iter = attributes.keySet().iterator();
-            while (iter.hasNext()) {
-                list.add(iter.next());
-            }
-        }
-
-        // Remove application originated attributes
-        // (read only attributes will be left in place)
-        Iterator keys = list.iterator();
-        while (keys.hasNext()) {
-            String key = (String) keys.next();
-            removeAttribute(key);
-        }
-    }
-
-    public void initFilters() throws ServletException {
-        Iterator fI = getFilters().values().iterator();
-        while (fI.hasNext()) {
-            FilterConfigImpl fc = (FilterConfigImpl)fI.next();
-            try {
-                fc.getFilter(); // will triger init()
-            } catch (Throwable e) {
-                log.log(Level.WARNING, getContextPath() + " Filter.init() " +
-                        fc.getFilterName(), e);
-            }
-
-        }
-    }
-
-    public void initServlets() throws ServletException {
-        Iterator fI = getServletConfigs().values().iterator();
-        Map/*<Integer, List<ServletConfigImpl>>*/ onStartup =
-            new TreeMap/*<Integer, List<ServletConfigImpl>>*/();
-        while (fI.hasNext()) {
-            ServletConfigImpl fc = (ServletConfigImpl)fI.next();
-            if (fc.getLoadOnStartup() > 0 ) {
-                Integer i = new Integer(fc.getLoadOnStartup());
-                List/*<ServletConfigImpl>*/ old = (List)onStartup.get(i);
-                if (old == null) {
-                    old = new ArrayList/*<ServletConfigImpl>*/();
-                    onStartup.put(i, old);
-                }
-                old.add(fc);
-            }
-        }
-        Iterator keys = onStartup.keySet().iterator();
-        while (keys.hasNext()) {
-            Integer key = (Integer)keys.next();
-            List/*<ServletConfigImpl>*/ servlets = (List)onStartup.get(key);
-            Iterator servletsI = servlets.iterator();
-            while (servletsI.hasNext()) {
-                ServletConfigImpl fc = (ServletConfigImpl) servletsI.next();
-                try {
-                    fc.loadServlet();
-                } catch (Throwable e) {
-                    log.log(Level.WARNING, "Error initializing  " + fc.getServletName(), e);
-                }
-            }
-        }
-    }
-
-    public void initListeners() throws ServletException {
-        Iterator fI = contextConfig.listenerClass.iterator();
-        while (fI.hasNext()) {
-            String listenerClass = (String)fI.next();
-            try {
-                Object l =
-                    getClassLoader().loadClass(listenerClass).newInstance();
-                lifecycleListeners.add((EventListener) l);
-            } catch (Throwable e) {
-                log.log(Level.WARNING, "Error initializing listener " + listenerClass, e);
-            }
-        }
-    }
-
-    public ClassLoader getClassLoader() {
-        return classLoader;
-    }
-
-    public void addMapping(String path, String name) {
-      ServletConfigImpl wrapper = getServletConfig(name);
-      addMapping(path, wrapper);
-    }
-
-    public void addMapping(String path, ServletConfig wrapper) {
-        getMapper().addWrapper(getMapper().contextMapElement, path, wrapper);
-    }
-
-
-
-    public void setWelcomeFiles(String[] name) {
-      getMapper().contextMapElement.welcomeResources = name;
-    }
-
-    public String[] getWelcomeFiles() {
-      return getMapper().contextMapElement.welcomeResources;
-    }
-
-    public void setSessionTimeout(int to) {
-      getManager().setSessionTimeout(to);
-    }
-
-    /**
-     * Initialize the context from the parsed config.
-     *
-     * Note that WebAppData is serializable.
-     */
-    public void processWebAppData(ServletContextConfig d) throws ServletException {
-        this.contextConfig = d;
-
-        for (String k: d.mimeMapping.keySet()) {
-            addMimeType(k, d.mimeMapping.get(k));
-        }
-
-        String[] wFiles = (String[])d.welcomeFileList.toArray(new String[0]);
-        if (wFiles.length == 0) {
-            wFiles = new String[] {"index.html" };
-        }
-        if (basePath != null) {
-          getMapper().contextMapElement.resources = new File(getBasePath());
-        }
-        setWelcomeFiles(wFiles);
-
-        Iterator i2 = d.filters.values().iterator();
-        while (i2.hasNext()) {
-            FilterData fd = (FilterData)i2.next();
-            addFilter(fd.filterName, fd.filterClass, fd.initParams);
-        }
-
-        Iterator i3 = d.servlets.values().iterator();
-        while (i3.hasNext()) {
-            ServletData sd = (ServletData) i3.next();
-            // jsp-file
-            if (sd.servletClass == null) {
-                if (sd.jspFile == null) {
-                    log.log(Level.WARNING, "Missing servlet class for " + sd.servletName);
-                    continue;
-                }
-            }
-
-            ServletConfigImpl sw =
-              new ServletConfigImpl(this, sd.servletName, sd.servletClass);
-            sw.setConfig(sd.initParams);
-            sw.setJspFile(sd.jspFile);
-            sw.setLoadOnStartup(sd.loadOnStartup);
-            //sw.setRunAs(sd.runAs);
-            sw.setSecurityRoleRef(sd.securityRoleRef);
-
-            addServletConfig(sw);
-        }
-
-        for (String k: d.servletMapping.keySet()) {
-            addMapping(k, d.servletMapping.get(k));
-        }
-
-        Iterator i5 = d.filterMappings.iterator();
-        while (i5.hasNext()) {
-            FilterMappingData k = (FilterMappingData) i5.next();
-            String[] disp = new String[k.dispatcher.size()];
-            if (k.urlPattern != null) {
-              addFilterMapping(k.urlPattern,
-                  k.filterName,
-                  (String[])k.dispatcher.toArray(disp));
-            }
-            if (k.servletName != null) {
-              addFilterServletMapping(k.servletName,
-                  k.filterName,
-                  (String[])k.dispatcher.toArray(disp));
-            }
-         }
-
-        for (String n: d.localeEncodingMapping.keySet()) {
-            getCharsetMapper().addCharsetMapping(n,
-                    d.localeEncodingMapping.get(n));
-        }
-    }
-
-    public void addServlet(String servletName, String servletClass,
-                           String jspFile, Map params) {
-      ServletConfigImpl sc = new ServletConfigImpl(this, servletName,
-          servletClass);
-      sc.setJspFile(jspFile);
-      sc.setConfig(params);
-      addServletConfig(sc);
-    }
-
-    @Override
-    public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) {
-      ServletConfigImpl sc = new ServletConfigImpl(this, servletName, null);
-      sc.setServlet(servlet);
-      addServletConfig(sc);
-      return sc.getDynamic();
-    }
-
-    public void addServletSec(String serlvetName, String runAs, Map roles) {
-      // TODO
-    }
-
-
-
-    public void addFilterMapping(String path, String filterName,
-                                 String[] dispatcher) {
-      getFilterMapper().addMapping(filterName,
-          path, null, dispatcher, true);
-
-    }
-
-    public void addFilterServletMapping(String servlet,
-                                        String filterName,
-                                        String[] dispatcher) {
-      getFilterMapper().addMapping(filterName,
-          null, servlet,
-          dispatcher, true);
-    }
-
-    /**
-     * Called from TomcatLite.init(), required before start.
-     *
-     * Will initialize defaults and load web.xml unless webAppData is
-     * already set and recent. No other processing is done except reading
-     * the config - you can add or alter it before start() is called.
-     *
-     * @throws ServletException
-     */
-    public void init() throws ServletException {
-        if (initDone) {
-            return;
-        }
-        initDone = true;
-        // Load global init params from the facade
-        initEngineDefaults();
-
-        initTempDir();
-
-
-        // Merge in web.xml - or other config source ( programmatic, etc )
-        ContextPreinitListener cfg =
-            (ContextPreinitListener) getObjectManager().get(
-                ContextPreinitListener.class);
-        if (cfg != null) {
-            cfg.preInit(this);
-        }
-
-        processWebAppData(contextConfig);
-
-        // if not defined yet:
-        addDefaultServlets();
-    }
-
-
-    protected void initTempDir() throws ServletException {
-        // We need a base path - at least for temp files, req. by spec
-        if (basePath == null) {
-            basePath = ("/".equals(contextPath)) ?
-                    facade.getWork().getAbsolutePath() + "/ROOT" :
-                    facade.getWork().getAbsolutePath() + contextPath;
-        }
-
-        File f = new File(basePath + "/WEB-INF/tmp");
-        f.mkdirs();
-        setAttribute("javax.servlet.context.tempdir", f);
-    }
-
-    /**
-     * Static file handler ( default )
-     * *.jsp support
-     *
-     */
-    protected void addDefaultServlets() throws ServletException {
-        if (servlets.get("default") == null) {
-            ServletConfigImpl fileS = new ServletConfigImpl(this,
-                    "default", null);
-            addServletConfig(fileS);
-            addMapping("/", fileS);
-        }
-
-        // *.jsp support
-        if (servlets.get("jspwildcard") == null) {
-            ServletConfigImpl fileS = new ServletConfigImpl(this,
-                        "jspwildcard", null);
-            addServletConfig(fileS);
-            addMapping("*.jsp", fileS);
-        }
-    }
-
-    protected void initEngineDefaults() throws ServletException {
-
-        // TODO: make this customizable, avoid loading it on startup
-        // Set the class name as default in the addon support
-        for (String sname: facade.ctxDefaultInitParam.keySet()) {
-            String path = facade.ctxDefaultInitParam.get(sname);
-            contextConfig.contextParam.put(sname, path);
-        }
-
-        for (String sname: facade.preloadServlets.keySet()) {
-            String sclass = facade.preloadServlets.get(sname);
-            ServletConfigImpl fileS = new ServletConfigImpl(this, sname, sclass);
-            addServletConfig(fileS);
-        }
-
-        for (String sname: facade.preloadMappings.keySet()) {
-            String path = facade.preloadMappings.get(sname);
-            ServletConfigImpl servletConfig = getServletConfig(sname);
-            addMapping(path, servletConfig);
-        }
-    }
-
-
-    public ArrayList getClasspath(File directory, File classesDir) {
-        ArrayList res = new ArrayList();
-        if (classesDir.isDirectory() && classesDir.exists() &&
-                classesDir.canRead()) {
-            try {
-                URL url = classesDir.toURL();
-                res.add(url);
-            } catch (MalformedURLException e) {
-            }
-        }
-        if (!directory.isDirectory() || !directory.exists()
-                || !directory.canRead()) {
-            return res;
-        }
-
-        File[] jars = directory.listFiles(new FilenameFilter() {
-            public boolean accept(File dir, String name) {
-              return name.endsWith(".jar");
-            }
-          });
-
-        for (int j = 0; j < jars.length; j++) {
-            try {
-                URL url = jars[j].toURL();
-                res.add(url);
-            } catch (MalformedURLException e) {
-            }
-        }
-        return res;
-    }
-
-
-    public void start() throws ServletException {
-        if (startDone) {
-            return;
-        }
-        String base = getBasePath();
-
-        ArrayList urls = getClasspath(new File(base + "/WEB-INF/lib"),
-                new File(base + "/WEB-INF/classes"));
-        URL[] urlsA = new URL[urls.size()];
-        urls.toArray(urlsA);
-
-        URLClassLoader parentLoader =
-            getEngine().getContextParentLoader();
-
-        // create a class loader.
-        // TODO: reimplement special 'deploy' dirs
-
-        /*
-          Repository ctxRepo = new Repository();
-          ctxRepo.setParentClassLoader(parentLoader);
-          ctxRepo.addURL(urlsA);
-          repository = ctxRepo;
-        */
-
-        classLoader = new URLClassLoader(urlsA, parentLoader);
-
-        // JMX should know about us ( TODO: is it too early ? )
-        facade.notifyAdd(this);
-
-        initListeners();
-
-        List listeners = this.getListeners();
-        ServletContextEvent event = null;
-        for (int i = 0; i < listeners.size(); i++) {
-            if (!(listeners.get(i) instanceof ServletContextListener))
-                continue;
-            ServletContextListener listener =
-                (ServletContextListener) listeners.get(i);
-            if (event == null) {
-                event = new ServletContextEvent(this);
-            }
-            try {
-                // May add servlets/filters
-                listener.contextInitialized(event);
-            } catch (Throwable t) {
-                log.log(Level.WARNING, "Context.init() contextInitialized() error:", t);
-            }
-        }
-
-
-        initFilters();
-        initServlets();
-
-        startDone = true;
-    }
-
-    public UserSessionManager getManager() {
-      if (manager == null) {
-          manager = (UserSessionManager) getObjectManager().get(
-                  UserSessionManager.class);
-          manager.setContext(this);
-          if (contextConfig.sessionTimeout > 0 ) {
-              manager.setSessionTimeout(contextConfig.sessionTimeout);
-          }
-      }
-      return manager;
-    }
-
-
-    // TODO: configurable ? init-params
-    public String getSessionCookieName() {
-        return "JSESSIONID";
-    }
-
-
-
-    public void destroy() throws ServletException {
-        // destroy filters
-        Iterator fI = filters.values().iterator();
-        while(fI.hasNext()) {
-            FilterConfigImpl fc = (FilterConfigImpl) fI.next();
-            try {
-                fc.getFilter().destroy();
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
-        // destroy servlets
-        fI = servlets.values().iterator();
-        while(fI.hasNext()) {
-            ServletConfigImpl fc = (ServletConfigImpl) fI.next();
-            try {
-                fc.unload();
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
-    }
-
-    public TomcatLite getEngine() {
-        return facade;
-    }
-
-    public String findStatusPage(int status) {
-        if (contextConfig.errorPageCode.size() == 0) {
-            return null;
-        }
-        if (status == 200) {
-            return null;
-        }
-
-        return (String) contextConfig.errorPageCode.get(Integer.toString(status));
-    }
-
-    public void handleStatusPage(ServletRequestImpl req,
-                                 ServletResponseImpl res,
-                                 int status,
-                                 String statusPage) {
-       String message = RequestUtil.filter(res.getMessage());
-       if (message == null)
-           message = "";
-       setErrorAttributes(req, status, message);
-       dispatchError(req, res, statusPage);
-   }
-
-   protected void setErrorAttributes(ServletRequestImpl req,
-                                   int status,
-                                   String message) {
-       req.setAttribute("javax.servlet.error.status_code",
-               new Integer(status));
-       if (req.getWrapper() != null) {
-           req.setAttribute("javax.servlet.error.servlet_name",
-                   req.getWrapper().servletName);
-       }
-       req.setAttribute("javax.servlet.error.request_uri",
-               req.getRequestURI());
-       req.setAttribute("javax.servlet.error.message",
-               message);
-
-   }
-
-   public void handleError(ServletRequestImpl req,
-                           ServletResponseImpl res,
-                           Throwable t) {
-       Throwable realError = t;
-       if (realError instanceof ServletException) {
-           realError = ((ServletException) realError).getRootCause();
-           if (realError == null) {
-               realError = t;
-           }
-       }
-      //if (realError instanceof ClientAbortException ) {
-
-       String errorPage = findErrorPage(t);
-       if ((errorPage == null) && (realError != t)) {
-           errorPage = findErrorPage(realError);
-       }
-
-       if (errorPage != null) {
-           setErrorAttributes(req, 500, t.getMessage());
-           req.setAttribute("javax.servlet.error.exception", realError);
-           req.setAttribute("javax.servlet.error.exception_type",
-                   realError.getClass());
-           dispatchError(req, res, errorPage);
-       } else {
-           log("Unhandled error", t);
-           if (t instanceof ServletException &&
-                   ((ServletException)t).getRootCause() != null) {
-               log("RootCause:", ((ServletException)t).getRootCause());
-           }
-           if (res.getStatus() < 500) {
-               res.setStatus(500);
-           }
-       }
-   }
-
-   protected void dispatchError(ServletRequestImpl req,
-                              ServletResponseImpl res,
-                              String errorPage) {
-       RequestDispatcher rd =
-           getRequestDispatcher(errorPage);
-       try {
-           // will clean up the buffer
-           rd.forward(req, res);
-           return; // handled
-       } catch (ServletException e) {
-           // TODO
-       } catch (IOException e) {
-           // TODO
-       }
-   }
-
-   protected String findErrorPage(Throwable exception) {
-       if (contextConfig.errorPageException.size() == 0) {
-           return null;
-       }
-       if (exception == null)
-           return (null);
-       Class clazz = exception.getClass();
-       String name = clazz.getName();
-       while (!Object.class.equals(clazz)) {
-           String page = (String)contextConfig.errorPageException.get(name);
-           if (page != null)
-               return (page);
-           clazz = clazz.getSuperclass();
-           if (clazz == null)
-               break;
-           name = clazz.getName();
-       }
-       return (null);
-
-   }
-
-
-   @Override
-   public EnumSet<SessionTrackingMode> getDefaultSessionTrackingModes() {
-       return null;
-   }
-
-
-   @Override
-   public EnumSet<SessionTrackingMode> getEffectiveSessionTrackingModes() {
-       return null;
-   }
-
-
-   @Override
-   public SessionCookieConfig getSessionCookieConfig() {
-       return null;
-   }
-
-
-   @Override
-   public void setSessionTrackingModes(EnumSet<SessionTrackingMode> sessionTrackingModes) {
-   }
-
-
-   public void addFilter(String filterName, String filterClass,
-                         Map params) {
-       FilterConfigImpl fc = new FilterConfigImpl(this);
-       fc.setData(filterName, filterClass, params);
-       filters.put(filterName, fc);
-   }
-
-
-   @Override
-   public Dynamic addFilter(String filterName, String className) {
-       FilterConfigImpl fc = new FilterConfigImpl(this);
-       fc.setData(filterName, className, new HashMap());
-       filters.put(filterName, fc);
-       return fc.getDynamic();
-   }
-
-
-   @Override
-   public Dynamic addFilter(String filterName, Filter filter) {
-       FilterConfigImpl fc = new FilterConfigImpl(this);
-       fc.setData(filterName, null, new HashMap());
-       fc.setFilter(filter);
-       filters.put(filterName, fc);
-       return fc.getDynamic();
-   }
-
-
-   @Override
-   public Dynamic addFilter(String filterName, Class<? extends Filter> filterClass) {
-       FilterConfigImpl fc = new FilterConfigImpl(this);
-       fc.setData(filterName, null, new HashMap());
-       fc.setFilterClass(filterClass);
-       filters.put(filterName, fc);
-       return fc.getDynamic();
-   }
-
-
-   @Override
-   public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName,
-                                                        String className) {
-       ServletConfigImpl sc = new ServletConfigImpl(this, servletName, className);
-       addServletConfig(sc);
-       return sc.getDynamic();
-   }
-
-
-   @Override
-   public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName,
-                                                        Class<? extends Servlet> servletClass) {
-       ServletConfigImpl sc = new ServletConfigImpl(this, servletName, servletClass.getName());
-       sc.setServletClass(servletClass);
-       addServletConfig(sc);
-       return sc.getDynamic();
-   }
-
-   // That's tricky - this filter will have no name. We need to generate one
-   // because our code relies on names.
-   AtomicInteger autoName = new AtomicInteger();
-
-
-   @Override
-   public <T extends Filter> T createFilter(Class<T> c) throws ServletException {
-       FilterConfigImpl fc = new FilterConfigImpl(this);
-       String filterName = "_tomcat_auto_filter_" + autoName.incrementAndGet();
-       fc.setData(filterName, null, new HashMap());
-       fc.setFilterClass(c);
-       filters.put(filterName, fc);
-
-       try {
-           return (T) fc.createFilter();
-       } catch (ClassCastException e) {
-           throw new ServletException(e);
-       } catch (ClassNotFoundException e) {
-           throw new ServletException(e);
-       } catch (IllegalAccessException e) {
-           throw new ServletException(e);
-       } catch (InstantiationException e) {
-           throw new ServletException(e);
-       }
-   }
-
-
-   @Override
-   public <T extends Servlet> T createServlet(Class<T> c) throws ServletException {
-       String filterName = "_tomcat_auto_servlet_" + autoName.incrementAndGet();
-       ServletConfigImpl fc = new ServletConfigImpl(this, filterName, null);
-       fc.setServletClass(c);
-       servlets.put(filterName, fc);
-
-       try {
-           return (T) fc.newInstance();
-       } catch (ClassCastException e) {
-           throw new ServletException(e);
-       }
-   }
-
-
-   public FilterRegistration findFilterRegistration(String filterName) {
-       return filters.get(filterName);
-   }
-
-
-   public ServletRegistration findServletRegistration(String servletName) {
-       return servlets.get(servletName);
-   }
-
-
-   @Override
-   public boolean setInitParameter(String name, String value) {
-       HashMap<String, String> params = contextConfig.contextParam;
-       return setInitParameter(this, params, name, value);
-   }
-
-
-   static Set<String> setInitParameters(ServletContextImpl ctx,
-           Map<String, String> params,
-           Map<String, String> initParameters)
-           throws IllegalArgumentException, IllegalStateException {
-       if (ctx.startDone) {
-           throw new IllegalStateException();
-       }
-       Set<String> result = new HashSet<String>();
-       for (String name: initParameters.keySet()) {
-           String value = initParameters.get(name);
-           if (name == null || value == null) {
-               throw new IllegalArgumentException();
-           }
-           if (!setInitParameter(ctx, params, name, value)) {
-               result.add(name);
-           }
-       }
-       return result;
-   }
-
-   /**
-    * true if the context initialization parameter with the given name and value was set successfully on this ServletContext, and false if it was not set because this ServletContext already contains a context initialization parameter with a matching name
-    * Throws:
-    * java.lang.IllegalStateException - if this ServletContext has already been initialized
-    */
-   static boolean setInitParameter(ServletContextImpl ctx, Map<String, String> params,
-                                   String name, String value) {
-       if (name == null || value == null) {
-           throw new IllegalArgumentException();
-       }
-       if (ctx.startDone) {
-           throw new IllegalStateException();
-       }
-       String oldValue = params.get(name);
-       if (oldValue != null) {
-           return false;
-       } else {
-           params.put(name, value);
-           return true;
-       }
-   }
-
-    public JspConfigDescriptor getJspConfigDescriptor() {
-        // fix me - just here to compile
-        return null;
-    }
-
-
-
-    public void declareRoles(String... roleNames) {
-        // implement me
-    }
-
-    public <T extends EventListener> T createListener(Class<T> c) throws ServletException {
-        // implement me
-        return null;
-    }
-
-    public Collection<String> getMappings() {
-        // implement me
-        return null;
-    }
-
-    public Map<String, ? extends FilterRegistration> getFilterRegistrations() {
-        // implement me
-        return null;
-    }
-
-    public FilterRegistration getFilterRegistration(String filterName) {
-        // implement me
-        return null;
-    }
-
-    public Map<String, ? extends ServletRegistration> getServletRegistrations() {
-        // implement me
-        return null;
-    }
-
-    public ServletRegistration getServletRegistration(String servletName) {
-        // implement me
-        return null;
-    }
-
-    public int getEffectiveMinorVersion() {
-        // implement me
-        return -1;
-    }
-
-    public int getEffectiveMajorVersion() {
-        // implement me
-        return -1;
-    }
-
-}
-
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletInputStreamImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletInputStreamImpl.java
deleted file mode 100644 (file)
index 5f5d914..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- * 
- * 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.apache.tomcat.lite;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.servlet.ServletInputStream;
-
-
-/**
- * Wrapper around MessageReader
- * 
- * @author Remy Maucherat
- * @author Jean-Francois Arcand
- * @author Costin Manolache
- */
-public class ServletInputStreamImpl extends ServletInputStream {
-
-
-    // ----------------------------------------------------- Instance Variables
-
-
-    protected InputStream ib;
-
-
-    // ----------------------------------------------------------- Constructors
-
-
-    public ServletInputStreamImpl(InputStream ib) {
-        this.ib = ib;
-    }
-
-    // --------------------------------------------- ServletInputStream Methods
-
-    public long skip(long n)
-        throws IOException {
-        return ib.skip(n);
-    }
-    
-    public void mark(int readAheadLimit)
-    {
-        //try {
-        ib.mark(readAheadLimit);
-//        } catch (IOException e) {
-//            e.printStackTrace();
-//        }
-    }
-
-
-    public void reset()
-        throws IOException {
-        ib.reset();
-    }
-    
-
-
-    public int read()
-        throws IOException {    
-        return ib.read();
-    }
-
-    public int available() throws IOException {
-        return ib.available();
-    }
-
-    public int read(final byte[] b) throws IOException {
-        return ib.read(b, 0, b.length);
-    }
-
-
-    public int read(final byte[] b, final int off, final int len)
-        throws IOException {
-            
-        return ib.read(b, off, len);
-    }
-
-
-    public int readLine(byte[] b, int off, int len) throws IOException {
-        return super.readLine(b, off, len);
-    }
-
-    /** 
-     * Close the stream
-     * Since we re-cycle, we can't allow the call to super.close()
-     * which would permantely disable us.
-     */
-    public void close() throws IOException {
-        ib.close();
-    }
-
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletOutputStreamImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletOutputStreamImpl.java
deleted file mode 100644 (file)
index 53ae9d0..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- * 
- * 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.apache.tomcat.lite;
-
-import java.io.IOException;
-
-import javax.servlet.ServletOutputStream;
-
-
-/**
- * Coyote implementation of the servlet output stream.
- * 
- * @author Costin Manolache
- * @author Remy Maucherat
- */
-public class ServletOutputStreamImpl 
-    extends ServletOutputStream {
-
-
-    // ----------------------------------------------------- Instance Variables
-
-
-    protected BodyWriter ob;
-
-
-    // ----------------------------------------------------------- Constructors
-
-
-    public ServletOutputStreamImpl(BodyWriter ob) {
-        this.ob = ob;
-    }
-
-
-    // --------------------------------------------------------- Public Methods
-
-
-    /**
-     * Prevent cloning the facade.
-     */
-    protected Object clone()
-        throws CloneNotSupportedException {
-        throw new CloneNotSupportedException();
-    }
-
-
-    // -------------------------------------------------------- Package Methods
-
-
-    /**
-     * Clear facade.
-     */
-    void clear() {
-        ob = null;
-    }
-
-
-    // --------------------------------------------------- OutputStream Methods
-
-
-    public void write(int i)
-        throws IOException {
-        ob.writeByte(i);
-    }
-
-
-    public void write(byte[] b)
-        throws IOException {
-        write(b, 0, b.length);
-    }
-
-
-    public void write(byte[] b, int off, int len)
-        throws IOException {
-        ob.write(b, off, len);
-    }
-
-
-    /**
-     * Will send the buffer to the client.
-     */
-    public void flush()
-        throws IOException {
-        ob.flush();
-    }
-
-
-    public void close()
-        throws IOException {
-        ob.close();
-    }
-
-
-    // -------------------------------------------- ServletOutputStream Methods
-
-
-    public void print(String s)
-        throws IOException {
-        ob.write(s);
-    }
-
-
-}
-
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletReaderImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletReaderImpl.java
deleted file mode 100644 (file)
index 3bb3308..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- * 
- * 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.apache.tomcat.lite;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.Reader;
-
-
-
-/**
- * Coyote implementation of the buffred reader.
- * 
- * @author Remy Maucherat
- */
-public class ServletReaderImpl
-    extends BufferedReader {
-
-
-    // -------------------------------------------------------------- Constants
-
-
-    private static final char[] LINE_SEP = { '\r', '\n' };
-    private static final int MAX_LINE_LENGTH = 4096;
-
-
-    // ----------------------------------------------------- Instance Variables
-
-
-    protected Reader ib;
-
-
-    protected char[] lineBuffer = null;
-
-
-    // ----------------------------------------------------------- Constructors
-
-
-    public ServletReaderImpl(Reader ib) {
-        super(ib, 1);
-        this.ib = ib;
-    }
-    
-    public void close()
-        throws IOException {
-        ib.close();
-    }
-
-
-    public int read()
-        throws IOException {
-        return ib.read();
-    }
-
-
-    public int read(char[] cbuf)
-        throws IOException {
-        return ib.read(cbuf, 0, cbuf.length);
-    }
-
-
-    public int read(char[] cbuf, int off, int len)
-        throws IOException {
-        return ib.read(cbuf, off, len);
-    }
-
-
-    public long skip(long n)
-        throws IOException {
-        return ib.skip(n);
-    }
-
-
-    public boolean ready()
-        throws IOException {
-        return ib.ready();
-    }
-
-
-    public boolean markSupported() {
-        return true;
-    }
-
-
-    public void mark(int readAheadLimit)
-        throws IOException {
-        ib.mark(readAheadLimit);
-    }
-
-
-    public void reset()
-        throws IOException {
-        ib.reset();
-    }
-
-
-    // TODO: move the readLine functionality to base coyote IO
-    public String readLine()
-        throws IOException {
-
-        if (lineBuffer == null) {
-            lineBuffer = new char[MAX_LINE_LENGTH];
-       }
-
-        String result = null;
-
-        int pos = 0;
-        int end = -1;
-        int skip = -1;
-        StringBuilder aggregator = null;
-        while (end < 0) {
-            mark(MAX_LINE_LENGTH);
-            while ((pos < MAX_LINE_LENGTH) && (end < 0)) {
-                int nRead = read(lineBuffer, pos, MAX_LINE_LENGTH - pos);
-                if (nRead < 0) {
-                    if (pos == 0) {
-                        return null;
-                    }
-                    end = pos;
-                    skip = pos;
-                }
-                for (int i = pos; (i < (pos + nRead)) && (end < 0); i++) {
-                    if (lineBuffer[i] == LINE_SEP[0]) {
-                        end = i;
-                        skip = i + 1;
-                        char nextchar;
-                        if (i == (pos + nRead - 1)) {
-                            nextchar = (char) read();
-                        } else {
-                            nextchar = lineBuffer[i+1];
-                        }
-                        if (nextchar == LINE_SEP[1]) {
-                            skip++;
-                        }
-                    } else if (lineBuffer[i] == LINE_SEP[1]) {
-                        end = i;
-                        skip = i + 1;
-                    }
-                }
-                if (nRead > 0) {
-                    pos += nRead;
-                }
-            }
-            if (end < 0) {
-                if (aggregator == null) {
-                    aggregator = new StringBuilder();
-                }
-                aggregator.append(lineBuffer);
-                pos = 0;
-            } else {
-                reset();
-                skip(skip);
-            }
-        }
-
-        if (aggregator == null) {
-            result = new String(lineBuffer, 0, end);
-        } else {
-            aggregator.append(lineBuffer, 0, end);
-            result = aggregator.toString();
-        }
-
-        return result;
-
-    }
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestImpl.java
deleted file mode 100644 (file)
index 4d9a622..0000000
+++ /dev/null
@@ -1,2572 +0,0 @@
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- *
- * 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.apache.tomcat.lite;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.UnsupportedEncodingException;
-import java.security.Principal;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.TimeZone;
-import java.util.TreeMap;
-import java.util.logging.Level;
-
-import javax.security.auth.Subject;
-import javax.servlet.AsyncContext;
-import javax.servlet.AsyncListener;
-import javax.servlet.DispatcherType;
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletInputStream;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletRequestAttributeEvent;
-import javax.servlet.ServletRequestAttributeListener;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-import javax.servlet.http.Part;
-
-import org.apache.tomcat.addons.UserSessionManager;
-import org.apache.tomcat.servlets.util.Enumerator;
-import org.apache.tomcat.servlets.util.LocaleParser;
-import org.apache.tomcat.servlets.util.RequestUtil;
-import org.apache.tomcat.util.buf.B2CConverter;
-import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.buf.UriNormalizer;
-import org.apache.tomcat.util.http.Cookies;
-import org.apache.tomcat.util.http.FastHttpDateFormat;
-import org.apache.tomcat.util.http.HttpRequest;
-import org.apache.tomcat.util.http.Parameters;
-import org.apache.tomcat.util.http.ServerCookie;
-import org.apache.tomcat.util.http.mapper.MappingData;
-
-
-/**
- *
- * Wrapper object for the Coyote request.
- *
- * @author Remy Maucherat
- * @author Craig R. McClanahan
- */
-public class ServletRequestImpl implements HttpServletRequest {
-
-    /**
-     * The request attribute under which we store the array of X509Certificate
-     * objects representing the certificate chain presented by our client,
-     * if any.
-     */
-    public static final String CERTIFICATES_ATTR =
-        "javax.servlet.request.X509Certificate";
-
-    /**
-     * The request attribute under which we store the name of the cipher suite
-     * being used on an SSL connection (as an object of type
-     * java.lang.String).
-     */
-    public static final String CIPHER_SUITE_ATTR =
-        "javax.servlet.request.cipher_suite";
-
-    /**
-     * Request dispatcher state.
-     */
-    public static final String DISPATCHER_TYPE_ATTR =
-        "org.apache.catalina.core.DISPATCHER_TYPE";
-
-    /**
-     * Request dispatcher path.
-     */
-    public static final String DISPATCHER_REQUEST_PATH_ATTR =
-        "org.apache.catalina.core.DISPATCHER_REQUEST_PATH";
-
-    /**
-     * The servlet context attribute under which we store the class path
-     * for our application class loader (as an object of type String),
-     * delimited with the appropriate path delimiter for this platform.
-     */
-    public static final String CLASS_PATH_ATTR =
-        "org.apache.catalina.jsp_classpath";
-
-
-    /**
-     * The request attribute under which we forward a Java exception
-     * (as an object of type Throwable) to an error page.
-     */
-    public static final String EXCEPTION_ATTR =
-        "javax.servlet.error.exception";
-
-
-    /**
-     * The request attribute under which we forward the request URI
-     * (as an object of type String) of the page on which an error occurred.
-     */
-    public static final String EXCEPTION_PAGE_ATTR =
-        "javax.servlet.error.request_uri";
-
-
-    /**
-     * The request attribute under which we forward a Java exception type
-     * (as an object of type Class) to an error page.
-     */
-    public static final String EXCEPTION_TYPE_ATTR =
-        "javax.servlet.error.exception_type";
-
-
-    /**
-     * The request attribute under which we forward an HTTP status message
-     * (as an object of type STring) to an error page.
-     */
-    public static final String ERROR_MESSAGE_ATTR =
-        "javax.servlet.error.message";
-
-
-    /**
-     * The request attribute under which we expose the value of the
-     * <code>&lt;jsp-file&gt;</code> value associated with this servlet,
-     * if any.
-     */
-    public static final String JSP_FILE_ATTR =
-        "org.apache.catalina.jsp_file";
-
-
-    /**
-     * The request attribute under which we store the key size being used for
-     * this SSL connection (as an object of type java.lang.Integer).
-     */
-    public static final String KEY_SIZE_ATTR =
-        "javax.servlet.request.key_size";
-
-    /**
-     * The request attribute under which we store the session id being used
-     * for this SSL connection (as an object of type java.lang.String).
-     */
-    public static final String SSL_SESSION_ID_ATTR =
-        "javax.servlet.request.ssl_session";
-
-    /**
-     * The request attribute under which we forward a servlet name to
-     * an error page.
-     */
-    public static final String SERVLET_NAME_ATTR =
-        "javax.servlet.error.servlet_name";
-
-
-    /**
-     * The name of the cookie used to pass the session identifier back
-     * and forth with the client.
-     */
-    public static final String SESSION_COOKIE_NAME = "JSESSIONID";
-
-
-    /**
-     * The name of the path parameter used to pass the session identifier
-     * back and forth with the client.
-     */
-    public static final String SESSION_PARAMETER_NAME = "jsessionid";
-
-
-    /**
-     * The request attribute under which we forward an HTTP status code
-     * (as an object of type Integer) to an error page.
-     */
-    public static final String STATUS_CODE_ATTR =
-        "javax.servlet.error.status_code";
-
-
-    /**
-     * The subject under which the AccessControlContext is running.
-     */
-    public static final String SUBJECT_ATTR =
-        "javax.security.auth.subject";
-
-
-    /**
-     * The servlet context attribute under which we store a temporary
-     * working directory (as an object of type File) for use by servlets
-     * within this web application.
-     */
-    public static final String WORK_DIR_ATTR =
-        "javax.servlet.context.tempdir";
-
-    protected static final TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT");
-
-
-    /**
-     * The default Locale if none are specified.
-     */
-    protected static Locale defaultLocale = Locale.getDefault();
-
-    // ApplicationFilterFactory. What's the use ???
-    private static Integer REQUEST_INTEGER = new Integer(8);
-
-    /**
-     * The match string for identifying a session ID parameter.
-     */
-    private static final String match = ";" + SESSION_PARAMETER_NAME + "=";
-
-    /**
-     * The set of cookies associated with this Request.
-     */
-    protected Cookie[] cookies = null;
-
-
-    /**
-     * The set of SimpleDateFormat formats to use in getDateHeader().
-     *
-     * Notice that because SimpleDateFormat is not thread-safe, we can't
-     * declare formats[] as a static variable.
-     */
-    protected SimpleDateFormat formats[] = null;
-
-
-    /**
-     * The attributes associated with this Request, keyed by attribute name.
-     */
-    protected HashMap attributes = new HashMap();
-
-
-    /**
-     * List of read only attributes for this Request.
-     */
-    //private HashMap readOnlyAttributes = new HashMap();
-
-
-    /**
-     * The preferred Locales assocaited with this Request.
-     */
-    protected ArrayList locales = new ArrayList();
-
-
-    /**
-     * Authentication type.
-     */
-    protected String authType = null;
-
-    /**
-     * User principal.
-     */
-    protected Principal userPrincipal = null;
-
-
-    /**
-     * The Subject associated with the current AccessControllerContext
-     */
-    protected transient Subject subject = null;
-
-
-    /**
-     * The current dispatcher type.
-     */
-    protected Object dispatcherType = null;
-
-
-    /**
-     * The associated input buffer.
-     */
-    protected BodyReader inputBuffer;
-
-    Connector connector;
-
-    /**
-     * ServletInputStream.
-     */
-    protected ServletInputStreamImpl inputStream;
-
-
-    /**
-     * Reader.
-     */
-    protected BufferedReader reader;
-
-
-    /**
-     * Using stream flag.
-     */
-    protected boolean usingInputStream = false;
-
-
-    /**
-     * Using writer flag.
-     */
-    protected boolean usingReader = false;
-
-
-    /**
-     * Session parsed flag.
-     */
-    protected boolean sessionParsed = false;
-
-
-    /**
-     * Request parameters parsed flag.
-     */
-    protected boolean parametersParsed = false;
-
-
-    /**
-     * Cookies parsed flag.
-     */
-    protected boolean cookiesParsed = false;
-
-
-    /**
-     * Secure flag.
-     */
-    protected boolean secure = false;
-
-
-    /**
-     * Hash map used in the getParametersMap method.
-     */
-    protected ParameterMap parameterMap = new ParameterMap();
-
-
-    /**
-     * The currently active session for this request.
-     */
-    protected HttpSession session = null;
-
-
-    /**
-     * The current request dispatcher path.
-     */
-    protected Object requestDispatcherPath = null;
-
-
-    /**
-     * Was the requested session ID received in a cookie?
-     */
-    protected boolean requestedSessionCookie = false;
-
-
-    /**
-     * The requested session ID (if any) for this request.
-     */
-    protected String requestedSessionId = null;
-
-
-    /**
-     * Was the requested session ID received in a URL?
-     */
-    protected boolean requestedSessionURL = false;
-
-
-    /**
-     * Parse locales.
-     */
-    protected boolean localesParsed = false;
-
-
-    /**
-     * Associated context.
-     */
-    protected ServletContextImpl context = null;
-
-
-
-    // --------------------------------------------------------- Public Methods
-
-    /**
-     * Filter chain associated with the request.
-     */
-    protected FilterChainImpl filterChain = new FilterChainImpl();
-
-    /**
-     * Mapping data.
-     */
-    protected MappingData mappingData = new MappingData();
-
-
-    // -------------------------------------------------------- Request Methods
-
-    /**
-     * The response with which this request is associated.
-     */
-    protected ServletResponseImpl response = new ServletResponseImpl();
-
-    /**
-     * URI byte to char converter (not recycled).
-     */
-   // protected B2CConverter URIConverter = null;
-
-    /**
-     * Associated wrapper.
-     */
-    protected ServletConfigImpl wrapper = null;
-
-    /**
-     * Post data buffer.
-     */
-    public final static int CACHED_POST_LEN = 8192;
-
-    public  byte[] postData = null;
-
-
-    private HttpRequest httpRequest;
-
-    /** New IO/buffer model
-     */
-    //protected Http11Connection con;
-
-
-    public ServletRequestImpl() {
-        response.setRequest(this);
-    }
-
-
-//    /**
-//     * Return the Host within which this Request is being processed.
-//     */
-//    public Host getHost() {
-//        if (getContext() == null)
-//            return null;
-//        return (Host) getContext().getParent();
-//        //return ((Host) mappingData.host);
-//    }
-//
-//
-//    /**
-//     * Set the Host within which this Request is being processed.  This
-//     * must be called as soon as the appropriate Host is identified, and
-//     * before the Request is passed to a context.
-//     *
-//     * @param host The newly associated Host
-//     */
-//    public void setHost(Host host) {
-//        mappingData.host = host;
-//    }
-
-    /**
-     * Add a Cookie to the set of Cookies associated with this Request.
-     *
-     * @param cookie The new cookie
-     */
-    public void addCookie(Cookie cookie) {
-
-        if (!cookiesParsed)
-            parseCookies();
-
-        int size = 0;
-        if (cookies != null) {
-            size = cookies.length;
-        }
-
-        Cookie[] newCookies = new Cookie[size + 1];
-        for (int i = 0; i < size; i++) {
-            newCookies[i] = cookies[i];
-        }
-        newCookies[size] = cookie;
-
-        cookies = newCookies;
-
-    }
-
-    /**
-     * Add a Header to the set of Headers associated with this Request.
-     *
-     * @param name The new header name
-     * @param value The new header value
-     */
-    public void addHeader(String name, String value) {
-        // Not used
-    }
-
-    public void setConnector(Connector c) {
-        connector = c;
-    }
-
-    public Connector getConnector() {
-        return connector;
-    }
-
-    /**
-     * Add a Locale to the set of preferred Locales for this Request.  The
-     * first added Locale will be the first one returned by getLocales().
-     *
-     * @param locale The new preferred Locale
-     */
-    public void addLocale(Locale locale) {
-        locales.add(locale);
-    }
-
-
-    /**
-     * Add a parameter name and corresponding set of values to this Request.
-     * (This is used when restoring the original request on a form based
-     * login).
-     *
-     * @param name Name of this request parameter
-     * @param values Corresponding values for this request parameter
-     */
-    public void addParameter(String name, String values[]) {
-        httpRequest.getParameters().addParameterValues(name, values);
-    }
-
-    /**
-     * Clear the collection of Cookies associated with this Request.
-     */
-    public void clearCookies() {
-        cookiesParsed = true;
-        cookies = null;
-    }
-
-    /**
-     * Clear the collection of Headers associated with this Request.
-     */
-    public void clearHeaders() {
-        // Not used
-    }
-
-    /**
-     * Clear the collection of Locales associated with this Request.
-     */
-    public void clearLocales() {
-        locales.clear();
-    }
-
-    /**
-     * Clear the collection of parameters associated with this Request.
-     */
-    public void clearParameters() {
-        // Not used
-    }
-
-
-    /**
-     * Create and return a ServletInputStream to read the content
-     * associated with this Request.
-     *
-     * @exception IOException if an input/output error occurs
-     */
-    public ServletInputStream createInputStream()
-        throws IOException {
-        return inputStream;
-    }
-
-    /**
-     * Perform whatever actions are required to flush and close the input
-     * stream or reader, in a single operation.
-     *
-     * @exception IOException if an input/output error occurs
-     */
-    public void finishRequest() throws IOException {
-        // The reader and input stream don't need to be closed
-    }
-
-
-    /**
-     * Return the specified request attribute if it exists; otherwise, return
-     * <code>null</code>.
-     *
-     * @param name Name of the request attribute to return
-     */
-    public Object getAttribute(String name) {
-
-        if (name.equals(ServletRequestImpl.DISPATCHER_TYPE_ATTR)) {
-            return (dispatcherType == null)
-                ? REQUEST_INTEGER
-                : dispatcherType;
-        } else if (name.equals(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR)) {
-            return (requestDispatcherPath == null)
-                ? getRequestPathMB().toString()
-                : requestDispatcherPath.toString();
-        }
-
-        Object attr=attributes.get(name);
-
-        if(attr!=null)
-            return(attr);
-
-//        attr =  reqB.getAttribute(name);
-//        if(attr != null)
-//            return attr;
-//        if( isSSLAttribute(name) ) {
-//            reqB.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE,
-//                                 reqB);
-//            attr = reqB.getAttribute(ServletRequestImpl.CERTIFICATES_ATTR);
-//            if( attr != null) {
-//                attributes.put(ServletRequestImpl.CERTIFICATES_ATTR, attr);
-//            }
-//            attr = reqB.getAttribute(ServletRequestImpl.CIPHER_SUITE_ATTR);
-//            if(attr != null) {
-//                attributes.put(ServletRequestImpl.CIPHER_SUITE_ATTR, attr);
-//            }
-//            attr = reqB.getAttribute(ServletRequestImpl.KEY_SIZE_ATTR);
-//            if(attr != null) {
-//                attributes.put(ServletRequestImpl.KEY_SIZE_ATTR, attr);
-//            }
-//            attr = reqB.getAttribute(ServletRequestImpl.SSL_SESSION_ID_ATTR);
-//            if(attr != null) {
-//                attributes.put(ServletRequestImpl.SSL_SESSION_ID_ATTR, attr);
-//            }
-//            attr = attributes.get(name);
-//        }
-        return attr;
-    }
-
-    /**
-     * Return the names of all request attributes for this Request, or an
-     * empty <code>Enumeration</code> if there are none.
-     */
-    public Enumeration getAttributeNames() {
-        if (isSecure()) {
-            getAttribute(ServletRequestImpl.CERTIFICATES_ATTR);
-        }
-        return new Enumerator(attributes.keySet(), true);
-    }
-
-
-    /**
-     * Return the authentication type used for this Request.
-     */
-    public String getAuthType() {
-        return (authType);
-    }
-
-
-    // ------------------------------------------------- Request Public Methods
-
-
-    /**
-     * Return the character encoding for this Request.
-     */
-    public String getCharacterEncoding() {
-      return (httpRequest.getCharacterEncoding());
-    }
-
-
-    /**
-     * Return the content length for this Request.
-     */
-    public int getContentLength() {
-        return (httpRequest.getContentLength());
-    }
-
-
-//    /**
-//     * Return the object bound with the specified name to the internal notes
-//     * for this request, or <code>null</code> if no such binding exists.
-//     *
-//     * @param name Name of the note to be returned
-//     */
-//    public Object getNote(String name) {
-//        return (notes.get(name));
-//    }
-//
-//
-//    /**
-//     * Return an Iterator containing the String names of all notes bindings
-//     * that exist for this request.
-//     */
-//    public Iterator getNoteNames() {
-//        return (notes.keySet().iterator());
-//    }
-//
-//
-//    /**
-//     * Remove any object bound to the specified name in the internal notes
-//     * for this request.
-//     *
-//     * @param name Name of the note to be removed
-//     */
-//    public void removeNote(String name) {
-//        notes.remove(name);
-//    }
-//
-//
-//    /**
-//     * Bind an object to a specified name in the internal notes associated
-//     * with this request, replacing any existing binding for this name.
-//     *
-//     * @param name Name to which the object should be bound
-//     * @param value Object to be bound to the specified name
-//     */
-//    public void setNote(String name, Object value) {
-//        notes.put(name, value);
-//    }
-//
-
-    /**
-     * Return the content type for this Request.
-     */
-    public String getContentType() {
-        return (httpRequest.getContentType());
-    }
-
-
-    /**
-     * Return the Context within which this Request is being processed.
-     */
-    public ServletContextImpl getContext() {
-        return (this.context);
-    }
-
-
-    /**
-     * Return the portion of the request URI used to select the Context
-     * of the Request.
-     */
-    public String getContextPath() {
-        return (mappingData.contextPath.toString());
-    }
-
-
-    /**
-     * Get the context path.
-     *
-     * @return the context path
-     */
-    public MessageBytes getContextPathMB() {
-        return (mappingData.contextPath);
-    }
-
-
-    /**
-     * Return the set of Cookies received with this Request.
-     */
-    public Cookie[] getCookies() {
-
-        if (!cookiesParsed)
-            parseCookies();
-
-        return cookies;
-
-    }
-
-
-    /**
-     * Return the value of the specified date header, if any; otherwise
-     * return -1.
-     *
-     * @param name Name of the requested date header
-     *
-     * @exception IllegalArgumentException if the specified header value
-     *  cannot be converted to a date
-     */
-    public long getDateHeader(String name) {
-
-        String value = getHeader(name);
-        if (value == null)
-            return (-1L);
-        if (formats == null) {
-            formats = new SimpleDateFormat[] {
-                new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
-                new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
-                new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US)
-            };
-            formats[0].setTimeZone(GMT_ZONE);
-            formats[1].setTimeZone(GMT_ZONE);
-            formats[2].setTimeZone(GMT_ZONE);
-        }
-
-        // Attempt to convert the date header in a variety of formats
-        long result = FastHttpDateFormat.parseDate(value, formats);
-        if (result != (-1L)) {
-            return result;
-        }
-        throw new IllegalArgumentException(value);
-
-    }
-
-
-    /**
-     * Get the decoded request URI.
-     *
-     * @return the URL decoded request URI
-     */
-    public String getDecodedRequestURI() {
-        return (httpRequest.decodedURI().toString());
-    }
-
-
-    /**
-     * Get the decoded request URI.
-     *
-     * @return the URL decoded request URI
-     */
-    public MessageBytes getDecodedRequestURIMB() {
-        return (httpRequest.decodedURI());
-    }
-
-
-    /**
-     * Get filter chain associated with the request.
-     */
-    public FilterChainImpl getFilterChain() {
-        return (this.filterChain);
-    }
-
-
-    // ------------------------------------------------- ServletRequest Methods
-
-    /**
-     * Return the first value of the specified header, if any; otherwise,
-     * return <code>null</code>
-     *
-     * @param name Name of the requested header
-     */
-    public String getHeader(String name) {
-        return httpRequest.getHeader(name);
-    }
-
-    /**
-     * Return the names of all headers received with this request.
-     */
-    public Enumeration getHeaderNames() {
-        return httpRequest.getMimeHeaders().names();
-    }
-
-
-    /**
-     * Return all of the values of the specified header, if any; otherwise,
-     * return an empty enumeration.
-     *
-     * @param name Name of the requested header
-     */
-    public Enumeration getHeaders(String name) {
-        return httpRequest.getMimeHeaders().values(name);
-    }
-
-    /**
-     * Return the servlet input stream for this Request.  The default
-     * implementation returns a servlet input stream created by
-     * <code>createInputStream()</code>.
-     *
-     * @exception IllegalStateException if <code>getReader()</code> has
-     *  already been called for this request
-     * @exception IOException if an input/output error occurs
-     */
-    public ServletInputStream getInputStream() throws IOException {
-
-        if (usingReader)
-            throw new IllegalStateException
-                ("usingReader");
-
-        usingInputStream = true;
-        return inputStream;
-
-    }
-
-
-    /**
-     * Return the value of the specified header as an integer, or -1 if there
-     * is no such header for this request.
-     *
-     * @param name Name of the requested header
-     *
-     * @exception IllegalArgumentException if the specified header value
-     *  cannot be converted to an integer
-     */
-    public int getIntHeader(String name) {
-
-        String value = getHeader(name);
-        if (value == null) {
-            return (-1);
-        } else {
-            return (Integer.parseInt(value));
-        }
-
-    }
-
-
-    /**
-     * Returns the Internet Protocol (IP) address of the interface on
-     * which the request  was received.
-     */
-    public String getLocalAddr(){
-        return httpRequest.localAddr().toString();
-    }
-
-
-    /**
-     * Return the preferred Locale that the client will accept content in,
-     * based on the value for the first <code>Accept-Language</code> header
-     * that was encountered.  If the request did not specify a preferred
-     * language, the server's default Locale is returned.
-     */
-    public Locale getLocale() {
-
-        if (!localesParsed)
-            parseLocales();
-
-        if (locales.size() > 0) {
-            return ((Locale) locales.get(0));
-        } else {
-            return (defaultLocale);
-        }
-
-    }
-
-
-    /**
-     * Return the set of preferred Locales that the client will accept
-     * content in, based on the values for any <code>Accept-Language</code>
-     * headers that were encountered.  If the request did not specify a
-     * preferred language, the server's default Locale is returned.
-     */
-    public Enumeration getLocales() {
-
-        if (!localesParsed)
-            parseLocales();
-
-        if (locales.size() > 0)
-            return (new Enumerator(locales));
-        ArrayList results = new ArrayList();
-        results.add(defaultLocale);
-        return (new Enumerator(results));
-
-    }
-
-
-    /**
-     * Returns the host name of the Internet Protocol (IP) interface on
-     * which the request was received.
-     */
-    public String getLocalName(){
-        return httpRequest.localName().toString();
-    }
-
-
-    /**
-     * Returns the Internet Protocol (IP) port number of the interface
-     * on which the request was received.
-     */
-    public int getLocalPort(){
-        return httpRequest.getLocalPort();
-    }
-
-
-    /**
-     * Return mapping data.
-     */
-    public MappingData getMappingData() {
-        return (mappingData);
-    }
-
-
-
-    /**
-     * Return the HTTP request method used in this Request.
-     */
-    public String getMethod() {
-        return httpRequest.method().toString();
-    }
-
-
-    /**
-     * Return the value of the specified request parameter, if any; otherwise,
-     * return <code>null</code>.  If there is more than one value defined,
-     * return only the first one.
-     *
-     * @param name Name of the desired request parameter
-     */
-    public String getParameter(String name) {
-
-        if (!parametersParsed)
-            parseParameters();
-
-        return httpRequest.getParameters().getParameter(name);
-
-    }
-
-
-    /**
-     * Returns a <code>Map</code> of the parameters of this request.
-     * Request parameters are extra information sent with the request.
-     * For HTTP servlets, parameters are contained in the query string
-     * or posted form data.
-     *
-     * @return A <code>Map</code> containing parameter names as keys
-     *  and parameter values as map values.
-     */
-    public Map getParameterMap() {
-
-        if (parameterMap.isLocked())
-            return parameterMap;
-
-        Enumeration enumeration = getParameterNames();
-        while (enumeration.hasMoreElements()) {
-            String name = enumeration.nextElement().toString();
-            String[] values = getParameterValues(name);
-            parameterMap.put(name, values);
-        }
-
-        parameterMap.setLocked(true);
-
-        return parameterMap;
-
-    }
-
-
-    /**
-     * Return the names of all defined request parameters for this request.
-     */
-    public Enumeration getParameterNames() {
-
-        if (!parametersParsed)
-            parseParameters();
-
-        return httpRequest.getParameters().getParameterNames();
-
-    }
-
-
-    /**
-     * Return the defined values for the specified request parameter, if any;
-     * otherwise, return <code>null</code>.
-     *
-     * @param name Name of the desired request parameter
-     */
-    public String[] getParameterValues(String name) {
-
-        if (!parametersParsed)
-            parseParameters();
-
-        return httpRequest.getParameters().getParameterValues(name);
-
-    }
-
-
-    /**
-     * Return the path information associated with this Request.
-     */
-    public String getPathInfo() {
-        return (mappingData.pathInfo.toString());
-    }
-
-
-    /**
-     * Get the path info.
-     *
-     * @return the path info
-     */
-    public MessageBytes getPathInfoMB() {
-        return (mappingData.pathInfo);
-    }
-
-
-    /**
-     * Return the extra path information for this request, translated
-     * to a real path.
-     */
-    public String getPathTranslated() {
-
-        if (context == null)
-            return (null);
-
-        if (getPathInfo() == null) {
-            return (null);
-        } else {
-            return (context.getServletContext().getRealPath(getPathInfo()));
-        }
-
-    }
-
-    /**
-     * Return the principal that has been authenticated for this Request.
-     */
-    public Principal getPrincipal() {
-        return (userPrincipal);
-    }
-
-    /**
-     * Return the protocol and version used to make this Request.
-     */
-    public String getProtocol() {
-        return httpRequest.protocol().toString();
-    }
-
-    /**
-     * Return the query string associated with this request.
-     */
-    public String getQueryString() {
-        String queryString = httpRequest.queryString().toString();
-        if (queryString == null || queryString.equals("")) {
-            return (null);
-        } else {
-            return queryString;
-        }
-    }
-
-
-    /**
-     * Read the Reader wrapping the input stream for this Request.  The
-     * default implementation wraps a <code>BufferedReader</code> around the
-     * servlet input stream returned by <code>createInputStream()</code>.
-     *
-     * @exception IllegalStateException if <code>getInputStream()</code>
-     *  has already been called for this request
-     * @exception IOException if an input/output error occurs
-     */
-    public BufferedReader getReader() throws IOException {
-
-        if (usingInputStream)
-            throw new IllegalStateException
-                ("usingInputStream");
-
-        usingReader = true;
-        //inputBuffer.setConverter();// getB2C());
-        return reader;
-
-    }
-
-    /**
-     * Cached list of encoders.
-     */
-    protected HashMap encoders = new HashMap();
-
-    public static final String DEFAULT_CHARACTER_ENCODING="ISO-8859-1";
-
-    /**
-     *  Converter for the encoding associated with the request.
-     *  If encoding is changed - a different encoder will be returned.
-     *
-     *  Encoders are cached ( per request ) - at least 8K per charset
-     */
-    public B2CConverter getB2C() throws IOException {
-      String enc = getCharacterEncoding();
-      if (enc == null) {
-        enc = DEFAULT_CHARACTER_ENCODING;
-      }
-      B2CConverter conv =
-        (B2CConverter) encoders.get(enc);
-      if (conv == null) {
-        conv = new B2CConverter(enc);
-        encoders.put(enc, conv);
-      }
-      return conv;
-    }
-
-    /**
-     * Return the real path of the specified virtual path.
-     *
-     * @param path Path to be translated
-     *
-     * @deprecated As of version 2.1 of the Java Servlet API, use
-     *  <code>ServletContext.getRealPath()</code>.
-     */
-    public String getRealPath(String path) {
-
-        if (context == null)
-            return (null);
-        ServletContext servletContext = context; // .getServletContext();
-        if (servletContext == null)
-            return (null);
-        else {
-            try {
-                return (servletContext.getRealPath(path));
-            } catch (IllegalArgumentException e) {
-                return (null);
-            }
-        }
-
-    }
-
-
-    /**
-     * Return the remote IP address making this Request.
-     */
-    public String getRemoteAddr() {
-      if (httpRequest.remoteAddr().isNull()) {
-        httpRequest.remoteAddr().setString(connector.getRemoteAddr(this));
-      }
-      return httpRequest.remoteAddr().toString();
-    }
-
-
-    /**
-     * Return the remote host name making this Request.
-     */
-    public String getRemoteHost() {
-      if (httpRequest.remoteHost().isNull()) {
-        httpRequest.remoteHost().setString(connector.getRemoteHost(this));
-      }
-      return httpRequest.remoteHost().toString();
-    }
-
-
-    /**
-     * Returns the Internet Protocol (IP) source port of the client
-     * or last proxy that sent the request.
-     */
-    public int getRemotePort(){
-        return httpRequest.getRemotePort();
-    }
-
-
-    /**
-     * Return the name of the remote user that has been authenticated
-     * for this Request.
-     */
-    public String getRemoteUser() {
-
-        if (userPrincipal != null) {
-            return (userPrincipal.getName());
-        } else {
-            return (null);
-        }
-
-    }
-
-
-    /**
-     * Return the <code>ServletRequest</code> for which this object
-     * is the facade.  This method must be implemented by a subclass.
-     */
-    public HttpServletRequest getRequest() {
-        return this;
-    }
-
-    public HttpRequest getHttpRequest() {
-      return httpRequest;
-    }
-
-    public void setHttpRequest(HttpRequest req, BodyReader in) {
-      this.httpRequest = req;
-      inputBuffer = in;
-      inputStream = new ServletInputStreamImpl(inputBuffer.asInputStream());
-      reader = new ServletReaderImpl(inputBuffer);
-    }
-
-    public BodyReader getBodyReader() {
-        return inputBuffer;
-    }
-
-    /**
-     * Return a RequestDispatcher that wraps the resource at the specified
-     * path, which may be interpreted as relative to the current request path.
-     *
-     * @param path Path of the resource to be wrapped
-     */
-    public RequestDispatcher getRequestDispatcher(String path) {
-
-        if (context == null)
-            return (null);
-
-        // If the path is already context-relative, just pass it through
-        if (path == null)
-            return (null);
-        else if (path.startsWith("/"))
-            return (context.getRequestDispatcher(path));
-
-        // Convert a request-relative path to a context-relative one
-        String servletPath = (String) getAttribute(RequestDispatcherImpl.INCLUDE_SERVLET_PATH_ATTR);
-        if (servletPath == null)
-            servletPath = getServletPath();
-
-        // Add the path info, if there is any
-        String pathInfo = getPathInfo();
-        String requestPath = null;
-
-        if (pathInfo == null) {
-            requestPath = servletPath;
-        } else {
-            requestPath = servletPath + pathInfo;
-        }
-
-        int pos = requestPath.lastIndexOf('/');
-        String relative = null;
-        if (pos >= 0) {
-            relative = RequestUtil.normalize
-                (requestPath.substring(0, pos + 1) + path);
-        } else {
-            relative = RequestUtil.normalize(requestPath + path);
-        }
-
-        return (context.getRequestDispatcher(relative));
-
-    }
-
-
-    /**
-     * Return the session identifier included in this request, if any.
-     */
-    public String getRequestedSessionId() {
-        return (requestedSessionId);
-    }
-
-
-    // ---------------------------------------------------- HttpRequest Methods
-
-
-    /**
-     * Get the request path.
-     *
-     * @return the request path
-     */
-    public MessageBytes getRequestPathMB() {
-        return (mappingData.requestPath);
-    }
-
-
-    /**
-     * Return the request URI for this request.
-     */
-    public String getRequestURI() {
-        return httpRequest.requestURI().toString();
-    }
-
-    /**
-     */
-    public void setRequestURI(String uri) {
-      httpRequest.decodedURI().setString(uri);
-      try {
-        UriNormalizer.decodeRequest(httpRequest.decodedURI(),
-                httpRequest.requestURI(), httpRequest.getURLDecoder());
-      } catch(IOException ioe) {
-        ioe.printStackTrace();
-        return;
-      }
-    }
-
-
-
-    /**
-     * Reconstructs the URL the client used to make the request.
-     * The returned URL contains a protocol, server name, port
-     * number, and server path, but it does not include query
-     * string parameters.
-     * <p>
-     * Because this method returns a <code>StringBuffer</code>,
-     * not a <code>String</code>, you can modify the URL easily,
-     * for example, to append query parameters.
-     * <p>
-     * This method is useful for creating redirect messages and
-     * for reporting errors.
-     *
-     * @return A <code>StringBuffer</code> object containing the
-     *  reconstructed URL
-     */
-    public StringBuffer getRequestURL() {
-
-        StringBuffer url = new StringBuffer();
-        String scheme = getScheme();
-        int port = getServerPort();
-        if (port < 0)
-            port = 80; // Work around java.net.URL bug
-
-        url.append(scheme);
-        url.append("://");
-        url.append(getServerName());
-        if ((scheme.equals("http") && (port != 80))
-            || (scheme.equals("https") && (port != 443))) {
-            url.append(':');
-            url.append(port);
-        }
-        url.append(getRequestURI());
-
-        return (url);
-
-    }
-
-
-    /**
-     * Return the Response with which this Request is associated.
-     */
-    public ServletResponseImpl getResponse() {
-        return (this.response);
-    }
-
-
-    /**
-     * Return the scheme used to make this Request.
-     */
-    public String getScheme() {
-        String scheme = httpRequest.scheme().toString();
-        if (scheme == null) {
-            scheme = (isSecure() ? "https" : "http");
-        }
-        return scheme;
-    }
-
-
-    /**
-     * Return the server name responding to this Request.
-     */
-    public String getServerName() {
-        return (httpRequest.serverName().toString());
-    }
-
-
-    /**
-     * Return the server port responding to this Request.
-     */
-    public int getServerPort() {
-        return (httpRequest.getServerPort());
-    }
-
-
-    /**
-     * Return the portion of the request URI used to select the servlet
-     * that will process this request.
-     */
-    public String getServletPath() {
-        return (mappingData.wrapperPath.toString());
-    }
-
-
-    /**
-     * Get the servlet path.
-     *
-     * @return the servlet path
-     */
-    public MessageBytes getServletPathMB() {
-        return (mappingData.wrapperPath);
-    }
-
-
-
-    /**
-     * Return the input stream associated with this Request.
-     */
-    public InputStream getStream() {
-        return inputStream;
-    }
-
-
-    /**
-     * Return the principal that has been authenticated for this Request.
-     */
-    public Principal getUserPrincipal() {
-        return userPrincipal;
-    }
-
-
-    /**
-     * Return the Wrapper within which this Request is being processed.
-     */
-    public ServletConfigImpl getWrapper() {
-        return (this.wrapper);
-    }
-
-
-    /**
-     * Return <code>true</code> if the session identifier included in this
-     * request came from a cookie.
-     */
-    public boolean isRequestedSessionIdFromCookie() {
-
-        if (requestedSessionId != null)
-            return (requestedSessionCookie);
-        else
-            return (false);
-
-    }
-
-
-    /**
-     * Return <code>true</code> if the session identifier included in this
-     * request came from the request URI.
-     *
-     * @deprecated As of Version 2.1 of the Java Servlet API, use
-     *  <code>isRequestedSessionIdFromURL()</code> instead.
-     */
-    public boolean isRequestedSessionIdFromUrl() {
-        return (isRequestedSessionIdFromURL());
-    }
-
-
-    /**
-     * Return <code>true</code> if the session identifier included in this
-     * request came from the request URI.
-     */
-    public boolean isRequestedSessionIdFromURL() {
-
-        if (requestedSessionId != null)
-            return (requestedSessionURL);
-        else
-            return (false);
-
-    }
-
-
-    /**
-     * Return <code>true</code> if the session identifier included in this
-     * request identifies a valid session.
-     */
-    public boolean isRequestedSessionIdValid() {
-
-        if (requestedSessionId == null)
-            return (false);
-        if (context == null)
-            return (false);
-        UserSessionManager manager = context.getManager();
-        if (manager == null)
-            return (false);
-        HttpSession session = null;
-        try {
-            session = manager.findSession(requestedSessionId);
-        } catch (IOException e) {
-            session = null;
-        }
-        if ((session != null) && manager.isValid(session))
-            return (true);
-        else
-            return (false);
-
-    }
-
-    /**
-     * Was this request received on a secure connection?
-     */
-    public boolean isSecure() {
-        return (secure);
-    }
-
-
-    /**
-     * Return <code>true</code> if the authenticated user principal
-     * possesses the specified role name.
-     *
-     * @param role Role name to be validated
-     */
-    public boolean isUserInRole(String role) {
-        // Have we got an authenticated principal at all?
-        Principal userPrincipal = getPrincipal();
-        if (userPrincipal == null)
-            return (false);
-
-        // Identify the Realm we will use for checking role assignmenets
-        if (context == null)
-            return (false);
-
-        // Check for a role alias defined in a <security-role-ref> element
-        if (wrapper != null) {
-            String realRole = wrapper.getSecurityRoleRef(role);
-            if (realRole != null) {
-                role = realRole;
-            }
-        }
-
-        if (role.equals(userPrincipal.getName())) {
-            return true;
-        }
-
-        // TODO: check !!!!
-        // Check for a role defined directly as a <security-role>
-        return false;
-    }
-
-    /**
-     * Release all object references, and initialize instance variables, in
-     * preparation for reuse of this object.
-     */
-    public void recycle() {
-
-        wrapper = null;
-
-        dispatcherType = null;
-        requestDispatcherPath = null;
-
-        authType = null;
-        inputBuffer.recycle();
-        usingInputStream = false;
-        usingReader = false;
-        userPrincipal = null;
-        subject = null;
-        sessionParsed = false;
-        parametersParsed = false;
-        cookiesParsed = false;
-        locales.clear();
-        localesParsed = false;
-        secure = false;
-
-        attributes.clear();
-        //notes.clear();
-        cookies = null;
-
-        if (session != null) {
-            context.getManager().endAccess(session);
-        }
-        context = null;
-        session = null;
-        requestedSessionCookie = false;
-        requestedSessionId = null;
-        requestedSessionURL = false;
-
-        parameterMap.setLocked(false);
-        parameterMap.clear();
-
-        mappingData.recycle();
-        httpRequest.recycle();
-    }
-
-
-    /**
-     * Remove the specified request attribute if it exists.
-     *
-     * @param name Name of the request attribute to remove
-     */
-    public void removeAttribute(String name) {
-        Object value = null;
-        boolean found = false;
-
-        // Remove the specified attribute
-        // Check for read only attribute
-        // requests are per thread so synchronization unnecessary
-//        if (readOnlyAttributes.containsKey(name)) {
-//            return;
-//        }
-        found = attributes.containsKey(name);
-        if (found) {
-            value = attributes.get(name);
-            attributes.remove(name);
-        } else {
-            return;
-        }
-
-        // Notify interested application event listeners
-        List listeners = context.getListeners();
-        if (listeners.size() == 0)
-            return;
-        ServletRequestAttributeEvent event = null;
-        for (int i = 0; i < listeners.size(); i++) {
-            if (!(listeners.get(i) instanceof ServletRequestAttributeListener))
-                continue;
-            ServletRequestAttributeListener listener =
-                (ServletRequestAttributeListener) listeners.get(i);
-            try {
-                if (event == null) {
-                    event =
-                        new ServletRequestAttributeEvent(context.getServletContext(),
-                            getRequest(), name, value);
-                }
-                listener.attributeRemoved(event);
-            } catch (Throwable t) {
-                context.getLogger().log(Level.WARNING, "ServletRequestAttributeListner.attributeRemoved()", t);
-                // Error valve will pick this execption up and display it to user
-                attributes.put( ServletRequestImpl.EXCEPTION_ATTR, t );
-            }
-        }
-    }
-
-
-    /**
-     * Set the specified request attribute to the specified value.
-     *
-     * @param name Name of the request attribute to set
-     * @param value The associated value
-     */
-    public void setAttribute(String name, Object value) {
-
-        // Name cannot be null
-        if (name == null)
-            throw new IllegalArgumentException
-                ("setAttribute() name == null");
-
-        // Null value is the same as removeAttribute()
-        if (value == null) {
-            removeAttribute(name);
-            return;
-        }
-
-        if (name.equals(ServletRequestImpl.DISPATCHER_TYPE_ATTR)) {
-            dispatcherType = value;
-            return;
-        } else if (name.equals(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR)) {
-            requestDispatcherPath = value;
-            return;
-        }
-
-        Object oldValue = null;
-        boolean replaced = false;
-
-        // Add or replace the specified attribute
-        // Check for read only attribute
-        // requests are per thread so synchronization unnecessary
-//        if (readOnlyAttributes.containsKey(name)) {
-//            return;
-//        }
-
-        oldValue = attributes.put(name, value);
-        if (oldValue != null) {
-            replaced = true;
-        }
-
-        // Pass special attributes to the native layer
-//        if (name.startsWith("org.apache.tomcat.")) {
-//            reqB.setAttribute(name, value);
-//        }
-//
-        // Notify interested application event listeners
-        List listeners = context.getListeners();
-        if (listeners.size() == 0)
-            return;
-        ServletRequestAttributeEvent event = null;
-
-        for (int i = 0; i < listeners.size(); i++) {
-            if (!(listeners.get(i) instanceof ServletRequestAttributeListener))
-                continue;
-            ServletRequestAttributeListener listener =
-                (ServletRequestAttributeListener) listeners.get(i);
-            try {
-                if (event == null) {
-                    if (replaced)
-                        event =
-                            new ServletRequestAttributeEvent(context.getServletContext(),
-                                                             getRequest(), name, oldValue);
-                    else
-                        event =
-                            new ServletRequestAttributeEvent(context.getServletContext(),
-                                                             getRequest(), name, value);
-                }
-                if (replaced) {
-                    listener.attributeReplaced(event);
-                } else {
-                    listener.attributeAdded(event);
-                }
-            } catch (Throwable t) {
-                context.getLogger().log(Level.WARNING, "ServletRequestAttributeListener error", t);
-                // Error valve will pick this execption up and display it to user
-                attributes.put( ServletRequestImpl.EXCEPTION_ATTR, t );
-            }
-        }
-    }
-
-
-    // --------------------------------------------- HttpServletRequest Methods
-
-
-    /**
-     * Set the authentication type used for this request, if any; otherwise
-     * set the type to <code>null</code>.  Typical values are "BASIC",
-     * "DIGEST", or "SSL".
-     *
-     * @param type The authentication type used
-     */
-    public void setAuthType(String type) {
-        this.authType = type;
-    }
-
-
-    /**
-     * Overrides the name of the character encoding used in the body of
-     * this request.  This method must be called prior to reading request
-     * parameters or reading input using <code>getReader()</code>.
-     *
-     * @param enc The character encoding to be used
-     *
-     * @exception UnsupportedEncodingException if the specified encoding
-     *  is not supported
-     *
-     * @since Servlet 2.3
-     */
-    public void setCharacterEncoding(String enc)
-        throws UnsupportedEncodingException {
-
-        // Ensure that the specified encoding is valid
-        byte buffer[] = new byte[1];
-        buffer[0] = (byte) 'a';
-        String dummy = new String(buffer, enc);
-
-        // Save the validated encoding
-        httpRequest.setCharacterEncoding(enc);
-
-    }
-
-
-//    public void setConnection(Http11Connection con) {
-//        this.con = con;
-//        //reqB.messageWriter.setConnection(con);
-//        //inputBuffer.setRequest(req);
-//    }
-
-
-    /**
-     * Set the content length associated with this Request.
-     *
-     * @param length The new content length
-     */
-    public void setContentLength(int length) {
-        // Not used
-    }
-
-
-    /**
-     * Set the content type (and optionally the character encoding)
-     * associated with this Request.  For example,
-     * <code>text/html; charset=ISO-8859-4</code>.
-     *
-     * @param type The new content type
-     */
-    public void setContentType(String type) {
-        // Not used
-    }
-
-
-    /**
-     * Set the Context within which this Request is being processed.  This
-     * must be called as soon as the appropriate Context is identified, because
-     * it identifies the value to be returned by <code>getContextPath()</code>,
-     * and thus enables parsing of the request URI.
-     *
-     * @param context The newly associated Context
-     */
-    public void setContext(ServletContextImpl context) {
-        this.context = context;
-    }
-
-
-    /**
-     * Set the context path for this Request.  This will normally be called
-     * when the associated Context is mapping the Request to a particular
-     * Wrapper.
-     *
-     * @param path The context path
-     */
-    public void setContextPath(String path) {
-
-        if (path == null) {
-            mappingData.contextPath.setString("");
-        } else {
-            mappingData.contextPath.setString(path);
-        }
-
-    }
-
-
-    /**
-     * Set the set of cookies recieved with this Request.
-     */
-    public void setCookies(Cookie[] cookies) {
-
-        this.cookies = cookies;
-
-    }
-
-
-    /**
-     * Set the decoded request URI.
-     *
-     * @param uri The decoded request URI
-     */
-    public void setDecodedRequestURI(String uri) {
-        // Not used
-    }
-
-
-    /**
-     * Set the HTTP request method used for this Request.
-     *
-     * @param method The request method
-     */
-    public void setMethod(String method) {
-      httpRequest.method().setString(method);
-    }
-
-
-    /**
-     * Set the path information for this Request.  This will normally be called
-     * when the associated Context is mapping the Request to a particular
-     * Wrapper.
-     *
-     * @param path The path information
-     */
-    public void setPathInfo(String path) {
-        mappingData.pathInfo.setString(path);
-    }
-
-
-    /**
-     * Set the protocol name and version associated with this Request.
-     *
-     * @param protocol Protocol name and version
-     */
-    public void setProtocol(String protocol) {
-        // Not used
-    }
-
-
-    /**
-     * Set the query string for this Request.  This will normally be called
-     * by the HTTP Connector, when it parses the request headers.
-     *
-     * @param query The query string
-     */
-    public void setQueryString(String query) {
-        // Not used
-    }
-
-
-    /**
-     * Set the IP address of the remote client associated with this Request.
-     *
-     * @param remoteAddr The remote IP address
-     */
-    public void setRemoteAddr(String remoteAddr) {
-        // Not used
-    }
-
-
-    /**
-     * Set the fully qualified name of the remote client associated with this
-     * Request.
-     *
-     * @param remoteHost The remote host name
-     */
-    public void setRemoteHost(String remoteHost) {
-        // Not used
-    }
-
-
-    /**
-     * Set a flag indicating whether or not the requested session ID for this
-     * request came in through a cookie.  This is normally called by the
-     * HTTP Connector, when it parses the request headers.
-     *
-     * @param flag The new flag
-     */
-    public void setRequestedSessionCookie(boolean flag) {
-
-        this.requestedSessionCookie = flag;
-
-    }
-
-
-    /**
-     * Set the requested session ID for this request.  This is normally called
-     * by the HTTP Connector, when it parses the request headers.
-     *
-     * @param id The new session id
-     */
-    public void setRequestedSessionId(String id) {
-
-        this.requestedSessionId = id;
-
-    }
-
-
-    /**
-     * Set a flag indicating whether or not the requested session ID for this
-     * request came in through a URL.  This is normally called by the
-     * HTTP Connector, when it parses the request headers.
-     *
-     * @param flag The new flag
-     */
-    public void setRequestedSessionURL(boolean flag) {
-
-        this.requestedSessionURL = flag;
-
-    }
-
-
-    /**
-     * Set the name of the scheme associated with this request.  Typical values
-     * are <code>http</code>, <code>https</code>, and <code>ftp</code>.
-     *
-     * @param scheme The scheme
-     */
-    public void setScheme(String scheme) {
-        // Not used
-    }
-
-
-    /**
-     * Set the value to be returned by <code>isSecure()</code>
-     * for this Request.
-     *
-     * @param secure The new isSecure value
-     */
-    public void setSecure(boolean secure) {
-        this.secure = secure;
-    }
-
-
-    /**
-     * Set the name of the server (virtual host) to process this request.
-     *
-     * @param name The server name
-     */
-    public void setServerName(String name) {
-        httpRequest.serverName().setString(name);
-    }
-
-
-    /**
-     * Set the port number of the server to process this request.
-     *
-     * @param port The server port
-     */
-    public void setServerPort(int port) {
-        httpRequest.setServerPort(port);
-    }
-
-
-    /**
-     * Set the servlet path for this Request.  This will normally be called
-     * when the associated Context is mapping the Request to a particular
-     * Wrapper.
-     *
-     * @param path The servlet path
-     */
-    public void setServletPath(String path) {
-        if (path != null)
-            mappingData.wrapperPath.setString(path);
-    }
-
-
-    /**
-     * Set the input stream associated with this Request.
-     *
-     * @param stream The new input stream
-     */
-    public void setStream(InputStream stream) {
-        // Ignore
-    }
-
-
-    /**
-     * Set the Principal who has been authenticated for this Request.  This
-     * value is also used to calculate the value to be returned by the
-     * <code>getRemoteUser()</code> method.
-     *
-     * @param principal The user Principal
-     */
-    public void setUserPrincipal(Principal principal) {
-
-        if (System.getSecurityManager() != null){
-            HttpSession session = getSession(false);
-            if ( (subject != null) &&
-                 (!subject.getPrincipals().contains(principal)) ){
-                subject.getPrincipals().add(principal);
-            } else if (session != null &&
-                        session.getAttribute(ServletRequestImpl.SUBJECT_ATTR) == null) {
-                subject = new Subject();
-                subject.getPrincipals().add(principal);
-            }
-            if (session != null){
-                session.setAttribute(ServletRequestImpl.SUBJECT_ATTR, subject);
-            }
-        }
-
-        this.userPrincipal = principal;
-    }
-
-
-    /**
-     * Set the Wrapper within which this Request is being processed.  This
-     * must be called as soon as the appropriate Wrapper is identified, and
-     * before the Request is ultimately passed to an application servlet.
-     * @param wrapper The newly associated Wrapper
-     */
-    public void setWrapper(ServletConfigImpl wrapper) {
-        this.wrapper = wrapper;
-    }
-
-
-    public String toString() {
-        return httpRequest.requestURI().toString();
-    }
-
-
-    /**
-     * Configures the given JSESSIONID cookie.
-     *
-     * @param cookie The JSESSIONID cookie to be configured
-     */
-    protected void configureSessionCookie(Cookie cookie) {
-        cookie.setMaxAge(-1);
-        String contextPath = null;
-        if (//!connector.getEmptySessionPath() &&
-                (getContext() != null)) {
-            contextPath = getContext().getEncodedPath();
-        }
-        if ((contextPath != null) && (contextPath.length() > 0)) {
-            cookie.setPath(contextPath);
-        } else {
-            cookie.setPath("/");
-        }
-        if (isSecure()) {
-            cookie.setSecure(true);
-        }
-    }
-
-
-    /**
-     * Return the session associated with this Request, creating one
-     * if necessary.
-     */
-    public HttpSession getSession() {
-        return getSession(true);
-    }
-
-
-    public HttpSession getSession(boolean create) {
-
-        // There cannot be a session if no context has been assigned yet
-        if (context == null)
-            return (null);
-
-
-        // Return the requested session if it exists and is valid
-        UserSessionManager manager = null;
-        if (context != null)
-            manager = context.getManager();
-        if (manager == null)
-            return (null);      // Sessions are not supported
-
-        // Return the current session if it exists and is valid
-        if ((session != null) && !manager.isValid(session))
-            session = null;
-        if (session != null)
-            return (session);
-
-
-        if (requestedSessionId != null) {
-            try {
-                session = manager.findSession(requestedSessionId);
-            } catch (IOException e) {
-                session = null;
-            }
-            if ((session != null) && !manager.isValid(session))
-                session = null;
-            if (session != null) {
-                manager.access(session);
-                return (session);
-            }
-        }
-
-        // Create a new session if requested and the response is not committed
-        if (!create)
-            return (null);
-        if ((context != null) && (response != null) &&
-            context.getCookies() &&
-            getResponse().isCommitted()) {
-            throw new IllegalStateException
-              ("isCommited()");
-        }
-
-        // Attempt to reuse session id if one was submitted in a cookie
-        // Do not reuse the session id if it is from a URL, to prevent possible
-        // phishing attacks
-        if (// connector.getEmptySessionPath() &&
-                isRequestedSessionIdFromCookie()) {
-            session = manager.createSession(getRequestedSessionId());
-        } else {
-            session = manager.createSession(null);
-        }
-
-        // Creating a new session cookie based on that session
-        if ((session != null) && (getContext() != null)
-               && getContext().getCookies()) {
-            Cookie cookie = new Cookie(ServletRequestImpl.SESSION_COOKIE_NAME,
-                                       session.getId());
-            configureSessionCookie(cookie);
-            response.addCookie(cookie);
-        }
-
-        if (session != null) {
-            manager.access(session);
-            return (session);
-        } else {
-            return (null);
-        }
-
-    }
-
-
-    /**
-     * Return the URI converter.
-     */
-//    protected B2CConverter getURIConverter() {
-//        return URIConverter;
-//    }
-//
-
-    // ------------------------------------------------------ Protected Methods
-
-
-    /**
-     * Parse cookies.
-     */
-    protected void parseCookies() {
-
-        cookiesParsed = true;
-
-        Cookies serverCookies = httpRequest.getCookies();
-        int count = serverCookies.getCookieCount();
-        if (count <= 0)
-            return;
-
-        cookies = new Cookie[count];
-
-        int idx=0;
-        for (int i = 0; i < count; i++) {
-            ServerCookie scookie = serverCookies.getCookie(i);
-            try {
-                Cookie cookie = new Cookie(scookie.getName().toString(),
-                                           scookie.getValue().toString());
-                cookie.setPath(scookie.getPath().toString());
-                cookie.setVersion(scookie.getVersion());
-                String domain = scookie.getDomain().toString();
-                if (domain != null) {
-                    cookie.setDomain(scookie.getDomain().toString());
-                }
-                cookies[idx++] = cookie;
-            } catch(IllegalArgumentException e) {
-                // Ignore bad cookie
-            }
-        }
-        if( idx < count ) {
-            Cookie [] ncookies = new Cookie[idx];
-            System.arraycopy(cookies, 0, ncookies, 0, idx);
-            cookies = ncookies;
-        }
-
-    }
-
-    /**
-     * Parse request locales.
-     */
-    protected void parseLocales() {
-
-        localesParsed = true;
-
-        Enumeration values = getHeaders("accept-language");
-
-        while (values.hasMoreElements()) {
-            String value = values.nextElement().toString();
-            parseLocalesHeader(value);
-        }
-
-    }
-
-    /**
-     * Parse accept-language header value.
-     */
-    protected void parseLocalesHeader(String value) {
-
-      TreeMap locales = new LocaleParser().parseLocale(value);
-      // Process the quality values in highest->lowest order (due to
-      // negating the Double value when creating the key)
-      Iterator keys = locales.keySet().iterator();
-      while (keys.hasNext()) {
-        Double key = (Double) keys.next();
-        ArrayList list = (ArrayList) locales.get(key);
-        Iterator values = list.iterator();
-        while (values.hasNext()) {
-          Locale locale = (Locale) values.next();
-          addLocale(locale);
-        }
-      }
-
-    }
-
-    /**
-     * Parse request parameters.
-     */
-    protected void parseParameters() {
-
-        parametersParsed = true;
-
-        Parameters parameters = httpRequest.getParameters();
-
-        // getCharacterEncoding() may have been overridden to search for
-        // hidden form field containing request encoding
-        String enc = getCharacterEncoding();
-
-//        boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();
-        if (enc != null) {
-            parameters.setEncoding(enc);
-//            if (useBodyEncodingForURI) {
-//                parameters.setQueryStringEncoding(enc);
-//            }
-        } else {
-            parameters.setEncoding(DEFAULT_CHARACTER_ENCODING);
-//            if (useBodyEncodingForURI) {
-//                parameters.setQueryStringEncoding
-//                    (DEFAULT_CHARACTER_ENCODING);
-//            }
-        }
-
-        parameters.handleQueryParameters();
-
-        if (usingInputStream || usingReader)
-            return;
-
-        if (!getMethod().equalsIgnoreCase("POST"))
-            return;
-
-        String contentType = getContentType();
-        if (contentType == null)
-            contentType = "";
-        int semicolon = contentType.indexOf(';');
-        if (semicolon >= 0) {
-            contentType = contentType.substring(0, semicolon).trim();
-        } else {
-            contentType = contentType.trim();
-        }
-        if (!("application/x-www-form-urlencoded".equals(contentType)))
-            return;
-
-        int len = getContentLength();
-
-        if (len > 0) {
-//            int maxPostSize = connector.getMaxPostSize();
-//            if ((maxPostSize > 0) && (len > maxPostSize)) {
-//                context.getLogger().info
-//                    (sm.getString("reqB.postTooLarge"));
-//                throw new IllegalStateException("Post too large");
-//            }
-            try {
-                byte[] formData = null;
-                if (len < CACHED_POST_LEN) {
-                    if (postData == null)
-                        postData = new byte[CACHED_POST_LEN];
-                    formData = postData;
-                } else {
-                    formData = new byte[len];
-                }
-                int actualLen = readPostBody(formData, len);
-                if (actualLen == len) {
-                    parameters.processParameters(formData, 0, len);
-                }
-            } catch (Throwable t) {
-                ; // Ignore
-            }
-        }
-
-    }
-
-
-    /**
-     * Parse session id in URL. Done in request for performance.
-     * TODO: should be done in manager
-     */
-    protected void parseSessionCookiesId() {
-        String sessionCookieName = context.getSessionCookieName();
-
-        // Parse session id from cookies
-        Cookies serverCookies = httpRequest.getCookies();
-        int count = serverCookies.getCookieCount();
-        if (count <= 0)
-            return;
-
-        for (int i = 0; i < count; i++) {
-            ServerCookie scookie = serverCookies.getCookie(i);
-            if (scookie.getName().equals(sessionCookieName)) {
-                // Override anything requested in the URL
-                if (!isRequestedSessionIdFromCookie()) {
-                    // Accept only the first session id cookie
-                    //scookie.getValue().convertToAscii();
-
-                    setRequestedSessionId
-                        (scookie.getValue().toString());
-                    setRequestedSessionCookie(true);
-                    setRequestedSessionURL(false);
-                } else {
-                    if (!isRequestedSessionIdValid()) {
-                        // Replace the session id until one is valid
-                        //scookie.getValue().convertToAscii();
-                        setRequestedSessionId
-                            (scookie.getValue().toString());
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Parse session id in URL.
-     */
-    protected void parseSessionId() {
-        ServletRequestImpl request = this;
-        ByteChunk uriBC = httpRequest.requestURI().getByteChunk();
-        int semicolon = uriBC.indexOf(match, 0, match.length(), 0);
-
-        if (semicolon > 0) {
-
-            // Parse session ID, and extract it from the decoded request URI
-            int start = uriBC.getStart();
-            int end = uriBC.getEnd();
-
-            int sessionIdStart = semicolon + match.length();
-            int semicolon2 = uriBC.indexOf(';', sessionIdStart);
-            if (semicolon2 >= 0) {
-                request.setRequestedSessionId
-                    (new String(uriBC.getBuffer(), start + sessionIdStart,
-                            semicolon2 - sessionIdStart));
-                // Extract session ID from request URI
-                byte[] buf = uriBC.getBuffer();
-                for (int i = 0; i < end - start - semicolon2; i++) {
-                    buf[start + semicolon + i]
-                        = buf[start + i + semicolon2];
-                }
-                uriBC.setBytes(buf, start, end - start - semicolon2 + semicolon);
-            } else {
-                request.setRequestedSessionId
-                    (new String(uriBC.getBuffer(), start + sessionIdStart,
-                            (end - start) - sessionIdStart));
-                uriBC.setEnd(start + semicolon);
-            }
-            request.setRequestedSessionURL(true);
-
-        } else {
-            request.setRequestedSessionId(null);
-            request.setRequestedSessionURL(false);
-        }
-
-    }
-
-
-    /**
-     * Read post body in an array.
-     */
-    protected int readPostBody(byte body[], int len)
-        throws IOException {
-
-        int offset = 0;
-        do {
-            int inputLen = getStream().read(body, offset, len - offset);
-            if (inputLen <= 0) {
-                return offset;
-            }
-            offset += inputLen;
-        } while ((len - offset) > 0);
-        return len;
-
-    }
-
-
-    /**
-     * Test if a given name is one of the special Servlet-spec SSL attributes.
-     */
-    static boolean isSSLAttribute(String name) {
-        return ServletRequestImpl.CERTIFICATES_ATTR.equals(name) ||
-            ServletRequestImpl.CIPHER_SUITE_ATTR.equals(name) ||
-            ServletRequestImpl.KEY_SIZE_ATTR.equals(name)  ||
-            ServletRequestImpl.SSL_SESSION_ID_ATTR.equals(name);
-    }
-
-
-    public void addAsyncListener(AsyncListener listener) {
-    }
-
-
-
-    public void addAsyncListener(AsyncListener listener,
-                                 ServletRequest servletRequest,
-                                 ServletResponse servletResponse) {
-    }
-
-
-
-    @Override
-    public AsyncContext getAsyncContext() {
-        return null;
-    }
-
-
-
-    @Override
-    public ServletContext getServletContext() {
-        return null;
-    }
-
-
-
-    @Override
-    public boolean isAsyncStarted() {
-        return false;
-    }
-
-
-
-    @Override
-    public boolean isAsyncSupported() {
-        return false;
-    }
-
-
-    public void setAsyncTimeout(long timeout) {
-    }
-
-
-
-   @Override
-    public AsyncContext startAsync() throws IllegalStateException {
-        return null;
-    }
-
-
-   @Override
-    public AsyncContext startAsync(ServletRequest servletRequest,
-                                   ServletResponse servletResponse)
-            throws IllegalStateException {
-        return null;
-    }
-
-
-
-   @Override
-    public boolean authenticate(HttpServletResponse response)
-            throws IOException, ServletException {
-        return false;
-    }
-
-
-
-   @Override
-    public Part getPart(String name) {
-        return null;
-    }
-
-
-
-   @Override
-    public void login(String username, String password) throws ServletException {
-    }
-
-
-
-   @Override
-    public void logout() throws ServletException {
-    }
-
-
-
-    public long getAsyncTimeout() {
-        return 0;
-    }
-
-
-
-   @Override
-    public DispatcherType getDispatcherType() {
-        return null;
-    }
-
-
-   @Override
-    public Collection<Part> getParts() throws IOException, ServletException {
-        return null;
-    }
-
-
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestWrapperImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletRequestWrapperImpl.java
deleted file mode 100644 (file)
index af400d8..0000000
+++ /dev/null
@@ -1,943 +0,0 @@
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- * 
- * 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.apache.tomcat.lite;
-
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.NoSuchElementException;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
-import javax.servlet.http.HttpSession;
-
-import org.apache.tomcat.addons.UserSessionManager;
-import org.apache.tomcat.servlets.util.Enumerator;
-import org.apache.tomcat.servlets.util.RequestUtil;
-
-
-/**
- * Wrapper around a <code>javax.servlet.http.HttpServletRequest</code>
- * that transforms an application request object (which might be the original
- * one passed to a servlet, or might be based on the 2.3
- * <code>javax.servlet.http.HttpServletRequestWrapper</code> class)
- * back into an internal <code>org.apache.catalina.HttpRequest</code>.
- * <p>
- * <strong>WARNING</strong>:  Due to Java's lack of support for multiple
- * inheritance, all of the logic in <code>ApplicationRequest</code> is
- * duplicated in <code>ApplicationHttpRequest</code>.  Make sure that you
- * keep these two classes in synchronization when making changes!
- *
- * @author Craig R. McClanahan
- * @author Remy Maucherat
- */
-public class ServletRequestWrapperImpl extends HttpServletRequestWrapper {
-
-
-    // ------------------------------------------------------- Static Variables
-
-
-    /**
-     * The set of attribute names that are special for request dispatchers.
-     */
-    protected static final String specials[] =
-    { RequestDispatcherImpl.INCLUDE_REQUEST_URI_ATTR, 
-      RequestDispatcherImpl.INCLUDE_CONTEXT_PATH_ATTR,
-      RequestDispatcherImpl.INCLUDE_SERVLET_PATH_ATTR, 
-      RequestDispatcherImpl.INCLUDE_PATH_INFO_ATTR,
-      RequestDispatcherImpl.INCLUDE_QUERY_STRING_ATTR, 
-      RequestDispatcherImpl.FORWARD_REQUEST_URI_ATTR, 
-      RequestDispatcherImpl.FORWARD_CONTEXT_PATH_ATTR, 
-      RequestDispatcherImpl.FORWARD_SERVLET_PATH_ATTR, 
-      RequestDispatcherImpl.FORWARD_PATH_INFO_ATTR, 
-      RequestDispatcherImpl.FORWARD_QUERY_STRING_ATTR };
-
-
-    // ----------------------------------------------------------- Constructors
-
-
-    /**
-     * Construct a new wrapped request around the specified servlet request.
-     *
-     * @param request The servlet request being wrapped
-     */
-    public ServletRequestWrapperImpl(HttpServletRequest request, 
-                                     ServletContextImpl context,
-                                     boolean crossContext) {
-
-        super(request);
-        this.context = context;
-        this.crossContext = crossContext;
-        setRequest(request);
-
-    }
-
-
-    // ----------------------------------------------------- Instance Variables
-
-
-    /**
-     * The context for this request.
-     */
-    protected ServletContextImpl context = null;
-
-
-    /**
-     * The context path for this request.
-     */
-    protected String contextPath = null;
-
-
-    /**
-     * If this request is cross context, since this changes session accesss
-     * behavior.
-     */
-    protected boolean crossContext = false;
-
-
-    /**
-     * The current dispatcher type.
-     */
-    protected Object dispatcherType = null;
-
-
-    /**
-     * Descriptive information about this implementation.
-     */
-    protected static final String info =
-        "org.apache.catalina.core.ApplicationHttpRequest/1.0";
-
-
-    /**
-     * The request parameters for this request.  This is initialized from the
-     * wrapped request, but updates are allowed.
-     */
-    protected Map parameters = null;
-
-
-    /**
-     * Have the parameters for this request already been parsed?
-     */
-    private boolean parsedParams = false;
-
-
-    /**
-     * The path information for this request.
-     */
-    protected String pathInfo = null;
-
-
-    /**
-     * The query parameters for the current request.
-     */
-    private String queryParamString = null;
-
-
-    /**
-     * The query string for this request.
-     */
-    protected String queryString = null;
-
-
-    /**
-     * The current request dispatcher path.
-     */
-    protected Object requestDispatcherPath = null;
-
-
-    /**
-     * The request URI for this request.
-     */
-    protected String requestURI = null;
-
-
-    /**
-     * The servlet path for this request.
-     */
-    protected String servletPath = null;
-
-
-    /**
-     * The currently active session for this request.
-     */
-    protected HttpSession session = null;
-
-
-    /**
-     * Special attributes.
-     */
-    protected Object[] specialAttributes = new Object[specials.length];
-
-
-    // ------------------------------------------------- ServletRequest Methods
-
-
-    /**
-     * Override the <code>getAttribute()</code> method of the wrapped request.
-     *
-     * @param name Name of the attribute to retrieve
-     */
-    public Object getAttribute(String name) {
-
-        if (name.equals(ServletRequestImpl.DISPATCHER_TYPE_ATTR)) {
-            return dispatcherType;
-        } else if (name.equals(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR)) {
-            if ( requestDispatcherPath != null ){
-                return requestDispatcherPath.toString();
-            } else {
-                return null;   
-            }
-        }
-
-        int pos = getSpecial(name);
-        if (pos == -1) {
-            return getRequest().getAttribute(name);
-        } else {
-            if ((specialAttributes[pos] == null) 
-                && (specialAttributes[5] == null) && (pos >= 5)) {
-                // If it's a forward special attribute, and null, it means this
-                // is an include, so we check the wrapped request since 
-                // the request could have been forwarded before the include
-                return getRequest().getAttribute(name);
-            } else {
-                return specialAttributes[pos];
-            }
-        }
-
-    }
-
-
-    /**
-     * Override the <code>getAttributeNames()</code> method of the wrapped
-     * request.
-     */
-    public Enumeration getAttributeNames() {
-        return (new AttributeNamesEnumerator());
-    }
-
-
-    /**
-     * Override the <code>removeAttribute()</code> method of the
-     * wrapped request.
-     *
-     * @param name Name of the attribute to remove
-     */
-    public void removeAttribute(String name) {
-
-        if (!removeSpecial(name))
-            getRequest().removeAttribute(name);
-
-    }
-
-
-    /**
-     * Override the <code>setAttribute()</code> method of the
-     * wrapped request.
-     *
-     * @param name Name of the attribute to set
-     * @param value Value of the attribute to set
-     */
-    public void setAttribute(String name, Object value) {
-
-        if (name.equals(ServletRequestImpl.DISPATCHER_TYPE_ATTR)) {
-            dispatcherType = value;
-            return;
-        } else if (name.equals(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR)) {
-            requestDispatcherPath = value;
-            return;
-        }
-
-        if (!setSpecial(name, value)) {
-            getRequest().setAttribute(name, value);
-        }
-
-    }
-
-
-    /**
-     * Return a RequestDispatcher that wraps the resource at the specified
-     * path, which may be interpreted as relative to the current request path.
-     *
-     * @param path Path of the resource to be wrapped
-     */
-    public RequestDispatcher getRequestDispatcher(String path) {
-
-        if (context == null)
-            return (null);
-
-        // If the path is already context-relative, just pass it through
-        if (path == null)
-            return (null);
-        else if (path.startsWith("/"))
-            return (context.getServletContext().getRequestDispatcher(path));
-
-        // Convert a request-relative path to a context-relative one
-        String servletPath = 
-            (String) getAttribute(RequestDispatcherImpl.INCLUDE_SERVLET_PATH_ATTR);
-        if (servletPath == null)
-            servletPath = getServletPath();
-
-        // Add the path info, if there is any
-        String pathInfo = getPathInfo();
-        String requestPath = null;
-
-        if (pathInfo == null) {
-            requestPath = servletPath;
-        } else {
-            requestPath = servletPath + pathInfo;
-        }
-
-        int pos = requestPath.lastIndexOf('/');
-        String relative = null;
-        if (pos >= 0) {
-            relative = RequestUtil.normalize
-                (requestPath.substring(0, pos + 1) + path);
-        } else {
-            relative = RequestUtil.normalize(requestPath + path);
-        }
-
-        return (context.getServletContext().getRequestDispatcher(relative));
-
-    }
-
-
-    // --------------------------------------------- HttpServletRequest Methods
-
-
-    /**
-     * Override the <code>getContextPath()</code> method of the wrapped
-     * request.
-     */
-    public String getContextPath() {
-
-        return (this.contextPath);
-
-    }
-
-
-    /**
-     * Override the <code>getParameter()</code> method of the wrapped request.
-     *
-     * @param name Name of the requested parameter
-     */
-    public String getParameter(String name) {
-
-       parseParameters();
-
-        Object value = parameters.get(name);
-        if (value == null)
-            return (null);
-        else if (value instanceof String[])
-            return (((String[]) value)[0]);
-        else if (value instanceof String)
-            return ((String) value);
-        else
-            return (value.toString());
-
-    }
-
-
-    /**
-     * Override the <code>getParameterMap()</code> method of the
-     * wrapped request.
-     */
-    public Map getParameterMap() {
-
-       parseParameters();
-        return (parameters);
-
-    }
-
-
-    /**
-     * Override the <code>getParameterNames()</code> method of the
-     * wrapped request.
-     */
-    public Enumeration getParameterNames() {
-
-       parseParameters();
-        return (new Enumerator(parameters.keySet()));
-
-    }
-
-
-    /**
-     * Override the <code>getParameterValues()</code> method of the
-     * wrapped request.
-     *
-     * @param name Name of the requested parameter
-     */
-    public String[] getParameterValues(String name) {
-
-       parseParameters();
-        Object value = parameters.get(name);
-        if (value == null)
-            return ((String[]) null);
-        else if (value instanceof String[])
-            return ((String[]) value);
-        else if (value instanceof String) {
-            String values[] = new String[1];
-            values[0] = (String) value;
-            return (values);
-        } else {
-            String values[] = new String[1];
-            values[0] = value.toString();
-            return (values);
-        }
-
-    }
-
-
-    /**
-     * Override the <code>getPathInfo()</code> method of the wrapped request.
-     */
-    public String getPathInfo() {
-
-        return (this.pathInfo);
-
-    }
-
-
-    /**
-     * Override the <code>getQueryString()</code> method of the wrapped
-     * request.
-     */
-    public String getQueryString() {
-
-        return (this.queryString);
-
-    }
-
-
-    /**
-     * Override the <code>getRequestURI()</code> method of the wrapped
-     * request.
-     */
-    public String getRequestURI() {
-
-        return (this.requestURI);
-
-    }
-
-
-    /**
-     * Override the <code>getRequestURL()</code> method of the wrapped
-     * request.
-     */
-    public StringBuffer getRequestURL() {
-
-        StringBuffer url = new StringBuffer();
-        String scheme = getScheme();
-        int port = getServerPort();
-        if (port < 0)
-            port = 80; // Work around java.net.URL bug
-
-        url.append(scheme);
-        url.append("://");
-        url.append(getServerName());
-        if ((scheme.equals("http") && (port != 80))
-            || (scheme.equals("https") && (port != 443))) {
-            url.append(':');
-            url.append(port);
-        }
-        url.append(getRequestURI());
-
-        return (url);
-
-    }
-
-
-    /**
-     * Override the <code>getServletPath()</code> method of the wrapped
-     * request.
-     */
-    public String getServletPath() {
-
-        return (this.servletPath);
-
-    }
-
-
-    /**
-     * Return the session associated with this Request, creating one
-     * if necessary.
-     */
-    public HttpSession getSession() {
-        return (getSession(true));
-    }
-
-
-    /**
-     * Return the session associated with this Request, creating one
-     * if necessary and requested.
-     *
-     * @param create Create a new session if one does not exist
-     */
-    public HttpSession getSession(boolean create) {
-
-        if (crossContext) {
-            
-            // There cannot be a session if no context has been assigned yet
-            if (context == null)
-                return (null);
-            UserSessionManager manager = context.getManager();
-            // Return the current session if it exists and is valid
-            if (session != null && manager.isValid(session)) {
-                return session;
-            }
-
-            HttpSession other = super.getSession(false);
-            if (create && (other == null)) {
-                // First create a session in the first context: the problem is
-                // that the top level request is the only one which can 
-                // create the cookie safely
-                other = super.getSession(true);
-            }
-            if (other != null) {
-                HttpSession localSession = null;
-                try {
-                    localSession =
-                      manager.findSession(other.getId());
-                } catch (IOException e) {
-                    // Ignore
-                }
-                if (localSession == null && create) {
-                    localSession = 
-                        context.getManager().createSession(other.getId());
-                }
-                if (localSession != null) {
-                    context.getManager().access(localSession);
-                    session = localSession;
-                    return session;
-                }
-            }
-            return null;
-
-        } else {
-            return super.getSession(create);
-        }
-
-    }
-
-
-    /**
-     * Returns true if the request specifies a JSESSIONID that is valid within
-     * the context of this ApplicationHttpRequest, false otherwise.
-     *
-     * @return true if the request specifies a JSESSIONID that is valid within
-     * the context of this ApplicationHttpRequest, false otherwise.
-     */
-    public boolean isRequestedSessionIdValid() {
-
-        if (crossContext) {
-
-            String requestedSessionId = getRequestedSessionId();
-            if (requestedSessionId == null)
-                return (false);
-            if (context == null)
-                return (false);
-            UserSessionManager manager = context.getManager();
-            if (manager == null)
-                return (false);
-            HttpSession session = null;
-            try {
-                session = manager.findSession(requestedSessionId);
-            } catch (IOException e) {
-                session = null;
-            }
-            if ((session != null) && manager.isValid(session)) {
-                return (true);
-            } else {
-                return (false);
-            }
-
-        } else {
-            return super.isRequestedSessionIdValid();
-        }
-    }
-
-
-    // -------------------------------------------------------- Package Methods
-
-
-    /**
-     * Recycle this request
-     */
-    public void recycle() {
-        if (session != null) {
-            context.getManager().endAccess(session);
-        }
-    }
-
-
-    /**
-     * Return descriptive information about this implementation.
-     */
-    public String getInfo() {
-
-        return (info);
-
-    }
-
-
-    /**
-     * Perform a shallow copy of the specified Map, and return the result.
-     *
-     * @param orig Origin Map to be copied
-     */
-    Map copyMap(Map orig) {
-
-        if (orig == null)
-            return (new HashMap());
-        HashMap dest = new HashMap();
-        Iterator keys = orig.keySet().iterator();
-        while (keys.hasNext()) {
-            String key = (String) keys.next();
-            dest.put(key, orig.get(key));
-        }
-        return (dest);
-
-    }
-
-
-    /**
-     * Set the context path for this request.
-     *
-     * @param contextPath The new context path
-     */
-    void setContextPath(String contextPath) {
-
-        this.contextPath = contextPath;
-
-    }
-
-
-    /**
-     * Set the path information for this request.
-     *
-     * @param pathInfo The new path info
-     */
-    void setPathInfo(String pathInfo) {
-
-        this.pathInfo = pathInfo;
-
-    }
-
-
-    /**
-     * Set the query string for this request.
-     *
-     * @param queryString The new query string
-     */
-    void setQueryString(String queryString) {
-
-        this.queryString = queryString;
-
-    }
-
-
-    /**
-     * Set the request that we are wrapping.
-     *
-     * @param request The new wrapped request
-     */
-    void setRequest(HttpServletRequest request) {
-
-        super.setRequest(request);
-
-        // Initialize the attributes for this request
-        dispatcherType = request.getAttribute(ServletRequestImpl.DISPATCHER_TYPE_ATTR);
-        requestDispatcherPath = 
-            request.getAttribute(ServletRequestImpl.DISPATCHER_REQUEST_PATH_ATTR);
-
-        // Initialize the path elements for this request
-        contextPath = request.getContextPath();
-        pathInfo = request.getPathInfo();
-        queryString = request.getQueryString();
-        requestURI = request.getRequestURI();
-        servletPath = request.getServletPath();
-
-    }
-
-
-    /**
-     * Set the request URI for this request.
-     *
-     * @param requestURI The new request URI
-     */
-    void setRequestURI(String requestURI) {
-
-        this.requestURI = requestURI;
-
-    }
-
-
-    /**
-     * Set the servlet path for this request.
-     *
-     * @param servletPath The new servlet path
-     */
-    void setServletPath(String servletPath) {
-
-        this.servletPath = servletPath;
-
-    }
-
-
-    /**
-     * Parses the parameters of this request.
-     *
-     * If parameters are present in both the query string and the request
-     * content, they are merged.
-     */
-    void parseParameters() {
-
-       if (parsedParams) {
-           return;
-       }
-
-        parameters = new HashMap();
-        parameters = copyMap(getRequest().getParameterMap());
-        mergeParameters();
-        parsedParams = true;
-    }
-
-
-    /**
-     * Save query parameters for this request.
-     *
-     * @param queryString The query string containing parameters for this
-     *                    request
-     */
-    void setQueryParams(String queryString) {
-        this.queryParamString = queryString;
-    }
-
-
-    // ------------------------------------------------------ Protected Methods
-
-
-    /**
-     * Is this attribute name one of the special ones that is added only for
-     * included servlets?
-     *
-     * @param name Attribute name to be tested
-     */
-    protected boolean isSpecial(String name) {
-
-        for (int i = 0; i < specials.length; i++) {
-            if (specials[i].equals(name))
-                return (true);
-        }
-        return (false);
-
-    }
-
-
-    /**
-     * Get a special attribute.
-     *
-     * @return the special attribute pos, or -1 if it is not a special 
-     *         attribute
-     */
-    protected int getSpecial(String name) {
-        for (int i = 0; i < specials.length; i++) {
-            if (specials[i].equals(name)) {
-                return (i);
-            }
-        }
-        return (-1);
-    }
-
-
-    /**
-     * Set a special attribute.
-     * 
-     * @return true if the attribute was a special attribute, false otherwise
-     */
-    protected boolean setSpecial(String name, Object value) {
-        for (int i = 0; i < specials.length; i++) {
-            if (specials[i].equals(name)) {
-                specialAttributes[i] = value;
-                return (true);
-            }
-        }
-        return (false);
-    }
-
-
-    /**
-     * Remove a special attribute.
-     * 
-     * @return true if the attribute was a special attribute, false otherwise
-     */
-    protected boolean removeSpecial(String name) {
-        for (int i = 0; i < specials.length; i++) {
-            if (specials[i].equals(name)) {
-                specialAttributes[i] = null;
-                return (true);
-            }
-        }
-        return (false);
-    }
-
-
-    /**
-     * Merge the two sets of parameter values into a single String array.
-     *
-     * @param values1 First set of values
-     * @param values2 Second set of values
-     */
-    protected String[] mergeValues(Object values1, Object values2) {
-
-        ArrayList results = new ArrayList();
-
-        if (values1 == null)
-            ;
-        else if (values1 instanceof String)
-            results.add(values1);
-        else if (values1 instanceof String[]) {
-            String values[] = (String[]) values1;
-            for (int i = 0; i < values.length; i++)
-                results.add(values[i]);
-        } else
-            results.add(values1.toString());
-
-        if (values2 == null)
-            ;
-        else if (values2 instanceof String)
-            results.add(values2);
-        else if (values2 instanceof String[]) {
-            String values[] = (String[]) values2;
-            for (int i = 0; i < values.length; i++)
-                results.add(values[i]);
-        } else
-            results.add(values2.toString());
-
-        String values[] = new String[results.size()];
-        return ((String[]) results.toArray(values));
-
-    }
-
-
-    // ------------------------------------------------------ Private Methods
-
-
-    /**
-     * Merge the parameters from the saved query parameter string (if any), and
-     * the parameters already present on this request (if any), such that the
-     * parameter values from the query string show up first if there are
-     * duplicate parameter names.
-     */
-    private void mergeParameters() {
-
-        if ((queryParamString == null) || (queryParamString.length() < 1))
-            return;
-
-        HashMap queryParameters = new HashMap();
-        String encoding = getCharacterEncoding();
-        if (encoding == null)
-            encoding = "ISO-8859-1";
-        try {
-            RequestUtil.parseParameters
-                (queryParameters, queryParamString, encoding);
-        } catch (Exception e) {
-            ;
-        }
-        Iterator keys = parameters.keySet().iterator();
-        while (keys.hasNext()) {
-            String key = (String) keys.next();
-            Object value = queryParameters.get(key);
-            if (value == null) {
-                queryParameters.put(key, parameters.get(key));
-                continue;
-            }
-            queryParameters.put
-                (key, mergeValues(value, parameters.get(key)));
-        }
-        parameters = queryParameters;
-
-    }
-
-
-    // ----------------------------------- AttributeNamesEnumerator Inner Class
-
-
-    /**
-     * Utility class used to expose the special attributes as being available
-     * as request attributes.
-     */
-    protected class AttributeNamesEnumerator implements Enumeration {
-
-        protected int pos = -1;
-        protected int last = -1;
-        protected Enumeration parentEnumeration = null;
-        protected String next = null;
-
-        public AttributeNamesEnumerator() {
-            parentEnumeration = getRequest().getAttributeNames();
-            for (int i = 0; i < specialAttributes.length; i++) {
-                if (getAttribute(specials[i]) != null) {
-                    last = i;
-                }
-            }
-        }
-
-        public boolean hasMoreElements() {
-            return ((pos != last) || (next != null) 
-                    || ((next = findNext()) != null));
-        }
-
-        public Object nextElement() {
-            if (pos != last) {
-                for (int i = pos + 1; i <= last; i++) {
-                    if (getAttribute(specials[i]) != null) {
-                        pos = i;
-                        return (specials[i]);
-                    }
-                }
-            }
-            String result = next;
-            if (next != null) {
-                next = findNext();
-            } else {
-                throw new NoSuchElementException();
-            }
-            return result;
-        }
-
-        protected String findNext() {
-            String result = null;
-            while ((result == null) && (parentEnumeration.hasMoreElements())) {
-                String current = (String) parentEnumeration.nextElement();
-                if (!isSpecial(current)) {
-                    result = current;
-                }
-            }
-            return result;
-        }
-
-    }
-
-
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseImpl.java
deleted file mode 100644 (file)
index d876697..0000000
+++ /dev/null
@@ -1,1463 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.tomcat.lite;
-
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.Locale;
-import java.util.TimeZone;
-import java.util.Vector;
-
-import javax.servlet.ServletOutputStream;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-import org.apache.tomcat.util.buf.CharChunk;
-import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.buf.UEncoder;
-import org.apache.tomcat.util.http.FastHttpDateFormat;
-import org.apache.tomcat.util.http.HttpResponse;
-import org.apache.tomcat.util.http.MimeHeaders;
-import org.apache.tomcat.util.http.ServerCookie;
-
-/**
- * Wrapper object for the Coyote response.
- *
- * @author Remy Maucherat
- * @author Craig R. McClanahan
- * @version $Revision$ $Date$
- */
-
-public class ServletResponseImpl
-    implements HttpServletResponse {
-
-    /**
-     * Format for http response header date field
-     * From DateTool
-     */
-    public static final String HTTP_RESPONSE_DATE_HEADER =
-        "EEE, dd MMM yyyy HH:mm:ss zzz";
-
-    // ----------------------------------------------------------- Constructors
-
-
-    ServletResponseImpl() {
-        urlEncoder.addSafeCharacter('/');
-    }
-
-
-    /**
-     * The date format we will use for creating date headers.
-     */
-    protected SimpleDateFormat format = null;
-
-
-    /**
-     * The associated output buffer.
-     */
-    protected BodyWriter outputBuffer;
-
-
-    /**
-     * The associated output stream.
-     */
-    protected ServletOutputStreamImpl outputStream;
-
-
-    /**
-     * The associated writer.
-     */
-    protected PrintWriter writer;
-
-
-    /**
-     * The application commit flag.
-     */
-    protected boolean appCommitted = false;
-
-
-    /**
-     * The included flag.
-     */
-    protected boolean included = false;
-
-
-    /**
-     * The characterEncoding flag
-     */
-    private boolean isCharacterEncodingSet = false;
-
-    /**
-     * The error flag.
-     */
-    protected boolean error = false;
-
-
-    /**
-     * The set of Cookies associated with this Response.
-     */
-    protected ArrayList cookies = new ArrayList();
-
-
-    /**
-     * Using output stream flag.
-     */
-    protected boolean usingOutputStream = false;
-
-
-    /**
-     * Using writer flag.
-     */
-    protected boolean usingWriter = false;
-
-
-    /**
-     * The request with which this response is associated.
-     */
-    protected ServletRequestImpl req = null;
-
-    /**
-     * URL encoder.
-     */
-    protected UEncoder urlEncoder = new UEncoder();
-
-
-    /**
-     * Recyclable buffer to hold the redirect URL.
-     */
-    protected CharChunk redirectURLCC = new CharChunk(1024);
-
-
-    private HttpResponse resB;
-
-
-    // Cached/derived information - reflected in headers
-    protected static Locale DEFAULT_LOCALE = Locale.getDefault();
-
-    public static final String DEFAULT_CHARACTER_ENCODING="ISO-8859-1";
-
-    protected Locale locale = DEFAULT_LOCALE;
-
-    // XXX
-    protected boolean commited = false;
-    protected String contentType = null;
-
-    /**
-     * Has the charset been explicitly set.
-     */
-    protected boolean charsetSet = false;
-    protected String characterEncoding = DEFAULT_CHARACTER_ENCODING;
-
-
-    // --------------------------------------------------------- Public Methods
-
-
-    /**
-     * Release all object references, and initialize instance variables, in
-     * preparation for reuse of this object.
-     */
-    public void recycle() {
-
-        usingOutputStream = false;
-        usingWriter = false;
-        appCommitted = false;
-        commited = false;
-        included = false;
-        error = false;
-        isCharacterEncodingSet = false;
-
-        cookies.clear();
-
-        outputBuffer.recycle();
-
-        resB.recycle();
-    }
-
-
-    // ------------------------------------------------------- Response Methods
-
-
-    /**
-     * Return the number of bytes actually written to the output stream.
-     */
-    public int getContentCount() {
-        return outputBuffer.getBytesWritten() + outputBuffer.getCharsWritten();
-    }
-
-
-    /**
-     * Set the application commit flag.
-     *
-     * @param appCommitted The new application committed flag value
-     */
-    public void setAppCommitted(boolean appCommitted) {
-        this.appCommitted = appCommitted;
-    }
-
-
-    /**
-     * Application commit flag accessor.
-     */
-    public boolean isAppCommitted() {
-        return (this.appCommitted || isCommitted() || isSuspended()
-                || ((getHttpResponse().getContentLength() > 0)
-                    && (getContentCount() >= getHttpResponse().getContentLength())));
-    }
-
-
-    /**
-     * Return the "processing inside an include" flag.
-     */
-    public boolean getIncluded() {
-        return included;
-    }
-
-
-    /**
-     * Set the "processing inside an include" flag.
-     *
-     * @param included <code>true</code> if we are currently inside a
-     *  RequestDispatcher.include(), else <code>false</code>
-     */
-    public void setIncluded(boolean included) {
-        this.included = included;
-    }
-
-
-    /**
-     * Return the Request with which this Response is associated.
-     */
-    public ServletRequestImpl getRequest() {
-        return (this.req);
-    }
-
-    /**
-     * Set the Request with which this Response is associated.
-     *
-     * @param request The new associated request
-     */
-    public void setRequest(ServletRequestImpl request) {
-        this.req = (ServletRequestImpl) request;
-    }
-
-
-    /**
-     * Return the output stream associated with this Response.
-     */
-    public OutputStream getStream() {
-        return outputStream;
-    }
-
-
-    /**
-     * Set the output stream associated with this Response.
-     *
-     * @param stream The new output stream
-     */
-    public void setStream(OutputStream stream) {
-        // This method is evil
-    }
-
-
-    /**
-     * Set the suspended flag.
-     *
-     * @param suspended The new suspended flag value
-     */
-    public void setSuspended(boolean suspended) throws IOException {
-        //coyoteResponse.setCommitted(true);
-        flushBuffer();
-        outputBuffer.setSuspended(suspended);
-    }
-
-
-    /**
-     * Suspended flag accessor.
-     */
-    public boolean isSuspended() {
-        return outputBuffer.isSuspended();
-    }
-
-
-    /**
-     * Set the error flag.
-     */
-    public void setError() {
-        error = true;
-    }
-
-
-    /**
-     * Error flag accessor.
-     */
-    public boolean isError() {
-        return error;
-    }
-
-
-    /**
-     * Create and return a ServletOutputStream to write the content
-     * associated with this Response.
-     *
-     * @exception IOException if an input/output error occurs
-     */
-    public ServletOutputStream createOutputStream()
-        throws IOException {
-        // Probably useless
-        return outputStream;
-    }
-
-    /**
-     * Return the content type that was set or calculated for this response,
-     * or <code>null</code> if no content type was set.
-     */
-    public String getContentType() {
-        String ret = contentType;
-
-        if (ret != null
-            && characterEncoding != null
-            && charsetSet) {
-            ret = ret + ";charset=" + characterEncoding;
-        }
-
-        return ret;
-    }
-
-
-    /**
-     * Return a PrintWriter that can be used to render error messages,
-     * regardless of whether a stream or writer has already been acquired.
-     *
-     * @return Writer which can be used for error reports. If the response is
-     * not an error report returned using sendError or triggered by an
-     * unexpected exception thrown during the servlet processing
-     * (and only in that case), null will be returned if the response stream
-     * has already been used.
-     *
-     * @exception IOException if an input/output error occurs
-     */
-    public PrintWriter getReporter() throws IOException {
-        if (outputBuffer.isNew()) {
-            outputBuffer.checkConverter();
-            if (writer == null) {
-                writer = new ServletWriterImpl(outputBuffer);
-            }
-            return writer;
-        } else {
-            return null;
-        }
-    }
-
-
-    // ------------------------------------------------ ServletResponse Methods
-
-
-    /**
-     * Flush the buffer and commit this response.
-     *
-     * @exception IOException if an input/output error occurs
-     */
-    public void flushBuffer()
-        throws IOException {
-        outputBuffer.flush();
-    }
-
-
-    /**
-     * Return the actual buffer size used for this Response.
-     */
-    public int getBufferSize() {
-        return outputBuffer.getBufferSize();
-    }
-
-
-    /**
-     * Return the character encoding used for this Response.
-     */
-    public String getCharacterEncoding() {
-        return characterEncoding;
-    }
-
-
-    /**
-     * Return the servlet output stream associated with this Response.
-     *
-     * @exception IllegalStateException if <code>getWriter</code> has
-     *  already been called for this response
-     * @exception IOException if an input/output error occurs
-     */
-    public ServletOutputStream getOutputStream()
-        throws IOException {
-
-        if (usingWriter)
-            throw new IllegalStateException
-                ("usingWriter");
-
-        usingOutputStream = true;
-        return outputStream;
-
-    }
-
-    public BodyWriter getBodyWriter() {
-        return outputBuffer;
-    }
-
-    /**
-     * Return the Locale assigned to this response.
-     */
-    public Locale getLocale() {
-        return locale;
-    }
-
-
-    /**
-     * Return the writer associated with this Response.
-     *
-     * @exception IllegalStateException if <code>getOutputStream</code> has
-     *  already been called for this response
-     * @exception IOException if an input/output error occurs
-     */
-    public PrintWriter getWriter()
-        throws IOException {
-
-        if (usingOutputStream)
-            throw new IllegalStateException
-                ("usingOutputStream");
-
-        /*
-         * If the response's character encoding has not been specified as
-         * described in <code>getCharacterEncoding</code> (i.e., the method
-         * just returns the default value <code>ISO-8859-1</code>),
-         * <code>getWriter</code> updates it to <code>ISO-8859-1</code>
-         * (with the effect that a subsequent call to getContentType() will
-         * include a charset=ISO-8859-1 component which will also be
-         * reflected in the Content-Type response header, thereby satisfying
-         * the Servlet spec requirement that containers must communicate the
-         * character encoding used for the servlet response's writer to the
-         * client).
-         */
-        setCharacterEncoding(getCharacterEncoding());
-
-        usingWriter = true;
-        outputBuffer.checkConverter();
-        if (writer == null) {
-            writer = new ServletWriterImpl(outputBuffer);
-        }
-        return writer;
-
-    }
-
-
-    /**
-     * Has the output of this response already been committed?
-     */
-    public boolean isCommitted() {
-        return getHttpResponse().isCommitted();
-    }
-
-    /**
-     * Clear any content written to the buffer.
-     *
-     * @exception IllegalStateException if this response has already
-     *  been committed
-     */
-    public void reset() {
-
-        if (included)
-            return;     // Ignore any call from an included servlet
-
-        if (isCommitted())
-            throw new IllegalStateException("isCommitted");
-
-        resB.recycle(); // reset headers, status code, message
-        req.getConnector().reset(this);
-        contentType = null;
-        locale = DEFAULT_LOCALE;
-        characterEncoding = DEFAULT_CHARACTER_ENCODING;
-        charsetSet = false;
-
-        outputBuffer.reset();
-    }
-
-
-    /**
-     * Reset the data buffer but not any status or header information.
-     *
-     * @exception IllegalStateException if the response has already
-     *  been committed
-     */
-    public void resetBuffer() {
-
-        if (isCommitted())
-            throw new IllegalStateException("isCommitted");
-
-        outputBuffer.reset();
-
-    }
-
-
-    /**
-     * Set the buffer size to be used for this Response.
-     *
-     * @param size The new buffer size
-     *
-     * @exception IllegalStateException if this method is called after
-     *  output has been committed for this response
-     */
-    public void setBufferSize(int size) {
-
-        if (isCommitted() || !outputBuffer.isNew())
-            throw new IllegalStateException
-                ("isCommitted || !isNew");
-
-        outputBuffer.setBufferSize(size);
-
-    }
-
-
-    /**
-     * Set the content length (in bytes) for this Response.
-     * Ignored for writers if non-ISO-8859-1 encoding ( we could add more
-     * encodings that are constant.
-     */
-    public void setContentLength(int length) {
-
-        if (isCommitted())
-            return;
-
-        // Ignore any call from an included servlet
-        if (included)
-            return;
-
-        // writers can use variable-length encoding.
-        if (usingWriter && !"ISO-8859-1".equals(getCharacterEncoding())) {
-            return;
-        }
-        getHttpResponse().setContentLength(length);
-
-    }
-
-
-    /**
-     * Set the content type for this Response.
-     *
-     * @param type The new content type
-     */
-    public void setContentType(String type) {
-
-        if (isCommitted())
-            return;
-
-        // Ignore any call from an included servlet
-        if (included)
-            return;
-
-        // Ignore charset if getWriter() has already been called
-        if (usingWriter) {
-            if (type != null) {
-                int index = type.indexOf(";");
-                if (index != -1) {
-                    type = type.substring(0, index);
-                }
-            }
-        }
-
-        getHttpResponse().setContentType(type);
-
-        // Check to see if content type contains charset
-        if (type != null) {
-            int index = type.indexOf(";");
-            if (index != -1) {
-                int len = type.length();
-                index++;
-                while (index < len && Character.isSpace(type.charAt(index))) {
-                    index++;
-                }
-                if (index+7 < len
-                        && type.charAt(index) == 'c'
-                        && type.charAt(index+1) == 'h'
-                        && type.charAt(index+2) == 'a'
-                        && type.charAt(index+3) == 'r'
-                        && type.charAt(index+4) == 's'
-                        && type.charAt(index+5) == 'e'
-                        && type.charAt(index+6) == 't'
-                        && type.charAt(index+7) == '=') {
-                    isCharacterEncodingSet = true;
-                }
-            }
-        }
-    }
-
-
-    /*
-     * Overrides the name of the character encoding used in the body
-     * of the request. This method must be called prior to reading
-     * request parameters or reading input using getReader().
-     *
-     * @param charset String containing the name of the chararacter encoding.
-     */
-    public void setCharacterEncoding(String charset) {
-
-        if (isCommitted())
-            return;
-
-        // Ignore any call from an included servlet
-        if (included)
-            return;
-
-        // Ignore any call made after the getWriter has been invoked
-        // The default should be used
-        if (usingWriter)
-            return;
-
-        if (isCommitted())
-            return;
-        if (charset == null)
-            return;
-
-        characterEncoding = charset;
-        charsetSet=true;
-        isCharacterEncodingSet = true;
-    }
-
-
-
-    /**
-     * Set the Locale that is appropriate for this response, including
-     * setting the appropriate character encoding.
-     *
-     * @param locale The new locale
-     */
-    public void setLocale(Locale locale) {
-
-        if (isCommitted())
-            return;
-
-        // Ignore any call from an included servlet
-        if (included)
-            return;
-
-        if (locale == null) {
-            return;  // throw an exception?
-        }
-
-        // Save the locale for use by getLocale()
-        this.locale = locale;
-
-        // Set the contentLanguage for header output
-        String contentLanguage = locale.getLanguage();
-        if ((contentLanguage != null) && (contentLanguage.length() > 0)) {
-            String country = locale.getCountry();
-            StringBuffer value = new StringBuffer(contentLanguage);
-            if ((country != null) && (country.length() > 0)) {
-                value.append('-');
-                value.append(country);
-            }
-            contentLanguage = value.toString();
-        }
-        resB.setHeader("Content-Language", contentLanguage);
-
-        // Ignore any call made after the getWriter has been invoked.
-        // The default should be used
-        if (usingWriter)
-            return;
-
-        if (isCharacterEncodingSet) {
-            return;
-        }
-
-        Locale2Charset cm = req.getContext().getCharsetMapper();
-        String charset = cm.getCharset( locale );
-        if ( charset != null ){
-            setCharacterEncoding(charset);
-        }
-
-    }
-
-
-    // --------------------------------------------------- HttpResponse Methods
-
-
-    /**
-     * Return an array of all cookies set for this response, or
-     * a zero-length array if no cookies have been set.
-     */
-    public Cookie[] getCookies() {
-        return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()]));
-    }
-
-
-    /**
-     * Return the value for the specified header, or <code>null</code> if this
-     * header has not been set.  If more than one value was added for this
-     * name, only the first is returned; use getHeaderValues() to retrieve all
-     * of them.
-     *
-     * @param name Header name to look up
-     */
-    public String getHeader(String name) {
-        return getHttpResponse().getMimeHeaders().getHeader(name);
-    }
-
-
-    /**
-     * Return an array of all the header names set for this response, or
-     * a zero-length array if no headers have been set.
-     */
-    public Collection<String> getHeaderNames() {
-
-        MimeHeaders headers = getHttpResponse().getMimeHeaders();
-        int n = headers.size();
-        ArrayList<String> result = new ArrayList<String>();
-        for (int i = 0; i < n; i++) {
-            result.add(headers.getName(i).toString());
-        }
-        return result;
-    }
-
-
-    /**
-     * Return an array of all the header values associated with the
-     * specified header name, or an zero-length array if there are no such
-     * header values.
-     *
-     * @param name Header name to look up
-     */
-    public String[] getHeaderValues(String name) {
-
-        Enumeration enumeration = getHttpResponse().getMimeHeaders().values(name);
-        Vector result = new Vector();
-        while (enumeration.hasMoreElements()) {
-            result.addElement(enumeration.nextElement());
-        }
-        String[] resultArray = new String[result.size()];
-        result.copyInto(resultArray);
-        return resultArray;
-
-    }
-
-
-    /**
-     * Return the error message that was set with <code>sendError()</code>
-     * for this Response.
-     */
-    public String getMessage() {
-        return getHttpResponse().getMessage();
-    }
-
-
-    /**
-     * Return the HTTP status code associated with this Response.
-     */
-    public int getStatus() {
-        return getHttpResponse().getStatus();
-    }
-
-
-    /**
-     * Reset this response, and specify the values for the HTTP status code
-     * and corresponding message.
-     *
-     * @exception IllegalStateException if this response has already been
-     *  committed
-     */
-    public void reset(int status, String message) {
-        reset();
-        setStatus(status, message);
-    }
-
-
-    // -------------------------------------------- HttpServletResponse Methods
-
-
-    /**
-     * Add the specified Cookie to those that will be included with
-     * this Response.
-     *
-     * @param cookie Cookie to be added
-     */
-    public void addCookie(final Cookie cookie) {
-
-        if (isCommitted())
-            return;
-
-        // Ignore any call from an included servlet
-        if (included)
-            return;
-
-        cookies.add(cookie);
-
-        final StringBuffer sb = new StringBuffer();
-        ServerCookie.appendCookieValue
-        (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(),
-                cookie.getPath(), cookie.getDomain(), cookie.getComment(),
-                cookie.getMaxAge(), cookie.getSecure(), false);
-
-        // the header name is Set-Cookie for both "old" and v.1 ( RFC2109 )
-        // RFC2965 is not supported by browsers and the Servlet spec
-        // asks for 2109.
-        addHeader("Set-Cookie", sb.toString());
-
-    }
-
-
-    /**
-     * Add the specified date header to the specified value.
-     *
-     * @param name Name of the header to set
-     * @param value Date value to be set
-     */
-    public void addDateHeader(String name, long value) {
-
-        if (isCommitted())
-            return;
-
-        // Ignore any call from an included servlet
-        if (included) {
-            return;
-        }
-
-        if (format == null) {
-            format = new SimpleDateFormat(HTTP_RESPONSE_DATE_HEADER,
-                                          Locale.US);
-            format.setTimeZone(TimeZone.getTimeZone("GMT"));
-        }
-
-        addHeader(name, FastHttpDateFormat.formatDate(value, format));
-
-    }
-
-
-    /**
-     * Add the specified header to the specified value.
-     *
-     * @param name Name of the header to set
-     * @param value Value to be set
-     */
-    public void addHeader(String name, String value) {
-
-        if (isCommitted())
-            return;
-
-        // Ignore any call from an included servlet
-        if (included)
-            return;
-
-        getHttpResponse().addHeader(name, value);
-
-    }
-
-
-    /**
-     * Add the specified integer header to the specified value.
-     *
-     * @param name Name of the header to set
-     * @param value Integer value to be set
-     */
-    public void addIntHeader(String name, int value) {
-
-        if (isCommitted())
-            return;
-
-        // Ignore any call from an included servlet
-        if (included)
-            return;
-
-        addHeader(name, "" + value);
-
-    }
-
-
-    /**
-     * Has the specified header been set already in this response?
-     *
-     * @param name Name of the header to check
-     */
-    public boolean containsHeader(String name) {
-        // Need special handling for Content-Type and Content-Length due to
-        // special handling of these in coyoteResponse
-        char cc=name.charAt(0);
-        if(cc=='C' || cc=='c') {
-            if(name.equalsIgnoreCase("Content-Type")) {
-                // Will return null if this has not been set
-                return getContentType() != null;
-            }
-            if(name.equalsIgnoreCase("Content-Length")) {
-                // -1 means not known and is not sent to client
-                return (getHttpResponse().getContentLength() != -1);
-            }
-        }
-
-        return getHttpResponse().containsHeader(name);
-    }
-
-
-    /**
-     * Encode the session identifier associated with this response
-     * into the specified redirect URL, if necessary.
-     *
-     * @param url URL to be encoded
-     */
-    public String encodeRedirectURL(String url) {
-
-        if (isEncodeable(toAbsolute(url))) {
-            return (toEncoded(url, req.getSession().getId()));
-        } else {
-            return (url);
-        }
-
-    }
-
-
-    /**
-     * Encode the session identifier associated with this response
-     * into the specified redirect URL, if necessary.
-     *
-     * @param url URL to be encoded
-     *
-     * @deprecated As of Version 2.1 of the Java Servlet API, use
-     *  <code>encodeRedirectURL()</code> instead.
-     */
-    public String encodeRedirectUrl(String url) {
-        return (encodeRedirectURL(url));
-    }
-
-
-    /**
-     * Encode the session identifier associated with this response
-     * into the specified URL, if necessary.
-     *
-     * @param url URL to be encoded
-     */
-    public String encodeURL(String url) {
-
-        String absolute = toAbsolute(url);
-        if (isEncodeable(absolute)) {
-            // W3c spec clearly said
-            if (url.equalsIgnoreCase("")){
-                url = absolute;
-            }
-            return (toEncoded(url, req.getSession().getId()));
-        } else {
-            return (url);
-        }
-
-    }
-
-
-    /**
-     * Encode the session identifier associated with this response
-     * into the specified URL, if necessary.
-     *
-     * @param url URL to be encoded
-     *
-     * @deprecated As of Version 2.1 of the Java Servlet API, use
-     *  <code>encodeURL()</code> instead.
-     */
-    public String encodeUrl(String url) {
-        return (encodeURL(url));
-    }
-
-
-    /**
-     * Send an acknowledgment of a request.
-     *
-     * @exception IOException if an input/output error occurs
-     */
-    public void sendAcknowledgement()
-        throws IOException {
-
-        if (isCommitted())
-            return;
-
-        // Ignore any call from an included servlet
-        if (included)
-            return;
-
-        req.getConnector().acknowledge(this);
-    }
-
-
-    /**
-     * Send an error response with the specified status and a
-     * default message.
-     *
-     * @param status HTTP status code to send
-     *
-     * @exception IllegalStateException if this response has
-     *  already been committed
-     * @exception IOException if an input/output error occurs
-     */
-    public void sendError(int status)
-        throws IOException {
-        sendError(status, null);
-    }
-
-
-    /**
-     * Send an error response with the specified status and message.
-     *
-     * @param status HTTP status code to send
-     * @param message Corresponding message to send
-     *
-     * @exception IllegalStateException if this response has
-     *  already been committed
-     * @exception IOException if an input/output error occurs
-     */
-    public void sendError(int status, String message)
-        throws IOException {
-
-        if (isCommitted())
-            throw new IllegalStateException
-                ("isCommitted");
-
-        // Ignore any call from an included servlet
-        if (included)
-            return;
-
-        setError();
-
-        getHttpResponse().setStatus(status);
-        getHttpResponse().setMessage(message);
-
-        // Clear any data content that has been buffered
-        resetBuffer();
-
-        // Cause the response to be finished (from the application perspective)
-        String statusPage = req.getContext().findStatusPage(status);
-
-        if (statusPage != null) {
-            req.getContext().handleStatusPage(req, this, status, statusPage);
-        } else {
-            // Send a default message body.
-            // TODO: maybe other mechanism to customize default.
-            defaultStatusPage(status, message);
-        }
-        setSuspended(true);
-    }
-
-    /**
-     * Default handler for status code != 200
-     */
-    void defaultStatusPage(int status, String message)
-            throws IOException {
-        setContentType("text/html");
-        if (status > 400 && status < 600) {
-            if (getOutputBuffer().getBytesWritten() == 0) {
-                getOutputBuffer().write("<html><body><h1>Status: " +
-                        status + "</h1><h1>Message: " + message +
-                        "</h1></body></html>");
-                getOutputBuffer().flush();
-            }
-        }
-    }
-
-
-
-    /**
-     * Send a temporary redirect to the specified redirect location URL.
-     *
-     * @param location Location URL to redirect to
-     *
-     * @exception IllegalStateException if this response has
-     *  already been committed
-     * @exception IOException if an input/output error occurs
-     */
-    public void sendRedirect(String location)
-        throws IOException {
-
-        if (isCommitted())
-            throw new IllegalStateException
-                ("isCommitted");
-
-        // Ignore any call from an included servlet
-        if (included)
-            return;
-
-        // Clear any data content that has been buffered
-        resetBuffer();
-
-        // Generate a temporary redirect to the specified location
-        try {
-            String absolute = toAbsolute(location);
-            setStatus(SC_FOUND);
-            setHeader("Location", absolute);
-        } catch (IllegalArgumentException e) {
-            setStatus(SC_NOT_FOUND);
-        }
-
-        // Cause the response to be finished (from the application perspective)
-        setSuspended(true);
-
-    }
-
-
-    /**
-     * Set the specified date header to the specified value.
-     *
-     * @param name Name of the header to set
-     * @param value Date value to be set
-     */
-    public void setDateHeader(String name, long value) {
-
-        if (isCommitted())
-            return;
-
-        // Ignore any call from an included servlet
-        if (included) {
-            return;
-        }
-
-        if (format == null) {
-            format = new SimpleDateFormat(HTTP_RESPONSE_DATE_HEADER,
-                                          Locale.US);
-            format.setTimeZone(TimeZone.getTimeZone("GMT"));
-        }
-
-        setHeader(name, FastHttpDateFormat.formatDate(value, format));
-
-    }
-
-
-    /**
-     * Set the specified header to the specified value.
-     *
-     * @param name Name of the header to set
-     * @param value Value to be set
-     */
-    public void setHeader(String name, String value) {
-
-        if (isCommitted())
-            return;
-
-        // Ignore any call from an included servlet
-        if (included)
-            return;
-
-        getHttpResponse().setHeader(name, value);
-
-    }
-
-
-    /**
-     * Set the specified integer header to the specified value.
-     *
-     * @param name Name of the header to set
-     * @param value Integer value to be set
-     */
-    public void setIntHeader(String name, int value) {
-
-        if (isCommitted())
-            return;
-
-        // Ignore any call from an included servlet
-        if (included)
-            return;
-
-        setHeader(name, "" + value);
-
-    }
-
-
-    /**
-     * Set the HTTP status to be returned with this response.
-     *
-     * @param status The new HTTP status
-     */
-    public void setStatus(int status) {
-        setStatus(status, null);
-    }
-
-
-    /**
-     * Set the HTTP status and message to be returned with this response.
-     *
-     * @param status The new HTTP status
-     * @param message The associated text message
-     *
-     * @deprecated As of Version 2.1 of the Java Servlet API, this method
-     *  has been deprecated due to the ambiguous meaning of the message
-     *  parameter.
-     */
-    public void setStatus(int status, String message) {
-
-        if (isCommitted())
-            return;
-
-        // Ignore any call from an included servlet
-        if (included)
-            return;
-
-        getHttpResponse().setStatus(status);
-        getHttpResponse().setMessage(message);
-
-    }
-
-
-    // ------------------------------------------------------ Protected Methods
-
-
-    /**
-     * Return <code>true</code> if the specified URL should be encoded with
-     * a session identifier.  This will be true if all of the following
-     * conditions are met:
-     * <ul>
-     * <li>The request we are responding to asked for a valid session
-     * <li>The requested session ID was not received via a cookie
-     * <li>The specified URL points back to somewhere within the web
-     *     application that is responding to this request
-     * </ul>
-     *
-     * @param location Absolute URL to be validated
-     */
-    protected boolean isEncodeable(final String location) {
-
-        if (location == null)
-            return (false);
-
-        // Is this an intra-document reference?
-        if (location.startsWith("#"))
-            return (false);
-
-        // Are we in a valid session that is not using cookies?
-        final ServletRequestImpl hreq = req;
-        final HttpSession session = hreq.getSession(false);
-        if (session == null)
-            return (false);
-        if (hreq.isRequestedSessionIdFromCookie())
-            return (false);
-
-        // Is this a valid absolute URL?
-        URL url = null;
-        try {
-            url = new URL(location);
-        } catch (MalformedURLException e) {
-            return (false);
-        }
-
-        // Does this URL match down to (and including) the context path?
-        if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol()))
-            return (false);
-        if (!hreq.getServerName().equalsIgnoreCase(url.getHost()))
-            return (false);
-        int serverPort = hreq.getServerPort();
-        if (serverPort == -1) {
-            if ("https".equals(hreq.getScheme()))
-                serverPort = 443;
-            else
-                serverPort = 80;
-        }
-        int urlPort = url.getPort();
-        if (urlPort == -1) {
-            if ("https".equals(url.getProtocol()))
-                urlPort = 443;
-            else
-                urlPort = 80;
-        }
-        if (serverPort != urlPort)
-            return (false);
-
-        String contextPath = req.getContext().getContextPath();
-        if (contextPath != null) {
-            String file = url.getFile();
-            if ((file == null) || !file.startsWith(contextPath))
-                return (false);
-            if( file.indexOf(";jsessionid=" + session.getId()) >= 0 )
-                return (false);
-        }
-
-        // This URL belongs to our web application, so it is encodeable
-        return (true);
-
-    }
-
-
-    /**
-     * Convert (if necessary) and return the absolute URL that represents the
-     * resource referenced by this possibly relative URL.  If this URL is
-     * already absolute, return it unchanged.
-     *
-     * @param location URL to be (possibly) converted and then returned
-     *
-     * @exception IllegalArgumentException if a MalformedURLException is
-     *  thrown when converting the relative URL to an absolute one
-     */
-    private String toAbsolute(String location) {
-
-        if (location == null)
-            return (location);
-
-        boolean leadingSlash = location.startsWith("/");
-
-        if (leadingSlash || !hasScheme(location)) {
-
-            redirectURLCC.recycle();
-
-            String scheme = req.getScheme();
-            String name = req.getServerName();
-            int port = req.getServerPort();
-
-            try {
-                redirectURLCC.append(scheme, 0, scheme.length());
-                redirectURLCC.append("://", 0, 3);
-                redirectURLCC.append(name, 0, name.length());
-                if ((scheme.equals("http") && port != 80)
-                    || (scheme.equals("https") && port != 443)) {
-                    redirectURLCC.append(':');
-                    String portS = port + "";
-                    redirectURLCC.append(portS, 0, portS.length());
-                }
-                if (!leadingSlash) {
-                    String relativePath = req.getDecodedRequestURI();
-                    int pos = relativePath.lastIndexOf('/');
-                    relativePath = relativePath.substring(0, pos);
-
-                    String encodedURI = null;
-                    encodedURI = urlEncoder.encodeURL(relativePath);
-                    redirectURLCC.append(encodedURI, 0, encodedURI.length());
-                    redirectURLCC.append('/');
-                }
-                redirectURLCC.append(location, 0, location.length());
-            } catch (IOException e) {
-                IllegalArgumentException iae =
-                    new IllegalArgumentException(location);
-                iae.initCause(e);
-                throw iae;
-            }
-
-            return redirectURLCC.toString();
-
-        } else {
-
-            return (location);
-
-        }
-
-    }
-
-
-    /**
-     * Determine if a URI string has a <code>scheme</code> component.
-     */
-    private boolean hasScheme(String uri) {
-        int len = uri.length();
-        for(int i=0; i < len ; i++) {
-            char c = uri.charAt(i);
-            if(c == ':') {
-                return i > 0;
-            } else if(!isSchemeChar(c)) {
-                return false;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Determine if the character is allowed in the scheme of a URI.
-     * See RFC 2396, Section 3.1
-     */
-    private static boolean isSchemeChar(char c) {
-        return Character.isLetterOrDigit(c) ||
-            c == '+' || c == '-' || c == '.';
-    }
-
-
-    /**
-     * Return the specified URL with the specified session identifier
-     * suitably encoded.
-     *
-     * @param url URL to be encoded with the session id
-     * @param sessionId Session id to be included in the encoded URL
-     */
-    protected String toEncoded(String url, String sessionId) {
-
-        if ((url == null) || (sessionId == null))
-            return (url);
-
-        String path = url;
-        String query = "";
-        String anchor = "";
-        int question = url.indexOf('?');
-        if (question >= 0) {
-            path = url.substring(0, question);
-            query = url.substring(question);
-        }
-        int pound = path.indexOf('#');
-        if (pound >= 0) {
-            anchor = path.substring(pound);
-            path = path.substring(0, pound);
-        }
-        StringBuffer sb = new StringBuffer(path);
-        if( sb.length() > 0 ) { // jsessionid can't be first.
-            sb.append(";jsessionid=");
-            sb.append(sessionId);
-        }
-        sb.append(anchor);
-        sb.append(query);
-        return (sb.toString());
-
-    }
-
-
-    public int getBytesWritten() {
-      return outputBuffer.getBytesWritten();
-    }
-
-    public BodyWriter getOutputBuffer() {
-      return outputBuffer;
-    }
-
-    public void setWriter(BodyWriter ob) {
-        outputBuffer = ob;
-        outputStream = new ServletOutputStreamImpl(outputBuffer);
-    }
-
-    public CharSequence getResponseHeader(String name) {
-      MessageBytes v = getHttpResponse().getMimeHeaders().getValue(name);
-      return (v == null) ? null : v.toString();
-    }
-
-
-    public HttpResponse getHttpResponse() {
-      return resB;
-    }
-
-
-    public void setHttpResponse(HttpResponse resB, BodyWriter ob) {
-        this.resB = resB;
-        setWriter(ob);
-    }
-
-
-
-   @Override
-    public Collection<String> getHeaders(String name) {
-        return null;
-    }
-
-
-}
-
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseIncludeWrapper.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletResponseIncludeWrapper.java
deleted file mode 100644 (file)
index 6f8b260..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- * 
- * 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.apache.tomcat.lite;
-
-
-import java.io.IOException;
-import java.util.Locale;
-
-import javax.servlet.ServletResponse;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpServletResponseWrapper;
-
-
-/**
- * Wrapper around the response object received as parameter to 
- * RequestDispatcher.include().
- * 
- * @author Costin Manolache
- */
-public class ServletResponseIncludeWrapper extends HttpServletResponseWrapper {
-    public ServletResponseIncludeWrapper(ServletResponse current) {
-        super((HttpServletResponse) current);
-    }
-
-    // Not overriden:
-    /*
-    public boolean containsHeader(String name)
-    public String encodeRedirectUrl(String url)
-    public String encodeRedirectURL(String url)
-    public String encodeUrl(String url)
-    public String encodeURL(String url)
-    public void flushBuffer() throws IOException
-    public int getBufferSize()
-    public String getCharacterEncoding()
-    public String getContentType()
-    public Locale getLocale()
-    public ServletOutputStream getOutputStream() throws IOException
-    public ServletResponse getResponse()
-    public PrintWriter getWriter() throws IOException
-    public boolean isCommitted()
-    public void resetBuffer()
-    public void setCharacterEncoding(String charset)
-    public void setResponse(ServletResponse response)
-     */
-    
-    public void reset() {
-        if (getResponse().isCommitted())
-            getResponse().reset(); 
-        else
-            throw new IllegalStateException();
-    }
-
-    public void setContentLength(int len) {
-    }
-
-    public void setContentType(String type) {
-    }
-
-    public void setLocale(Locale loc) {
-    }
-
-    public void setBufferSize(int size) {
-    }
-
-    public void addCookie(Cookie cookie) {
-    }
-
-    public void addDateHeader(String name, long value) {
-    }
-
-    public void addHeader(String name, String value) {
-    }
-
-    public void addIntHeader(String name, int value) {
-    }
-
-    public void sendError(int sc) throws IOException {
-    }
-
-    public void sendError(int sc, String msg) throws IOException {
-    }
-
-    public void sendRedirect(String location) throws IOException {
-    }
-
-    public void setDateHeader(String name, long value) {
-    }
-
-    public void setHeader(String name, String value) {
-    }
-
-    public void setIntHeader(String name, int value) {
-    }
-
-    public void setStatus(int sc) {
-    }
-
-    public void setStatus(int sc, String msg) {
-    }
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletWriterImpl.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/ServletWriterImpl.java
deleted file mode 100644 (file)
index a27d693..0000000
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- * 
- * 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.apache.tomcat.lite;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.Writer;
-
-/**
- * Coyote implementation of the servlet writer.
- * 
- * @author Remy Maucherat
- */
-public class ServletWriterImpl
-    extends PrintWriter {
-
-
-    // -------------------------------------------------------------- Constants
-
-
-    private static final char[] LINE_SEP = { '\r', '\n' };
-
-
-    // ----------------------------------------------------- Instance Variables
-
-
-    protected Writer ob;
-    protected boolean error = false;
-
-
-    // ----------------------------------------------------------- Constructors
-
-
-    public ServletWriterImpl(Writer ob) {
-        super(ob);
-        this.ob = ob;
-    }
-
-
-    // --------------------------------------------------------- Public Methods
-
-
-    /**
-     * Prevent cloning the facade.
-     */
-    protected Object clone()
-        throws CloneNotSupportedException {
-        throw new CloneNotSupportedException();
-    }
-
-
-    // -------------------------------------------------------- Package Methods
-
-
-    /**
-     * Clear facade.
-     */
-    void clear() {
-        ob = null;
-    }
-
-
-    /**
-     * Recycle.
-     */
-    void recycle() {
-        error = false;
-    }
-
-
-    // --------------------------------------------------------- Writer Methods
-
-
-    public void flush() {
-
-        if (error)
-            return;
-
-        try {
-            ob.flush();
-        } catch (IOException e) {
-            error = true;
-        }
-
-    }
-
-
-    public void close() {
-
-        // We don't close the PrintWriter - super() is not called,
-        // so the stream can be reused. We close ob.
-        try {
-            ob.close();
-        } catch (IOException ex ) {
-            ;
-        }
-        error = false;
-
-    }
-
-
-    public boolean checkError() {
-        flush();
-        return error;
-    }
-
-
-    public void write(int c) {
-
-        if (error)
-            return;
-
-        try {
-            ob.write(c);
-        } catch (IOException e) {
-            error = true;
-        }
-
-    }
-
-
-    public void write(char buf[], int off, int len) {
-
-        if (error)
-            return;
-
-        try {
-            ob.write(buf, off, len);
-        } catch (IOException e) {
-            error = true;
-        }
-
-    }
-
-
-    public void write(char buf[]) {
-       write(buf, 0, buf.length);
-    }
-
-
-    public void write(String s, int off, int len) {
-
-        if (error)
-            return;
-
-        try {
-            ob.write(s, off, len);
-        } catch (IOException e) {
-            error = true;
-        }
-
-    }
-
-
-    public void write(String s) {
-        write(s, 0, s.length());
-    }
-
-
-    // ---------------------------------------------------- PrintWriter Methods
-
-
-    public void print(boolean b) {
-        if (b) {
-            write("true");
-        } else {
-            write("false");
-        }
-    }
-
-
-    public void print(char c) {
-        write(c);
-    }
-
-
-    public void print(int i) {
-        write(String.valueOf(i));
-    }
-
-
-    public void print(long l) {
-        write(String.valueOf(l));
-    }
-
-
-    public void print(float f) {
-        write(String.valueOf(f));
-    }
-
-
-    public void print(double d) {
-        write(String.valueOf(d));
-    }
-
-
-    public void print(char s[]) {
-        write(s);
-    }
-
-
-    public void print(String s) {
-        if (s == null) {
-            s = "null";
-        }
-        write(s);
-    }
-
-
-    public void print(Object obj) {
-        write(String.valueOf(obj));
-    }
-
-
-    public void println() {
-        write(LINE_SEP);
-    }
-
-
-    public void println(boolean b) {
-        print(b);
-        println();
-    }
-
-
-    public void println(char c) {
-        print(c);
-        println();
-    }
-
-
-    public void println(int i) {
-        print(i);
-        println();
-    }
-
-
-    public void println(long l) {
-        print(l);
-        println();
-    }
-
-
-    public void println(float f) {
-        print(f);
-        println();
-    }
-
-
-    public void println(double d) {
-        print(d);
-        println();
-    }
-
-
-    public void println(char c[]) {
-        print(c);
-        println();
-    }
-
-
-    public void println(String s) {
-        print(s);
-        println();
-    }
-
-
-    public void println(Object o) {
-        print(o);
-        println();
-    }
-
-
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/TomcatLite.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/TomcatLite.java
deleted file mode 100644 (file)
index b012205..0000000
+++ /dev/null
@@ -1,646 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.apache.tomcat.lite;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-import javax.servlet.Filter;
-import javax.servlet.Servlet;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.UnavailableException;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.tomcat.integration.ObjectManager;
-import org.apache.tomcat.integration.simple.SimpleObjectManager;
-import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.buf.UriNormalizer;
-import org.apache.tomcat.util.http.mapper.MappingData;
-
-/**
- * Simpler, lower footprint serlvet engine.  
- * 
- * Uses ObjectManager to integate with an embedding app 
- * - the object names it uses:
- * 
- * Internal objects created by Tomcat and registered for management 
- * and injection: 
- * - Servlet:CONTEXT_PATH:SERVLETNAME - a ServletWrapper
- * - ServletContext:CONTEXT_PATH
- * - ProtocolHandler:ep-PORT - coyote ProtocolHandler
- * - CoyoteServer:CoyoteServer-PORT
- * - CoyoteAdapter:PATH - for the coyote used Adapter 
- * - TomcatLite - this object.
- * - Connector - the connector object
- * 
- * Plugins to be constructed by framework ( defaults set in initDefaults ):
- * - UserSessionManager
- * - UserTemplateClassMapper
- * - ContextPreinitListener
- * - Connector
- * - WebappServletMapper
- * - WebappFilterMapper
- * - default-servlet  
- * - jspwildcard-servlet
- * - Foo-servlet - servlet named Foo
- * 
- * 
- * @author Costin Manolache
- */
-public class TomcatLite implements Runnable {
-
-    private String serverDirName;
-    private File workDir;
-    
-    // all contexts - hostMapper knows about hostnames and how they are mapped.
-    // this shouldn't be needed if we want to delegate ctx management
-    private ArrayList<ServletContextImpl> contexts = new ArrayList();
-
-    URLClassLoader contextParentLoader;
-    
-    // Discovered or default Host/Context mapper
-    Filter hostMapper;
-
-    // Servlets to preload in each context, configurable from CLI or API
-    Map<String,String> preloadServlets = new HashMap();
-    Map<String,String> preloadMappings = new HashMap();
-    
-    Map<String,String> ctxDefaultInitParam = new HashMap();
-        
-    Connector connector;
-    
-    ObjectManager om;
-    
-    static String SERVLETS_PACKAGE = "org.apache.tomcat.servlets";
-    
-    
-    protected boolean daemon = false;
-    
-    public TomcatLite() {
-    }
-
-    public TomcatLite(ObjectManager om) {
-        this.setObjectManager(om);
-    }
-
-    // --------------- start/stop ---------------
-
-    public static ObjectManager defaultObjectManager() {
-        SimpleObjectManager cfg = new SimpleObjectManager();
-        cfg.loadResource("org/apache/tomcat/lite/config.properties");
-        return cfg;
-    }
-    /**
-     * Return the object manager associated with this tomcat.
-     * If none set, create a minimal one with the default 
-     * values.
-     */
-    public ObjectManager getObjectManager() {
-        if (om == null) {
-            om = defaultObjectManager();
-        }
-        return om;
-    }
-    
-    public void setObjectManager(ObjectManager om) {
-        this.om = om;
-    }
-    
-    public List/*<ServletContextImpl>*/ getWebapps() {
-        return contexts;
-    }
-    
-    public URLClassLoader getContextParentLoader() {
-        if (contextParentLoader == null) {
-            
-            ClassLoader parent = this.getClass().getClassLoader();
-            contextParentLoader = new URLClassLoader(new URL[] {},
-                    parent);
-            
-            /*if (engineRepo == null) {
-                engineRepo = new Repository();
-                engineRepo.setParentClassLoader(parent);
-            }
-            
-            contextParentLoader = 
-                engineRepo.getClassLoader();
-            */
-        }
-        return contextParentLoader;
-    }
-        
-    public void start() throws IOException {
-        long t0 = System.currentTimeMillis();
-        
-        // start all contexts
-        // init all contexts
-        Iterator i1 = contexts.iterator();
-        while (i1.hasNext()) {
-           ServletContextImpl ctx = (ServletContextImpl) i1.next();
-           try {
-               ctx.start();
-           } catch (Throwable e) {
-               e.printStackTrace();
-           }
-        }
-        long t1 = System.currentTimeMillis();
-        System.err.println("Engine.start() " + (t1-t0));
-    }
-    
-      
-    /**
-     * Add a context - used for IntrospectionUtils.
-     * 
-     * ContextPath:ContextBaseDir
-     */
-    public void setContext(String c) throws ServletException {
-        String[] pathDir = c.split(":", 2);
-        addServletContext("", pathDir[1], pathDir[0]);
-    }
-    
-    public void setServletContexts(List<ServletContext> c) throws ServletException {
-        for (ServletContext ctx: c) {
-            addServletContext((ServletContextImpl) ctx);
-        }
-    }
-    
-    public void setPreload(String servletNameClass) {
-        String[] nv = servletNameClass.split(":");
-        preloadServlets.put(nv[0], nv[1]);
-    }
-    
-    public void addPreload(String servletName, String servletClassName) {
-        preloadServlets.put(servletName, servletClassName);
-    }
-
-    public void setDefaultInitParam(String nameValue) {
-        String[] nv = nameValue.split(":");
-        ctxDefaultInitParam.put(nv[0], nv[1]);
-    }
-    
-    public void addDefaultInitParam(String name, String value) {
-        ctxDefaultInitParam.put(name, value);
-    }
-    
-    public void setPreloadMappings(String servletPath) {
-        String[] nv = servletPath.split(":");
-        preloadMappings.put(nv[0], nv[1]);
-    }
-    
-    public void addPreloadMapping(String servletName, String path) {
-        preloadMappings.put(servletName, path);
-    }
-    
-    public void stop() {
-        Iterator i1 = contexts.iterator();
-        while (i1.hasNext()) {
-           ServletContextImpl ctx = (ServletContextImpl) i1.next();
-            try {
-                ctx.destroy();
-            } catch (Throwable e) {
-                e.printStackTrace();
-            }
-        }
-        try {
-            stopConnector();
-        } catch (Exception e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
-    }
-
-    // -------------- Context add/remove --------------
-
-    public static String[] DEFAULT_WELCOME = { "index.html" };
-    
-    public void addServletContext(ServletContextImpl ctx) throws ServletException {
-        ctx.setTomcat(this);
-        if (hostMapper == null) { 
-            hostMapper = new WebappContextMapper();
-        }
-
-        ((WebappContextMapper) hostMapper).addHost(ctx.getHostname(), null);
-        ((WebappContextMapper) hostMapper).addContext(ctx.getHostname(), 
-                ctx);
-
-        contexts.add(ctx);
-        
-        getObjectManager().bind("ServletContext:" + ctx.getContextPath(), 
-                ctx);
-
-    }
-    
-    /**
-     * Add a context. 
-     * 
-     * web.xml will be read as part of init, and the initialization will be 
-     * part of start or lazy.
-     * 
-     * @param hostname - ""
-     *            if default host, or string to be matched with Host header
-     * @param basePath = directory where the webapp is installed           
-     * @param path -
-     *            context path, "/" for root, "/examples", etc
-     * @return a servlet context
-     * @throws ServletException
-     */
-    public ServletContext addServletContext(String hostname, 
-                                            String basePath,
-                                            String path)
-        throws ServletException
-    {
-        ServletContextImpl ctx = new ServletContextImpl();
-        ctx.setContextPath(path);
-        ctx.setBasePath(basePath);
-        addServletContext(ctx);
-        return ctx;
-    }
-    
-    public void removeServletContext(ServletContext sctx)
-        throws ServletException
-    {
-        ServletContextImpl ctx = (ServletContextImpl) sctx;
-        // TODO: destroy all servlets and filters
-        // TODO: clean up any other reference to the context or its loader
-        notifyRemove(ctx);
-    }
-    
-    
-    /** 
-     * Required for ServletContext.getContext(uri);
-     * @throws ServletException 
-     * @throws IOException 
-     */
-    public ServletContextImpl getContext(ServletContextImpl impl, String uri) 
-            throws IOException, ServletException {
-        // Create a request - needs to be simplified
-        ServletRequestImpl req = createMessage(impl, impl.contextPath, uri);
-        hostMapper.doFilter(req, null, null);
-        return req.getContext();
-    }
-    
-    public ServletResponseImpl service(ServletRequestImpl req) throws IOException, Exception {
-      ServletResponseImpl res = req.getResponse();
-      service(req, res);
-      endRequest(req, res);
-      return res;
-    }
-    
-    public void service(ServletRequestImpl req, ServletResponseImpl res) 
-            throws Exception, IOException {
-        // parse the session id from URI
-        req.parseSessionId();
-        
-        try {
-          UriNormalizer.decodeRequest(req.getHttpRequest().decodedURI(), 
-                  req.getHttpRequest().requestURI(),
-                  req.getHttpRequest().getURLDecoder());
-        } catch(IOException ioe) {
-            res.setStatus(400);
-            return;
-        }
-        
-        MappingData mapRes = req.getMappingData();
-        try {
-          // TODO: make hostMapper configurable, implement interface,
-          // simple to set on ROOT context
-          hostMapper.doFilter(req, null, null);
-            
-
-          ServletContextImpl ctx = (ServletContextImpl)mapRes.context;
-          if( ctx == null ) {
-            // TODO: 404
-            res.setStatus(404);
-            return;
-          }
-          req.setContext(ctx);
-
-          // bind class loader 
-          Thread.currentThread().setContextClassLoader(ctx.getClassLoader());
-
-          WebappServletMapper mapper = ctx.getMapper();
-          mapper.map(req.getHttpRequest().decodedURI(), mapRes);
-
-          // Possible redirect
-          MessageBytes redirectPathMB = mapRes.redirectPath;
-          if (!redirectPathMB.isNull()) {
-              String redirectPath = res.urlEncoder.encodeURL(redirectPathMB.toString());
-              String query = req.getQueryString();
-              if (req.isRequestedSessionIdFromURL()) {
-                  // This is not optimal, but as this is not very common, it
-                  // shouldn't matter
-                  redirectPath = redirectPath + ";" + ServletRequestImpl.SESSION_PARAMETER_NAME + "=" 
-                      + req.getRequestedSessionId();
-              }
-              if (query != null) {
-                  // This is not optimal, but as this is not very common, it
-                  // shouldn't matter
-                  redirectPath = redirectPath + "?" + query;
-              }
-              res.sendRedirect(redirectPath);
-              return;
-          }
-          
-          req.parseSessionCookiesId();
-
-          ServletConfigImpl h=(ServletConfigImpl)mapRes.wrapper;
-          if (h != null) {
-            req.setWrapper((ServletConfigImpl)mapRes.wrapper);
-            serviceServlet(ctx, req, res, h, mapRes );
-            // send the response...
-
-            //res.flushBuffer();
-
-            // Recycle the wrapper request and response
-            //req.recycle();
-            //res.recycle();
-          }
-        } finally {
-            if(mapRes != null ) 
-                mapRes.recycle();
-        }
-    }
-    
-    /** Coyote / mapper adapter. Result of the mapper.
-     *  
-     *  This replaces the valve chain, the path is: 
-     *    1. coyote calls mapper -> result Adapter 
-     *    2. service is called. Additional filters are set on the wrapper. 
-     * @param mapRes 
-     */
-    private void serviceServlet(ServletContextImpl ctx, 
-                               ServletRequestImpl req, 
-                               ServletResponseImpl res,
-                               ServletConfigImpl servletConfig, 
-                               MappingData mapRes) 
-            throws IOException {
-        Servlet servlet = null;
-        try {
-            if (servletConfig.isUnavailable()) {
-                handleUnavailable(res, servletConfig);
-                return;
-            }
-            try {
-                servlet = servletConfig.allocate();
-            } catch(ServletException ex) {
-                handleUnavailable(res, servletConfig);
-            }
-            WebappFilterMapper filterMap = ctx.getFilterMapper();
-            FilterChainImpl chain = 
-                filterMap.createFilterChain(req, servletConfig, servlet);
-            
-            try {
-                if (chain == null) {
-                    if (servlet != null) {
-                        servlet.service(req, res);
-                    } else {
-                        System.err.println("No servlet " + req.getRequestURI());
-                        res.sendError(404);
-                    }
-                } else {
-                    chain.doFilter(req, res);
-                }
-            } catch(UnavailableException ex) {
-                servletConfig.unavailable(ex);
-                handleUnavailable(res, servletConfig);
-                return;
-            }
-            
-            // servlet completed without exception. Check status
-            int status = res.getStatus();
-            if (status != 200 && !res.isCommitted()) {
-                String statusPage = ctx.findStatusPage(status);
-
-                if (statusPage != null) {
-                    ctx.handleStatusPage(req, res, status, statusPage);
-                } else {
-                    // Send a default message body.
-                    // TODO: maybe other mechanism to customize default.
-                    res.defaultStatusPage(status, res.getMessage());
-                }
-            }
-        } catch (Throwable t) {
-            ctx.handleError(req, res, t);
-        } finally {
-            if (servlet != null) {
-                servletConfig.deallocate(servlet);
-            }
-        }
-    }
-
-    private void handleUnavailable(ServletResponseImpl response, 
-                                   ServletConfigImpl servletConfig) 
-            throws IOException {
-        long available = servletConfig.getAvailable();
-        if ((available > 0L) && (available < Long.MAX_VALUE))
-            response.setDateHeader("Retry-After", available);
-        //  TODO: handle via error pages !
-        response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, 
-                "Service unavailable");
-    }
-    
-
-    // ------------ Notifications for JMX ----------------
-
-    void notifyAdd(Object o) {
-    }
-
-    void notifyRemove(Object o) {
-    }
-
-    public void setServerDir(String dir) {
-      this.serverDirName = dir;
-    }
-        
-    public File getWork() {
-        if (workDir == null) {
-          if (serverDirName == null) {
-              serverDirName = "./";
-          }
-          File rootDirFile = new File(serverDirName);
-          workDir = new File(rootDirFile, "tomcat-work");
-          if (workDir.exists()) {
-            workDir.mkdirs();
-          }
-        }
-        return workDir;
-    }
-    
-    /** 
-     * Init
-     * 
-     * @throws ServletException
-     * @throws IOException
-     */
-    public void init() throws ServletException, IOException {
-      getObjectManager().bind("TomcatLite", this);
-      if (contexts.size() == 0) {
-        setContext("/:./webapps/ROOT");
-      }
-      getConnector().setObjectManager(getObjectManager());
-      Iterator i1 = contexts.iterator();
-      while (i1.hasNext()) {
-        ServletContextImpl ctx = (ServletContextImpl) i1.next();
-        try {
-          ctx.init();
-        } catch (Throwable e) {
-          e.printStackTrace();
-        }
-      }
-    }
-    
-    /**
-     * Initialize an webapp and add it to the server. 
-     * - load web.xml
-     * - call 
-     * 
-     * @param rootDir
-     * @param path
-     * @param deployServlet
-     */
-    public void init(String rootDir, String path) 
-            throws ServletException, IOException {
-        
-        long t0 = System.currentTimeMillis();
-
-        ServletContextImpl ctx = 
-            (ServletContextImpl)addServletContext(null, 
-                                                  rootDir, 
-                                                  path);
-        ctx.init();
-        
-        long t1 = System.currentTimeMillis();
-        
-        // At this point all config is loaded. Contexts are not yet init()
-        // - this will happen on start.
-        System.err.println("Context.init() " + path + " " + (t1-t0));
-    }
-
-    /** 
-     * Get an empty request/response pair ( response available 
-     * as getResponse() ). Optional set input and output buffers.
-     * 
-     * This can be used for a connector-less interface to tomcat lite.
-     * 
-     * TODO: make it independent of coyote !
-     */
-    
-    public  ServletRequestImpl createMessage() {
-      ServletRequestImpl req = new ServletRequestImpl();
-      ServletResponseImpl res = req.getResponse();
-      
-      getConnector().initRequest(req, res);
-      
-      req.getHttpRequest().method().setString("GET");
-      req.getHttpRequest().protocol().setString("HTTP/1.1");
-      
-      return req;
-    }
-    
-    /**
-     * Used internally for mapping. 
-     */
-    private ServletRequestImpl createMessage(ServletContextImpl deployCtx,
-                                            String ctxPath,
-                                            String reqPath) {
-      ServletRequestImpl req = createMessage();
-      req.setContextPath(ctxPath);
-      req.setContext(deployCtx);
-      req.setRequestURI(ctxPath + reqPath);
-      return req;
-    }
-    
-
-    /** 
-     * Set a global filter that will be used for context mapping.
-     * 
-     * The filter will get a request, with requestUri and hostname set.
-     *  
-     * It needs to compute the context path and set it as an attribute.
-     * 
-     * Advanced features may include on-demand loading of webapps, large scale
-     * virtual hosting, etc.
-     */
-    public void setContextMapper(Filter hostMapper2) {
-        this.hostMapper = hostMapper2;
-    }
-
-    public void endRequest(ServletRequestImpl req,
-                           ServletResponseImpl res) throws IOException {
-     res.outputBuffer.flush();
-     req.getConnector().finishResponse(res);
-    }
-    
-    public Connector getConnector() {
-        if (connector == null) {
-            connector = (Connector) getObjectManager().get(Connector.class);
-            setConnector(connector);
-        }
-        return connector;
-    }
-
-    public void setConnector(Connector c) {
-        connector = c;
-        connector.setTomcatLite(this);
-        getObjectManager().bind("Connector", connector);
-    }
-
-    
-    public void setDaemon(boolean d) {
-        getConnector();
-        if (connector != null) {
-            connector.setDaemon(d);
-        }
-    }
-
-    public void startConnector() throws IOException {
-        getConnector();
-        if (connector != null) {
-            connector.start();
-        }
-    }
-
-    public void stopConnector() throws Exception {
-        if (connector != null) {
-            connector.stop();
-        }
-    }
-
-    public void run() {
-        try {
-            execute();
-        } catch (ServletException e) {
-            e.printStackTrace();
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-    }
-    
-    public void execute() throws ServletException, IOException {
-        init();
-        start();
-        startConnector();
-    }
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/WebappContextMapper.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/WebappContextMapper.java
deleted file mode 100644 (file)
index ae0d969..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You 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.apache.tomcat.lite;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-import org.apache.tomcat.util.buf.CharChunk;
-import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.http.mapper.MappingData;
-
-/** 
- * This handles host and context mapping.
- * 
- * The default implementation for tomcat lite is very limitted - 
- * no support for virtual hosts, no support for contexts deeper than 
- * 1 level. The intention is to override this with more advanced mappers.
- * 
- * With 'ConfigurableHosts' interface it is possible for a smart 
- * mapper to load/unload virtual hosts at runtime, maybe from a 
- * database. It should be possible to use databases to store huge number 
- * of hosts or webapps. 
- * 
- */
-public class WebappContextMapper implements Filter {
-
-  ServletContext rootContext;
-  Map<MessageBytes, ServletContext> contexts = new HashMap();
-
-  public WebappContextMapper() {
-  }
-
-  public void addHost(String name, String[] aliases) {
-  }
-  
-  /**
-   * Add a new Context to an existing Host.
-   *
-   * @param hostName Virtual host name this context belongs to
-   * @param contextPath Context path
-   * @param context Context object
-   * @param welcomeResources Welcome files defined for this context
-   * @param resources Static resources of the context
-   */
-  public void addContext(String hostName, 
-                         ServletContext context)
-      throws ServletException
-  {
-    String path = context.getContextPath();
-    if (path.lastIndexOf("/") > 0) {
-      throw new ServletException("Base context mapper supports only one level");
-    }
-    if ("/".equals(path)) {
-      rootContext = context;
-    }
-    MessageBytes mb = MessageBytes.newInstance();
-    mb.setChars(path.toCharArray(), 0, path.length());
-    contexts.put(mb, context);
-  }
-
-
-  /**
-   * Remove a context from an existing host.
-   *
-   * @param hostName Virtual host name this context belongs to
-   * @param path Context path
-   */
-  public void removeContext(String hostName, String path) 
-      throws ServletException {
-    if ("/".equals(path)) {
-      rootContext = null;
-    }
-    contexts.remove(path);  
-  }
-
-  /**
-   * Map the specified URI.
-   */
-  private void mapContext(ServletRequestImpl req)
-      throws IOException, ServletException {
-    MessageBytes uriMB = req.getDecodedRequestURIMB();
-    MappingData mappingData = req.getMappingData(); 
-    uriMB.toChars();
-    CharChunk uri = uriMB.getCharChunk();
-
-    
-    if (uri.length() < 2 || contexts.size() == 0) {
-      mappingData.context = rootContext;
-      if (rootContext != null) {
-        mappingData.contextPath.setString(rootContext.getContextPath());
-      }
-      return;
-    }
-    
-    int nextSlash = uri.indexOf('/', 1);
-    if (nextSlash == -1) {
-      nextSlash = uri.length();
-    }
-    mappingData.contextPath.setChars(uri.getChars(), 0, nextSlash);
-    ServletContext servletContext = contexts.get(mappingData.contextPath);
-
-    if (servletContext != null) {
-      mappingData.context = servletContext;
-    } else {
-      mappingData.context = rootContext;
-      if (rootContext != null) {
-        mappingData.contextPath.setString(rootContext.getContextPath());      
-      }
-    }
-  }
-
-  public void init(FilterConfig filterConfig) throws ServletException {
-  }
-    
-  public void doFilter(ServletRequest request, 
-                       ServletResponse response, 
-                       FilterChain chain) 
-      throws IOException, ServletException {
-    ServletRequestImpl req = (ServletRequestImpl)request;
-    mapContext(req);
-  }
-    
-  public void destroy() {
-  }
-}
\ No newline at end of file
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/WebappFilterMapper.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/WebappFilterMapper.java
deleted file mode 100644 (file)
index f6cfaed..0000000
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- * 
- * 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.apache.tomcat.lite;
-
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.ArrayList;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.Servlet;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.tomcat.servlets.util.RequestUtil;
-
-/**
- * First filter after the context and servlet are mapped. It will add 
- * web.xml-defined filters. 
- * 
- * costin: This is another mapping - done in RequestDispatcher or initial 
- * mapping.
- * Also: StandardHostValve - sets attribute for error pages,
- *   StandardWrapperValve - mapping per invocation
- *
- * @author Greg Murray
- * @author Remy Maucherat
- */
-public class WebappFilterMapper implements Filter {
-
-
-    // -------------------------------------------------------------- Constants
-
-
-    public static final int ERROR = 1;
-    public static final Integer ERROR_INTEGER = new Integer(ERROR);
-    public static final int FORWARD = 2;
-    public static final Integer FORWARD_INTEGER = new Integer(FORWARD);
-    public static final int INCLUDE = 4;
-    public static final Integer INCLUDE_INTEGER = new Integer(INCLUDE);
-    public static final int REQUEST = 8;
-    public static final Integer REQUEST_INTEGER = new Integer(REQUEST);
-
-    /**
-     * Request dispatcher state.
-     */
-    public static final String DISPATCHER_TYPE_ATTR = 
-        "org.apache.catalina.core.DISPATCHER_TYPE";
-
-    /**
-     * Request dispatcher path.
-     */
-    public static final String DISPATCHER_REQUEST_PATH_ATTR = 
-        "org.apache.catalina.core.DISPATCHER_REQUEST_PATH";
-
-
-    // ----------------------------------------------------------- Constructors
-    ServletContextImpl servletContext;
-
-    public WebappFilterMapper() {
-    }
-
-    public WebappFilterMapper(ServletContextImpl impl) {
-        servletContext = impl;
-    }
-
-    public void setServletContext(ServletContextImpl sc) {
-        servletContext = sc;
-    }
-
-    // --------------------------------------------------------- Public Methods
-
-    ArrayList filterMaps = new ArrayList();
-    
-    public void addMapping(String filterName, 
-                           String url, 
-                           String servletName, 
-                           String type[], boolean isMatchAfter) {
-        FilterMap map = new FilterMap();
-        map.setURLPattern(url);
-        map.setFilterName(filterName);
-        map.setServletName(servletName);
-        if (isMatchAfter) {
-            filterMaps.add(map);
-        } else {
-            filterMaps.add(0, map);
-        }
-    }
-
-    /**
-     * Construct and return a FilterChain implementation that will wrap the
-     * execution of the specified servlet instance.  If we should not execute
-     * a filter chain at all, return <code>null</code>.
-     *
-     * @param request The servlet request we are processing
-     * @param servlet The servlet instance to be wrapped
-     */
-    public FilterChainImpl createFilterChain(ServletRequest request, 
-                                             ServletConfigImpl wrapper, 
-                                             Servlet servlet) {
-
-        // If there is no servlet to execute, return null
-        if (servlet == null)
-            return (null);
-
-        // get the dispatcher type
-        int dispatcher = -1; 
-        if (request.getAttribute(DISPATCHER_TYPE_ATTR) != null) {
-            Integer dispatcherInt = 
-                (Integer) request.getAttribute(DISPATCHER_TYPE_ATTR);
-            dispatcher = dispatcherInt.intValue();
-        }
-        String requestPath = null;
-        Object attribute = request.getAttribute(DISPATCHER_REQUEST_PATH_ATTR);
-        
-        if (attribute != null){
-            requestPath = attribute.toString();
-        }
-        
-        HttpServletRequest hreq = null;
-        if (request instanceof HttpServletRequest) 
-            hreq = (HttpServletRequest)request;
-
-        // Create and initialize a filter chain object
-        FilterChainImpl filterChain = null;
-        if ((request instanceof ServletRequestImpl)) {
-            ServletRequestImpl req = (ServletRequestImpl) request;
-            filterChain = (FilterChainImpl) req.getFilterChain();
-            filterChain.release();
-        } else {
-            // Security: Do not recycle
-            filterChain = new FilterChainImpl();
-        }
-
-        filterChain.setServlet(wrapper, servlet);
-
-        // If there are no filter mappings, we are done
-        if ((filterMaps.size() == 0))
-            return (filterChain);
-
-        // Acquire the information we will need to match filter mappings
-        String servletName = wrapper.getServletName();
-
-        int n = 0;
-
-        // TODO(costin): optimize: separate in 2 lists, one for url-mapped, one for
-        // servlet-name. Maybe even separate list for dispatcher and 
-        // non-dispatcher
-        
-        // TODO(costin): optimize: set the FilterConfig in the FilterMap, to 
-        // avoid second hash lookup
-        
-        // Add the relevant path-mapped filters to this filter chain
-        for (int i = 0; i < filterMaps.size(); i++) {
-            FilterMap filterMap = (FilterMap)filterMaps.get(i);
-            if (!matchDispatcher(filterMap ,dispatcher)) {
-                continue;
-            }
-            if (!matchFiltersURL(filterMap, requestPath))
-                continue;
-            FilterConfigImpl filterConfig = 
-                servletContext.getFilter(filterMap.getFilterName());
-            if (filterConfig == null) {
-                // FIXME - log configuration problem
-                continue;
-            }
-            filterChain.addFilter(filterConfig);
-            n++;
-        }
-
-        // Add filters that match on servlet name second
-        for (int i = 0; i < filterMaps.size(); i++) {
-            FilterMap filterMap = (FilterMap)filterMaps.get(i);
-            if (!matchDispatcher(filterMap ,dispatcher)) {
-                continue;
-            }
-            if (!matchFiltersServlet(filterMap, servletName))
-                continue;
-            FilterConfigImpl filterConfig = 
-                servletContext.getFilter(filterMap.getFilterName());
-            if (filterConfig == null) {
-                ;       // FIXME - log configuration problem
-                continue;
-            }
-            filterChain.addFilter(filterConfig);
-            n++;
-        }
-
-        // Return the completed filter chain
-        return (filterChain);
-
-    }
-
-
-    // -------------------------------------------------------- Private Methods
-
-
-    /**
-     * Return <code>true</code> if the context-relative request path
-     * matches the requirements of the specified filter mapping;
-     * otherwise, return <code>null</code>.
-     *
-     * @param filterMap Filter mapping being checked
-     * @param requestPath Context-relative request path of this request
-     */
-    private boolean matchFiltersURL(FilterMap filterMap, String requestPath) {
-
-        if (requestPath == null)
-            return (false);
-
-        // Match on context relative request path
-        String testPath = filterMap.getURLPattern();
-        if (testPath == null)
-            return (false);
-
-        // Case 1 - Exact Match
-        if (testPath.equals(requestPath))
-            return (true);
-
-        // Case 2 - Path Match ("/.../*")
-        if (testPath.equals("/*"))
-            return (true);
-        if (testPath.endsWith("/*")) {
-            if (testPath.regionMatches(0, requestPath, 0, 
-                                       testPath.length() - 2)) {
-                if (requestPath.length() == (testPath.length() - 2)) {
-                    return (true);
-                } else if ('/' == requestPath.charAt(testPath.length() - 2)) {
-                    return (true);
-                }
-            }
-            return (false);
-        }
-
-        // Case 3 - Extension Match
-        if (testPath.startsWith("*.")) {
-            int slash = requestPath.lastIndexOf('/');
-            int period = requestPath.lastIndexOf('.');
-            if ((slash >= 0) && (period > slash) 
-                && (period != requestPath.length() - 1)
-                && ((requestPath.length() - period) 
-                    == (testPath.length() - 1))) {
-                return (testPath.regionMatches(2, requestPath, period + 1,
-                                               testPath.length() - 2));
-            }
-        }
-
-        // Case 4 - "Default" Match
-        return (false); // NOTE - Not relevant for selecting filters
-
-    }
-
-
-    /**
-     * Return <code>true</code> if the specified servlet name matches
-     * the requirements of the specified filter mapping; otherwise
-     * return <code>false</code>.
-     *
-     * @param filterMap Filter mapping being checked
-     * @param servletName Servlet name being checked
-     */
-    private boolean matchFiltersServlet(FilterMap filterMap, 
-                                        String servletName) {
-
-        if (servletName == null) {
-            return (false);
-        } else {
-            if (servletName.equals(filterMap.getServletName())) {
-                return (true);
-            } else {
-                return false;
-            }
-        }
-
-    }
-
-
-    /**
-     * Convienience method which returns true if  the dispatcher type
-     * matches the dispatcher types specified in the FilterMap
-     */
-    private boolean matchDispatcher(FilterMap filterMap, int dispatcher) {
-        switch (dispatcher) {
-            case FORWARD : {
-                if (filterMap.getDispatcherMapping() == FilterMap.FORWARD ||
-                    filterMap.getDispatcherMapping() == FilterMap.FORWARD_ERROR ||
-                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_FORWARD ||
-                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE) {
-                        return true;
-                }
-                break;
-            }
-            case INCLUDE : {
-                if (filterMap.getDispatcherMapping() == FilterMap.INCLUDE ||
-                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR ||
-                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_FORWARD ||
-                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_INCLUDE ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE) {
-                        return true;
-                }
-                break;
-            }
-            case REQUEST : {
-                if (filterMap.getDispatcherMapping() == FilterMap.REQUEST ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_INCLUDE ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE) {
-                        return true;
-                }
-                break;
-            }
-            case ERROR : {
-                if (filterMap.getDispatcherMapping() == FilterMap.ERROR ||
-                    filterMap.getDispatcherMapping() == FilterMap.FORWARD_ERROR || 
-                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR || 
-                    filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD || 
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE ||
-                    filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE) {
-                        return true;
-                }
-                break;
-            }
-        }
-        return false;
-    }
-
-
-    // -------------------- Map elements -----------------------
-    
-    public static class FilterMap implements Serializable {
-
-
-        // ------------------------------------------------------------- Properties
-
-
-        /**
-         * The name of this filter to be executed when this mapping matches
-         * a particular request.
-         */
-        
-        public static final int ERROR = 1;
-        public static final int FORWARD = 2;
-        public static final int FORWARD_ERROR =3;  
-        public static final int INCLUDE = 4;
-        public static final int INCLUDE_ERROR  = 5;
-        public static final int INCLUDE_ERROR_FORWARD  =6;
-        public static final int INCLUDE_FORWARD  = 7;
-        public static final int REQUEST = 8;
-        public static final int REQUEST_ERROR = 9;
-        public static final int REQUEST_ERROR_FORWARD = 10;
-        public static final int REQUEST_ERROR_FORWARD_INCLUDE = 11;
-        public static final int REQUEST_ERROR_INCLUDE = 12;
-        public static final int REQUEST_FORWARD = 13;
-        public static final int REQUEST_INCLUDE = 14;
-        public static final int REQUEST_FORWARD_INCLUDE= 15;
-        
-        // represents nothing having been set. This will be seen 
-        // as equal to a REQUEST
-        private static final int NOT_SET = -1;
-        
-        private int dispatcherMapping=NOT_SET;
-        
-        private String filterName = null;    
-
-        /**
-         * The URL pattern this mapping matches.
-         */
-        private String urlPattern = null;
-
-        /**
-         * The servlet name this mapping matches.
-         */
-        private String servletName = null;
-
-
-
-        public String getFilterName() {
-            return (this.filterName);
-        }
-
-        public void setFilterName(String filterName) {
-            this.filterName = filterName;
-        }
-
-
-        public String getServletName() {
-            return (this.servletName);
-        }
-
-        public void setServletName(String servletName) {
-            this.servletName = servletName;
-        }
-
-
-        public String getURLPattern() {
-            return (this.urlPattern);
-        }
-
-        public void setURLPattern(String urlPattern) {
-            this.urlPattern = RequestUtil.URLDecode(urlPattern);
-        }
-        
-        /**
-         *
-         * This method will be used to set the current state of the FilterMap
-         * representing the state of when filters should be applied:
-         *
-         *        ERROR
-         *        FORWARD
-         *        FORWARD_ERROR
-         *        INCLUDE
-         *        INCLUDE_ERROR
-         *        INCLUDE_ERROR_FORWARD
-         *        REQUEST
-         *        REQUEST_ERROR
-         *        REQUEST_ERROR_INCLUDE
-         *        REQUEST_ERROR_FORWARD_INCLUDE
-         *        REQUEST_INCLUDE
-         *        REQUEST_FORWARD,
-         *        REQUEST_FORWARD_INCLUDE
-         *
-         */
-        public void setDispatcher(String dispatcherString) {
-            String dispatcher = dispatcherString.toUpperCase();
-            
-            if (dispatcher.equals("FORWARD")) {
-
-                // apply FORWARD to the global dispatcherMapping.
-                switch (dispatcherMapping) {
-                    case NOT_SET  :  dispatcherMapping = FORWARD; break;
-                    case ERROR : dispatcherMapping = FORWARD_ERROR; break;
-                    case INCLUDE  :  dispatcherMapping = INCLUDE_FORWARD; break;
-                    case INCLUDE_ERROR  :  dispatcherMapping = INCLUDE_ERROR_FORWARD; break;
-                    case REQUEST : dispatcherMapping = REQUEST_FORWARD; break;
-                    case REQUEST_ERROR : dispatcherMapping = REQUEST_ERROR_FORWARD; break;
-                    case REQUEST_ERROR_INCLUDE : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
-                    case REQUEST_INCLUDE : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break;
-                }
-            } else if (dispatcher.equals("INCLUDE")) {
-                // apply INCLUDE to the global dispatcherMapping.
-                switch (dispatcherMapping) {
-                    case NOT_SET  :  dispatcherMapping = INCLUDE; break;
-                    case ERROR : dispatcherMapping = INCLUDE_ERROR; break;
-                    case FORWARD  :  dispatcherMapping = INCLUDE_FORWARD; break;
-                    case FORWARD_ERROR  :  dispatcherMapping = INCLUDE_ERROR_FORWARD; break;
-                    case REQUEST : dispatcherMapping = REQUEST_INCLUDE; break;
-                    case REQUEST_ERROR : dispatcherMapping = REQUEST_ERROR_INCLUDE; break;
-                    case REQUEST_ERROR_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
-                    case REQUEST_FORWARD : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break;
-                }
-            } else if (dispatcher.equals("REQUEST")) {
-                // apply REQUEST to the global dispatcherMapping.
-                switch (dispatcherMapping) {
-                    case NOT_SET  :  dispatcherMapping = REQUEST; break;
-                    case ERROR : dispatcherMapping = REQUEST_ERROR; break;
-                    case FORWARD  :  dispatcherMapping = REQUEST_FORWARD; break;
-                    case FORWARD_ERROR  :  dispatcherMapping = REQUEST_ERROR_FORWARD; break;
-                    case INCLUDE  :  dispatcherMapping = REQUEST_INCLUDE; break;
-                    case INCLUDE_ERROR  :  dispatcherMapping = REQUEST_ERROR_INCLUDE; break;
-                    case INCLUDE_FORWARD : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break;
-                    case INCLUDE_ERROR_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
-                }
-            }  else if (dispatcher.equals("ERROR")) {
-                // apply ERROR to the global dispatcherMapping.
-                switch (dispatcherMapping) {
-                    case NOT_SET  :  dispatcherMapping = ERROR; break;
-                    case FORWARD  :  dispatcherMapping = FORWARD_ERROR; break;
-                    case INCLUDE  :  dispatcherMapping = INCLUDE_ERROR; break;
-                    case INCLUDE_FORWARD : dispatcherMapping = INCLUDE_ERROR_FORWARD; break;
-                    case REQUEST : dispatcherMapping = REQUEST_ERROR; break;
-                    case REQUEST_INCLUDE : dispatcherMapping = REQUEST_ERROR_INCLUDE; break;
-                    case REQUEST_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD; break;
-                    case REQUEST_FORWARD_INCLUDE : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break;
-                }
-            }
-        }
-        
-        public int getDispatcherMapping() {
-            // per the SRV.6.2.5 absence of any dispatcher elements is
-            // equivelant to a REQUEST value
-            if (dispatcherMapping == NOT_SET) return REQUEST;
-            else return dispatcherMapping; 
-        }
-
-    }
-
-
-    public void init(FilterConfig filterConfig) throws ServletException {
-    }
-
-
-    public void doFilter(ServletRequest request, ServletResponse response, 
-                         FilterChain chain) 
-            throws IOException, ServletException {
-    }
-
-
-    public void destroy() {
-    }
-
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/WebappServletMapper.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/WebappServletMapper.java
deleted file mode 100644 (file)
index a6eb284..0000000
+++ /dev/null
@@ -1,883 +0,0 @@
-/*
- *  Copyright 1999-2004 The Apache Software Foundation
- *
- *  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.apache.tomcat.lite;
-
-import java.io.File;
-import java.io.IOException;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-
-import org.apache.tomcat.util.buf.Ascii;
-import org.apache.tomcat.util.buf.CharChunk;
-import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.http.mapper.MappingData;
-
-/**
- * Mapper, which implements the servlet API mapping rules (which are derived
- * from the HTTP rules).
- * 
- * Based on catalina mapper - but simplified. All host and context mappings
- * is done in HostMapper - this is just dealing with web.xml.
- * 
- * For corner cases ( very large number of rules, dynamic rules, etc ) you 
- * can override the mapper for a context with a class extending this.
- * 
- * TODO: remove, use coyote-level mapper or user-space
- */
-public class WebappServletMapper implements Filter {
-
-    /**
-     * Context associated with this wrapper, used for wrapper mapping.
-     */
-    public ContextMapElement contextMapElement = new ContextMapElement();
-
-
-    // --------------------------------------------------------- Public Methods
-    public WebappServletMapper() {
-    }
-    
-    public void setServletContext(ServletContextImpl impl) {
-        contextMapElement.object = impl;
-        contextMapElement.name = impl.getContextPath();        
-    }
-
-
-   /** Set context, used for wrapper mapping (request dispatcher).
-     *
-     * @param welcomeResources Welcome files defined for this context
-     * @param resources Static resources of the context
-     */
-    public void setContext(String path, String[] welcomeResources,
-                           File resources) {
-        contextMapElement.name = path;
-        contextMapElement.welcomeResources = welcomeResources;
-        contextMapElement.resources = resources;
-    }
-
-
-    /**
-     * Add a wrapper to the context associated with this wrapper.
-     *
-     * @param path Wrapper mapping
-     * @param wrapper The Wrapper object
-     */
-    public void addWrapper(String path, Object wrapper) {
-        addWrapper(contextMapElement, path, wrapper);
-    }
-
-
-    public void addWrapper(String path, Object wrapper, boolean jspWildCard) {
-        addWrapper(contextMapElement, path, wrapper, jspWildCard);
-    }
-
-
-    public void addWrapper(ContextMapElement context, String path, Object wrapper) {
-        addWrapper(context, path, wrapper, false);
-    }
-
-
-    /**
-     * Adds a wrapper to the given context.
-     *
-     * @param context The context to which to add the wrapper
-     * @param path Wrapper mapping
-     * @param wrapper The Wrapper object
-     * @param jspWildCard true if the wrapper corresponds to the JspServlet
-     * and the mapping path contains a wildcard; false otherwise
-     */
-    protected void addWrapper(ContextMapElement context, String path, Object wrapper,
-                              boolean jspWildCard) {
-
-        synchronized (context) {
-            WrapperMapElement newWrapper = new WrapperMapElement();
-            newWrapper.object = wrapper;
-            newWrapper.jspWildCard = jspWildCard;
-            if (path.endsWith("/*")) {
-                // Wildcard wrapper
-                newWrapper.name = path.substring(0, path.length() - 2);
-                WrapperMapElement[] oldWrappers = context.wildcardWrappers;
-                WrapperMapElement[] newWrappers =
-                    new WrapperMapElement[oldWrappers.length + 1];
-                if (insertMap(oldWrappers, newWrappers, newWrapper)) {
-                    context.wildcardWrappers = newWrappers;
-                    int slashCount = slashCount(newWrapper.name);
-                    if (slashCount > context.nesting) {
-                        context.nesting = slashCount;
-                    }
-                }
-            } else if (path.startsWith("*.")) {
-                // Extension wrapper
-                newWrapper.name = path.substring(2);
-                WrapperMapElement[] oldWrappers = context.extensionWrappers;
-                WrapperMapElement[] newWrappers =
-                    new WrapperMapElement[oldWrappers.length + 1];
-                if (insertMap(oldWrappers, newWrappers, newWrapper)) {
-                    context.extensionWrappers = newWrappers;
-                }
-            } else if (path.equals("/")) {
-                // Default wrapper
-                newWrapper.name = "";
-                context.defaultWrapper = newWrapper;
-            } else {
-                // Exact wrapper
-                newWrapper.name = path;
-                WrapperMapElement[] oldWrappers = context.exactWrappers;
-                WrapperMapElement[] newWrappers =
-                    new WrapperMapElement[oldWrappers.length + 1];
-                if (insertMap(oldWrappers, newWrappers, newWrapper)) {
-                    context.exactWrappers = newWrappers;
-                }
-            }
-        }
-    }
-
-
-    /**
-     * Remove a wrapper from the context associated with this wrapper.
-     *
-     * @param path Wrapper mapping
-     */
-    public void removeWrapper(String path) {
-        removeWrapper(contextMapElement, path);
-    }
-
-
-    protected void removeWrapper(ContextMapElement context, String path) {
-        synchronized (context) {
-            if (path.endsWith("/*")) {
-                // Wildcard wrapper
-                String name = path.substring(0, path.length() - 2);
-                WrapperMapElement[] oldWrappers = context.wildcardWrappers;
-                WrapperMapElement[] newWrappers =
-                    new WrapperMapElement[oldWrappers.length - 1];
-                if (removeMap(oldWrappers, newWrappers, name)) {
-                    // Recalculate nesting
-                    context.nesting = 0;
-                    for (int i = 0; i < newWrappers.length; i++) {
-                        int slashCount = slashCount(newWrappers[i].name);
-                        if (slashCount > context.nesting) {
-                            context.nesting = slashCount;
-                        }
-                    }
-                    context.wildcardWrappers = newWrappers;
-                }
-            } else if (path.startsWith("*.")) {
-                // Extension wrapper
-                String name = path.substring(2);
-                WrapperMapElement[] oldWrappers = context.extensionWrappers;
-                WrapperMapElement[] newWrappers =
-                    new WrapperMapElement[oldWrappers.length - 1];
-                if (removeMap(oldWrappers, newWrappers, name)) {
-                    context.extensionWrappers = newWrappers;
-                }
-            } else if (path.equals("/")) {
-                // Default wrapper
-                context.defaultWrapper = null;
-            } else {
-                // Exact wrapper
-                String name = path;
-                WrapperMapElement[] oldWrappers = context.exactWrappers;
-                WrapperMapElement[] newWrappers =
-                    new WrapperMapElement[oldWrappers.length - 1];
-                if (removeMap(oldWrappers, newWrappers, name)) {
-                    context.exactWrappers = newWrappers;
-                }
-            }
-        }
-    }
-
-    /**
-     * Map the specified URI relative to the context,
-     * mutating the given mapping data.
-     *
-     * @param uri URI
-     * @param mappingData This structure will contain the result of the mapping
-     *                    operation
-     */
-    public void map(MessageBytes uri, MappingData mappingData)
-        throws Exception {
-
-        uri.toChars();
-        CharChunk uricc = uri.getCharChunk();
-        //uricc.setLimit(-1);
-        internalMapWrapper(contextMapElement, uricc, mappingData);
-
-    }
-
-
-    // -------------------------------------------------------- Private Methods
-
-
-    /**
-     * Wrapper mapping.
-     */
-    private final void internalMapWrapper(ContextMapElement context,
-                                          CharChunk path,
-                                          MappingData mappingData)
-        throws Exception {
-
-        int pathOffset = path.getOffset();
-        int pathEnd = path.getEnd();
-        int servletPath = pathOffset;
-        boolean noServletPath = false;
-
-        int length = context.name.length();
-        if (length == 1) length--;
-        if (length != (pathEnd - pathOffset)) {
-            servletPath = pathOffset + length;
-        } else {
-            noServletPath = true;
-            // What is this doing ??? 
-            path.append('/');
-            pathOffset = path.getOffset();
-            pathEnd = path.getEnd();
-            servletPath = pathOffset+length;
-        }
-
-        path.setOffset(servletPath);
-
-        // Rule 1 -- Exact Match
-        WrapperMapElement[] exactWrappers = context.exactWrappers;
-        internalMapExactWrapper(exactWrappers, path, mappingData);
-
-        // Rule 2 -- Prefix Match
-        boolean checkJspWelcomeFiles = false;
-        WrapperMapElement[] wildcardWrappers = context.wildcardWrappers;
-        if (mappingData.wrapper == null) {
-            internalMapWildcardWrapper(wildcardWrappers, context.nesting, 
-                                       path, mappingData);
-            if (mappingData.wrapper != null && mappingData.jspWildCard) {
-                char[] buf = path.getBuffer();
-                if (buf[pathEnd - 1] == '/') {
-                    /*
-                     * Path ending in '/' was mapped to JSP servlet based on
-                     * wildcard match (e.g., as specified in url-pattern of a
-                     * jsp-property-group.
-                     * Force the context's welcome files, which are interpreted
-                     * as JSP files (since they match the url-pattern), to be
-                     * considered. See Bugzilla 27664.
-                     */ 
-                    mappingData.wrapper = null;
-                    checkJspWelcomeFiles = true;
-                } else {
-                    // See Bugzilla 27704
-                    mappingData.wrapperPath.setChars(buf, path.getStart(),
-                                                     path.getLength());
-                    mappingData.pathInfo.recycle();
-                }
-            }
-        }
-
-        if(mappingData.wrapper == null && noServletPath) {
-            // The path is empty, redirect to "/"
-            mappingData.redirectPath.setChars
-                (path.getBuffer(), pathOffset, pathEnd);
-            path.setEnd(pathEnd - 1);
-            return;
-        }
-
-        // Rule 3 -- Extension Match
-        WrapperMapElement[] extensionWrappers = context.extensionWrappers;
-        if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
-            internalMapExtensionWrapper(extensionWrappers, path, mappingData);
-        }
-
-        File file = null;
-        // Rule 4 -- Welcome resources processing for servlets
-        if (mappingData.wrapper == null) {
-            boolean checkWelcomeFiles = checkJspWelcomeFiles;
-            if (!checkWelcomeFiles) {
-                char[] buf = path.getBuffer();
-                checkWelcomeFiles = (buf[pathEnd - 1] == '/');
-            }
-            if (checkWelcomeFiles) {
-                for (int i = 0; (i < context.welcomeResources.length)
-                         && (mappingData.wrapper == null); i++) {
-                    path.setOffset(pathOffset);
-                    path.setEnd(pathEnd);
-                    path.append(context.welcomeResources[i], 0,
-                                context.welcomeResources[i].length());
-                    path.setOffset(servletPath);
-
-                    // Rule 4a -- Welcome resources processing for exact macth
-                    internalMapExactWrapper(exactWrappers, path, mappingData);
-
-                    // Rule 4b -- Welcome resources processing for prefix match
-                    if (mappingData.wrapper == null) {
-                        internalMapWildcardWrapper
-                            (wildcardWrappers, context.nesting, 
-                             path, mappingData);
-                    }
-
-                    // Rule 4c -- Welcome resources processing
-                    //            for physical folder
-                    if (mappingData.wrapper == null
-                        && context.resources != null) {
-                        // Default servlet: check if it's file or dir to apply
-                        // welcome files rules. 
-                        // TODO: Save the File in attributes, 
-                        // to avoid duplication in DefaultServlet.
-                        
-                        String pathStr = path.toString();
-                        file = new File(context.resources, pathStr);
-                        if (file.exists() && !(file.isDirectory()) ) {
-                            
-                            internalMapExtensionWrapper(extensionWrappers,
-                                                        path, mappingData);
-                            if (mappingData.wrapper == null
-                                && context.defaultWrapper != null) {
-                                mappingData.wrapper =
-                                    context.defaultWrapper.object;
-                                mappingData.requestPath.setChars
-                                    (path.getBuffer(), path.getStart(), 
-                                     path.getLength());
-                                mappingData.wrapperPath.setChars
-                                    (path.getBuffer(), path.getStart(), 
-                                     path.getLength());
-                                mappingData.requestPath.setString(pathStr);
-                                mappingData.wrapperPath.setString(pathStr);
-                            }
-                        }
-                    }
-                }
-
-                path.setOffset(servletPath);
-                path.setEnd(pathEnd);
-            }
-                                        
-        }
-
-
-        // Rule 7 -- Default servlet
-        if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
-            if (context.defaultWrapper != null) {
-                mappingData.wrapper = context.defaultWrapper.object;
-                mappingData.requestPath.setChars
-                    (path.getBuffer(), path.getStart(), path.getLength());
-                mappingData.wrapperPath.setChars
-                    (path.getBuffer(), path.getStart(), path.getLength());
-            }
-            // Redirection to a folder
-            char[] buf = path.getBuffer();
-            if (context.resources != null && buf[pathEnd -1 ] != '/') {
-                String pathStr = path.toString();
-                file = new File( context.resources, pathStr);
-                if (file.exists() && file.isDirectory()) {
-                    // Note: this mutates the path: do not do any processing 
-                    // after this (since we set the redirectPath, there 
-                    // shouldn't be any)
-                    path.setOffset(pathOffset);
-                    path.append('/');
-                    mappingData.redirectPath.setChars
-                        (path.getBuffer(), path.getStart(), path.getLength());
-                } else {
-                    mappingData.requestPath.setString(pathStr);
-                    mappingData.wrapperPath.setString(pathStr);
-                }
-            }
-        }
-
-        path.setOffset(pathOffset);
-        path.setEnd(pathEnd);
-    }
-
-
-    /**
-     * Exact mapping.
-     */
-    private final void internalMapExactWrapper
-        (WrapperMapElement[] wrappers, CharChunk path, MappingData mappingData) {
-        int pos = find(wrappers, path);
-        if ((pos != -1) && (path.equals(wrappers[pos].name))) {
-            mappingData.requestPath.setString(wrappers[pos].name);
-            mappingData.wrapperPath.setString(wrappers[pos].name);
-            mappingData.wrapper = wrappers[pos].object;
-        }
-    }
-
-
-    /**
-     * Wildcard mapping.
-     */
-    private final void internalMapWildcardWrapper
-        (WrapperMapElement[] wrappers, int nesting, CharChunk path, 
-         MappingData mappingData) {
-
-        int pathEnd = path.getEnd();
-        int pathOffset = path.getOffset();
-
-        int lastSlash = -1;
-        int length = -1;
-        int pos = find(wrappers, path);
-        if (pos != -1) {
-            boolean found = false;
-            while (pos >= 0) {
-                if (path.startsWith(wrappers[pos].name)) {
-                    length = wrappers[pos].name.length();
-                    if (path.getLength() == length) {
-                        found = true;
-                        break;
-                    } else if (path.startsWithIgnoreCase("/", length)) {
-                        found = true;
-                        break;
-                    }
-                }
-                if (lastSlash == -1) {
-                    lastSlash = nthSlash(path, nesting + 1);
-                } else {
-                    lastSlash = lastSlash(path);
-                }
-                path.setEnd(lastSlash);
-                pos = find(wrappers, path);
-            }
-            path.setEnd(pathEnd);
-            if (found) {
-                mappingData.wrapperPath.setString(wrappers[pos].name);
-                if (path.getLength() > length) {
-                    mappingData.pathInfo.setChars
-                        (path.getBuffer(),
-                         path.getOffset() + length,
-                         path.getLength() - length);
-                }
-                mappingData.requestPath.setChars
-                    (path.getBuffer(), path.getOffset(), path.getLength());
-                mappingData.wrapper = wrappers[pos].object;
-                mappingData.jspWildCard = wrappers[pos].jspWildCard;
-            }
-        }
-    }
-
-
-    /**
-     * Extension mappings.
-     */
-    private final void internalMapExtensionWrapper
-        (WrapperMapElement[] wrappers, CharChunk path, MappingData mappingData) {
-        char[] buf = path.getBuffer();
-        int pathEnd = path.getEnd();
-        int servletPath = path.getOffset();
-        int slash = -1;
-        for (int i = pathEnd - 1; i >= servletPath; i--) {
-            if (buf[i] == '/') {
-                slash = i;
-                break;
-            }
-        }
-        if (slash == -1 ) slash = 0;
-        if (slash >= 0) {
-            int period = -1;
-            for (int i = pathEnd - 1; i > slash; i--) {
-                if (buf[i] == '.') {
-                    period = i;
-                    break;
-                }
-            }
-            if (period >= 0) {
-                path.setOffset(period + 1);
-                path.setEnd(pathEnd);
-                int pos = find(wrappers, path);
-                if ((pos != -1)
-                    && (path.equals(wrappers[pos].name))) {
-                    mappingData.wrapperPath.setChars
-                        (buf, servletPath, pathEnd - servletPath);
-                    mappingData.requestPath.setChars
-                        (buf, servletPath, pathEnd - servletPath);
-                    mappingData.wrapper = wrappers[pos].object;
-                }
-                path.setOffset(servletPath);
-                path.setEnd(pathEnd);
-            }
-        }
-    }
-
-
-    /**
-     * Find a map elemnt given its name in a sorted array of map elements.
-     * This will return the index for the closest inferior or equal item in the
-     * given array.
-     */
-    public static final int find(MapElement[] map, CharChunk name) {
-        return find(map, name, name.getStart(), name.getEnd());
-    }
-
-
-    /**
-     * Find a map elemnt given its name in a sorted array of map elements.
-     * This will return the index for the closest inferior or equal item in the
-     * given array.
-     */
-    private static final int find(MapElement[] map, CharChunk name,
-                                  int start, int end) {
-
-        int a = 0;
-        int b = map.length - 1;
-
-        // Special cases: -1 and 0
-        if (b == -1) {
-            return -1;
-        }
-        
-        if (compare(name, start, end, map[0].name) < 0 ) {
-            return -1;
-        }         
-        if (b == 0) {
-            return 0;
-        }
-
-        int i = 0;
-        while (true) {
-            i = (b + a) / 2;
-            int result = compare(name, start, end, map[i].name);
-            if (result == 1) {
-                a = i;
-            } else if (result == 0) {
-                return i;
-            } else {
-                b = i;
-            }
-            if ((b - a) == 1) {
-                int result2 = compare(name, start, end, map[b].name);
-                if (result2 < 0) {
-                    return a;
-                } else {
-                    return b;
-                }
-            }
-        }
-
-    }
-
-    /**
-     * Find a map elemnt given its name in a sorted array of map elements.
-     * This will return the index for the closest inferior or equal item in the
-     * given array.
-     */
-    private static final int findIgnoreCase(MapElement[] map, CharChunk name) {
-        return findIgnoreCase(map, name, name.getStart(), name.getEnd());
-    }
-
-
-    /**
-     * Find a map elemnt given its name in a sorted array of map elements.
-     * This will return the index for the closest inferior or equal item in the
-     * given array.
-     */
-    private static final int findIgnoreCase(MapElement[] map, CharChunk name,
-                                  int start, int end) {
-
-        int a = 0;
-        int b = map.length - 1;
-
-        // Special cases: -1 and 0
-        if (b == -1) {
-            return -1;
-        }
-        if (compareIgnoreCase(name, start, end, map[0].name) < 0 ) {
-            return -1;
-        }         
-        if (b == 0) {
-            return 0;
-        }
-
-        int i = 0;
-        while (true) {
-            i = (b + a) / 2;
-            int result = compareIgnoreCase(name, start, end, map[i].name);
-            if (result == 1) {
-                a = i;
-            } else if (result == 0) {
-                return i;
-            } else {
-                b = i;
-            }
-            if ((b - a) == 1) {
-                int result2 = compareIgnoreCase(name, start, end, map[b].name);
-                if (result2 < 0) {
-                    return a;
-                } else {
-                    return b;
-                }
-            }
-        }
-
-    }
-
-
-    /**
-     * Find a map elemnt given its name in a sorted array of map elements.
-     * This will return the index for the closest inferior or equal item in the
-     * given array.
-     */
-    public static final int find(MapElement[] map, String name) {
-
-        int a = 0;
-        int b = map.length - 1;
-
-        // Special cases: -1 and 0
-        if (b == -1) {
-            return -1;
-        }
-        
-        if (name.compareTo(map[0].name) < 0) {
-            return -1;
-        } 
-        if (b == 0) {
-            return 0;
-        }
-
-        int i = 0;
-        while (true) {
-            i = (b + a) / 2;
-            int result = name.compareTo(map[i].name);
-            if (result > 0) {
-                a = i;
-            } else if (result == 0) {
-                return i;
-            } else {
-                b = i;
-            }
-            if ((b - a) == 1) {
-                int result2 = name.compareTo(map[b].name);
-                if (result2 < 0) {
-                    return a;
-                } else {
-                    return b;
-                }
-            }
-        }
-
-    }
-
-
-    /**
-     * Compare given char chunk with String.
-     * Return -1, 0 or +1 if inferior, equal, or superior to the String.
-     */
-    private static final int compare(CharChunk name, int start, int end,
-                                     String compareTo) {
-        int result = 0;
-        char[] c = name.getBuffer();
-        int len = compareTo.length();
-        if ((end - start) < len) {
-            len = end - start;
-        }
-        for (int i = 0; (i < len) && (result == 0); i++) {
-            if (c[i + start] > compareTo.charAt(i)) {
-                result = 1;
-            } else if (c[i + start] < compareTo.charAt(i)) {
-                result = -1;
-            }
-        }
-        if (result == 0) {
-            if (compareTo.length() > (end - start)) {
-                result = -1;
-            } else if (compareTo.length() < (end - start)) {
-                result = 1;
-            }
-        }
-        return result;
-    }
-
-
-    /**
-     * Compare given char chunk with String ignoring case.
-     * Return -1, 0 or +1 if inferior, equal, or superior to the String.
-     */
-    private static final int compareIgnoreCase(CharChunk name, int start, int end,
-                                     String compareTo) {
-        int result = 0;
-        char[] c = name.getBuffer();
-        int len = compareTo.length();
-        if ((end - start) < len) {
-            len = end - start;
-        }
-        for (int i = 0; (i < len) && (result == 0); i++) {
-            if (Ascii.toLower(c[i + start]) > Ascii.toLower(compareTo.charAt(i))) {
-                result = 1;
-            } else if (Ascii.toLower(c[i + start]) < Ascii.toLower(compareTo.charAt(i))) {
-                result = -1;
-            }
-        }
-        if (result == 0) {
-            if (compareTo.length() > (end - start)) {
-                result = -1;
-            } else if (compareTo.length() < (end - start)) {
-                result = 1;
-            }
-        }
-        return result;
-    }
-
-
-    /**
-     * Find the position of the last slash in the given char chunk.
-     */
-    public static final int lastSlash(CharChunk name) {
-
-        char[] c = name.getBuffer();
-        int end = name.getEnd();
-        int start = name.getStart();
-        int pos = end;
-
-        while (pos > start) {
-            if (c[--pos] == '/') {
-                break;
-            }
-        }
-
-        return (pos);
-
-    }
-
-
-    /**
-     * Find the position of the nth slash, in the given char chunk.
-     */
-    public static final int nthSlash(CharChunk name, int n) {
-
-        char[] c = name.getBuffer();
-        int end = name.getEnd();
-        int start = name.getStart();
-        int pos = start;
-        int count = 0;
-
-        while (pos < end) {
-            if ((c[pos++] == '/') && ((++count) == n)) {
-                pos--;
-                break;
-            }
-        }
-
-        return (pos);
-
-    }
-
-
-    /**
-     * Return the slash count in a given string.
-     */
-    public static final int slashCount(String name) {
-        int pos = -1;
-        int count = 0;
-        while ((pos = name.indexOf('/', pos + 1)) != -1) {
-            count++;
-        }
-        return count;
-    }
-
-
-    /**
-     * Insert into the right place in a sorted MapElement array, and prevent
-     * duplicates.
-     */
-    public static final boolean insertMap
-        (MapElement[] oldMap, MapElement[] newMap, MapElement newElement) {
-        int pos = find(oldMap, newElement.name);
-        if ((pos != -1) && (newElement.name.equals(oldMap[pos].name))) {
-            return false;
-        }
-        System.arraycopy(oldMap, 0, newMap, 0, pos + 1);
-        newMap[pos + 1] = newElement;
-        System.arraycopy
-            (oldMap, pos + 1, newMap, pos + 2, oldMap.length - pos - 1);
-        return true;
-    }
-
-
-    /**
-     * Insert into the right place in a sorted MapElement array.
-     */
-    public static final boolean removeMap
-        (MapElement[] oldMap, MapElement[] newMap, String name) {
-        int pos = find(oldMap, name);
-        if ((pos != -1) && (name.equals(oldMap[pos].name))) {
-            System.arraycopy(oldMap, 0, newMap, 0, pos);
-            System.arraycopy(oldMap, pos + 1, newMap, pos,
-                             oldMap.length - pos - 1);
-            return true;
-        }
-        return false;
-    }
-
-
-    // ------------------------------------------------- MapElement Inner Class
-
-
-    protected static abstract class MapElement {
-        /** hostname or path  
-         */
-        public String name = null;
-        public Object object = null;
-
-        public String toString() {
-            return "MapElement: \"" + name +"\"";
-        }
-    }
-
-
-    // ---------------------------------------------------- Context Inner Class
-
-
-    public static final class ContextMapElement
-        extends MapElement {
-
-        public String[] welcomeResources = new String[0];
-        public File resources = null;
-        public WrapperMapElement defaultWrapper = null;
-        public WrapperMapElement[] exactWrappers = new WrapperMapElement[0];
-        public WrapperMapElement[] wildcardWrappers = new WrapperMapElement[0];
-        public WrapperMapElement[] extensionWrappers = new WrapperMapElement[0];
-        public int nesting = 0;
-
-        public String toString() {
-            return "ContextMapElement {" +
-            "name: \"" + name +
-            "\"\nnesting: \"" + nesting +
-            "\"\n}";
-        }
-    }
-
-
-    // ---------------------------------------------------- Wrapper Inner Class
-
-
-    public static class WrapperMapElement
-        extends MapElement {
-        public boolean jspWildCard = false;
-    }
-
-
-    public void destroy() {
-    }
-
-
-    public void doFilter(ServletRequest request, ServletResponse response,
-                         FilterChain chain) throws IOException,
-        ServletException {
-    }
-
-
-    public void init(FilterConfig filterConfig) throws ServletException {
-    }
-
-   
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/config.properties b/modules/tomcat-lite/java/org/apache/tomcat/lite/config.properties
deleted file mode 100644 (file)
index c1ef53d..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-# Support for PropertiesSpi - the 'dummy' framework used for tomcat-lite
-# If tomcat is used with a proper framework, you need to bind and configure 
-# those objects in the framework. 
-
-Main.(class)=org.apache.tomcat.lite.TomcatLite
-
-Jmx.(class)=org.apache.tomcat.integration.jmx.JmxObjectManagerSpi
-
-# --- Class names for required plugin interfaces --- 
-
-org.apache.tomcat.lite.WebappServletMapper.(class)=org.apache.tomcat.lite.WebappServletMapper
-org.apache.tomcat.lite.WebappFilterMapper.(class)=org.apache.tomcat.lite.WebappFilterMapper
-
-# Sessions
-org.apache.tomcat.addons.UserSessionManager.(class)=org.apache.tomcat.servlets.session.SimpleSessionManager
-
-# *.jsp support
-org.apache.tomcat.addons.UserTemplateClassMapper.(class)=org.apache.tomcat.servlets.jsp.JasperCompilerTemplateClassMapper
-
-org.apache.tomcat.addons.Filesystem.(class)=org.apache.tomcat.integration.simple.LocalFilesystem
-
-# Loader for web.xml - you can have your own custom class using a more efficient
-# or hardcoded.
-org.apache.tomcat.lite.ContextPreinitListener.(class)=org.apache.tomcat.lite.webxml.TomcatLiteWebXmlConfig
-
-# Connector class
-org.apache.tomcat.lite.Connector.(class)=org.apache.tomcat.lite.coyote.CoyoteConnector
-
-# JMX 
-jmx-connector.(class)=org.apache.tomcat.integration.jmx.JmxObjectManagerSpi
-
-# --- Other required settings ---
-
-# Customize default and *.jsp mappings
-default-servlet.(class)=org.apache.tomcat.servlets.file.WebdavServlet
-jspwildcard-servlet.(class)=org.apache.tomcat.servlets.jsp.WildcardTemplateServlet
-filetemplate-servlet.(class)=org.apache.tomcat.servlets.jsp.JspFileTemplateServlet
-
-
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/CoyoteConnector.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/coyote/CoyoteConnector.java
deleted file mode 100644 (file)
index 1a69269..0000000
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You 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.apache.tomcat.lite.coyote;
-
-import java.io.IOException;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.coyote.ActionCode;
-import org.apache.coyote.ActionHook;
-import org.apache.coyote.Adapter;
-import org.apache.coyote.ProtocolHandler;
-import org.apache.coyote.Request;
-import org.apache.coyote.Response;
-import org.apache.coyote.http11.Http11NioProtocol;
-import org.apache.tomcat.integration.ObjectManager;
-import org.apache.tomcat.lite.BodyReader;
-import org.apache.tomcat.lite.BodyWriter;
-import org.apache.tomcat.lite.ClientAbortException;
-import org.apache.tomcat.lite.Connector;
-import org.apache.tomcat.lite.ServletRequestImpl;
-import org.apache.tomcat.lite.ServletResponseImpl;
-import org.apache.tomcat.lite.TomcatLite;
-import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.buf.UriNormalizer;
-import org.apache.tomcat.util.http.HttpRequest;
-import org.apache.tomcat.util.http.HttpResponse;
-import org.apache.tomcat.util.net.SocketStatus;
-
-public class CoyoteConnector implements Adapter, Connector {
-
-    private TomcatLite lite;
-
-    public CoyoteConnector() {
-    }
-
-
-
-    public void acknowledge(HttpServletResponse res) throws IOException {
-        Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse;
-        cres.acknowledge();
-    }
-
-    public void reset(HttpServletResponse res) {
-        Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse;
-        cres.reset();
-    }
-
-    public void recycle(HttpServletRequest req, HttpServletResponse res) {
-
-    }
-
-    public static HttpResponse getResponse(final Response cres) {
-        HttpResponse hres = new HttpResponse() {
-            public int getStatus() {
-                return cres.getStatus();
-            }
-            public void setStatus(int i) {
-                super.setStatus(i);
-                cres.setStatus(i);
-            }
-            public void setMessage(String s) {
-                super.setMessage(s);
-                cres.setMessage(s);
-            }
-            public String getMessage() {
-                return cres.getMessage();
-            }
-            public boolean isCommitted() {
-                return cres.isCommitted();
-            }
-
-            public void setCommitted(boolean b) {
-                cres.setCommitted(b);
-            }
-        };
-
-        hres.setMimeHeaders(cres.getMimeHeaders());
-        hres.nativeResponse = cres;
-
-        return hres;
-    }
-
-    public static HttpRequest getRequest(Request req) {
-
-        HttpRequest httpReq = new HttpRequest(req.scheme(),
-                req.method(),
-                req.unparsedURI(),
-                req.protocol(),
-                req.getMimeHeaders(),
-                req.requestURI(),
-                req.decodedURI(),
-                req.query(), req.getParameters(),
-                req.serverName(),
-                req.getCookies()) {
-
-        };
-        httpReq.nativeRequest = req;
-
-        // TODO: anything else computed in coyote ?
-
-        return httpReq;
-    }
-
-    @Override
-    public void initRequest(HttpServletRequest hreq, HttpServletResponse hres) {
-        ServletRequestImpl req = (ServletRequestImpl) hreq;
-        ServletResponseImpl res = (ServletResponseImpl) hres;
-        req.setConnector(this);
-
-        Request creq = new Request();
-        Response cres = new Response();
-        HttpResponse nRes = getResponse(cres);
-
-        BodyWriter out = new BodyWriter(4096);
-        out.setConnector(this, res);
-
-        res.setHttpResponse(nRes, out);
-
-        cres.setRequest(creq);
-        cres.setHook(new ActionHook() {
-          public void action(ActionCode actionCode,
-                             Object param) {
-          }
-        });
-
-        BodyReader in = new BodyReader();
-        in.setConnector(this, req);
-        HttpRequest nReq = getRequest(creq);
-        req.setHttpRequest(nReq, in);
-
-    }
-
-
-    // ---- Coyote Adapter interface ---
-
-    @Override
-    public void service(Request creq, Response cres) throws Exception {
-        long t0 = System.currentTimeMillis();
-
-        // compute decodedURI - not done by connector
-        UriNormalizer.decodeRequest(creq.decodedURI(), creq.requestURI(), creq.getURLDecoder());
-
-        // find the facades
-        ServletRequestImpl req = (ServletRequestImpl) creq.getNote(ADAPTER_REQ_NOTE);
-        ServletResponseImpl res = (ServletResponseImpl) cres.getNote(ADAPTER_RES_NOTE);
-
-
-        if (req == null) {
-          req = new ServletRequestImpl();
-          res = req.getResponse();
-
-          BodyReader in = new BodyReader();
-          in.setConnector(this, req);
-
-          HttpRequest nReq = getRequest(creq);
-          nReq.setServerPort(creq.getServerPort());
-          HttpResponse nRes = getResponse(cres);
-
-          req.setHttpRequest(nReq, in);
-          BodyWriter out = new BodyWriter(4096);
-          out.setConnector(this, res);
-
-          res.setHttpResponse(nRes, out);
-
-          creq.setNote(ADAPTER_REQ_NOTE, req);
-          cres.setNote(ADAPTER_RES_NOTE, res);
-
-        }
-        req.setConnector(this);
-
-        try {
-            lite.service(req, res);
-        } catch(IOException ex) {
-            throw ex;
-        } catch( Throwable t ) {
-            t.printStackTrace();
-        } finally {
-            long t1 = System.currentTimeMillis();
-
-//            log.info("<<<<<<<< DONE: " + creq.method() + " " +
-//                    creq.decodedURI() + " " +
-//                    res.getStatus() + " " +
-//                    (t1 - t0));
-
-            // Final processing
-            // TODO: only if not commet, this doesn't work with the
-            // other connectors since we don't have the info
-            // TODO: add this note in the nio/apr connectors
-            // TODO: play nice with TomcatLite, other adapters that flush/close
-            if (cres.getNote(COMET_RES_NOTE) == null) {
-
-                if (!res.isCommitted()) {
-                    cres.sendHeaders();
-                }
-                res.getOutputBuffer().flush();
-
-                BodyWriter mw = res.getBodyWriter();
-                //MessageWriter.getWriter(creq, cres, 0);
-                mw.flush();
-                mw.recycle();
-
-                BodyReader reader = req.getBodyReader();
-                //getReader(creq);
-                reader.recycle();
-
-                cres.finish();
-
-                creq.recycle();
-                cres.recycle();
-
-                req.recycle();
-                res.recycle();
-            }
-        }
-    }
-
-    @Override
-    public boolean event(Request req, Response res, SocketStatus status)
-        throws Exception {
-      return false;
-    }
-
-
-    public void setTomcatLite(TomcatLite lite) {
-        this.lite = lite;
-    }
-
-
-    public String getRemoteHost(HttpServletRequest hreq) {
-        ServletRequestImpl req = (ServletRequestImpl) hreq;
-
-        Request creq = (Request) req.getHttpRequest().nativeRequest;
-        creq.action(ActionCode.ACTION_REQ_HOST_ATTRIBUTE, creq);
-        return creq.remoteHost().toString();
-    }
-
-    public String getRemoteAddr(HttpServletRequest hreq) {
-        ServletRequestImpl req = (ServletRequestImpl) hreq;
-
-        Request creq = (Request) req.getHttpRequest().nativeRequest;
-        creq.action(ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE, creq);
-        return creq.remoteAddr().toString();
-    }
-
-
-    @Override
-    public void beforeClose(HttpServletResponse res, int len) throws IOException {
-        Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse;
-
-        if ((!cres.isCommitted())
-                && (cres.getContentLengthLong() == -1)) {
-                // Flushing the char buffer
-                // If this didn't cause a commit of the response, the final content
-                // length can be calculated
-                if (!cres.isCommitted()) {
-                    cres.setContentLength(len);
-                }
-            }
-    }
-
-    public int doRead(ServletRequestImpl hreq, ByteChunk bb) throws IOException {
-        ServletRequestImpl req = (ServletRequestImpl) hreq;
-
-        Request creq = (Request) req.getHttpRequest().nativeRequest;
-        return creq.doRead(bb);
-    }
-
-    @Override
-    public void doWrite(HttpServletResponse res, ByteChunk chunk)
-            throws IOException {
-        Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse;
-        cres.doWrite(chunk);
-
-    }
-
-
-    @Override
-    public void realFlush(HttpServletResponse res) throws IOException {
-        Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse;
-        cres.action(ActionCode.ACTION_CLIENT_FLUSH,
-                cres);
-        // If some exception occurred earlier, or if some IOE occurred
-        // here, notify the servlet with an IOE
-        if (cres.isExceptionPresent()) {
-            throw new ClientAbortException
-            (cres.getErrorException());
-        }
-
-    }
-
-
-    @Override
-    public void sendHeaders(HttpServletResponse res) throws IOException {
-        Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse;
-
-        // This should happen before 'prepareResponse' is called !!
-        // Now update coyote response based on response
-        // don't set charset/locale - they're computed in lite
-        cres.setContentType(res.getContentType());
-        cres.sendHeaders();
-    }
-
-    @Override
-    public void finishResponse(HttpServletResponse res) throws IOException {
-        Response cres = (Response) ((ServletResponseImpl) res).getHttpResponse().nativeResponse;
-        cres.finish();
-    }
-
-    protected int port = 8800;
-    protected boolean daemon = false;
-
-    /**
-     * Note indicating the response is COMET.
-     */
-    public static final int COMET_RES_NOTE = 2;
-    public static final int COMET_REQ_NOTE = 2;
-
-    public static final int ADAPTER_RES_NOTE = 1;
-    public static final int ADAPTER_REQ_NOTE = 1;
-
-    protected ProtocolHandler proto;
-
-    //protected Adapter adapter = new MapperAdapter();
-    protected int maxThreads = 20;
-    boolean started = false;
-    boolean async = false; // use old nio connector
-
-    protected ObjectManager om;
-
-
-    public void setObjectManager(ObjectManager om) {
-        this.om = om;
-    }
-
-    /**
-     * Add an adapter. If more than the 'default' adapter is
-     * added, a MapperAdapter will be inserted.
-     *
-     * @param path Use "/" for the default.
-     * @param adapter
-     */
-//    public void addAdapter(String path, Adapter added) {
-//        if ("/".equals(path)) {
-//            ((MapperAdapter) adapter).setDefaultAdapter(added);
-//        } else {
-//            ((MapperAdapter) adapter).getMapper().addWrapper(path, added);
-//        }
-//    }
-
-    /**
-     */
-    public void run() {
-        try {
-            init();
-            start();
-        } catch(IOException ex) {
-            ex.printStackTrace();
-        }
-    }
-
-    public void setDaemon(boolean b) {
-      daemon = b;
-    }
-
-    protected void initAdapters() {
-        if (proto == null) {
-            addProtocolHandler(port, daemon);
-        }
-      // adapter = ...
-      // Adapter secondaryadapter = ...
-      //registry.registerComponent(secondaryadapter, ":name=adapter", null);
-    }
-
-    public void stop() throws Exception {
-      if (!started) {
-        return;
-      }
-      proto.destroy();
-      started = false;
-    }
-
-//    /**
-//     *  Simple CLI support - arg is a path:className pair.
-//     */
-//    public void setAdapter(String arg)  {
-//      String[] pathClass = arg.split(":", 2);
-//      try {
-//        Class c = Class.forName(pathClass[1]);
-//        Adapter a = (Adapter) c.newInstance();
-//        addAdapter(pathClass[0],a);
-//      } catch (Throwable e) {
-//        e.printStackTrace();
-//      }
-//    }
-
-    public void setConnector(ProtocolHandler h) {
-        this.proto = h;
-        h.setAttribute("port", Integer.toString(port));
-
-        om.bind("ProtocolHandler:" + "ep-" + port, proto);
-    }
-
-    public void addProtocolHandler(int port, boolean daemon) {
-        Http11NioProtocol proto = new Http11NioProtocol();
-        proto.setCompression("on");
-        proto.setCompressionMinSize(32);
-        proto.setPort(port);
-        proto.getEndpoint().setDaemon(daemon);
-        setConnector(proto);
-        setPort(port);
-        setDaemon(daemon);
-    }
-
-    public void addProtocolHandler(ProtocolHandler proto,
-                                   int port, boolean daemon) {
-        setConnector(proto);
-        setPort(port);
-        setDaemon(daemon);
-    }
-
-    public void setPort(int port) {
-        if (proto != null) {
-            proto.setAttribute("port", Integer.toString(port));
-        }
-        this.port = port;
-      }
-
-
-    public void init() {
-        //JdkLoggerConfig.loadCustom();
-        om.bind("CoyoteConnector:" + "CoyoteConnector-" + port,
-                this);
-    }
-
-
-    public void start() throws IOException {
-      try {
-        if (started) {
-          return;
-        }
-        init();
-        initAdapters();
-
-        // not required - should run fine without a connector.
-        if (proto != null) {
-            proto.setAdapter(this);
-
-            proto.init();
-            proto.start();
-        }
-
-        started = true;
-      } catch (Throwable e) {
-        e.printStackTrace();
-        throw new RuntimeException(e);
-      }
-    }
-
-    public boolean getStarted() {
-      return started;
-    }
-
-    public boolean asyncDispatch(Request req,Response res, SocketStatus status) throws Exception {
-        // implement me
-        return false;
-    }
-
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/service/IOStatus.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/service/IOStatus.java
new file mode 100644 (file)
index 0000000..fee4d18
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ */
+package org.apache.tomcat.lite.service;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.tomcat.lite.http.HttpRequest;
+import org.apache.tomcat.lite.http.HttpResponse;
+import org.apache.tomcat.lite.http.HttpWriter;
+import org.apache.tomcat.lite.http.HttpChannel.HttpService;
+import org.apache.tomcat.lite.http.HttpConnector.ConnectionPool;
+import org.apache.tomcat.lite.http.HttpConnector.RemoteServer;
+import org.apache.tomcat.lite.io.IOChannel;
+
+/**
+ * Dump status of a connection pool.
+ */
+public class IOStatus implements HttpService {
+
+    private ConnectionPool pool;
+
+    public IOStatus() {
+        
+    }
+    
+    public IOStatus(ConnectionPool pool) {
+        this.pool = pool;
+    }
+    
+    @Override
+    public void service(HttpRequest httpReq, HttpResponse httpRes)
+            throws IOException {
+        ConnectionPool sc = pool == null ? 
+                httpReq.getHttpChannel().getConnector().cpool :
+                    pool;
+        HttpWriter out = httpRes.getBodyWriter();
+        
+        httpRes.setContentType("text/plain");
+        out.println("hosts=" + sc.getTargetCount());
+        out.println("waiting=" + sc.getSocketCount());
+        out.println("closed=" + sc.getClosedSockets());
+        out.println();
+
+        for (Map.Entry<CharSequence, RemoteServer> e: sc.hosts.entrySet()) {
+            out.append(e.getKey());
+            out.append("=");
+            out.println(Integer.toString(e.getValue().connections.size()));
+
+            for (IOChannel ch: e.getValue().connections) {
+                out.println(ch.getId() + 
+                        " " + ch.toString());
+            }
+            out.println();
+        }
+
+    }
+
+}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/service/JMXProxy.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/service/JMXProxy.java
new file mode 100644 (file)
index 0000000..284ee25
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.tomcat.lite.service;
+
+
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import org.apache.tomcat.integration.DynamicObject;
+import org.apache.tomcat.integration.ObjectManager;
+
+/**
+ * Send all registered JMX objects and properties as JSON.
+ * 
+ * Based on JMXProxy servlet, but:
+ * - Async handler instead of servlet - so it works with 'raw' connector
+ * - doesn't use JMX - integrates with the ObjectManager ( assuming OM 
+ * provies a list of managed objects )
+ * - all the reflection magic from modeler is implemented here.
+ *
+ * @author Costin Manolache
+ */
+public class JMXProxy extends ObjectManager implements Runnable  {
+
+    static Logger log = Logger.getLogger(JMXProxy.class.getName());
+    
+    protected ObjectManager om;
+    
+    Map<Class, DynamicObject> types = new HashMap<Class, DynamicObject>();
+    
+    Map<String, Object> objects = new HashMap();
+    
+    
+    public void bind(String name, Object o) {
+        objects.put(name, o);
+    }
+
+    public void unbind(String name) {
+        objects.remove(name);
+    }
+
+    
+    public void setObjectManager(ObjectManager om) {
+        this.om = om;
+    }
+    
+    
+    private DynamicObject getClassInfo(Class beanClass) {
+        if (types.get(beanClass) != null) {
+            return types.get(beanClass);
+        }
+        DynamicObject res = new DynamicObject(beanClass);
+        types.put(beanClass, res);
+        return res;
+    }
+
+    
+    // --------------------------------------------------------- Public Methods
+
+    public void getAttribute(PrintWriter writer, String onameStr, String att) {
+        try {
+            
+            Object bean = objects.get(onameStr);
+            Class beanClass = bean.getClass();
+            DynamicObject ci = getClassInfo(beanClass);
+            
+            Object value = ci.getAttribute(bean, att);
+            writer.println("OK - Attribute get '" + onameStr + "' - " + att
+                    + "= " + escape(value.toString()));
+        } catch (Exception ex) {
+            writer.println("Error - " + ex.toString());
+        }
+    }
+
+
+    public void setAttribute( PrintWriter writer,
+                              String onameStr, String att, String val )
+    {
+        try {
+            Object bean = objects.get(onameStr);
+            Class beanClass = bean.getClass();
+            DynamicObject ci = getClassInfo(beanClass);
+
+            ci.setProperty(bean, att, val);
+            writer.println("OK - Attribute set");
+        } catch( Exception ex ) {
+            writer.println("Error - " + ex.toString());
+        }
+    }
+
+    public void listBeans( PrintWriter writer, String qry, boolean json )
+    {
+        if (json) {
+            listBeansJson(writer, qry);
+            return;
+        }
+        Set<String> names = objects.keySet();
+        writer.println("OK - Number of results: " + names.size());
+        writer.println();
+        
+        Iterator<String> it=names.iterator();
+        while( it.hasNext()) {
+            String oname=it.next();
+            writer.println( "Name: " + oname);
+
+            try {
+                Object bean = objects.get(oname);
+                Class beanClass = bean.getClass();
+                DynamicObject ci = getClassInfo(beanClass);
+                writer.println("modelerType: " + beanClass.getName());
+
+                Object value=null;
+                for (String attName: ci.attributeNames()) {
+                    try {
+                        value = ci.getAttribute(bean, attName);
+                    } catch( Throwable t) {
+                        System.err.println("Error getting attribute " + oname +
+                            " " + attName + " " + t.toString());
+                        continue;
+                    }
+                    if( value==null ) continue;
+                    String valueString=value.toString();
+                    writer.println( attName + ": " + escape(valueString));
+                }
+            } catch (Exception e) {
+                // Ignore
+            }
+            writer.println();
+        }
+
+    }
+
+    private static void json(PrintWriter writer, String name, String value) {
+        writer.write("\"" + name +"\":" + "\"" + escapeJson(value) + "\",");
+    }
+    
+   private void listBeansJson(PrintWriter writer, String qry) {
+       Set<String> names = objects.keySet();
+       writer.println("[");
+       
+       Iterator<String> it=names.iterator();
+       while( it.hasNext()) {
+           writer.print("{");
+           String oname=it.next();
+           json(writer, "name", oname);
+
+           try {
+               Object bean = objects.get(oname);
+               Class beanClass = bean.getClass();
+               DynamicObject ci = getClassInfo(beanClass);
+               json(writer, "modelerType", beanClass.getName());
+
+               Object value=null;
+               for (String attName: ci.attributeNames()) {
+                   try {
+                       value = ci.getAttribute(bean, attName);
+                   } catch( Throwable t) {
+                       System.err.println("Error getting attribute " + oname +
+                           " " + attName + " " + t.toString());
+                       continue;
+                   }
+                   if( value==null ) continue;
+                   String valueString=value.toString();
+                   json(writer, attName, valueString);
+               }
+               writer.println("}");
+           } catch (Exception e) {
+               // Ignore
+           }
+       }
+       writer.println("]");
+   }
+   
+   public static String escapeJson(String value) {
+       return value;
+   }
+
+   public static String escape(String value) {
+        // The only invalid char is \n
+        // We also need to keep the string short and split it with \nSPACE
+        // XXX TODO
+        int idx=value.indexOf( "\n" );
+        if( idx < 0 ) return value;
+
+        int prev=0;
+        StringBuffer sb=new StringBuffer();
+        while( idx >= 0 ) {
+            appendHead(sb, value, prev, idx);
+
+            sb.append( "\\n\n ");
+            prev=idx+1;
+            if( idx==value.length() -1 ) break;
+            idx=value.indexOf('\n', idx+1);
+        }
+        if( prev < value.length() )
+            appendHead( sb, value, prev, value.length());
+        return sb.toString();
+    }
+
+    private static void appendHead( StringBuffer sb, String value, int start, int end) {
+        if (end < 1) return;
+
+        int pos=start;
+        while( end-pos > 78 ) {
+            sb.append( value.substring(pos, pos+78));
+            sb.append( "\n ");
+            pos=pos+78;
+        }
+        sb.append( value.substring(pos,end));
+    }
+
+    public boolean isSupported( String type ) {
+        return true;
+    }
+
+    @Override
+    public void run() {
+        
+    }
+}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/service/LogConfig.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/service/LogConfig.java
new file mode 100644 (file)
index 0000000..bbb5224
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ * Copyright 2004 Costin Manolache
+ * 
+ * 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.apache.tomcat.lite.service;
+
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.tomcat.lite.http.HttpRequest;
+import org.apache.tomcat.lite.http.HttpResponse;
+import org.apache.tomcat.lite.http.HttpChannel.HttpService;
+
+/**
+ * Log configuration
+ * 
+ */
+public class LogConfig implements HttpService {
+    
+    /**
+     * Framework can set this attribute with comma separated
+     * list of loggers to set to debug level.
+     * This is used at startup. 
+     */
+    public void setDebug(String debug) {
+        for (String log : debug.split(",")) {
+            Logger logger = Logger.getLogger(log);
+            logger.setLevel(Level.INFO);
+        }
+    }
+
+    /**
+     * 
+     */
+    public void setWarn(String nodebug) {
+        for (String log : nodebug.split(",")) {
+            Logger logger = Logger.getLogger(log);
+            logger.setLevel(Level.WARNING);
+        }
+    }
+
+    @Override
+    public void service(HttpRequest httpReq, HttpResponse httpRes)
+            throws IOException {
+        String debug = httpReq.getParameter("debug");
+        setDebug(debug);
+        String warn = httpReq.getParameter("warn");
+        setWarn(warn);
+    }
+}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/ServletContextConfig.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/ServletContextConfig.java
deleted file mode 100644 (file)
index 59dbd62..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You 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.apache.tomcat.lite.webxml;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-/**
- * All the data in web.xml, annotations, etc should be represented 
- * here. This class is serializable.
- * 
- * Public fields to make it easy to access it. 
- * Naming should match the web.xml element name.
- * 
- * @author Costin Manolache
- */
-public class ServletContextConfig  implements Serializable {
-    
-    private static final long serialVersionUID = 1728492145981883124L;
-    
-    public String fileName;
-    public long timestamp;
-
-    public boolean full;
-    
-    public String displayName;
-
-    public HashMap<String, String> contextParam = new HashMap<String, String>();
-    
-    public HashMap<String, String> mimeMapping = new HashMap<String, String>(); // extension -> mime-type
-    
-    public ArrayList<String> listenerClass = new ArrayList<String>();
-    
-    public ArrayList<String> welcomeFileList = new ArrayList<String>();
-    
-    // code -> location 
-    public HashMap<String, String> errorPageCode= new HashMap<String, String>(); 
-    
-    // exception -> location
-    public HashMap<String, String> errorPageException= new HashMap<String, String>(); 
-
-    public HashMap<String, String> localeEncodingMapping= new HashMap<String, String>(); // locale -> encoding
-    
-    // public HashMap tagLibs; // uri->location
-    // jsp-property-group
-
-    // securityConstraint
-    public ArrayList<SecurityConstraintData> securityConstraint = new ArrayList<SecurityConstraintData>();
-    
-    // loginConfig
-    public String authMethod;
-    public String realmName;
-    public String formLoginPage;
-    public String formErrorPage;
-    
-    public ArrayList<String> securityRole = new ArrayList<String>();
-    
-    // envEntry
-    public ArrayList<EnvEntryData> envEntry = new ArrayList<EnvEntryData>();
-    
-    // ejbRef
-    // ejbLocalRef
-    // serviceRef
-    // resourceRef
-    // resourceEnvRef
-    // message-destination
-    // message-destinationRef
-    public HashMap<String, FilterData> filters = new HashMap<String, FilterData>();
-    public HashMap<String, ServletData> servlets = new HashMap<String, ServletData>();
-
-    public int sessionTimeout;
-    public boolean distributable;
-    
-    public HashMap<String, String> servletMapping = new HashMap<String, String>(); // url -> servlet
-    public ArrayList<FilterMappingData> filterMappings = new ArrayList<FilterMappingData>();
-    
-
-    public static class FilterData implements Serializable {
-        private static final long serialVersionUID = -535820271746973166L;
-
-        public HashMap<String, String> initParams = new HashMap<String, String>();
-        public String filterClass;
-        public String filterName;
-    }
-    
-    // Normalized
-    public static class FilterMappingData implements Serializable {
-        private static final long serialVersionUID = -4533568066713041994L;
-        public String filterName;
-        
-        // Only one of the 2
-        public String urlPattern;
-        public String servletName;
-        
-        // REQUEST, FORWARD, INCLUDE, ERROR, ASYNC
-        public ArrayList<String> dispatcher = new ArrayList<String>();
-    }
-    
-    public static class EnvEntryData  implements Serializable {
-        private static final long serialVersionUID = 7023847615343715257L;
-        public String envEntryName;
-        public String envEntryType;
-        public String envEntryValue;
-    }
-    
-    public static class ServletData implements Serializable {
-        private static final long serialVersionUID = -3216904178501185930L;
-
-        public ServletData() {
-        }
-        public ServletData(String servletName, String servletClass) {
-            this.servletClass = servletClass;
-            this.servletName = servletName;
-        }
-
-        public HashMap<String, String> initParams = new HashMap<String, String>();
-        public String servletName;
-        public String servletClass;
-        public String jspFile;
-        public int loadOnStartup = -1;
-        public String runAs;
-        public HashMap<String, String> securityRoleRef = new HashMap<String, String>(); // roleName -> [roleLink]
-        
-    }
-    
-    public static class WebResourceCollectionData implements Serializable {
-        public String webResourceName;
-        public ArrayList urlPattern = new ArrayList();
-        public ArrayList httpMethod = new ArrayList();
-    }    
-    
-    public static class SecurityConstraintData  implements Serializable {
-        private static final long serialVersionUID = -4780214921810871769L;
-
-        public ArrayList<String> roleName = new ArrayList<String>(); //   auth-constraint/role
-
-        public ArrayList<WebResourceCollectionData> webResourceCollection = 
-            new ArrayList<WebResourceCollectionData>();
-        public String transportGuarantee;
-        
-    }    
-}
\ No newline at end of file
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/TomcatLiteWebXmlConfig.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/TomcatLiteWebXmlConfig.java
deleted file mode 100644 (file)
index c79fa14..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You 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.apache.tomcat.lite.webxml;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-
-import org.apache.tomcat.lite.ContextPreinitListener;
-import org.apache.tomcat.lite.ServletContextImpl;
-
-/**
- * Default configurator - parse web.xml, init the context.
- * 
- * Will be executed first - if set as the default config addon.
- * 
- * Possible extensions: 
- *   - read from a .ser file instead of web.xml
- *   - custom code for manual/extra config
- *   - read from a central repo
- *  
- * @author Costin Manolache
- */
-public class TomcatLiteWebXmlConfig implements ContextPreinitListener {
-
-    protected void readWebXml(ServletContextImpl ctx, 
-                              String base) throws ServletException {
-        // TODO: .ser, reloading, etc
-//        if (contextConfig != null && contextConfig.fileName != null) {
-//            // TODO: this should move to deploy - if not set, there is no point
-//            File f = new File(contextConfig.fileName);
-//            if (f.exists()) {
-//                if (f.lastModified() > contextConfig.timestamp + 1000) {
-//                    log("Reloading web.xml");
-//                    contextConfig = null;
-//                }
-//            } else {
-//                log("Old web.xml");
-//                contextConfig = null;
-//            }
-//        }
-        if (base != null) {
-            WebXml webXml = new WebXml(ctx.getContextConfig());
-            webXml.readWebXml(base);
-        }
-    }
-
-    @Override
-    public void preInit(ServletContext ctx) {
-        ServletContextImpl servletContext =  
-            (ServletContextImpl) ctx;
-        
-        String base = servletContext.getBasePath();
-        if (base == null) {
-            return; // nothing we can do
-        }
-        try {
-            readWebXml(servletContext, base);
-        } catch (ServletException e) {
-            // TODO Auto-generated catch block
-            throw new RuntimeException(e);
-        }
-    }
-    
-}
diff --git a/modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/WebXml.java b/modules/tomcat-lite/java/org/apache/tomcat/lite/webxml/WebXml.java
deleted file mode 100644 (file)
index 6f4c08a..0000000
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You 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.apache.tomcat.lite.webxml;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-import javax.servlet.ServletException;
-
-import org.apache.tomcat.lite.webxml.ServletContextConfig.EnvEntryData;
-import org.apache.tomcat.lite.webxml.ServletContextConfig.FilterData;
-import org.apache.tomcat.lite.webxml.ServletContextConfig.FilterMappingData;
-import org.apache.tomcat.lite.webxml.ServletContextConfig.SecurityConstraintData;
-import org.apache.tomcat.lite.webxml.ServletContextConfig.ServletData;
-import org.apache.tomcat.lite.webxml.ServletContextConfig.WebResourceCollectionData;
-import org.apache.tomcat.util.DomUtil;
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-
-/** 
- * General-purpose utility to process an web.xml file. Result
- *  is a tree of objects starting with WebAppData.
- * 
- * TODO: allow writting of web.xml, allow modification ( preserving 
- * comments )
- * 
- * @author costin
- */
-public class WebXml {
-    ServletContextConfig d;
-    
-    public WebXml(ServletContextConfig cfg) {
-        d = cfg;
-    }
-
-    public ServletContextConfig getWebAppData() {
-        return d;
-    }
-    
-    public void readWebXml(String baseDir) throws ServletException {
-        try {
-            File webXmlFile = new File( baseDir + "/WEB-INF/web.xml");
-            if (!webXmlFile.exists()) {
-                return;
-            }
-            d.fileName = webXmlFile.getCanonicalPath();
-            d.timestamp = webXmlFile.lastModified();
-            
-            FileInputStream fileInputStream = new FileInputStream(webXmlFile);
-            readWebXml(fileInputStream);
-        } catch (Exception e) {
-            e.printStackTrace();
-            throw new ServletException(e);
-        }
-    }
-    
-     public void readWebXml(InputStream fileInputStream) 
-             throws ServletException {
-         try {
-                    
-            Document document = DomUtil.readXml(fileInputStream);
-            Node webappNode = DomUtil.getChild(document, "web-app");
-
-            String fullS = DomUtil.getAttribute(webappNode, "full");
-            if (fullS != null && fullS.equalsIgnoreCase("true")) {
-                d.full = true;
-            }
-            
-            d.displayName = DomUtil.getAttribute(webappNode, "display-name");
-                        
-            // Process each child of web-app
-            Node confNode = DomUtil.getChild(webappNode, "filter");
-            while (confNode != null ) {
-                processFilter(confNode);
-                confNode = DomUtil.getNext(confNode);
-            }
-
-            confNode = DomUtil.getChild(webappNode, "filter-mapping");
-            while (confNode != null ) {
-                processFilterMapping(confNode);
-                confNode = DomUtil.getNext(confNode);
-            }
-
-            confNode = DomUtil.getChild(webappNode, "context-param");
-            while (confNode != null ) {
-                String n = DomUtil.getChildContent(confNode, "param-name").trim();
-                String v = DomUtil.getChildContent(confNode, "param-value").trim();
-                d.contextParam.put(n, v);
-                confNode = DomUtil.getNext(confNode);
-            }
-
-            confNode = DomUtil.getChild(webappNode, "mime-mapping");
-            while (confNode != null ) {
-                String n = DomUtil.getChildContent(confNode, "extension");
-                String t = DomUtil.getChildContent(confNode, "mime-type");
-                d.mimeMapping.put(n, t);
-                confNode = DomUtil.getNext(confNode);
-            }
-
-            confNode = DomUtil.getChild(webappNode, "error-page");
-            while (confNode != null ) {
-                processErrorPage(confNode);
-                confNode = DomUtil.getNext(confNode);
-            }
-
-            confNode = DomUtil.getChild(webappNode, "jsp-config");
-            while (confNode != null ) {
-                processJspConfig(confNode);
-                confNode = DomUtil.getNext(confNode);
-            }
-
-            confNode = DomUtil.getChild(webappNode, "servlet");
-            while (confNode != null ) {
-                processServlet(confNode);
-                confNode = DomUtil.getNext(confNode);
-            }
-
-            confNode = DomUtil.getChild(webappNode, "servlet-mapping");
-            while (confNode != null ) {
-                processServletMapping(confNode);
-                confNode = DomUtil.getNext(confNode);
-            }
-
-            confNode = DomUtil.getChild(webappNode, "listener");
-            while (confNode != null ) {
-                String lClass = DomUtil.getChildContent(confNode, "listener-class");
-                d.listenerClass.add(lClass);
-                confNode = DomUtil.getNext(confNode);
-            }
-
-            confNode = DomUtil.getChild(webappNode, "security-constraint");
-            while (confNode != null ) {
-                processSecurityConstraint(confNode);
-                confNode = DomUtil.getNext(confNode);
-            }
-
-            confNode = DomUtil.getChild(webappNode, "login-config");
-            while (confNode != null ) {
-                processLoginConfig(confNode);
-                confNode = DomUtil.getNext(confNode);
-                if (confNode != null) 
-                    throw new ServletException("Multiple login-config");
-            }
-
-            confNode = DomUtil.getChild(webappNode, "session-config");
-            while (confNode != null ) {
-                String n = DomUtil.getChildContent(confNode, "session-timeout");
-                int stout = Integer.parseInt(n);
-                d.sessionTimeout = stout;
-                confNode = DomUtil.getNext(confNode);
-                if (confNode != null) 
-                    throw new ServletException("Multiple session-config");
-            }
-
-            confNode = DomUtil.getChild(webappNode, "welcome-file-list");
-            while (confNode != null ) {
-                Node wf = DomUtil.getChild(confNode, "welcome-file");
-                while (wf != null) {
-                    String file = DomUtil.getContent(wf);
-                    d.welcomeFileList.add(file);
-                    wf = DomUtil.getNext(wf);
-                }
-                // more sections ?
-                confNode = DomUtil.getNext(confNode);
-            }
-
-            // Not supported right now - TODO: collect, have jndi plugin
-            confNode = DomUtil.getChild(webappNode, "env-entry");
-            while (confNode != null ) {
-                processEnvEntry(confNode);
-                confNode = DomUtil.getNext(confNode);
-            }
-            
-            confNode = DomUtil.getChild(webappNode, "locale-encoding-mapping-list");
-            while (confNode != null ) {
-                confNode = DomUtil.getNext(confNode);
-                String n = DomUtil.getChildContent(confNode, "locale");
-                String t = DomUtil.getChildContent(confNode, "encoding");
-                d.localeEncodingMapping.put(n, t);
-            }
-
-            confNode = DomUtil.getChild(webappNode, "distributable");
-            while (confNode != null ) {
-                d.distributable = true;
-                confNode = DomUtil.getNext(confNode);
-            }
-
-            confNode = DomUtil.getChild(confNode, "security-role");
-            while (confNode != null ) {
-                String n = DomUtil.getChildContent(confNode, "role-name");
-                d.securityRole.add(n);
-                confNode = DomUtil.getNext(confNode);
-            }
-
-                } catch (Exception e) {
-                    e.printStackTrace();
-                    throw new ServletException(e);
-                }
-    }
-    
-    private void processJspConfig(Node confNode) {
-        Node tagLib = DomUtil.getChild(confNode, "taglib");
-        while (tagLib != null) {
-            String uri = DomUtil.getChildContent(tagLib, "taglib-uri");
-            String l = DomUtil.getChildContent(tagLib, "taglib-location");
-            //d.tagLibs.put(uri, l);
-            tagLib = DomUtil.getNext(tagLib);
-        }
-        
-        tagLib = DomUtil.getChild(confNode, "jsp-property-group");
-        while (tagLib != null) {
-            // That would be the job of the JSP servlet to process.
-            tagLib = DomUtil.getNext(tagLib);
-        }
-    }
-
-    private void processEnvEntry(Node confNode) {
-        EnvEntryData ed = new EnvEntryData();
-        ed.envEntryName = DomUtil.getChildContent(confNode,"env-entry-name");
-        ed.envEntryType = DomUtil.getChildContent(confNode,"env-entry-type");
-        ed.envEntryValue = DomUtil.getChildContent(confNode,"env-entry-value");
-        d.envEntry.add(ed);
-    }
-
-    private void processLoginConfig(Node confNode) {
-        d.authMethod = DomUtil.getChildContent(confNode,"auth-method");
-        d.realmName = DomUtil.getChildContent(confNode,"auth-method");
-        Node formNode = DomUtil.getChild(confNode, "form-login-config");
-        if (formNode != null) {
-            d.formLoginPage = DomUtil.getChildContent(formNode,"form-login-page");
-            d.formErrorPage = DomUtil.getChildContent(formNode,"form-error-page");
-        }
-    }
-
-    private void processSecurityConstraint(Node confNode) {
-        SecurityConstraintData sd = new SecurityConstraintData();
-        Node cn = DomUtil.getChild(confNode, "web-resource-collection");
-        while (cn != null) {
-            WebResourceCollectionData wrd = new WebResourceCollectionData();
-            wrd.webResourceName = DomUtil.getChildContent(cn, "web-resource-name");
-            Node scn = DomUtil.getChild(cn,"url-pattern");
-            while (scn != null) {
-                wrd.urlPattern.add(DomUtil.getContent(scn));
-                scn = DomUtil.getNext(scn);
-            }
-            scn = DomUtil.getChild(cn,"http-method");
-            while (scn != null) {
-                wrd.httpMethod.add(DomUtil.getContent(scn));
-                scn = DomUtil.getNext(scn);
-            }
-            cn = DomUtil.getNext(cn);
-            sd.webResourceCollection.add(wrd);
-        }
-        
-        d.securityConstraint.add(sd);
-    }
-
-    private void processErrorPage(Node confNode) {
-        String name = DomUtil.getChildContent(confNode,"location");
-        String c = DomUtil.getChildContent(confNode,"error-code");
-        String t = DomUtil.getChildContent(confNode,"exception-type");
-        if (c != null) {
-            d.errorPageCode.put(c, name);
-        }
-        if (t != null) {
-            d.errorPageException.put(t, name);
-        }
-    }
-
-    private void processServlet(Node confNode) throws ServletException {
-        ServletData sd = new ServletData();
-
-        sd.servletName = DomUtil.getChildContent(confNode,"servlet-name");
-        sd.servletClass = DomUtil.getChildContent(confNode,"servlet-class");
-        sd.jspFile = DomUtil.getChildContent(confNode,"jsp-file");
-        
-        processInitParams(confNode, sd.initParams);
-        
-        d.servlets.put( sd.servletName, sd );
-        
-        String los = DomUtil.getChildContent(confNode, "load-on-startup");
-        if (los != null ) { 
-            sd.loadOnStartup = Integer.parseInt(los);
-        }
-        
-        Node sn = DomUtil.getChild(confNode, "security-role-ref");
-        while (sn != null ) {
-            String roleName = DomUtil.getChildContent(sn, "role-name");
-            String roleLink = DomUtil.getChildContent(sn, "role-link");
-            if (roleLink == null) {
-                sd.securityRoleRef.put(roleName, "");
-            } else {
-                sd.securityRoleRef.put(roleName, roleLink);
-            }
-            sn = DomUtil.getNext(sn);
-        }
-    }
-
-    private void processInitParams(Node confNode, HashMap initParams) {
-        Node initN = DomUtil.getChild(confNode, "init-param");
-        while (initN != null ) {
-            String n = DomUtil.getChildContent(initN, "param-name");
-            String v = DomUtil.getChildContent(initN, "param-value");
-            initParams.put(n, v);
-            initN = DomUtil.getNext(initN);
-        }
-    }
-
-    private void processServletMapping(Node confNode) {
-        String name = DomUtil.getChildContent(confNode,"servlet-name");
-        Node dataN = DomUtil.getChild(confNode, "url-pattern");
-        while (dataN != null) {
-            String path = DomUtil.getContent(dataN).trim();
-            dataN = DomUtil.getNext(dataN);
-            
-            if (! (path.startsWith("/") || path.startsWith("*"))) {
-                // backward compat 
-                path = "/" + path;
-            }
-            d.servletMapping.put(path, name);
-        }
-    }
-
-    private void processFilterMapping(Node confNode) {
-      String filterName = DomUtil.getChildContent(confNode,"filter-name");
-      // multiple 
-      ArrayList dispatchers = new ArrayList();
-      Node dataN = DomUtil.getChild(confNode, "dispatcher");
-      while (dataN != null ) {
-          String d = DomUtil.getContent(dataN);
-          dispatchers.add(d);
-          dataN = DomUtil.getNext(dataN);
-      }
-      
-      // Multiple url-pattern and servlet-name in one
-      // mapping rule. Need to be applied in order.
-      dataN = DomUtil.getChild(confNode, "url-pattern");
-      while (dataN != null ) {
-        FilterMappingData fm = new FilterMappingData();
-        fm.filterName = filterName;
-        fm.dispatcher = dispatchers;
-        String path = DomUtil.getContent(dataN);
-        dataN = DomUtil.getNext(dataN);
-        fm.urlPattern = path;
-        d.filterMappings.add(fm);
-      }
-      dataN = DomUtil.getChild(confNode, "servlet-name");
-      while (dataN != null ) {
-        FilterMappingData fm = new FilterMappingData();
-        fm.filterName = filterName;
-        fm.dispatcher = dispatchers;
-        String sn = DomUtil.getContent(dataN);
-        dataN = DomUtil.getNext(dataN);
-        fm.servletName = sn;
-        d.filterMappings.add(fm);
-      }
-    }
-
-    private void processFilter(Node confNode) {
-        String name = DomUtil.getChildContent(confNode,"filter-name");
-        String sclass = DomUtil.getChildContent(confNode,"filter-class");
-        
-        FilterData fd = new FilterData();
-        processInitParams(confNode, fd.initParams);
-        fd.filterName = name;
-        fd.filterClass = sclass;
-        d.filters.put(name, fd);
-    }
-    
-}