/*
* Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
* Copyright 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.glassfish.grizzly.http.server.util;
import org.glassfish.grizzly.http.HttpRequestPacket;
import org.glassfish.grizzly.http.util.Constants;
import java.io.IOException;
import java.util.logging.Level;
import org.glassfish.grizzly.Grizzly;
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import java.util.logging.Logger;
import org.glassfish.grizzly.http.server.naming.DirContext;
import org.glassfish.grizzly.http.server.naming.NamingContext;
import org.glassfish.grizzly.http.server.naming.NamingException;
import org.glassfish.grizzly.http.util.Ascii;
import org.glassfish.grizzly.http.util.CharChunk;
import org.glassfish.grizzly.http.util.DataChunk;
import org.glassfish.grizzly.http.util.MessageBytes;
import org.glassfish.grizzly.utils.Charsets;
Mapper, which implements the servlet API mapping rules (which are derived
from the HTTP rules).
/**
* Mapper, which implements the servlet API mapping rules (which are derived
* from the HTTP rules).
*
*/
@SuppressWarnings({"UnusedDeclaration"})
public class Mapper {
private final static Logger logger = Grizzly.logger(Mapper.class);
private static final String DEFAULT_SERVLET =
System.getProperty("org.glassfish.grizzly.servlet.defaultServlet", "default");
private static final String JSP_SERVLET =
System.getProperty("org.glassfish.grizzly.servlet.jspServlet", "jsp");
private static final CharChunk SLASH = new CharChunk();
/**
* Allow replacement of already added {@link Host}, {@link Context}
* and {@link Wrapper}
*/
private static boolean allowReplacement = false;
static {
try {
SLASH.append('/');
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
// ----------------------------------------------------- Instance Variables
Array containing the virtual hosts definitions.
/**
* Array containing the virtual hosts definitions.
*/
protected Host[] hosts = new Host[0];
Default host name.
/**
* Default host name.
*/
protected String defaultHostName = null;
Context associated with this wrapper, used for wrapper mapping.
/**
* Context associated with this wrapper, used for wrapper mapping.
*/
protected final Context context = new Context();
// START GlassFish 1024
private final Map<String, String> defaultContextPathsMap = new HashMap<>();
The port this Mapper is used
/**
* The port this Mapper is used
*/
private int port = 0;
// --------------------------------------------------------- Public Methods
Allow replacement of already added Host
, Context
and Wrapper
when invoking addHost
, addContext
etc. Default is false
/**
* Allow replacement of already added {@link Host}, {@link Context} and
* {@link Wrapper} when invoking {@link #addHost}, {@link #addContext} etc.
* Default is <tt>false</tt>
*/
public static void setAllowReplacement(boolean ar){
allowReplacement = ar;
}
true if replacement of already added [@link Host}, Context
and Wrapper
when invoking addHost
, addContext
etc. Default is false
/**
* <tt>true</tt> if replacement of already added [@link Host}, {@link Context} and
* {@link Wrapper} when invoking {@link #addHost}, {@link #addContext} etc.
* Default is <tt>false</tt>
*/
public static boolean allowReplacement(){
return allowReplacement;
}
The Port this instance is used for mapping.
/**
* The Port this instance is used for mapping.
*/
public void setPort(int port){
this.port = port;
}
Returns: the port this instance is used for mapping.
/**
* @return the port this instance is used for mapping.
*/
public int getPort(){
return port;
}
Returns: Default host name
/**
* @return Default host name
*/
public String getDefaultHostName() {
return defaultHostName;
}
Set default host.
Params: - defaultHostName – Default host name
/**
* Set default host.
*
* @param defaultHostName Default host name
*/
public void setDefaultHostName(String defaultHostName) {
this.defaultHostName = defaultHostName;
}
Add a new host to the mapper.
Params: - name – Virtual host name
- host – Host object
/**
* Add a new host to the mapper.
*
* @param name Virtual host name
* @param host Host object
*/
public synchronized void addHost(String name, String[] aliases, Object host) {
Host[] newHosts = new Host[hosts.length + 1];
Host newHost = new Host();
ContextList contextList = new ContextList();
// START GlassFish 1024
Context[] defaultContexts = new Context[1];
String[] defaultContextPaths = new String[1];
// END GlassFish 1024
newHost.name = name;
newHost.contextList = contextList;
newHost.object = host;
// START GlassFish 1024
newHost.defaultContexts = defaultContexts;
newHost.defaultContextPaths = defaultContextPaths;
// END GlassFish 1024
Host oldElem = (Host) insertMapIgnoreCase(hosts, newHosts, newHost);
if (oldElem == null) {
hosts = newHosts;
} else if (allowReplacement) {
oldElem.object = host;
contextList = oldElem.contextList;
}
for (String alias : aliases) {
newHosts = new Host[hosts.length + 1];
newHost = new Host();
newHost.name = alias;
newHost.contextList = contextList;
// START GlassFish 1024
newHost.defaultContexts = defaultContexts;
newHost.defaultContextPaths = defaultContextPaths;
// END GlassFish 1024
newHost.object = host;
if (insertMapIgnoreCase(hosts, newHosts, newHost) == null) {
hosts = newHosts;
}
}
String defaultContextPath = defaultContextPathsMap.get(name);
if (defaultContextPath != null) {
newHost.defaultContextPaths[0] = defaultContextPath;
}
}
Remove a host from the mapper.
Params: - name – Virtual host name
/**
* Remove a host from the mapper.
*
* @param name Virtual host name
*/
public synchronized void removeHost(String name) {
// Find and remove the old host
int pos = findIgnoreCase(hosts, name);
if (pos < 0) {
return;
}
Object host = hosts[pos].object;
Host[] newHosts = new Host[hosts.length - 1];
if (removeMapIgnoreCase(hosts, newHosts, name)) {
hosts = newHosts;
}
// Remove all aliases (they will map to the same host object)
for (Host newHost : newHosts) {
if (newHost.object == host) {
Host[] newHosts2 = new Host[hosts.length - 1];
if (removeMapIgnoreCase(hosts, newHosts2, newHost.name)) {
hosts = newHosts2;
}
}
}
// START GlassFish 1024
defaultContextPathsMap.remove(name);
// END GlassFish 1024
}
public String[] getHosts() {
String hostN[] = new String[hosts.length];
for( int i = 0; i < hosts.length; i++ ) {
hostN[i] = hosts[i].name;
}
return hostN;
}
Set context, used for wrapper mapping (request dispatcher).
Params: - welcomeResources – Welcome files defined for this context
- resources – Static resources of the context
/**
* 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,
NamingContext resources) {
context.name = path;
context.welcomeResources = welcomeResources;
context.resources = resources;
}
Add a new Context to an existing Host.
Params: - hostName – Virtual host name this context belongs to
- path – Context path
- context – Context object
- welcomeResources – Welcome files defined for this context
- resources – Static resources of the context
/**
* 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
*/
public void addContext
(String hostName, String path, Object context,
String[] welcomeResources, NamingContext resources) {
addContext(hostName, path, context, welcomeResources, resources, null);
}
Add a new Context to an existing Host.
Params: - hostName – Virtual host name this context belongs to
- path – Context path
- context – Context object
- welcomeResources – Welcome files defined for this context
- resources – Static resources of the context
- alternateDocBases – the alternate docbases of the context
/**
* 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
* @param alternateDocBases the alternate docbases of the context
*/
public void addContext
(String hostName, String path, Object context,
String[] welcomeResources, NamingContext resources,
List<AlternateDocBase> alternateDocBases) {
Host[] newHosts = hosts;
int pos = findIgnoreCase(newHosts, hostName);
if( pos <0 ) {
addHost(hostName, new String[0], "");
newHosts = hosts;
pos = findIgnoreCase(newHosts, hostName);
}
if (pos < 0) {
logger.log(Level.FINE, "No host found: {0} for Mapper listening on port: {1}",
new Object[]{hostName, port});
return;
}
Host host = newHosts[pos];
if (host.name.equalsIgnoreCase(hostName)) {
int slashCount = slashCount(path);
//noinspection SynchronizationOnLocalVariableOrMethodParameter
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;
newContext.alternateDocBases = alternateDocBases;
Context oldElem = (Context) insertMap(contexts, newContexts, newContext);
if (oldElem == null) {
host.contextList.contexts = newContexts;
// START GlassFish 1024
if (path.equals(host.defaultContextPaths[0])) {
host.defaultContexts[0] = newContext;
}
// END GlassFish 1024
} else if (allowReplacement) {
oldElem.object = context;
oldElem.welcomeResources = welcomeResources;
oldElem.resources = resources;
}
}
}
}
Remove a context from an existing host.
Params: - hostName – Virtual host name this context belongs to
- path – Context path
/**
* Remove a context from an existing host.
*
* @param hostName Virtual host name this context belongs to
* @param path Context path
*/
public void removeContext(String hostName, String path) {
Host[] newHosts = hosts;
int pos = findIgnoreCase(newHosts, hostName);
if (pos < 0) {
return;
}
Host host = newHosts[pos];
if (host.name.equalsIgnoreCase(hostName)) {
//noinspection SynchronizationOnLocalVariableOrMethodParameter
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 (Context newContext : newContexts) {
int slashCount = slashCount(newContext.name);
if (slashCount > host.contextList.nesting) {
host.contextList.nesting = slashCount;
}
}
}
}
}
}
Return all contexts, in //HOST/PATH form
Returns: The context names
/**
* Return all contexts, in //HOST/PATH form
*
* @return The context names
*/
public String[] getContextNames() {
List<String> list= new ArrayList<>();
for (Host host : hosts) {
for (int j = 0; j < host.contextList.contexts.length; j++) {
String cname = host.contextList.contexts[j].name;
list.add("//" + host.name + (cname.startsWith("/") ? cname : "/"));
}
}
String res[] = new String[list.size()];
return list.toArray(res);
}
Add a new Wrapper to an existing Context.
Params: - hostName – Virtual host name this wrapper belongs to
- contextPath – Context path this wrapper belongs to
- path – Wrapper mapping
- wrapper – Wrapper object
/**
* 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
*/
public void addWrapper(String hostName, String contextPath, String path,
Object wrapper) {
addWrapper(hostName, contextPath, path, wrapper, false);
}
Add a new Wrapper to an existing Context.
Params: - hostName – Virtual host name this wrapper belongs to
- contextPath – Context path this wrapper belongs to
- path – Wrapper mapping
- wrapper – Wrapper object
- jspWildCard – jsp wildcard
/**
* 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
* @param jspWildCard jsp wildcard
*/
public void addWrapper(String hostName, String contextPath, String path,
Object wrapper, boolean jspWildCard) {
addWrapper(hostName, contextPath, path, wrapper, jspWildCard, null, false);
}
Add a new Wrapper to an existing Context.
Params: - hostName – Virtual host name this wrapper belongs to
- contextPath – Context path this wrapper belongs to
- path – Wrapper mapping
- wrapper – Wrapper object
- jspWildCard – jsp wildcard
- servletName – servlet name or null if unknown
/**
* 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
* @param jspWildCard jsp wildcard
* @param servletName servlet name or null if unknown
*/
public void addWrapper(String hostName, String contextPath, String path,
Object wrapper, boolean jspWildCard,
String servletName, boolean isEmptyPathSpecial) {
Host[] newHosts = hosts;
int pos = findIgnoreCase(newHosts, hostName);
if (pos < 0) {
return;
}
Host host = newHosts[pos];
if (host.name.equalsIgnoreCase(hostName)) {
Context[] contexts = host.contextList.contexts;
int pos2 = find(contexts, contextPath);
if( pos2<0 ) {
logger.log(Level.SEVERE, "No context found: {0}", contextPath);
return;
}
Context ctx = contexts[pos2];
if (ctx.name.equals(contextPath)) {
addWrapper(ctx, path, wrapper, jspWildCard, servletName, isEmptyPathSpecial);
}
}
}
Add a wrapper to the context associated with this wrapper.
Params: - path – Wrapper mapping
- wrapper – The Wrapper object
/**
* 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(context, path, wrapper);
}
public void addWrapper(String path, Object wrapper, boolean jspWildCard,
boolean isEmptyPathSpecial) {
addWrapper(context, path, wrapper, jspWildCard, isEmptyPathSpecial);
}
public void addWrapper(String path, Object wrapper, boolean jspWildCard,
String servletName, boolean isEmptyPathSpecial) {
addWrapper(context, path, wrapper, jspWildCard, servletName,
isEmptyPathSpecial);
}
protected void addWrapper(Context context, String path, Object wrapper) {
addWrapper(context, path, wrapper, false, false);
}
protected void addWrapper(Context context, String path, Object wrapper,
boolean jspWildCard, boolean isEmptyPathSpecial) {
addWrapper(context, path, wrapper, jspWildCard, null, isEmptyPathSpecial);
}
Adds a wrapper to the given context.
Params: - context – The context to which to add the wrapper
- path – Wrapper mapping
- wrapper – The Wrapper object
- jspWildCard – true if the wrapper corresponds to the JspServlet
and the mapping path contains a wildcard; false otherwise
- servletName – then name of servletName or null if unknown
/**
* 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
* @param servletName then name of servletName or null if unknown
*/
protected void addWrapper(Context context, String path, Object wrapper, boolean jspWildCard, String servletName,
boolean isEmptyPathSpecial) {
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (context) {
Wrapper newWrapper = new Wrapper();
newWrapper.object = wrapper;
newWrapper.jspWildCard = jspWildCard;
newWrapper.servletName = servletName;
newWrapper.path = path;
if (path.endsWith("/*")) {
// Wildcard wrapper
newWrapper.name = path.substring(0, path.length() - 2);
Wrapper[] oldWrappers = context.wildcardWrappers;
Wrapper[] newWrappers =
new Wrapper[oldWrappers.length + 1];
Wrapper oldElem = (Wrapper)
insertMap(oldWrappers, newWrappers, newWrapper);
if (oldElem == null) {
context.wildcardWrappers = newWrappers;
int slashCount = slashCount(newWrapper.name);
if (slashCount > context.nesting) {
context.nesting = slashCount;
}
} else if (allowReplacement) {
oldElem.object = wrapper;
oldElem.jspWildCard = jspWildCard;
}
} else if (path.startsWith("*.")) {
// Extension wrapper
newWrapper.name = path.substring(2);
Wrapper[] oldWrappers = context.extensionWrappers;
Wrapper[] newWrappers =
new Wrapper[oldWrappers.length + 1];
Wrapper oldElem = (Wrapper)insertMap(oldWrappers, newWrappers, newWrapper);
if (oldElem == null) {
context.extensionWrappers = newWrappers;
} else if (allowReplacement){
oldElem.object = wrapper;
oldElem.jspWildCard = jspWildCard;
}
} else {
boolean isSlashPath = "/".equals(path);
if (isSlashPath) {
// Default wrapper
newWrapper.name = "";
context.defaultWrapper = newWrapper;
}
// Exact wrapper
// also for "/" and non default servlet
if (!isSlashPath || !DEFAULT_SERVLET.equals(servletName)) {
newWrapper.name = path;
if (isEmptyPathSpecial && path.length() == 0) {
context.emptyPathWrapper = newWrapper;
} else {
Wrapper[] oldWrappers = context.exactWrappers;
Wrapper[] newWrappers =
new Wrapper[oldWrappers.length + 1];
Wrapper oldElem = (Wrapper)insertMap(oldWrappers,
newWrappers, newWrapper);
if (oldElem == null) {
context.exactWrappers = newWrappers;
} else if (allowReplacement){
oldElem.object = wrapper;
oldElem.jspWildCard = jspWildCard;
}
}
}
}
}
}
Remove a wrapper from the context associated with this wrapper.
Params: - path – Wrapper mapping
/**
* Remove a wrapper from the context associated with this wrapper.
*
* @param path Wrapper mapping
*/
public void removeWrapper(String path) {
removeWrapper(context, path);
}
Remove a wrapper from an existing context.
Params: - hostName – Virtual host name this wrapper belongs to
- contextPath – Context path this wrapper belongs to
- path – Wrapper mapping
/**
* 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
*/
public void removeWrapper
(String hostName, String contextPath, String path) {
Host[] newHosts = hosts;
int pos = findIgnoreCase(newHosts, hostName);
if (pos < 0) {
return;
}
Host host = newHosts[pos];
if (host.name.equalsIgnoreCase(hostName)) {
Context[] contexts = host.contextList.contexts;
int pos2 = find(contexts, contextPath);
if (pos2 < 0) {
return;
}
Context ctx = contexts[pos2];
if (ctx.name.equals(contextPath)) {
removeWrapper(ctx, path);
}
}
}
protected void removeWrapper(Context context, String path) {
//noinspection SynchronizationOnLocalVariableOrMethodParameter
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 (Wrapper newWrapper : newWrappers) {
int slashCount = slashCount(newWrapper.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 ("/".equals(path)) {
// Default wrapper
context.defaultWrapper = null;
} else {
// Exact wrapper
Wrapper[] oldWrappers = context.exactWrappers;
Wrapper[] newWrappers =
new Wrapper[oldWrappers.length - 1];
if (removeMap(oldWrappers, newWrappers, path)) {
context.exactWrappers = newWrappers;
}
}
}
}
public String getWrappersString( String host, String context ) {
String names[]=getWrapperNames(host, context);
StringBuilder sb=new StringBuilder();
for (String name : names) {
sb.append(name).append(":");
}
return sb.toString();
}
public String[] getWrapperNames( String host, String context ) {
List<String> list= new ArrayList<>();
if( host==null ) host="";
if( context==null ) context="";
for (Host host1 : hosts) {
if (!host.equals(host1.name)) {
continue;
}
for (int j = 0; j < host1.contextList.contexts.length; j++) {
if (!context.equals(host1.contextList.contexts[j].name)) {
continue;
}
// found the context
Context ctx = host1.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 list.toArray(res);
}
// START GlassFish 1024
Configures the given virtual server with the given default context path.
The given default path corresponds to the context path of one of the
web contexts deployed on the virtual server that has been designated as
the virtual server's new default-web-module.
Throws: - Exception – if there is no web context deployed on the given
virtual server that matches the given default context path
/**
* Configures the given virtual server with the given default context path.
*
* The given default path corresponds to the context path of one of the
* web contexts deployed on the virtual server that has been designated as
* the virtual server's new default-web-module.
*
* @throws Exception if there is no web context deployed on the given
* virtual server that matches the given default context path
*/
public void setDefaultContextPath(String hostName,
String defaultContextPath)
throws Exception {
if (defaultContextPath != null) {
defaultContextPathsMap.put(hostName, defaultContextPath);
}
int pos = findIgnoreCase(hosts, hostName);
if (pos < 0) {
return;
}
hosts[pos].defaultContextPaths[0] = defaultContextPath;
if (defaultContextPath != null) {
addDefaultContext(hosts[pos], defaultContextPath);
} else {
hosts[pos].defaultContexts[0] = null;
defaultContextPathsMap.remove(hostName);
}
}
Configures the given virtual server with the given default context path.
The given default path corresponds to the context path of one of the
web contexts deployed on the virtual server that has been designated as
the virtual server's new default-web-module.
Throws: - Exception – if there is no web context deployed on the given
virtual server that matches the given default context path
/**
* Configures the given virtual server with the given default context path.
*
* The given default path corresponds to the context path of one of the
* web contexts deployed on the virtual server that has been designated as
* the virtual server's new default-web-module.
*
* @throws Exception if there is no web context deployed on the given
* virtual server that matches the given default context path
*/
private void addDefaultContext(Host host, String defaultContextPath)
throws Exception {
boolean defaultContextFound = false;
Context[] contexts = host.contextList.contexts;
if (contexts != null) {
for (Context context1 : contexts) {
if (context1.name.equals(defaultContextPath)) {
host.defaultContexts[0] = context1;
defaultContextFound = true;
break;
}
}
}
if (!defaultContextFound) {
throw new Exception("No context matching " + defaultContextPath
+ " deployed on virtual server "
+ host.name);
}
}
// END GlassFish 1024
Maps the decodedURI to the corresponding HttpHandler, considering that URI
may have a semicolon with extra data followed, which shouldn't be a part
of mapping process.
Params: - requestPacket – the request packet containing the host information
to be used by the mapping process.
- decodedURI – decoded URI
- mappingData –
MappingData
based on the URI. - semicolonPos – semicolon position. Might be 0 if position
wasn't resolved yet (so it will be resolved in the method),
or -1 if there is no semicolon in the URI.
Throws: - Exception – if an error occurs mapping the request
/**
* Maps the decodedURI to the corresponding HttpHandler, considering that URI
* may have a semicolon with extra data followed, which shouldn't be a part
* of mapping process.
*
* @param requestPacket the request packet containing the host information
* to be used by the mapping process.
* @param decodedURI decoded URI
* @param mappingData {@link MappingData} based on the URI.
* @param semicolonPos semicolon position. Might be <tt>0</tt> if position
* wasn't resolved yet (so it will be resolved in the method),
* or <tt>-1</tt> if there is no semicolon in the URI.
* @throws Exception if an error occurs mapping the request
*/
public void mapUriWithSemicolon(final HttpRequestPacket requestPacket,
final DataChunk decodedURI,
final MappingData mappingData,
int semicolonPos) throws Exception {
final CharChunk charChunk = decodedURI.getCharChunk();
final int oldEnd = charChunk.getEnd();
if (semicolonPos == 0) {
semicolonPos = decodedURI.indexOf(';', 0);
}
DataChunk localDecodedURI = decodedURI;
if (semicolonPos >= 0) {
charChunk.setEnd(semicolonPos);
// duplicate the URI path, because Mapper may corrupt the attributes,
// which follow the path
localDecodedURI = mappingData.tmpMapperDC;
localDecodedURI.duplicate(decodedURI);
}
map(requestPacket, localDecodedURI, mappingData);
charChunk.setEnd(oldEnd);
}
Maps the decodedURI to the corresponding HttpHandler, considering that URI
may have a semicolon with extra data followed, which shouldn't be a part
of mapping process.
Params: - serverName – the server name as described by the Host header.
- decodedURI – decoded URI
- mappingData –
MappingData
based on the URI. - semicolonPos – semicolon position. Might be 0 if position
wasn't resolved yet (so it will be resolved in the method),
or -1 if there is no semicolon in the URI.
Throws: - Exception – if an error occurs mapping the request
/**
* Maps the decodedURI to the corresponding HttpHandler, considering that URI
* may have a semicolon with extra data followed, which shouldn't be a part
* of mapping process.
*
* @param serverName the server name as described by the Host header.
* @param decodedURI decoded URI
* @param mappingData {@link MappingData} based on the URI.
* @param semicolonPos semicolon position. Might be <tt>0</tt> if position
* wasn't resolved yet (so it will be resolved in the method),
* or <tt>-1</tt> if there is no semicolon in the URI.
*
* @throws Exception if an error occurs mapping the request
*/
public void mapUriWithSemicolon(final DataChunk serverName,
final DataChunk decodedURI,
final MappingData mappingData,
int semicolonPos)
throws Exception {
final CharChunk charChunk = decodedURI.getCharChunk();
final int oldEnd = charChunk.getEnd();
if (semicolonPos == 0) {
semicolonPos = decodedURI.indexOf(';', 0);
}
DataChunk localDecodedURI = decodedURI;
if (semicolonPos >= 0) {
charChunk.setEnd(semicolonPos);
// duplicate the URI path, because Mapper may corrupt the attributes,
// which follow the path
localDecodedURI = mappingData.tmpMapperDC;
localDecodedURI.duplicate(decodedURI);
}
map(serverName, localDecodedURI, mappingData);
charChunk.setEnd(oldEnd);
}
Map the specified host name and URI, mutating the given mapping data.
Params: - host – Virtual host name
- uri – URI
- mappingData – This structure will contain the result of the mapping
operation
/**
* 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
*/
public void map(final DataChunk host, final DataChunk uri,
final MappingData mappingData) throws Exception {
if (host.isNull()) {
host.getCharChunk().append(defaultHostName);
} else if (host.getLength() == 0) {
throw new Exception("Host is not set");
}
host.toChars(Constants.DEFAULT_HTTP_CHARSET);
uri.toChars(Charsets.UTF8_CHARSET);
internalMap(host.getCharChunk(), uri.getCharChunk(), mappingData);
}
Map the specified host name and URI, mutating the given mapping data.
Params: - requestPacket – the http request containing host name information
used by the mapping process.
- uri – URI
- mappingData – This structure will contain the result of the mapping
operation
/**
* Map the specified host name and URI, mutating the given mapping data.
*
* @param requestPacket the http request containing host name information
* used by the mapping process.
* @param uri URI
* @param mappingData This structure will contain the result of the mapping
* operation
*/
public void map(final HttpRequestPacket requestPacket, final DataChunk uri,
final MappingData mappingData) throws Exception {
final CharChunk hostCC;
if (hosts.length > 1) {
final DataChunk host = requestPacket.serverName();
if (host.isNull()) {
host.getCharChunk().append(defaultHostName);
} else if (host.getLength() == 0) {
throw new Exception("Host is not set");
} else {
host.toChars(Constants.DEFAULT_HTTP_CHARSET);
}
hostCC = host.getCharChunk();
} else {
hostCC = null;
}
uri.toChars(Charsets.UTF8_CHARSET);
internalMap(hostCC,
uri.getCharChunk(),
mappingData);
}
Map the specified URI relative to the context,
mutating the given mapping data.
Params: - uri – URI
- mappingData – This structure will contain the result of the mapping
operation
/**
* 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(context, uricc, mappingData);
}
// -------------------------------------------------------- Private Methods
Map the specified URI.
/**
* Map the specified URI.
*/
private void internalMap(CharChunk host, CharChunk uri,
MappingData mappingData)
throws Exception {
uri.setLimit(-1);
Context[] contexts = null;
Context ctx = null;
int nesting = 0;
int hostPos = -1;
// Virtual host mapping
if (mappingData.host == null) {
Host[] newHosts = hosts;
int pos = host == null || host.isNull() ?
-1 :
findIgnoreCase(newHosts, host);
if (pos != -1 && host.equalsIgnoreCase(newHosts[pos].name)) {
mappingData.host = newHosts[pos].object;
hostPos = pos;
contexts = newHosts[pos].contextList.contexts;
nesting = newHosts[pos].contextList.nesting;
} else {
if (defaultHostName == null) {
return;
}
pos = findIgnoreCase(newHosts, defaultHostName);
if (pos != -1 && defaultHostName.equalsIgnoreCase(newHosts[pos].name)) {
mappingData.host = newHosts[pos].object;
hostPos = pos;
contexts = newHosts[pos].contextList.contexts;
nesting = newHosts[pos].contextList.nesting;
} else {
return;
}
}
}
// Context mapping
if (mappingData.context == null) {
// START GlassFish 1024
boolean found = false;
// END GlassFish 1024
int pos = find(contexts, uri);
if (pos == -1) {
// START GlassFish 1024
if (hosts[hostPos].defaultContexts[0] == null) {
// END GlassFish 1024
return;
// START GlassFish 1024
}
ctx = hosts[hostPos].defaultContexts[0];
mappingData.context = ctx.object;
mappingData.contextPath.setString(ctx.name);
found = true;
mappingData.isDefaultContext = true;
// END GlassFish 1024
}
// START GlassFish 1024
if (!found) {
// END GlassFish 1024
int lastSlash = -1;
int uriEnd = uri.getEnd();
int length;
/* GlassFish 1024
boolean found = false;
*/
while (pos >= 0) {
if (contexts != null && 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 != null && "".equals(contexts[0].name)) {
ctx = contexts[0];
// START GlassFish 1024
} else if (hosts[hostPos].defaultContexts[0] != null) {
ctx = hosts[hostPos].defaultContexts[0];
mappingData.isDefaultContext = true;
// END GlassFish 1024
}
} else {
ctx = contexts[pos];
}
if (ctx != null) {
mappingData.context = ctx.object;
mappingData.contextPath.setString(ctx.name);
}
}
}
// Wrapper mapping
if (ctx != null && mappingData.wrapper == null) {
internalMapWrapper(ctx, uri, mappingData);
}
}
Wrapper mapping.
/**
* Wrapper mapping.
*/
private void internalMapWrapper(Context context, CharChunk path,
MappingData mappingData)
throws Exception {
int pathOffset = path.getStart();
int pathEnd = path.getEnd();
int servletPath;
boolean noServletPath = false;
// START GlassFish 1024
if (mappingData.isDefaultContext) {
servletPath = pathOffset;
} else {
// END GlassFish 1024
int length = context.name.length();
if (length != pathEnd - pathOffset) {
servletPath = pathOffset + length;
} else {
noServletPath = true;
path.append('/');
pathOffset = path.getStart();
pathEnd = path.getEnd();
servletPath = pathOffset+length;
}
// START GlassFish 1024
}
// END GlassFish 1024
path.setStart(servletPath);
// Rule 0 -- Empty path match
if (context.emptyPathWrapper != null) {
if (path.equals(SLASH)) {
mappingData.wrapper = context.emptyPathWrapper.object;
mappingData.requestPath.setString("");
mappingData.wrapperPath.setString("");
mappingData.pathInfo.setString("/");
mappingData.mappingType = MappingData.CONTEXT_ROOT;
mappingData.descriptorPath = "/";
mappingData.matchedPath = "/";
}
}
// Rule 1 -- Exact Match
Wrapper[] exactWrappers = context.exactWrappers;
if (mappingData.wrapper == null) {
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.getEnd());
mappingData.pathInfo.recycle();
}
}
}
if (noServletPath) {
boolean redirect = mappingData.wrapper == null;
if (!redirect) {
String wpath = mappingData.wrapperPath.toString();
// correspond to url-pattern /*
redirect = wpath != null && wpath.length() == 0;
}
if (redirect) {
// 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 && pathEnd > 0) {
char[] buf = path.getBuffer();
checkWelcomeFiles = buf[pathEnd - 1] == '/';
}
if (checkWelcomeFiles) {
// Rule 4a -- Static welcome resources
for (int i = 0; i < context.welcomeResources.length
&& mappingData.wrapper == null; i++) {
path.setStart(pathOffset);
path.setEnd(pathEnd);
path.append(context.welcomeResources[i], 0,
context.welcomeResources[i].length());
path.setStart(servletPath);
// Welcome resources processing for physical folder
if (mappingData.wrapper == null &&
context.resources != null) {
Object file = null;
String pathStr = path.toString();
if (context.alternateDocBases == null
|| context.alternateDocBases.isEmpty()) {
try {
file = context.resources.lookup(pathStr);
} catch(NamingException nex) {
// Swallow not found, since this is normal
}
} else {
AlternateDocBase match =
AlternateDocBase.findMatch(pathStr,
context.alternateDocBases);
if (match != null) {
try {
file = match.getResources().lookup(pathStr);
} catch(NamingException nex) {
// Swallow not found, since this is normal
}
} else {
// None of the url patterns for alternate
// docbases matched
try {
file = context.resources.lookup(pathStr);
} catch(NamingException nex) {
// Swallow not found, since this is normal
}
}
}
if (file != null && !(file instanceof DirContext) ) {
// Rule 4a1 -- exact match
internalMapExactWrapper(exactWrappers, path, mappingData);
// Rule 4a2 -- prefix match
if (mappingData.wrapper == null) {
internalMapWildcardWrapper(wildcardWrappers,
context.nesting, path, mappingData);
}
// Rule 4a3 -- extension match
if (mappingData.wrapper == null) {
internalMapExtensionWrapper(extensionWrappers,
path, mappingData);
}
// Rule 4a4 use default
if (mappingData.wrapper == null
&& context.defaultWrapper != null) {
mappingData.wrapper =
context.defaultWrapper.object;
mappingData.servletName =
context.defaultWrapper.servletName;
mappingData.requestPath.setChars
(path.getBuffer(), path.getStart(),
path.getEnd());
mappingData.wrapperPath.setChars
(path.getBuffer(), path.getStart(),
path.getEnd());
mappingData.requestPath.setString(pathStr);
mappingData.wrapperPath.setString(pathStr);
mappingData.mappingType = MappingData.DEFAULT;
mappingData.descriptorPath = "/";
mappingData.matchedPath = "/";
}
}
}
}
// Rule 4b -- Non-static welcome resources
if (mappingData.wrapper == null) {
for (int i = 0; i < context.welcomeResources.length
&& mappingData.wrapper == null; i++) {
path.setStart(pathOffset);
path.setEnd(pathEnd);
path.append(context.welcomeResources[i], 0,
context.welcomeResources[i].length());
path.setStart(servletPath);
// Rule 4b1 -- Welcome resources processing for exact match
internalMapExactWrapper(exactWrappers, path, mappingData);
// Rule 4b2 -- Welcome resources processing for prefix match
if (mappingData.wrapper == null) {
internalMapWildcardWrapper
(wildcardWrappers, context.nesting,
path, mappingData);
}
// Rule 4b3 -- Welcome resources processing for extension match
if (mappingData.wrapper == null) {
internalMapExtensionWrapper(
extensionWrappers, path, mappingData);
}
// cannot use jsp as the file does not exist
if (mappingData.wrapper != null &&
JSP_SERVLET.equals(mappingData.servletName)) {
mappingData.wrapper = null;
}
}
}
path.setStart(servletPath);
path.setEnd(pathEnd);
}
}
// Rule 7 -- Default servlet
if (mappingData.wrapper == null && !checkJspWelcomeFiles) {
if (context.defaultWrapper != null) {
mappingData.wrapper = context.defaultWrapper.object;
mappingData.servletName = context.defaultWrapper.servletName;
mappingData.requestPath.setChars
(path.getBuffer(), path.getStart(), path.getEnd());
mappingData.wrapperPath.setChars
(path.getBuffer(), path.getStart(), path.getEnd());
mappingData.mappingType = MappingData.DEFAULT;
mappingData.descriptorPath = "/";
mappingData.matchedPath = mappingData.requestPath.toString();
}
// Redirection to a folder
char[] buf = path.getBuffer();
if (context.resources != null && pathEnd > 0 && buf[pathEnd -1 ] != '/') {
Object file = null;
String pathStr = path.toString();
if (context.alternateDocBases == null
|| context.alternateDocBases.isEmpty()) {
try {
file = context.resources.lookup(pathStr);
} catch(NamingException nex) {
// Swallow, since someone else handles the 404
}
} else {
AlternateDocBase match =
AlternateDocBase.findMatch(pathStr,
context.alternateDocBases);
if (match != null) {
try {
file = match.getResources().lookup(pathStr);
} catch(NamingException nex) {
// Swallow, since someone else handles the 404
}
} else {
// None of the url patterns for alternate
// docbases matched
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.setStart(pathOffset);
path.append('/');
mappingData.redirectPath.setChars
(path.getBuffer(), path.getStart(), path.getEnd());
} else {
mappingData.requestPath.setString(pathStr);
mappingData.wrapperPath.setString(pathStr);
}
}
}
path.setStart(pathOffset);
path.setEnd(pathEnd);
}
Exact mapping.
/**
* Exact mapping.
*/
private void internalMapExactWrapper
(Wrapper[] 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;
mappingData.servletName = wrappers[pos].servletName;
mappingData.descriptorPath = wrappers[pos].path;
mappingData.matchedPath = path.toString();
mappingData.mappingType =
(("/".equals(mappingData.matchedPath))
? MappingData.DEFAULT
: MappingData.EXACT);
}
}
Wildcard mapping.
/**
* Wildcard mapping.
*/
private void internalMapWildcardWrapper
(Wrapper[] wrappers, int nesting, CharChunk path,
MappingData mappingData) {
int pathEnd = path.getEnd();
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.getStart() + length,
path.getEnd());
}
mappingData.requestPath.setChars
(path.getBuffer(), path.getStart(), path.getEnd());
mappingData.wrapper = wrappers[pos].object;
mappingData.servletName = wrappers[pos].servletName;
mappingData.jspWildCard = wrappers[pos].jspWildCard;
mappingData.mappingType = MappingData.PATH;
mappingData.descriptorPath = wrappers[pos].path;
mappingData.matchedPath = path.toString();
}
}
}
Extension mappings.
/**
* Extension mappings.
*/
private void internalMapExtensionWrapper
(Wrapper[] wrappers, CharChunk path, MappingData mappingData) {
char[] buf = path.getBuffer();
int pathEnd = path.getEnd();
int servletPath = path.getStart();
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.setStart(period + 1);
path.setEnd(pathEnd);
int pos = find(wrappers, path);
if (pos != -1
&& path.equals(wrappers[pos].name)) {
mappingData.wrapperPath.setChars
(buf, servletPath, pathEnd);
mappingData.requestPath.setChars
(buf, servletPath, pathEnd);
mappingData.wrapper = wrappers[pos].object;
mappingData.servletName = wrappers[pos].servletName;
mappingData.mappingType = MappingData.EXTENSION;
mappingData.descriptorPath = wrappers[pos].path;
}
path.setStart(servletPath);
path.setEnd(pathEnd);
mappingData.matchedPath = path.toString();
}
}
}
Find a map element 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.
/**
* Find a map element 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 int find(MapElement[] map, CharChunk name) {
return find(map, name, name.getStart(), name.getEnd());
}
Find a map element 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.
/**
* Find a map element 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 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;
while (true) {
i = (b + a) >>> 1;
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 element 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 int findIgnoreCase(MapElement[] map, String name) {
// CharChunk cc = new CharChunk();
// char[] chars = name.toCharArray();
// cc.setChars(chars, 0, chars.length);
// return findIgnoreCase(map, cc);
// }
Find a map element 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.
/**
* Find a map element 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 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.
/**
* 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 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;
while (true) {
i = (b + a) >>> 1;
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.
/**
* 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 int findIgnoreCase(final MapElement[] map, final String name) {
int a = 0;
int b = map.length - 1;
// Special cases: -1 and 0
if (b == -1) {
return -1;
}
if (compareIgnoreCase(name, map[0].name) < 0 ) {
return -1;
}
if (b == 0) {
return 0;
}
int i;
while (true) {
i = (b + a) >>> 1;
int result = compareIgnoreCase(name, 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, map[b].name);
if (result2 < 0) {
return a;
} else {
return b;
}
}
}
}
Find a map element 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.
/**
* Find a map element 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 int find(final MapElement[] map, final 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;
while (true) {
i = (b + a) >>> 1;
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.
/**
* Compare given char chunk with String.
* Return -1, 0 or +1 if inferior, equal, or superior to the String.
*/
private static 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.
/**
* Compare given char chunk with String ignoring case.
* Return -1, 0 or +1 if inferior, equal, or superior to the String.
*/
private static 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;
}
Compare given char chunk with String ignoring case.
Return -1, 0 or +1 if inferior, equal, or superior to the String.
/**
* Compare given char chunk with String ignoring case.
* Return -1, 0 or +1 if inferior, equal, or superior to the String.
*/
private static int compareIgnoreCase(String name, String compareTo) {
int result = 0;
final int nameLen = name.length();
final int compareToLen = compareTo.length();
final int len = nameLen < compareToLen ? nameLen : compareToLen;
for (int i = 0; i < len && result == 0; i++) {
final int nameLower = Ascii.toLower(name.charAt(i));
final int compareToLower = Ascii.toLower(compareTo.charAt(i));
if (nameLower > compareToLower) {
result = 1;
} else if (nameLower < compareToLower) {
result = -1;
}
}
if (result == 0) {
if (compareToLen > nameLen) {
result = -1;
} else if (compareToLen < nameLen) {
result = 1;
}
}
return result;
}
Find the position of the last slash in the given char chunk.
/**
* Find the position of the last slash in the given char chunk.
*/
private static 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.
/**
* Find the position of the nth slash, in the given char chunk.
*/
private static int nthSlash(CharChunk name, int n) {
char[] c = name.getBuffer();
int end = name.getEnd();
int pos = name.getStart();
int count = 0;
while (pos < end) {
if (c[pos++] == '/' && ++count == n) {
pos--;
break;
}
}
return pos;
}
Return the slash count in a given string.
/**
* Return the slash count in a given string.
*/
private static 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, preventing
duplicates.
Returns: old MapElement with matching name (this is an indication that
newElement has not been inserted), or null if oldMap did not contain
any MapElement with matching name (this is an indication that
newElement has been inserted)
/**
* Insert into the right place in a sorted MapElement array, preventing
* duplicates.
*
* @return old MapElement with matching name (this is an indication that
* newElement has not been inserted), or null if oldMap did not contain
* any MapElement with matching name (this is an indication that
* newElement has been inserted)
*/
private static MapElement insertMap
(MapElement[] oldMap, MapElement[] newMap, MapElement newElement) {
int pos = find(oldMap, newElement.name);
if (pos != -1 && newElement.name.equals(oldMap[pos].name)) {
return oldMap[pos];
}
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 null;
}
Inserts the given MapElement at the appropriate place in the given,
lexicograhically sorted, MapElement array, avoiding duplicates.
Name comparisons are performed in a case-insensitive manner.
Returns: old MapElement with matching name (this is an indication that
newElement has not been inserted), or null if oldMap did not contain
any MapElement with matching name (this is an indication that
newElement has been inserted)
/**
* Inserts the given MapElement at the appropriate place in the given,
* lexicograhically sorted, MapElement array, avoiding duplicates.
*
* Name comparisons are performed in a case-insensitive manner.
*
* @return old MapElement with matching name (this is an indication that
* newElement has not been inserted), or null if oldMap did not contain
* any MapElement with matching name (this is an indication that
* newElement has been inserted)
*/
private static MapElement insertMapIgnoreCase
(MapElement[] oldMap, MapElement[] newMap, MapElement newElement) {
CharChunk cc = new CharChunk();
char[] chars = newElement.name.toCharArray();
cc.setChars(chars, 0, chars.length);
int pos = findIgnoreCase(oldMap, cc);
if (pos != -1 && newElement.name.equalsIgnoreCase(oldMap[pos].name)) {
return oldMap[pos];
}
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 null;
}
Removes from a sorted MapElement array.
/**
* Removes from a sorted MapElement array.
*/
private static 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;
}
Removes the MapElement with the given name from the given,
lexicographically sorted, MapElement array.
Name comparisons are performed in a case-insensitive manner.
/**
* Removes the MapElement with the given name from the given,
* lexicographically sorted, MapElement array.
*
* Name comparisons are performed in a case-insensitive manner.
*/
private static boolean removeMapIgnoreCase
(MapElement[] oldMap, MapElement[] newMap, String name) {
CharChunk cc = new CharChunk();
char[] chars = name.toCharArray();
cc.setChars(chars, 0, chars.length);
int pos = findIgnoreCase(oldMap, cc);
if (pos != -1 && name.equalsIgnoreCase(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 {
public String name = null;
public Object object = null;
}
// ------------------------------------------------------- Host Inner Class
protected static final class Host
extends MapElement {
public ContextList contextList = null;
// START GlassFish 1024
public String[] defaultContextPaths = null;
public Context[] defaultContexts = null;
// END GlassFish 1024
}
// ------------------------------------------------ ContextList Inner Class
protected static final class ContextList {
public Context[] contexts = new Context[0];
public int nesting = 0;
}
// ---------------------------------------------------- Context Inner Class
protected static final class Context
extends MapElement {
public String path = null;
public String[] welcomeResources = new String[0];
public NamingContext resources = null;
public List<AlternateDocBase> alternateDocBases = null;
public Wrapper defaultWrapper = null;
public Wrapper emptyPathWrapper = null;
public Wrapper[] exactWrappers = new Wrapper[0];
public Wrapper[] wildcardWrappers = new Wrapper[0];
public Wrapper[] extensionWrappers = new Wrapper[0];
public int nesting = 0;
}
// ---------------------------------------------------- Wrapper Inner Class
protected static class Wrapper
extends MapElement {
public String path = null;
public boolean jspWildCard = false;
public String servletName = null;
}
// -------------------------------------------------------- Testing Methods
// FIXME: Externalize this
/*
public static void main(String args[]) {
try {
Mapper mapper = new Mapper();
System.out.println("Start");
mapper.addHost("sjbjdvwsbvhrb", new String[0], "blah1");
mapper.addHost("sjbjdvwsbvhr/", new String[0], "blah1");
mapper.addHost("wekhfewuifweuibf", new String[0], "blah2");
mapper.addHost("ylwrehirkuewh", new String[0], "blah3");
mapper.addHost("iohgeoihro", new String[0], "blah4");
mapper.addHost("fwehoihoihwfeo", new String[0], "blah5");
mapper.addHost("owefojiwefoi", new String[0], "blah6");
mapper.addHost("iowejoiejfoiew", new String[0], "blah7");
mapper.addHost("iowejoiejfoiew", new String[0], "blah17");
mapper.addHost("ohewoihfewoih", new String[0], "blah8");
mapper.addHost("fewohfoweoih", new String[0], "blah9");
mapper.addHost("ttthtiuhwoih", new String[0], "blah10");
mapper.addHost("lkwefjwojweffewoih", new String[0], "blah11");
mapper.addHost("zzzuyopjvewpovewjhfewoih", new String[0], "blah12");
mapper.addHost("xxxxgqwiwoih", new String[0], "blah13");
mapper.addHost("qwigqwiwoih", new String[0], "blah14");
System.out.println("Map:");
for (int i = 0; i < mapper.hosts.length; i++) {
System.out.println(mapper.hosts[i].name);
}
mapper.setDefaultHostName("ylwrehirkuewh");
String[] welcomes = new String[2];
welcomes[0] = "boo/baba";
welcomes[1] = "bobou";
mapper.addContext("iowejoiejfoiew", "", "context0", new String[0], null);
mapper.addContext("iowejoiejfoiew", "/foo", "context1", new String[0], null);
mapper.addContext("iowejoiejfoiew", "/foo/bar", "context2", welcomes, null);
mapper.addContext("iowejoiejfoiew", "/foo/bar/bla", "context3", new String[0], null);
mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/fo/*", "wrapper0");
mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/", "wrapper1");
mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blh", "wrapper2");
mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "*.jsp", "wrapper3");
mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blah/bou/*", "wrapper4");
mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blah/bobou/*", "wrapper5");
mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "*.htm", "wrapper6");
MappingData mappingData = new MappingData();
MessageBytes host = MessageBytes.newInstance();
host.setString("iowejoiejfoiew");
MessageBytes uri = MessageBytes.newInstance();
uri.setString("/foo/bar/blah/bobou/foo");
uri.toChars();
uri.getCharChunk().setLimit(-1);
mapper.map(host, uri, mappingData);
System.out.println("MD Host:" + mappingData.host);
System.out.println("MD Context:" + mappingData.context);
System.out.println("MD Wrapper:" + mappingData.wrapper);
System.out.println("contextPath:" + mappingData.contextPath);
System.out.println("wrapperPath:" + mappingData.wrapperPath);
System.out.println("pathInfo:" + mappingData.pathInfo);
System.out.println("redirectPath:" + mappingData.redirectPath);
mappingData.recycle();
mapper.map(host, uri, mappingData);
System.out.println("MD Host:" + mappingData.host);
System.out.println("MD Context:" + mappingData.context);
System.out.println("MD Wrapper:" + mappingData.wrapper);
System.out.println("contextPath:" + mappingData.contextPath);
System.out.println("wrapperPath:" + mappingData.wrapperPath);
System.out.println("pathInfo:" + mappingData.pathInfo);
System.out.println("redirectPath:" + mappingData.redirectPath);
for (int i = 0; i < 1000000; i++) {
mappingData.recycle();
mapper.map(host, uri, mappingData);
}
long time = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
mappingData.recycle();
mapper.map(host, uri, mappingData);
}
System.out.println("Elapsed:" + (System.currentTimeMillis() - time));
System.out.println("MD Host:" + mappingData.host);
System.out.println("MD Context:" + mappingData.context);
System.out.println("MD Wrapper:" + mappingData.wrapper);
System.out.println("contextPath:" + mappingData.contextPath);
System.out.println("wrapperPath:" + mappingData.wrapperPath);
System.out.println("requestPath:" + mappingData.requestPath);
System.out.println("pathInfo:" + mappingData.pathInfo);
System.out.println("redirectPath:" + mappingData.redirectPath);
} catch (Exception e) {
e.printStackTrace();
}
}
*/
}