FileDocCategorySizeDatePackage
Mapper.javaAPI DocApache Tomcat 6.0.1448880Fri Jul 20 04:20:32 BST 2007org.apache.tomcat.util.http.mapper

Mapper

public final class Mapper extends Object
Mapper, which implements the servlet API mapping rules (which are derived from the HTTP rules).
author
Remy Maucherat

Fields Summary
private static org.apache.juli.logging.Log
logger
protected Host[]
hosts
Array containing the virtual hosts definitions.
protected String
defaultHostName
Default host name.
protected Context
context
Context associated with this wrapper, used for wrapper mapping.
Constructors Summary
Methods Summary
public voidaddContext(java.lang.String hostName, java.lang.String path, java.lang.Object context, java.lang.String[] welcomeResources, javax.naming.Context resources)
Add a new Context to an existing Host.

param
hostName Virtual host name this context belongs to
param
path Context path
param
context Context object
param
welcomeResources Welcome files defined for this context
param
resources Static resources of the context


        Host[] hosts = this.hosts;
        int pos = find(hosts, hostName);
        if( pos <0 ) {
            addHost(hostName, new String[0], "");
            hosts = this.hosts;
            pos = find(hosts, hostName);
        }
        if (pos < 0) {
            logger.error("No host found: " + hostName);
        }
        Host host = hosts[pos];
        if (host.name.equals(hostName)) {
            int slashCount = slashCount(path);
            synchronized (host) {
                Context[] contexts = host.contextList.contexts;
                // Update nesting
                if (slashCount > host.contextList.nesting) {
                    host.contextList.nesting = slashCount;
                }
                Context[] newContexts = new Context[contexts.length + 1];
                Context newContext = new Context();
                newContext.name = path;
                newContext.object = context;
                newContext.welcomeResources = welcomeResources;
                newContext.resources = resources;
                if (insertMap(contexts, newContexts, newContext)) {
                    host.contextList.contexts = newContexts;
                }
            }
        }

    
public synchronized voidaddHost(java.lang.String name, java.lang.String[] aliases, java.lang.Object host)
Add a new host to the mapper.

param
name Virtual host name
param
host Host object

        Host[] newHosts = new Host[hosts.length + 1];
        Host newHost = new Host();
        ContextList contextList = new ContextList();
        newHost.name = name;
        newHost.contextList = contextList;
        newHost.object = host;
        if (insertMap(hosts, newHosts, newHost)) {
            hosts = newHosts;
        }
        for (int i = 0; i < aliases.length; i++) {
            newHosts = new Host[hosts.length + 1];
            newHost = new Host();
            newHost.name = aliases[i];
            newHost.contextList = contextList;
            newHost.object = host;
            if (insertMap(hosts, newHosts, newHost)) {
                hosts = newHosts;
            }
        }
    
public voidaddWrapper(java.lang.String hostName, java.lang.String contextPath, java.lang.String path, java.lang.Object wrapper)
Add a new Wrapper to an existing Context.

param
hostName Virtual host name this wrapper belongs to
param
contextPath Context path this wrapper belongs to
param
path Wrapper mapping
param
wrapper Wrapper object

        addWrapper(hostName, contextPath, path, wrapper, false);
    
public voidaddWrapper(java.lang.String hostName, java.lang.String contextPath, java.lang.String path, java.lang.Object wrapper, boolean jspWildCard)

        Host[] hosts = this.hosts;
        int pos = find(hosts, hostName);
        if (pos < 0) {
            return;
        }
        Host host = hosts[pos];
        if (host.name.equals(hostName)) {
            Context[] contexts = host.contextList.contexts;
            int pos2 = find(contexts, contextPath);
            if( pos2<0 ) {
                logger.error("No context found: " + contextPath );
                return;
            }
            Context context = contexts[pos2];
            if (context.name.equals(contextPath)) {
                addWrapper(context, path, wrapper, jspWildCard);
            }
        }
    
public voidaddWrapper(java.lang.String path, java.lang.Object wrapper)
Add a wrapper to the context associated with this wrapper.

param
path Wrapper mapping
param
wrapper The Wrapper object

        addWrapper(context, path, wrapper);
    
public voidaddWrapper(java.lang.String path, java.lang.Object wrapper, boolean jspWildCard)

        addWrapper(context, path, wrapper, jspWildCard);
    
protected voidaddWrapper(org.apache.tomcat.util.http.mapper.Mapper$Context context, java.lang.String path, java.lang.Object wrapper)

        addWrapper(context, path, wrapper, false);
    
protected voidaddWrapper(org.apache.tomcat.util.http.mapper.Mapper$Context context, java.lang.String path, java.lang.Object wrapper, boolean jspWildCard)
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


        synchronized (context) {
            Wrapper newWrapper = new Wrapper();
            newWrapper.object = wrapper;
            newWrapper.jspWildCard = jspWildCard;
            if (path.endsWith("/*")) {
                // Wildcard wrapper
                newWrapper.name = path.substring(0, path.length() - 2);
                Wrapper[] oldWrappers = context.wildcardWrappers;
                Wrapper[] newWrappers =
                    new Wrapper[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);
                Wrapper[] oldWrappers = context.extensionWrappers;
                Wrapper[] newWrappers =
                    new Wrapper[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;
                Wrapper[] oldWrappers = context.exactWrappers;
                Wrapper[] newWrappers =
                    new Wrapper[oldWrappers.length + 1];
                if (insertMap(oldWrappers, newWrappers, newWrapper)) {
                    context.exactWrappers = newWrappers;
                }
            }
        }
    
private static final intcompare(org.apache.tomcat.util.buf.CharChunk name, int start, int end, java.lang.String compareTo)
Compare given char chunk with String. Return -1, 0 or +1 if inferior, equal, or superior to the String.

        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;
    
private static final intcompareIgnoreCase(org.apache.tomcat.util.buf.CharChunk name, int start, int end, java.lang.String compareTo)
Compare given char chunk with String ignoring case. Return -1, 0 or +1 if inferior, equal, or superior to the String.

        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;
    
private static final intfind(org.apache.tomcat.util.http.mapper.Mapper$MapElement[] map, org.apache.tomcat.util.buf.CharChunk name)
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.

        return find(map, name, name.getStart(), name.getEnd());
    
private static final intfind(org.apache.tomcat.util.http.mapper.Mapper$MapElement[] map, org.apache.tomcat.util.buf.CharChunk name, int start, int end)
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.


        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;
                }
            }
        }

    
private static final intfind(org.apache.tomcat.util.http.mapper.Mapper$MapElement[] map, java.lang.String name)
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.


        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;
                }
            }
        }

    
private static final intfindIgnoreCase(org.apache.tomcat.util.http.mapper.Mapper$MapElement[] map, org.apache.tomcat.util.buf.CharChunk name)
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.

        return findIgnoreCase(map, name, name.getStart(), name.getEnd());
    
private static final intfindIgnoreCase(org.apache.tomcat.util.http.mapper.Mapper$MapElement[] map, org.apache.tomcat.util.buf.CharChunk name, int start, int end)
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.


        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;
                }
            }
        }

    
public java.lang.String[]getContextNames()
Return all contexts, in //HOST/PATH form

return
The context names

        List list=new ArrayList();
        for( int i=0; i<hosts.length; i++ ) {
            for( int j=0; j<hosts[i].contextList.contexts.length; j++ ) {
                String cname=hosts[i].contextList.contexts[j].name;
                list.add("//" + hosts[i].name +
                        (cname.startsWith("/") ? cname : "/"));
            }
        }
        String res[] = new String[list.size()];
        return (String[])list.toArray(res);
    
public java.lang.StringgetDefaultHostName()
Get default host.

return
Default host name



    // --------------------------------------------------------- Public Methods


                
       
        return defaultHostName;
    
public java.lang.String[]getHosts()

        String hostN[] = new String[hosts.length];
        for( int i = 0; i < hosts.length; i++ ) {
            hostN[i] = hosts[i].name;
        }
        return hostN;
    
public java.lang.String[]getWrapperNames(java.lang.String host, java.lang.String context)

        List list=new ArrayList();
        if( host==null ) host="";
        if( context==null ) context="";
        for( int i=0; i<hosts.length; i++ ) {
            if( ! host.equals( hosts[i].name ))
                continue;
            for( int j=0; j<hosts[i].contextList.contexts.length; j++ ) {
                if( ! context.equals( hosts[i].contextList.contexts[j].name))
                    continue;
                // found the context
                Context ctx=hosts[i].contextList.contexts[j];
                list.add( ctx.defaultWrapper.path);
                for( int k=0; k<ctx.exactWrappers.length; k++ ) {
                    list.add( ctx.exactWrappers[k].path);
                }
                for( int k=0; k<ctx.wildcardWrappers.length; k++ ) {
                    list.add( ctx.wildcardWrappers[k].path + "*");
                }
                for( int k=0; k<ctx.extensionWrappers.length; k++ ) {
                    list.add( "*." + ctx.extensionWrappers[k].path);
                }
            }
        }
        String res[]=new String[list.size()];
        return (String[])list.toArray(res);
    
public java.lang.StringgetWrappersString(java.lang.String host, java.lang.String context)

        String names[]=getWrapperNames(host, context);
        StringBuffer sb=new StringBuffer();
        for( int i=0; i<names.length; i++ ) {
            sb.append(names[i]).append(":");
        }
        return sb.toString();
    
private static final booleaninsertMap(org.apache.tomcat.util.http.mapper.Mapper$MapElement[] oldMap, org.apache.tomcat.util.http.mapper.Mapper$MapElement[] newMap, org.apache.tomcat.util.http.mapper.Mapper$MapElement newElement)
Insert into the right place in a sorted MapElement array, and prevent duplicates.

        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;
    
private final voidinternalMap(org.apache.tomcat.util.buf.CharChunk host, org.apache.tomcat.util.buf.CharChunk uri, MappingData mappingData)
Map the specified URI.


        uri.setLimit(-1);

        Context[] contexts = null;
        Context context = null;
        int nesting = 0;

        // Virtual host mapping
        if (mappingData.host == null) {
            Host[] hosts = this.hosts;
            int pos = findIgnoreCase(hosts, host);
            if ((pos != -1) && (host.equalsIgnoreCase(hosts[pos].name))) {
                mappingData.host = hosts[pos].object;
                contexts = hosts[pos].contextList.contexts;
                nesting = hosts[pos].contextList.nesting;
            } else {
                if (defaultHostName == null) {
                    return;
                }
                pos = find(hosts, defaultHostName);
                if ((pos != -1) && (defaultHostName.equals(hosts[pos].name))) {
                    mappingData.host = hosts[pos].object;
                    contexts = hosts[pos].contextList.contexts;
                    nesting = hosts[pos].contextList.nesting;
                } else {
                    return;
                }
            }
        }

        // Context mapping
        if (mappingData.context == null) {
            int pos = find(contexts, uri);
            if (pos == -1) {
                return;
            }

            int lastSlash = -1;
            int uriEnd = uri.getEnd();
            int length = -1;
            boolean found = false;
            while (pos >= 0) {
                if (uri.startsWith(contexts[pos].name)) {
                    length = contexts[pos].name.length();
                    if (uri.getLength() == length) {
                        found = true;
                        break;
                    } else if (uri.startsWithIgnoreCase("/", length)) {
                        found = true;
                        break;
                    }
                }
                if (lastSlash == -1) {
                    lastSlash = nthSlash(uri, nesting + 1);
                } else {
                    lastSlash = lastSlash(uri);
                }
                uri.setEnd(lastSlash);
                pos = find(contexts, uri);
            }
            uri.setEnd(uriEnd);

            if (!found) {
                if (contexts[0].name.equals("")) {
                    context = contexts[0];
                }
            } else {
                context = contexts[pos];
            }
            if (context != null) {
                mappingData.context = context.object;
                mappingData.contextPath.setString(context.name);
            }
        }

        // Wrapper mapping
        if ((context != null) && (mappingData.wrapper == null)) {
            internalMapWrapper(context, uri, mappingData);
        }

    
private final voidinternalMapExactWrapper(org.apache.tomcat.util.http.mapper.Mapper$Wrapper[] wrappers, org.apache.tomcat.util.buf.CharChunk path, MappingData mappingData)
Exact mapping.

        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;
        }
    
private final voidinternalMapExtensionWrapper(org.apache.tomcat.util.http.mapper.Mapper$Wrapper[] wrappers, org.apache.tomcat.util.buf.CharChunk path, MappingData mappingData)
Extension mappings.

        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);
            }
        }
    
private final voidinternalMapWildcardWrapper(org.apache.tomcat.util.http.mapper.Mapper$Wrapper[] wrappers, int nesting, org.apache.tomcat.util.buf.CharChunk path, MappingData mappingData)
Wildcard mapping.


        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;
            }
        }
    
private final voidinternalMapWrapper(org.apache.tomcat.util.http.mapper.Mapper$Context context, org.apache.tomcat.util.buf.CharChunk path, MappingData mappingData)
Wrapper mapping.


        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
        Wrapper[] exactWrappers = context.exactWrappers;
        internalMapExactWrapper(exactWrappers, path, mappingData);

        // Rule 2 -- Prefix Match
        boolean checkJspWelcomeFiles = false;
        Wrapper[] 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
        Wrapper[] extensionWrappers = context.extensionWrappers;
        if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
            internalMapExtensionWrapper(extensionWrappers, path, mappingData);
        }

        // 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) {
                        Object file = null;
                        String pathStr = path.toString();
                        try {
                            file = context.resources.lookup(pathStr);
                        } catch(NamingException nex) {
                            // Swallow not found, since this is normal
                        }
                        if (file != null && !(file instanceof DirContext) ) {
                            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 ] != '/") {
                Object file = null;
                String pathStr = path.toString();
                try {
                    file = context.resources.lookup(pathStr);
                } catch(NamingException nex) {
                    // Swallow, since someone else handles the 404
                }
                if (file != null && file instanceof DirContext) {
                    // 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);

    
private static final intlastSlash(org.apache.tomcat.util.buf.CharChunk name)
Find the position of the last slash in the given char chunk.


        char[] c = name.getBuffer();
        int end = name.getEnd();
        int start = name.getStart();
        int pos = end;

        while (pos > start) {
            if (c[--pos] == '/") {
                break;
            }
        }

        return (pos);

    
public voidmap(org.apache.tomcat.util.buf.MessageBytes host, org.apache.tomcat.util.buf.MessageBytes uri, MappingData mappingData)
Map the specified host name and URI, mutating the given mapping data.

param
host Virtual host name
param
uri URI
param
mappingData This structure will contain the result of the mapping operation


        if (host.isNull()) {
            host.getCharChunk().append(defaultHostName);
        }
        host.toChars();
        uri.toChars();
        internalMap(host.getCharChunk(), uri.getCharChunk(), mappingData);

    
public voidmap(org.apache.tomcat.util.buf.MessageBytes uri, MappingData mappingData)
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


        uri.toChars();
        CharChunk uricc = uri.getCharChunk();
        uricc.setLimit(-1);
        internalMapWrapper(context, uricc, mappingData);

    
private static final intnthSlash(org.apache.tomcat.util.buf.CharChunk name, int n)
Find the position of the nth slash, in the given char chunk.


        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);

    
public voidremoveContext(java.lang.String hostName, java.lang.String path)
Remove a context from an existing host.

param
hostName Virtual host name this context belongs to
param
path Context path

        Host[] hosts = this.hosts;
        int pos = find(hosts, hostName);
        if (pos < 0) {
            return;
        }
        Host host = hosts[pos];
        if (host.name.equals(hostName)) {
            synchronized (host) {
                Context[] contexts = host.contextList.contexts;
                if( contexts.length == 0 ){
                    return;
                }
                Context[] newContexts = new Context[contexts.length - 1];
                if (removeMap(contexts, newContexts, path)) {
                    host.contextList.contexts = newContexts;
                    // Recalculate nesting
                    host.contextList.nesting = 0;
                    for (int i = 0; i < newContexts.length; i++) {
                        int slashCount = slashCount(newContexts[i].name);
                        if (slashCount > host.contextList.nesting) {
                            host.contextList.nesting = slashCount;
                        }
                    }
                }
            }
        }
    
public synchronized voidremoveHost(java.lang.String name)
Remove a host from the mapper.

param
name Virtual host name

        // Find and remove the old host
        int pos = find(hosts, name);
        if (pos < 0) {
            return;
        }
        Object host = hosts[pos].object;
        Host[] newHosts = new Host[hosts.length - 1];
        if (removeMap(hosts, newHosts, name)) {
            hosts = newHosts;
        }
        // Remove all aliases (they will map to the same host object)
        for (int i = 0; i < newHosts.length; i++) {
            if (newHosts[i].object == host) {
                Host[] newHosts2 = new Host[hosts.length - 1];
                if (removeMap(hosts, newHosts2, newHosts[i].name)) {
                    hosts = newHosts2;
                }
            }
        }
    
private static final booleanremoveMap(org.apache.tomcat.util.http.mapper.Mapper$MapElement[] oldMap, org.apache.tomcat.util.http.mapper.Mapper$MapElement[] newMap, java.lang.String name)
Insert into the right place in a sorted MapElement array.

        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;
    
public voidremoveWrapper(java.lang.String path)
Remove a wrapper from the context associated with this wrapper.

param
path Wrapper mapping

        removeWrapper(context, path);
    
public voidremoveWrapper(java.lang.String hostName, java.lang.String contextPath, java.lang.String path)
Remove a wrapper from an existing context.

param
hostName Virtual host name this wrapper belongs to
param
contextPath Context path this wrapper belongs to
param
path Wrapper mapping

        Host[] hosts = this.hosts;
        int pos = find(hosts, hostName);
        if (pos < 0) {
            return;
        }
        Host host = hosts[pos];
        if (host.name.equals(hostName)) {
            Context[] contexts = host.contextList.contexts;
            int pos2 = find(contexts, contextPath);
            if (pos2 < 0) {
                return;
            }
            Context context = contexts[pos2];
            if (context.name.equals(contextPath)) {
                removeWrapper(context, path);
            }
        }
    
protected voidremoveWrapper(org.apache.tomcat.util.http.mapper.Mapper$Context context, java.lang.String path)

        synchronized (context) {
            if (path.endsWith("/*")) {
                // Wildcard wrapper
                String name = path.substring(0, path.length() - 2);
                Wrapper[] oldWrappers = context.wildcardWrappers;
                Wrapper[] newWrappers =
                    new Wrapper[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);
                Wrapper[] oldWrappers = context.extensionWrappers;
                Wrapper[] newWrappers =
                    new Wrapper[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;
                Wrapper[] oldWrappers = context.exactWrappers;
                Wrapper[] newWrappers =
                    new Wrapper[oldWrappers.length - 1];
                if (removeMap(oldWrappers, newWrappers, name)) {
                    context.exactWrappers = newWrappers;
                }
            }
        }
    
public voidsetContext(java.lang.String path, java.lang.String[] welcomeResources, javax.naming.Context resources)
Set context, used for wrapper mapping (request dispatcher).

param
welcomeResources Welcome files defined for this context
param
resources Static resources of the context

        context.name = path;
        context.welcomeResources = welcomeResources;
        context.resources = resources;
    
public voidsetDefaultHostName(java.lang.String defaultHostName)
Set default host.

param
defaultHostName Default host name

        this.defaultHostName = defaultHostName;
    
private static final intslashCount(java.lang.String name)
Return the slash count in a given string.

        int pos = -1;
        int count = 0;
        while ((pos = name.indexOf('/", pos + 1)) != -1) {
            count++;
        }
        return count;