tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cos...@apache.org
Subject svn commit: r433260 [4/5] - in /tomcat/sandbox/tomcat-lite: ./ java/org/apache/coyote/ java/org/apache/tomcat/lite/ java/org/apache/tomcat/lite/ctxmap/ java/org/apache/tomcat/lite/http/ java/org/apache/tomcat/lite/jmx/ java/org/apache/tomcat/lite/servl...
Date Mon, 21 Aug 2006 15:20:46 GMT
Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/webmap/WebappServletMapper.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/webmap/WebappServletMapper.java?rev=433260&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/webmap/WebappServletMapper.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/lite/webmap/WebappServletMapper.java Mon Aug 21 08:20:40 2006
@@ -0,0 +1,854 @@
+/*
+ *  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.webmap;
+
+import java.io.File;
+
+import org.apache.tomcat.lite.ServletContextImpl;
+import org.apache.tomcat.lite.util.MappingData;
+import org.apache.tomcat.util.buf.Ascii;
+import org.apache.tomcat.util.buf.CharChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
+
+/**
+ * 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.
+ */
+public class WebappServletMapper {
+
+    /**
+     * Context associated with this wrapper, used for wrapper mapping.
+     */
+    public ContextMapElement contextMapElement = new ContextMapElement();
+
+
+    // --------------------------------------------------------- Public Methods
+
+    public WebappServletMapper(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 != (pathEnd - pathOffset)) {
+            servletPath = pathOffset + length;
+        } else {
+            noServletPath = true;
+            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 >= 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;
+    }
+   
+}

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/EnvEntryData.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/EnvEntryData.java?rev=433260&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/EnvEntryData.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/EnvEntryData.java Mon Aug 21 08:20:40 2006
@@ -0,0 +1,12 @@
+/**
+ * 
+ */
+package org.apache.tomcat.servlets.config;
+
+import java.io.Serializable;
+
+public class EnvEntryData  implements Serializable {
+    public String envEntryName;
+    public String envEntryType;
+    public String envEntryValue;
+}
\ No newline at end of file

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/FilterData.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/FilterData.java?rev=433260&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/FilterData.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/FilterData.java Mon Aug 21 08:20:40 2006
@@ -0,0 +1,13 @@
+/**
+ * 
+ */
+package org.apache.tomcat.servlets.config;
+
+import java.io.Serializable;
+import java.util.HashMap;
+
+public class FilterData implements Serializable {
+    public HashMap initParams = new HashMap();
+    public String filterClass;
+    public String filterName;
+}
\ No newline at end of file

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/FilterMappingData.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/FilterMappingData.java?rev=433260&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/FilterMappingData.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/FilterMappingData.java Mon Aug 21 08:20:40 2006
@@ -0,0 +1,14 @@
+/**
+ * 
+ */
+package org.apache.tomcat.servlets.config;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+
+public class FilterMappingData implements Serializable {
+    public String filterName;
+    public String urlPattern;
+    public String servletName;
+    public ArrayList<String> dispatcher = new ArrayList();
+}
\ No newline at end of file

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/SecurityConstraintData.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/SecurityConstraintData.java?rev=433260&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/SecurityConstraintData.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/SecurityConstraintData.java Mon Aug 21 08:20:40 2006
@@ -0,0 +1,15 @@
+/**
+ * 
+ */
+package org.apache.tomcat.servlets.config;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+
+public class SecurityConstraintData  implements Serializable {
+    public ArrayList roleName = new ArrayList(); //   auth-constraint/role
+
+    public ArrayList webResourceCollection = new ArrayList();
+    public String transportGuarantee;
+    
+}
\ No newline at end of file

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/ServletData.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/ServletData.java?rev=433260&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/ServletData.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/ServletData.java Mon Aug 21 08:20:40 2006
@@ -0,0 +1,25 @@
+/**
+ * 
+ */
+package org.apache.tomcat.servlets.config;
+
+import java.io.Serializable;
+import java.util.HashMap;
+
+public class ServletData implements Serializable {
+    public ServletData() {
+    }
+    public ServletData(String servletName, String servletClass) {
+        this.servletClass = servletClass;
+        this.serlvetName = servletName;
+    }
+
+    public HashMap initParams = new HashMap();
+    public String serlvetName;
+    public String servletClass;
+    public String jspFile;
+    public int loadOnStartup;
+    public String runAs;
+    public HashMap securityRoleRef = new HashMap(); // roleName -> [roleLink]
+    
+}
\ No newline at end of file

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/WebAppData.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/WebAppData.java?rev=433260&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/WebAppData.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/WebAppData.java Mon Aug 21 08:20:40 2006
@@ -0,0 +1,58 @@
+/**
+ * 
+ */
+package org.apache.tomcat.servlets.config;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class WebAppData  implements Serializable {
+    
+    public String fileName;
+    public long timestamp;
+
+    public boolean full;
+    public HashMap<String, String> contextParam = new HashMap();
+    public HashMap<String, String> mimeMapping = new HashMap(); // extension -> mime-type
+    
+    public ArrayList<String> listenerClass = new ArrayList();
+    
+    public ArrayList<String> welcomeFileList = new ArrayList();
+    public HashMap<String, String> errorPageCode= new HashMap(); // code -> location 
+    public HashMap<String, String> errorPageException= new HashMap(); // exception -> location
+    public HashMap<String, String> localeEncodingMapping= new HashMap(); // locale -> encoding
+    
+    // public HashMap tagLibs; // uri->location
+    // jsp-property-group
+
+    // securityConstraint
+    public ArrayList<SecurityConstraintData> securityConstraint = new ArrayList();
+    // loginConfig
+    public String authMethod;
+    public String realmName;
+    public String formLoginPage;
+    public String formErrorPage;
+    
+    // securityRole
+    public ArrayList<String> securityRole = new ArrayList();
+    
+    // envEntry
+    public ArrayList<EnvEntryData> envEntry = new ArrayList();
+    
+    // ejbRef
+    // ejbLocalRef
+    // serviceRef
+    // resourceRef
+    // resourceEnvRef
+    // message-destination
+    // message-destinationRef
+    public HashMap<String, FilterData> filters = new HashMap();
+    public HashMap<String, ServletData> servlets = new HashMap();
+
+    public int sessionTimeout;
+    public boolean distributable;
+    
+    public HashMap<String, String> servletMapping = new HashMap(); // url -> servlet
+    public ArrayList<FilterMappingData> filterMappings = new ArrayList();
+}
\ No newline at end of file

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/WebResourceCollectionData.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/WebResourceCollectionData.java?rev=433260&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/WebResourceCollectionData.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/config/WebResourceCollectionData.java Mon Aug 21 08:20:40 2006
@@ -0,0 +1,13 @@
+/**
+ * 
+ */
+package org.apache.tomcat.servlets.config;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+
+public class WebResourceCollectionData implements Serializable {
+    public String webResourceName;
+    public ArrayList urlPattern = new ArrayList();
+    public ArrayList httpMethod = new ArrayList();
+}
\ No newline at end of file

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/InitServlet.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/InitServlet.java?rev=433260&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/InitServlet.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/InitServlet.java Mon Aug 21 08:20:40 2006
@@ -0,0 +1,77 @@
+package org.apache.tomcat.servlets.deploy;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tomcat.lite.TomcatLite;
+import org.apache.tomcat.lite.TomcatLite.ContextConfigData;
+import org.apache.tomcat.lite.TomcatLite.EngineData;
+
+public class InitServlet extends HttpServlet {
+
+    @Override
+    protected void service(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException
+    {
+        EngineData ed = initConfig();
+        req.setAttribute("engineData", ed);
+    }
+    
+    /** Read a config file or directory layouts, generate the EngineData config
+     * info object. 
+     * 
+     * The config object should include at least the set of webapps, including
+     * the connector webapp. Each webapp may include web.xml data, if not - 
+     * the WebXml servlet will be called to fill it in the first time or when
+     * changed.
+     * 
+     * It is possible to deploy tomcat-lite without a deploy webapp - in which
+     * case the EngineData will be used as reference, and now web.xml will be
+     * refreshed. 
+     * 
+     * Alternative implementations:
+     *  - various layouts and configs
+     *  - static set of settings ( hardcoded )
+     * 
+     * @return
+     */
+    public EngineData initConfig() {
+        EngineData ed = new TomcatLite.EngineData();
+        
+        File webappD = new File("webapps");
+        if (!webappD.exists()) {
+            return ed;
+        }
+        File[] dirs = webappD.listFiles();
+        for (File dir: dirs) {
+            if (dir.isDirectory()) {
+                String path = dir.getName();
+                // TODO: demangling, etc
+                if ("ROOT".equals(path)) { 
+                    path = "/";
+                } else {
+                    path = "/" + path;
+                }
+                ed.contexts.add(new ContextConfigData(dir.getAbsolutePath(), 
+                                                      path)); 
+            }
+        }
+        
+        return ed;
+    }
+    
+    public static void main(String args[]) throws IOException {
+        InitServlet is = new InitServlet();
+        EngineData ed = is.initConfig();
+        TomcatLite.getServletImpl().saveEngineData(ed);
+    }
+
+}

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/ReloadServlet.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/ReloadServlet.java?rev=433260&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/ReloadServlet.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/ReloadServlet.java Mon Aug 21 08:20:40 2006
@@ -0,0 +1,23 @@
+package org.apache.tomcat.servlets.deploy;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.tomcat.lite.TomcatLite;
+
+public class ReloadServlet extends HttpServlet {
+
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
+            throws ServletException, IOException {
+        
+        TomcatLite servletImpl = TomcatLite.getServletImpl();
+        //servletImpl.reloadServletContext(getServletContext());
+        
+    }
+
+    
+}

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/WebAnnotation.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/WebAnnotation.java?rev=433260&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/WebAnnotation.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/WebAnnotation.java Mon Aug 21 08:20:40 2006
@@ -0,0 +1,145 @@
+package org.apache.tomcat.servlets.deploy;
+
+import java.util.List;
+
+import javax.annotation.security.DeclareRoles;
+import javax.annotation.security.RunAs;
+
+import org.apache.tomcat.servlets.config.FilterData;
+import org.apache.tomcat.servlets.config.ServletData;
+import org.apache.tomcat.servlets.config.WebAppData;
+
+
+
+/**
+ * Based on catalina.WebAnnotationSet
+ * 
+ * Supports:
+ *  @DeclaresRoles - on Servlet class - web-app/security-role/role-name
+ *  @RunAs - on Servlet class - web-app/servlet/run-as
+ *  
+ * 
+ * No support for jndi @Resources, @Resource
+ * No @InjectionComplete callback annotation
+ * 
+ * No support for @EJB, @WebServiceRef
+ *  
+ * @author costin
+ * @author Fabien Carrion
+ */
+public class WebAnnotation {
+
+    /**
+     * Process the annotations on a context.
+     */
+    public static void loadApplicationAnnotations(WebAppData context, ClassLoader classLoader) {
+        loadApplicationListenerAnnotations(context, classLoader);
+        loadApplicationFilterAnnotations(context, classLoader);
+        loadApplicationServletAnnotations(context, classLoader);
+    }
+    
+    
+    // -------------------------------------------------------- protected Methods
+    
+    
+    /**
+     * Process the annotations for the listeners.
+     */
+    static void loadApplicationListenerAnnotations(WebAppData context, ClassLoader classLoader) {
+        List applicationListeners = context.listenerClass;
+        for (int i = 0; i < applicationListeners.size(); i++) {
+            loadClassAnnotation(context, (String)applicationListeners.get(i), classLoader);
+        }
+    }
+    
+    
+    /**
+     * Process the annotations for the filters.
+     */
+    static void loadApplicationFilterAnnotations(WebAppData context, ClassLoader classLoader) {
+        for(FilterData fc: context.filters.values()) {
+            loadClassAnnotation(context, fc.filterClass, classLoader);
+        }
+    }
+    
+    
+    /**
+     * Process the annotations for the servlets.
+     * @param classLoader 
+     */
+    static void loadApplicationServletAnnotations(WebAppData context, ClassLoader classLoader) {
+        Class classClass = null;
+        
+        for (ServletData sd: context.servlets.values()) {
+            if (sd.servletClass == null) {
+                continue;
+            }
+
+            try {
+                classClass = classLoader.loadClass(sd.servletClass);
+            } catch (ClassNotFoundException e) {
+                // We do nothing
+            } catch (NoClassDefFoundError e) {
+                // We do nothing
+            }
+
+            if (classClass == null) {
+                continue;
+            }
+
+            loadClassAnnotation(context, classClass);
+            /* Process RunAs annotation which can be only on servlets.
+             * Ref JSR 250, equivalent to the run-as element in
+             * the deployment descriptor
+             */
+            if (classClass.isAnnotationPresent(RunAs.class)) {
+                RunAs annotation = (RunAs) 
+                classClass.getAnnotation(RunAs.class);
+                sd.runAs = annotation.value();
+            }
+        }
+    }
+    
+    /**
+     * Process the annotations on a context for a given className.
+     */
+    static void loadClassAnnotation(WebAppData context, 
+                                    String classClass2, ClassLoader classLoader) {
+        
+        Class classClass = null;
+        
+        try {
+            classClass = classLoader.loadClass(classClass2);
+        } catch (ClassNotFoundException e) {
+            // We do nothing
+        } catch (NoClassDefFoundError e) {
+            // We do nothing
+        }
+        
+        if (classClass == null) {
+            return;
+        }
+        loadClassAnnotation(context, classClass);
+    }
+     
+    static void loadClassAnnotation(WebAppData context, 
+                                    Class classClass) {
+        
+        /* Process DeclareRoles annotation.
+         * Ref JSR 250, equivalent to the security-role element in
+         * the deployment descriptor
+         */
+        if (classClass.isAnnotationPresent(DeclareRoles.class)) {
+            DeclareRoles annotation = (DeclareRoles) 
+                classClass.getAnnotation(DeclareRoles.class);
+            for (int i = 0; annotation.value() != null && 
+                            i < annotation.value().length; i++) {
+                context.securityRole.add(annotation.value()[i]);
+            }
+        }
+        
+        
+    }
+
+    
+}

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/WebXml.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/WebXml.java?rev=433260&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/WebXml.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/deploy/WebXml.java Mon Aug 21 08:20:40 2006
@@ -0,0 +1,347 @@
+/*
+ */
+package org.apache.tomcat.servlets.deploy;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.servlet.ServletException;
+
+import org.apache.tomcat.servlets.config.EnvEntryData;
+import org.apache.tomcat.servlets.config.FilterData;
+import org.apache.tomcat.servlets.config.FilterMappingData;
+import org.apache.tomcat.servlets.config.SecurityConstraintData;
+import org.apache.tomcat.servlets.config.ServletData;
+import org.apache.tomcat.servlets.config.WebAppData;
+import org.apache.tomcat.servlets.config.WebResourceCollectionData;
+import org.apache.tomcat.util.DomUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+/** Process an web.xml file
+ * 
+ * @author costin
+ */
+public class WebXml {
+    WebAppData d = new WebAppData();
+    
+    public WebXml() {
+    }
+
+    public void saveWebAppData(String fileName) throws IOException {
+        ObjectOutputStream oos = 
+            new ObjectOutputStream(new FileOutputStream(fileName));
+        oos.writeObject(d);
+        oos.close();
+    }
+    
+    public WebAppData 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);
+            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;
+            }
+            // 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 ) {
+                confNode = DomUtil.getNext(confNode);
+                if (confNode != null) 
+                    throw new ServletException("Multiple session-config");
+                String n = DomUtil.getChildContent(confNode, "session-timeout");
+                int stout = Integer.parseInt(n);
+                d.sessionTimeout = stout;
+            }
+
+            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);
+        }
+        d.securityConstraint.add(sd);
+    }
+
+    private void processErrorPage(Node confNode) {
+        String name = DomUtil.getChildContent(confNode,"error-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.serlvetName = 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.serlvetName, 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");
+        String path = DomUtil.getChildContent(confNode,"url-pattern");
+
+        d.servletMapping.put(path, name);
+    }
+
+    private void processFilterMapping(Node confNode) {
+        FilterMappingData fm = new FilterMappingData();
+        fm.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);
+        }
+        fm.dispatcher = dispatchers;
+
+        dataN = DomUtil.getChild(confNode, "url-pattern");
+        while (dataN != null ) {
+            String path = DomUtil.getContent(dataN);
+            dataN = DomUtil.getNext(dataN);
+            fm.urlPattern = path;
+        }
+        dataN = DomUtil.getChild(confNode, "servlet-name");
+        while (dataN != null ) {
+            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);
+    }
+    
+}

Added: tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/HttpSessionImpl.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/HttpSessionImpl.java?rev=433260&view=auto
==============================================================================
--- tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/HttpSessionImpl.java (added)
+++ tomcat/sandbox/tomcat-lite/java/org/apache/tomcat/servlets/session/HttpSessionImpl.java Mon Aug 21 08:20:40 2006
@@ -0,0 +1,784 @@
+/*
+ * 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.servlets.session;
+
+
+import java.io.Serializable;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionAttributeListener;
+import javax.servlet.http.HttpSessionBindingEvent;
+import javax.servlet.http.HttpSessionBindingListener;
+import javax.servlet.http.HttpSessionContext;
+import javax.servlet.http.HttpSessionEvent;
+import javax.servlet.http.HttpSessionListener;
+
+import org.apache.tomcat.servlets.util.Enumerator;
+
+/**
+ * Standard implementation of the <b>Session</b> interface.  
+ * 
+ * This is a minimal, non-serializable HttpSession. You can use a different 
+ * session manager, but you should keep in mind that persistent or distributed
+ * sessions are a bad thing. 
+ * 
+ * The session is best for caching data across requests, and tracking the 
+ * user flow. For any data you don't want to lose or is worth preserving - 
+ * use a transaction manager, or any form of storage that provides the 
+ * set of ACID characteristics you need. 
+ * 
+ * Even the most sophisticated sessions managers can't guarantee data integrity
+ * in 100% of cases, and can't notify you of the cases where a replication 
+ * failed. Using such a manager might fool users into making incorrect 
+ * assumptions. Computers and networks do crash at random points, and all
+ * the theory on transactions exists for a good reason.
+ * 
+ * Note: this is a user-space implementation, i.e. this can be used in any
+ * container by using the WebappSessionManager class.
+ *
+ * @author Costin Manolache - removed most of the code
+ * @author Craig R. McClanahan
+ * @author Sean Legassick
+ * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
+ */
+public class HttpSessionImpl  implements HttpSession, Serializable {
+
+    /**
+     * Type array, used as param to toArray()
+     */
+    protected static final String EMPTY_ARRAY[] = new String[0];
+
+    /**
+     * The HTTP session context associated with this session.
+     */
+    protected static HttpSessionContext sessionContext = null;
+
+
+    /**
+     * The Manager with which this Session is associated.
+     */
+    protected transient SessionManagerServlet manager = null;
+
+    /**
+     * The session identifier of this Session.
+     */
+    protected String id = null;
+
+    /**
+     * The collection of user data attributes associated with this Session.
+     */
+    protected Map attributes = new HashMap();
+
+    /**
+     * The time this session was created, in milliseconds since midnight,
+     * January 1, 1970 GMT.
+     */
+    protected long creationTime = 0L;
+
+    /**
+     * The last accessed time for this Session.
+     */
+    protected long lastAccessedTime = creationTime;
+
+    /**
+     * The current accessed time for this session.
+     */
+    protected long thisAccessedTime = creationTime;
+
+    /**
+     * The maximum time interval, in seconds, between client requests before
+     * the servlet container may invalidate this session.  A negative time
+     * indicates that the session should never time out.
+     */
+    protected int maxInactiveInterval = -1;
+
+    /**
+     * The access count for this session - how many requests are using this
+     * session ( so we can prevent expiry )
+     */
+    protected transient int accessCount = 0;
+
+    /**
+     * We are currently processing a session expiration, so bypass
+     * certain IllegalStateException tests.  
+     */
+    protected transient boolean expiring = false;
+
+
+    /**
+     * Flag indicating whether this session is new or not.
+     */
+    protected boolean isNew = false;
+
+
+    /**
+     * Flag indicating whether this session is valid or not.
+     */
+    protected boolean isValid = false;
+
+
+    /** Only the manager can create sessions, so it knows about them.
+     */
+    HttpSessionImpl(SessionManagerServlet manager) {
+        this.manager = manager;
+    }
+
+    // ----------   API methods ---------
+
+    /**
+     * Return the session identifier for this session.
+     */
+    public String getId() {
+        return this.id;
+    }
+
+    /**
+     * Return the last time the client sent a request associated with this
+     * session, as the number of milliseconds since midnight, January 1, 1970
+     * GMT.  Actions that your application takes, such as getting or setting
+     * a value associated with the session, do not affect the access time.
+     */
+    public long getLastAccessedTime() {
+        checkValid();
+         return this.lastAccessedTime;
+
+    }
+
+    /**
+     * Return the maximum time interval, in seconds, between client requests
+     * before the servlet container will invalidate the session.  A negative
+     * time indicates that the session should never time out.
+     */
+    public int getMaxInactiveInterval() {
+        return this.maxInactiveInterval;
+    }
+
+
+    /**
+     * Set the maximum time interval, in seconds, between client requests
+     * before the servlet container will invalidate the session.  A negative
+     * time indicates that the session should never time out.
+     *
+     * @param interval The new maximum interval
+     */
+    public void setMaxInactiveInterval(int interval) {
+        this.maxInactiveInterval = interval;
+        if (isValid && interval == 0) {
+            expire();
+        }
+    }
+
+    /**
+     * Return the time when this session was created, in milliseconds since
+     * midnight, January 1, 1970 GMT.
+     *
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     */
+    public long getCreationTime() {
+        checkValid();
+        return this.creationTime;
+
+    }
+
+    public ServletContext getServletContext() {
+        if (manager == null)
+            return null; // Should never happen
+        ServletContext context = (ServletContext)manager.getContext();
+        return context;
+    }
+
+
+    public HttpSessionContext getSessionContext() {
+        if (sessionContext == null)
+            sessionContext = new StandardSessionContext();
+        return (sessionContext);
+    }
+
+    /**
+     * Return the object bound with the specified name in this session, or
+     * <code>null</code> if no object is bound with that name.
+     *
+     * @param name Name of the attribute to be returned
+     *
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     */
+    public Object getAttribute(String name) {
+        checkValid();
+        return attributes.get(name);
+    }
+
+
+    /**
+     * Return an <code>Enumeration</code> of <code>String</code> objects
+     * containing the names of the objects bound to this session.
+     *
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     */
+    public Enumeration getAttributeNames() {
+        checkValid();
+        return new Enumerator(attributes.keySet(), true);
+    }
+
+
+    /**
+     * Return the object bound with the specified name in this session, or
+     * <code>null</code> if no object is bound with that name.
+     *
+     * @param name Name of the value to be returned
+     *
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     *
+     * @deprecated As of Version 2.2, this method is replaced by
+     *  <code>getAttribute()</code>
+     */
+    public Object getValue(String name) {
+        return (getAttribute(name));
+    }
+
+
+    /**
+     * Return the set of names of objects bound to this session.  If there
+     * are no such objects, a zero-length array is returned.
+     *
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     *
+     * @deprecated As of Version 2.2, this method is replaced by
+     *  <code>getAttributeNames()</code>
+     */
+    public String[] getValueNames() {
+        checkValid();
+        return keys(); // same, but no check for validity
+    }
+
+
+    /**
+     * Invalidates this session and unbinds any objects bound to it.
+     *
+     * @exception IllegalStateException if this method is called on
+     *  an invalidated session
+     */
+    public void invalidate() {
+        checkValid();
+        expire();
+    }
+
+
+    /**
+     * Return <code>true</code> if the client does not yet know about the
+     * session, or if the client chooses not to join the session.  For
+     * example, if the server used only cookie-based sessions, and the client
+     * has disabled the use of cookies, then a session would be new on each
+     * request.
+     *
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     */
+    public boolean isNew() {
+        checkValid();
+        return (this.isNew);
+    }
+
+    public void putValue(String name, Object value) {
+        setAttribute(name, value);
+    }
+
+    public void removeAttribute(String name) {
+        checkValid();
+        removeAttributeInternal(name, true);
+    }
+
+    public void removeValue(String name) {
+        removeAttribute(name);
+    }
+
+
+    /**
+     * Bind an object to this session, using the specified name.  If an object
+     * of the same name is already bound to this session, the object is
+     * replaced.
+     * <p>
+     * After this method executes, and if the object implements
+     * <code>HttpSessionBindingListener</code>, the container calls
+     * <code>valueBound()</code> on the object.
+     *
+     * @param name Name to which the object is bound, cannot be null
+     * @param value Object to be bound, cannot be null
+     *
+     * @exception IllegalArgumentException if an attempt is made to add a
+     *  non-serializable object in an environment marked distributable.
+     * @exception IllegalStateException if this method is called on an
+     *  invalidated session
+     */
+    public void setAttribute(String name, Object value) {
+        // Name cannot be null
+        if (name == null) return;
+
+        // Null value is the same as removeAttribute()
+        if (value == null) {
+            removeAttribute(name);
+            return;
+        }
+
+        checkValid();
+        
+        if ((manager != null) && manager.getDistributable() &&
+          !(value instanceof Serializable))
+            throw new IllegalArgumentException("setAttribute() not serializable");
+
+        // Construct an event with the new value
+        HttpSessionBindingEvent event = null;
+
+        // Call the valueBound() method if necessary
+        if (value instanceof HttpSessionBindingListener) {
+            // Don't call any notification if replacing with the same value
+            Object oldValue = attributes.get(name);
+            if (value != oldValue) {
+                event = new HttpSessionBindingEvent(getSession(), name, value);
+                try {
+                    ((HttpSessionBindingListener) value).valueBound(event);
+                } catch (Throwable t){
+                    manager.log.error("Listener valueBound() error", t); 
+                }
+            }
+        }
+
+        // Replace or add this attribute
+        Object unbound = attributes.put(name, value);
+
+        // Call the valueUnbound() method if necessary
+        if ((unbound != null) && (unbound != value) &&
+            (unbound instanceof HttpSessionBindingListener)) {
+            try {
+                ((HttpSessionBindingListener) unbound).valueUnbound
+                    (new HttpSessionBindingEvent(getSession(), name));
+            } catch (Throwable t) {
+                manager.log.error("Listener valueUnbound()", t);
+            }
+        }
+
+        // Notify interested application event listeners
+        ServletContext context = manager.getContext();
+        List listeners = manager.getEventListeners();
+        if (listeners.size() == 0)
+            return;
+        for (int i = 0; i < listeners.size(); i++) {
+            if (!(listeners.get(i) instanceof HttpSessionAttributeListener))
+                continue;
+            HttpSessionAttributeListener listener =
+                (HttpSessionAttributeListener) listeners.get(i);
+            try {
+                if (unbound != null) {
+                    if (event == null) {
+                        event = new HttpSessionBindingEvent
+                            (getSession(), name, unbound);
+                    }
+                    listener.attributeReplaced(event);
+                } else {
+                    if (event == null) {
+                        event = new HttpSessionBindingEvent
+                            (getSession(), name, value);
+                    }
+                    listener.attributeAdded(event);
+                }
+            } catch (Throwable t) {
+                manager.log.error("Listener attibuteAdded/Replaced()", t);
+            }
+        }
+
+    }
+
+    // -------- Implementation - interactions with SessionManager -----
+    
+    /**
+     * Set the creation time for this session.  This method is called by the
+     * Manager when an existing Session instance is reused.
+     */
+    public void setCreationTime(long time) {
+        this.creationTime = time;
+        this.lastAccessedTime = time;
+        this.thisAccessedTime = time;
+    }
+
+    /**
+     * Set the session identifier for this session and notify listeners about
+     * new session
+     *
+     * @param id The new session identifier
+     */
+    public void setId(String id) {
+
+        if ((this.id != null) && (manager != null))
+            manager.remove(this);
+
+        this.id = id;
+
+        if (manager != null)
+            manager.add(this);
+        tellNew();
+    }
+
+
+    /**
+     * Inform the listeners about the new session.
+     */
+    public void tellNew() {
+        // Notify interested application event listeners
+        ServletContext context = manager.getContext();
+        List listeners = manager.getEventListeners();
+        if (listeners.size() > 0) {
+            HttpSessionEvent event =
+                new HttpSessionEvent(getSession());
+            for (int i = 0; i < listeners.size(); i++) {
+                Object listenerObj = listeners.get(i);
+                if (!(listenerObj instanceof HttpSessionListener))
+                    continue;
+                HttpSessionListener listener =
+                    (HttpSessionListener) listenerObj;
+                try {
+                    listener.sessionCreated(event);
+                } catch (Throwable t) {
+                    manager.log.error("listener.sessionCreated()", t);
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Return the Manager within which this Session is valid.
+     */
+    public SessionManagerServlet getManager() {
+        return (this.manager);
+    }
+
+
+
+    /**
+     * Set the <code>isNew</code> flag for this session.
+     *
+     * @param isNew The new value for the <code>isNew</code> flag
+     */
+    public void setNew(boolean isNew) {
+        this.isNew = isNew;
+    }
+
+    public HttpSession getSession() {
+        return this;
+    }
+
+    private void checkValid() {
+        if ( !isValid() ) {
+            throw new IllegalStateException("checkValid");
+        }
+    }
+
+    /**
+     * Return the <code>isValid</code> flag for this session.
+     */
+    public boolean isValid() {
+        if (this.expiring) {
+            return true;
+        }
+        if (!this.isValid ) {
+            return false;
+        }
+        if (accessCount > 0) {
+            return true;
+        }
+        if (maxInactiveInterval >= 0) { 
+            long timeNow = System.currentTimeMillis();
+            int timeIdle = (int) ((timeNow - thisAccessedTime) / 1000L);
+            if (timeIdle >= maxInactiveInterval) {
+                expire(true);
+            }
+        }
+        return this.isValid;
+    }
+
+    public void setValid(boolean isValid) {
+        this.isValid = isValid;
+    }
+
+    /**
+     * Update the accessed time information for this session.  This method
+     * should be called by the context when a request comes in for a particular
+     * session, even if the application does not reference it.
+     */
+    public void access() {
+        this.lastAccessedTime = this.thisAccessedTime;
+        this.thisAccessedTime = System.currentTimeMillis();
+
+        evaluateIfValid();
+        accessCount++;
+    }
+
+
+    /**
+     * End the access.
+     */
+    public void endAccess() {
+        isNew = false;
+        accessCount--;
+    }
+
+    /**
+     * Perform the internal processing required to invalidate this session,
+     * without triggering an exception if the session has already expired.
+     */
+    public void expire() {
+        expire(true);
+    }
+
+
+    /**
+     * Perform the internal processing required to invalidate this session,
+     * without triggering an exception if the session has already expired.
+     *
+     * @param notify Should we notify listeners about the demise of
+     *  this session?
+     */
+    public void expire(boolean notify) {
+
+        // Mark this session as "being expired" if needed
+        if (expiring)
+            return;
+
+        synchronized (this) {
+
+            if (manager == null)
+                return;
+
+            expiring = true;
+        
+            // Notify interested application event listeners
+            // FIXME - Assumes we call listeners in reverse order
+            ServletContext context = manager.getContext();
+            List listeners = manager.getEventListeners();
+            if (notify && (listeners.size() > 0)) {
+                HttpSessionEvent event =
+                    new HttpSessionEvent(getSession());
+                for (int i = 0; i < listeners.size(); i++) {
+                    Object listenerObj = listeners.get(i);
+                    int j = (listeners.size() - 1) - i;
+                    if (!(listenerObj instanceof HttpSessionListener))
+                        continue;
+                    HttpSessionListener listener =
+                        (HttpSessionListener) listenerObj;
+                    try {
+                        listener.sessionDestroyed(event);
+                    } catch (Throwable t) {
+                        manager.log.error("listener.sessionDestroyed", t);
+                    }
+                }
+            }
+            accessCount = 0;
+            isValid = false;
+
+            /*
+             * Compute how long this session has been alive, and update
+             * session manager's related properties accordingly
+             */
+            long timeNow = System.currentTimeMillis();
+            int timeAlive = (int) ((timeNow - creationTime)/1000);
+            manager.addExpiredSession(timeAlive);
+
+            // Remove this session from our manager's active sessions
+            manager.remove(this);
+
+            expiring = false;
+
+            // Unbind any objects associated with this session
+            String keys[] = keys();
+            for (int i = 0; i < keys.length; i++)
+                removeAttributeInternal(keys[i], notify);
+        }
+    }
+
+
+    /**
+     * Release all object references, and initialize instance variables, in
+     * preparation for reuse of this object.
+     */
+    public void recycle() {
+
+        // Reset the instance variables associated with this Session
+        attributes.clear();
+        creationTime = 0L;
+        expiring = false;
+        id = null;
+        lastAccessedTime = 0L;
+        maxInactiveInterval = -1;
+        accessCount = 0;
+        isNew = false;
+        isValid = false;
+        manager = null;
+
+    }
+
+    /**
+     * Return a string representation of this object.
+     */
+    public String toString() {
+
+        StringBuffer sb = new StringBuffer();
+        sb.append("StandardSession[");
+        sb.append(id);
+        sb.append("]");
+        return (sb.toString());
+    }
+
+    protected void evaluateIfValid() {
+        /*
+         * If this session has expired or is in the process of expiring or
+         * will never expire, return
+         */
+        if (!this.isValid || expiring || maxInactiveInterval < 0)
+            return;
+
+        isValid();
+
+    }
+              
+    /**
+     * Return the names of all currently defined session attributes
+     * as an array of Strings.  If there are no defined attributes, a
+     * zero-length array is returned.
+     */
+    protected String[] keys() {
+        return ((String[]) attributes.keySet().toArray(EMPTY_ARRAY));
+    }
+
+
+    /**
+     * Remove the object bound with the specified name from this session.  If
+     * the session does not have an object bound with this name, this method
+     * does nothing.
+     * <p>
+     * After this method executes, and if the object implements
+     * <code>HttpSessionBindingListener</code>, the container calls
+     * <code>valueUnbound()</code> on the object.
+     *
+     * @param name Name of the object to remove from this session.
+     * @param notify Should we notify interested listeners that this
+     *  attribute is being removed?
+     */
+    protected void removeAttributeInternal(String name, boolean notify) {
+        // Remove this attribute from our collection
+        Object value = attributes.remove(name);
+
+        // Do we need to do valueUnbound() and attributeRemoved() notification?
+        if (!notify || (value == null)) {
+            return;
+        }
+
+        // Call the valueUnbound() method if necessary
+        HttpSessionBindingEvent event = null;
+        if (value instanceof HttpSessionBindingListener) {
+            event = new HttpSessionBindingEvent(getSession(), name, value);
+            ((HttpSessionBindingListener) value).valueUnbound(event);
+        }
+
+        // Notify interested application event listeners
+        ServletContext context = manager.getContext();
+        List listeners = manager.getEventListeners();
+        if (listeners.size() == 0)
+            return;
+        for (int i = 0; i < listeners.size(); i++) {
+            if (!(listeners.get(i) instanceof HttpSessionAttributeListener))
+                continue;
+            HttpSessionAttributeListener listener =
+                (HttpSessionAttributeListener) listeners.get(i);
+            try {
+                if (event == null) {
+                    event = new HttpSessionBindingEvent
+                        (getSession(), name, value);
+                }
+                listener.attributeRemoved(event);
+            } catch (Throwable t) {
+                manager.log.error("listener.attributeRemoved", t);
+            }
+        }
+
+    }
+    
+}
+
+
+// ------------------------------------------------------------ Protected Class
+
+
+/**
+ * This class is a dummy implementation of the <code>HttpSessionContext</code>
+ * interface, to conform to the requirement that such an object be returned
+ * when <code>HttpSession.getSessionContext()</code> is called.
+ *
+ * @author Craig R. McClanahan
+ *
+ * @deprecated As of Java Servlet API 2.1 with no replacement.  The
+ *  interface will be removed in a future version of this API.
+ */
+
+final class StandardSessionContext implements HttpSessionContext {
+
+
+    protected HashMap dummy = new HashMap();
+
+    /**
+     * Return the session identifiers of all sessions defined
+     * within this context.
+     *
+     * @deprecated As of Java Servlet API 2.1 with no replacement.
+     *  This method must return an empty <code>Enumeration</code>
+     *  and will be removed in a future version of the API.
+     */
+    public Enumeration getIds() {
+
+        return (new Enumerator(dummy));
+
+    }
+
+
+    /**
+     * Return the <code>HttpSession</code> associated with the
+     * specified session identifier.
+     *
+     * @param id Session identifier for which to look up a session
+     *
+     * @deprecated As of Java Servlet API 2.1 with no replacement.
+     *  This method must return null and will be removed in a
+     *  future version of the API.
+     */
+    public HttpSession getSession(String id) {
+
+        return (null);
+
+    }
+
+
+
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


Mime
View raw message