You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@apache.org on 2006/06/20 23:45:28 UTC

svn commit: r415818 [3/3] - in /tomcat/sandbox: java/org/apache/coyote/servlet/ java/org/apache/coyote/servlet/mapper/ java/org/apache/coyote/servlet/servlets/ java/org/apache/coyote/servlet/util/ java/org/apache/coyote/servlet/webxml/ java/org/apache/...

Added: tomcat/sandbox/java/org/apache/coyote/servlet/WebappServletMapper.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/coyote/servlet/WebappServletMapper.java?rev=415818&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/coyote/servlet/WebappServletMapper.java (added)
+++ tomcat/sandbox/java/org/apache/coyote/servlet/WebappServletMapper.java Tue Jun 20 14:45:26 2006
@@ -0,0 +1,855 @@
+/*
+ *  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 org.apache.coyote.servlet.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 {
+
+
+    private static org.apache.commons.logging.Log logger =
+        org.apache.commons.logging.LogFactory.getLog(WebappServletMapper.class);
+    // ----------------------------------------------------- Instance Variables
+
+    /**
+     * 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;
+
+    }
+
+
+    // ---------------------------------------------------- Context Inner Class
+
+
+    public static final class ContextMapElement
+        extends MapElement {
+
+        public ContextMapElement() {
+            System.err.println("XXX");
+        }
+        public String path = null;
+        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;
+
+    }
+
+
+    // ---------------------------------------------------- Wrapper Inner Class
+
+
+    public static class WrapperMapElement
+        extends MapElement {
+
+        public String path = null;
+        public boolean jspWildCard = false;
+    }
+   
+}

Copied: tomcat/sandbox/java/org/apache/coyote/servlet/WebappSessionManager.java (from r410655, tomcat/sandbox/java/org/apache/coyote/servlet/SessionManager.java)
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/coyote/servlet/WebappSessionManager.java?p2=tomcat/sandbox/java/org/apache/coyote/servlet/WebappSessionManager.java&p1=tomcat/sandbox/java/org/apache/coyote/servlet/SessionManager.java&r1=410655&r2=415818&rev=415818&view=diff
==============================================================================
--- tomcat/sandbox/java/org/apache/coyote/servlet/SessionManager.java (original)
+++ tomcat/sandbox/java/org/apache/coyote/servlet/WebappSessionManager.java Tue Jun 20 14:45:26 2006
@@ -54,8 +54,8 @@
  * @version $Revision: 303871 $ $Date: 2005-04-19 05:15:51 -0700 (Tue, 19 Apr 2005) $
  */
 
-public class SessionManager {
-    protected Log log = LogFactory.getLog(SessionManager.class);
+public class WebappSessionManager {
+    protected Log log = LogFactory.getLog(WebappSessionManager.class);
 
     // ----------------------------------------------------- Instance Variables
 

Added: tomcat/sandbox/java/org/apache/coyote/servlet/servlets/ReloadServlet.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/coyote/servlet/servlets/ReloadServlet.java?rev=415818&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/coyote/servlet/servlets/ReloadServlet.java (added)
+++ tomcat/sandbox/java/org/apache/coyote/servlet/servlets/ReloadServlet.java Tue Jun 20 14:45:26 2006
@@ -0,0 +1,23 @@
+package org.apache.coyote.servlet.servlets;
+
+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.coyote.servlet.CoyoteServletFacade;
+
+public class ReloadServlet extends HttpServlet {
+
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
+            throws ServletException, IOException {
+        
+        CoyoteServletFacade servletImpl = CoyoteServletFacade.getServletImpl();
+        servletImpl.reloadServletContext(getServletContext());
+        
+    }
+
+    
+}

Added: tomcat/sandbox/java/org/apache/coyote/servlet/util/MappingData.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/coyote/servlet/util/MappingData.java?rev=415818&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/coyote/servlet/util/MappingData.java (added)
+++ tomcat/sandbox/java/org/apache/coyote/servlet/util/MappingData.java Tue Jun 20 14:45:26 2006
@@ -0,0 +1,52 @@
+/*
+ *  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.util;
+
+import org.apache.tomcat.util.buf.MessageBytes;
+
+/**
+ * Mapping data.
+ *
+ * @author Remy Maucherat
+ */
+public class MappingData {
+
+    public Object host = null;
+    public Object context = null;
+    public Object wrapper = null;
+    public boolean jspWildCard = false;
+
+    public MessageBytes contextPath = MessageBytes.newInstance();
+    public MessageBytes requestPath = MessageBytes.newInstance();
+    public MessageBytes wrapperPath = MessageBytes.newInstance();
+    public MessageBytes pathInfo = MessageBytes.newInstance();
+
+    public MessageBytes redirectPath = MessageBytes.newInstance();
+
+    public void recycle() {
+        host = null;
+        context = null;
+        wrapper = null;
+        pathInfo.recycle();
+        requestPath.recycle();
+        wrapperPath.recycle();
+        contextPath.recycle();
+        redirectPath.recycle();
+        jspWildCard = false;
+    }
+
+}

Modified: tomcat/sandbox/java/org/apache/coyote/servlet/util/MessageWriter.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/coyote/servlet/util/MessageWriter.java?rev=415818&r1=415817&r2=415818&view=diff
==============================================================================
--- tomcat/sandbox/java/org/apache/coyote/servlet/util/MessageWriter.java (original)
+++ tomcat/sandbox/java/org/apache/coyote/servlet/util/MessageWriter.java Tue Jun 20 14:45:26 2006
@@ -52,7 +52,7 @@
     implements ByteChunk.ByteOutputChannel, CharChunk.CharOutputChannel {
 
     // used in getWriter, until a method is added to res.
-    private static final int WRITER_NOTE = 3;
+    private static final int WRITER_NOTE = 9;
 
     // -------------------------------------------------------------- Constants
 

Added: tomcat/sandbox/java/org/apache/coyote/servlet/webxml/WebXml.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/coyote/servlet/webxml/WebXml.java?rev=415818&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/coyote/servlet/webxml/WebXml.java (added)
+++ tomcat/sandbox/java/org/apache/coyote/servlet/webxml/WebXml.java Tue Jun 20 14:45:26 2006
@@ -0,0 +1,237 @@
+/*
+ */
+package org.apache.coyote.servlet.webxml;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+import org.apache.coyote.servlet.CoyoteServletFacade;
+import org.apache.coyote.servlet.ServletConfigImpl;
+import org.apache.coyote.servlet.ServletContextImpl;
+import org.apache.tomcat.util.DomUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+public class WebXml {
+    ServletContextImpl ctx;
+    CoyoteServletFacade facade = CoyoteServletFacade.getServletImpl();
+    
+    public WebXml(ServletContext sctx) {
+        ctx = (ServletContextImpl) sctx;
+    }
+
+    public void readWebXml(String baseDir) throws ServletException {
+        try {
+            File webXmlFile = new File( baseDir + "/WEB-INF/web.xml");
+            if (!webXmlFile.exists()) {
+                return;
+            }
+            FileInputStream fileInputStream = new FileInputStream(webXmlFile);
+            Document document = 
+                DomUtil.readXml(fileInputStream);
+            
+            Node webappNode = DomUtil.getChild(document, "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 ) {
+                processContextParam(confNode);
+                confNode = DomUtil.getNext(confNode);
+            }
+
+            confNode = DomUtil.getChild(webappNode, "mime-mapping");
+            while (confNode != null ) {
+                processFilterMapping(confNode);
+                confNode = DomUtil.getNext(confNode);
+            }
+
+            confNode = DomUtil.getChild(webappNode, "error-page");
+            while (confNode != null ) {
+                processFilterMapping(confNode);
+                confNode = DomUtil.getNext(confNode);
+            }
+
+            confNode = DomUtil.getChild(webappNode, "jsp-config");
+            while (confNode != null ) {
+                processFilterMapping(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 ) {
+                processListener(confNode);
+                confNode = DomUtil.getNext(confNode);
+            }
+
+            confNode = DomUtil.getChild(webappNode, "security-constraint");
+            while (confNode != null ) {
+                processListener(confNode);
+                confNode = DomUtil.getNext(confNode);
+            }
+
+            confNode = DomUtil.getChild(webappNode, "login-config");
+            while (confNode != null ) {
+                processListener(confNode);
+                confNode = DomUtil.getNext(confNode);
+                if (confNode != null) 
+                    throw new ServletException("Multiple login-config");
+            }
+
+            confNode = DomUtil.getChild(webappNode, "session-config");
+            while (confNode != null ) {
+                processListener(confNode);
+                confNode = DomUtil.getNext(confNode);
+                if (confNode != null) 
+                    throw new ServletException("Multiple session-config");
+            }
+
+            confNode = DomUtil.getChild(webappNode, "security-role");
+            while (confNode != null ) {
+                processListener(confNode);
+                confNode = DomUtil.getNext(confNode);
+            }
+
+
+            confNode = DomUtil.getChild(webappNode, "env-entry");
+            while (confNode != null ) {
+                processListener(confNode);
+                confNode = DomUtil.getNext(confNode);
+            }
+
+            // concatenate
+            confNode = DomUtil.getChild(webappNode, "welcome-file-list");
+            while (confNode != null ) {
+                processListener(confNode);
+                confNode = DomUtil.getNext(confNode);
+            }
+
+            // concatenate
+            confNode = DomUtil.getChild(webappNode, "locale-encoding-mapping-list");
+            while (confNode != null ) {
+                processListener(confNode);
+                confNode = DomUtil.getNext(confNode);
+            }
+
+            // TODO: warning about uniqueness of servlet name, filter name
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new ServletException(e);
+        }
+    }
+    
+    private void processContextParam(Node confNode) {
+        ctx.getContextParameters().put("", "");
+    }
+
+    
+    /** Process anotations.
+     */
+    private void processMetadata() {
+        
+    }
+    
+    private void processListener(Node confNode) {
+        String lClass = DomUtil.getChildContent(confNode, "listener-class");
+        ctx.getListenersClassName().add(lClass);
+    }
+
+    private void processServlet(Node confNode) throws ServletException {
+        String name = DomUtil.getChildContent(confNode,"servlet-name");
+        String sclass = DomUtil.getChildContent(confNode,"servlet-class");
+        
+        HashMap initParams = new HashMap();
+        processInitParams(confNode, initParams);
+        
+        ServletConfigImpl wrapper = (ServletConfigImpl) 
+            facade.createServletWrapper(ctx, name, sclass, initParams);
+        
+        ctx.addServletConfig((ServletConfigImpl) wrapper);
+    }
+
+    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);
+            confNode = DomUtil.getNext(initN);
+        }
+    }
+
+    private void processServletMapping(Node confNode) {
+        String name = DomUtil.getChildContent(confNode,"servlet-name");
+        String path = DomUtil.getChildContent(confNode,"url-pattern");
+
+        ServletConfigImpl wrapper = ctx.getServletConfig(name);
+        facade.addMapping(path, wrapper);
+    }
+
+    private void processFilterMapping(Node confNode) {
+        String name = 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);
+        }
+        String[] dispA = new String[ dispatchers.size() ];
+        if (dispA.length > 0) {
+            dispatchers.toArray(dispA);
+        }
+        
+        dataN = DomUtil.getChild(confNode, "url-pattern");
+        while (dataN != null ) {
+            String path = DomUtil.getContent(dataN);
+            dataN = DomUtil.getNext(dataN);
+            ctx.getFilterMapper().addMapping(name, path, null, dispA);
+        }
+        dataN = DomUtil.getChild(confNode, "servlet-name");
+        while (dataN != null ) {
+            String sn = DomUtil.getContent(dataN);
+            dataN = DomUtil.getNext(dataN);
+            ctx.getFilterMapper().addMapping(name, null, sn, dispA);
+        }
+    }
+
+    private void processFilter(Node confNode) {
+        String name = DomUtil.getChildContent(confNode,"filter-name");
+        String sclass = DomUtil.getChildContent(confNode,"filter-class");
+        
+        HashMap initParams = new HashMap();
+        processInitParams(confNode, initParams);
+
+        ctx.addFilter(name, sclass, initParams);
+    }
+    
+}

Added: tomcat/sandbox/resources/coyote-servlet.MF
URL: http://svn.apache.org/viewvc/tomcat/sandbox/resources/coyote-servlet.MF?rev=415818&view=auto
==============================================================================
--- tomcat/sandbox/resources/coyote-servlet.MF (added)
+++ tomcat/sandbox/resources/coyote-servlet.MF Tue Jun 20 14:45:26 2006
@@ -0,0 +1,2 @@
+Manifest-version: 1.0
+Main-Class: org.apache.coyote.servlet.Main

Propchange: tomcat/sandbox/resources/coyote-servlet.MF
------------------------------------------------------------------------------
    svn:executable = *



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