103928aee4356845252ac6b662d5c72c29903813eJake Slack//
203928aee4356845252ac6b662d5c72c29903813eJake Slack//  ========================================================================
303928aee4356845252ac6b662d5c72c29903813eJake Slack//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
403928aee4356845252ac6b662d5c72c29903813eJake Slack//  ------------------------------------------------------------------------
503928aee4356845252ac6b662d5c72c29903813eJake Slack//  All rights reserved. This program and the accompanying materials
603928aee4356845252ac6b662d5c72c29903813eJake Slack//  are made available under the terms of the Eclipse Public License v1.0
703928aee4356845252ac6b662d5c72c29903813eJake Slack//  and Apache License v2.0 which accompanies this distribution.
803928aee4356845252ac6b662d5c72c29903813eJake Slack//
903928aee4356845252ac6b662d5c72c29903813eJake Slack//      The Eclipse Public License is available at
1003928aee4356845252ac6b662d5c72c29903813eJake Slack//      http://www.eclipse.org/legal/epl-v10.html
1103928aee4356845252ac6b662d5c72c29903813eJake Slack//
1203928aee4356845252ac6b662d5c72c29903813eJake Slack//      The Apache License v2.0 is available at
1303928aee4356845252ac6b662d5c72c29903813eJake Slack//      http://www.opensource.org/licenses/apache2.0.php
1403928aee4356845252ac6b662d5c72c29903813eJake Slack//
1503928aee4356845252ac6b662d5c72c29903813eJake Slack//  You may elect to redistribute this code under either of these licenses.
1603928aee4356845252ac6b662d5c72c29903813eJake Slack//  ========================================================================
1703928aee4356845252ac6b662d5c72c29903813eJake Slack//
1803928aee4356845252ac6b662d5c72c29903813eJake Slack
1903928aee4356845252ac6b662d5c72c29903813eJake Slackpackage org.eclipse.jetty.server.handler;
2003928aee4356845252ac6b662d5c72c29903813eJake Slack
2103928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.io.IOException;
2203928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.HashMap;
2303928aee4356845252ac6b662d5c72c29903813eJake Slackimport java.util.Map;
2403928aee4356845252ac6b662d5c72c29903813eJake Slack
2503928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.ServletException;
2603928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.http.HttpServletRequest;
2703928aee4356845252ac6b662d5c72c29903813eJake Slackimport javax.servlet.http.HttpServletResponse;
2803928aee4356845252ac6b662d5c72c29903813eJake Slack
2903928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.http.PathMap;
3003928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.server.AsyncContinuation;
3103928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.server.Handler;
3203928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.server.HandlerContainer;
3303928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.server.Request;
3403928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.LazyList;
3503928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.log.Log;
3603928aee4356845252ac6b662d5c72c29903813eJake Slackimport org.eclipse.jetty.util.log.Logger;
3703928aee4356845252ac6b662d5c72c29903813eJake Slack
3803928aee4356845252ac6b662d5c72c29903813eJake Slack/* ------------------------------------------------------------ */
3903928aee4356845252ac6b662d5c72c29903813eJake Slack/** ContextHandlerCollection.
4003928aee4356845252ac6b662d5c72c29903813eJake Slack *
4103928aee4356845252ac6b662d5c72c29903813eJake Slack * This {@link org.eclipse.jetty.server.handler.HandlerCollection} is creates a
4203928aee4356845252ac6b662d5c72c29903813eJake Slack * {@link org.eclipse.jetty.http.PathMap} to it's contained handlers based
4303928aee4356845252ac6b662d5c72c29903813eJake Slack * on the context path and virtual hosts of any contained {@link org.eclipse.jetty.server.handler.ContextHandler}s.
4403928aee4356845252ac6b662d5c72c29903813eJake Slack * The contexts do not need to be directly contained, only children of the contained handlers.
4503928aee4356845252ac6b662d5c72c29903813eJake Slack * Multiple contexts may have the same context path and they are called in order until one
4603928aee4356845252ac6b662d5c72c29903813eJake Slack * handles the request.
4703928aee4356845252ac6b662d5c72c29903813eJake Slack *
4803928aee4356845252ac6b662d5c72c29903813eJake Slack * @org.apache.xbean.XBean element="contexts"
4903928aee4356845252ac6b662d5c72c29903813eJake Slack */
5003928aee4356845252ac6b662d5c72c29903813eJake Slackpublic class ContextHandlerCollection extends HandlerCollection
5103928aee4356845252ac6b662d5c72c29903813eJake Slack{
5203928aee4356845252ac6b662d5c72c29903813eJake Slack    private static final Logger LOG = Log.getLogger(ContextHandlerCollection.class);
5303928aee4356845252ac6b662d5c72c29903813eJake Slack
5403928aee4356845252ac6b662d5c72c29903813eJake Slack    private volatile PathMap _contextMap;
5503928aee4356845252ac6b662d5c72c29903813eJake Slack    private Class<? extends ContextHandler> _contextClass = ContextHandler.class;
5603928aee4356845252ac6b662d5c72c29903813eJake Slack
5703928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
5803928aee4356845252ac6b662d5c72c29903813eJake Slack    public ContextHandlerCollection()
5903928aee4356845252ac6b662d5c72c29903813eJake Slack    {
6003928aee4356845252ac6b662d5c72c29903813eJake Slack        super(true);
6103928aee4356845252ac6b662d5c72c29903813eJake Slack    }
6203928aee4356845252ac6b662d5c72c29903813eJake Slack
6303928aee4356845252ac6b662d5c72c29903813eJake Slack
6403928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
6503928aee4356845252ac6b662d5c72c29903813eJake Slack    /**
6603928aee4356845252ac6b662d5c72c29903813eJake Slack     * Remap the context paths.
6703928aee4356845252ac6b662d5c72c29903813eJake Slack     */
6803928aee4356845252ac6b662d5c72c29903813eJake Slack    public void mapContexts()
6903928aee4356845252ac6b662d5c72c29903813eJake Slack    {
7003928aee4356845252ac6b662d5c72c29903813eJake Slack        PathMap contextMap = new PathMap();
7103928aee4356845252ac6b662d5c72c29903813eJake Slack        Handler[] branches = getHandlers();
7203928aee4356845252ac6b662d5c72c29903813eJake Slack
7303928aee4356845252ac6b662d5c72c29903813eJake Slack
7403928aee4356845252ac6b662d5c72c29903813eJake Slack        for (int b=0;branches!=null && b<branches.length;b++)
7503928aee4356845252ac6b662d5c72c29903813eJake Slack        {
7603928aee4356845252ac6b662d5c72c29903813eJake Slack            Handler[] handlers=null;
7703928aee4356845252ac6b662d5c72c29903813eJake Slack
7803928aee4356845252ac6b662d5c72c29903813eJake Slack            if (branches[b] instanceof ContextHandler)
7903928aee4356845252ac6b662d5c72c29903813eJake Slack            {
8003928aee4356845252ac6b662d5c72c29903813eJake Slack                handlers = new Handler[]{ branches[b] };
8103928aee4356845252ac6b662d5c72c29903813eJake Slack            }
8203928aee4356845252ac6b662d5c72c29903813eJake Slack            else if (branches[b] instanceof HandlerContainer)
8303928aee4356845252ac6b662d5c72c29903813eJake Slack            {
8403928aee4356845252ac6b662d5c72c29903813eJake Slack                handlers = ((HandlerContainer)branches[b]).getChildHandlersByClass(ContextHandler.class);
8503928aee4356845252ac6b662d5c72c29903813eJake Slack            }
8603928aee4356845252ac6b662d5c72c29903813eJake Slack            else
8703928aee4356845252ac6b662d5c72c29903813eJake Slack                continue;
8803928aee4356845252ac6b662d5c72c29903813eJake Slack
8903928aee4356845252ac6b662d5c72c29903813eJake Slack            for (int i=0;i<handlers.length;i++)
9003928aee4356845252ac6b662d5c72c29903813eJake Slack            {
9103928aee4356845252ac6b662d5c72c29903813eJake Slack                ContextHandler handler=(ContextHandler)handlers[i];
9203928aee4356845252ac6b662d5c72c29903813eJake Slack
9303928aee4356845252ac6b662d5c72c29903813eJake Slack                String contextPath=handler.getContextPath();
9403928aee4356845252ac6b662d5c72c29903813eJake Slack
9503928aee4356845252ac6b662d5c72c29903813eJake Slack                if (contextPath==null || contextPath.indexOf(',')>=0 || contextPath.startsWith("*"))
9603928aee4356845252ac6b662d5c72c29903813eJake Slack                    throw new IllegalArgumentException ("Illegal context spec:"+contextPath);
9703928aee4356845252ac6b662d5c72c29903813eJake Slack
9803928aee4356845252ac6b662d5c72c29903813eJake Slack                if(!contextPath.startsWith("/"))
9903928aee4356845252ac6b662d5c72c29903813eJake Slack                    contextPath='/'+contextPath;
10003928aee4356845252ac6b662d5c72c29903813eJake Slack
10103928aee4356845252ac6b662d5c72c29903813eJake Slack                if (contextPath.length()>1)
10203928aee4356845252ac6b662d5c72c29903813eJake Slack                {
10303928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (contextPath.endsWith("/"))
10403928aee4356845252ac6b662d5c72c29903813eJake Slack                        contextPath+="*";
10503928aee4356845252ac6b662d5c72c29903813eJake Slack                    else if (!contextPath.endsWith("/*"))
10603928aee4356845252ac6b662d5c72c29903813eJake Slack                        contextPath+="/*";
10703928aee4356845252ac6b662d5c72c29903813eJake Slack                }
10803928aee4356845252ac6b662d5c72c29903813eJake Slack
10903928aee4356845252ac6b662d5c72c29903813eJake Slack                Object contexts=contextMap.get(contextPath);
11003928aee4356845252ac6b662d5c72c29903813eJake Slack                String[] vhosts=handler.getVirtualHosts();
11103928aee4356845252ac6b662d5c72c29903813eJake Slack
11203928aee4356845252ac6b662d5c72c29903813eJake Slack
11303928aee4356845252ac6b662d5c72c29903813eJake Slack                if (vhosts!=null && vhosts.length>0)
11403928aee4356845252ac6b662d5c72c29903813eJake Slack                {
11503928aee4356845252ac6b662d5c72c29903813eJake Slack                    Map hosts;
11603928aee4356845252ac6b662d5c72c29903813eJake Slack
11703928aee4356845252ac6b662d5c72c29903813eJake Slack                    if (contexts instanceof Map)
11803928aee4356845252ac6b662d5c72c29903813eJake Slack                        hosts=(Map)contexts;
11903928aee4356845252ac6b662d5c72c29903813eJake Slack                    else
12003928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
12103928aee4356845252ac6b662d5c72c29903813eJake Slack                        hosts=new HashMap();
12203928aee4356845252ac6b662d5c72c29903813eJake Slack                        hosts.put("*",contexts);
12303928aee4356845252ac6b662d5c72c29903813eJake Slack                        contextMap.put(contextPath, hosts);
12403928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
12503928aee4356845252ac6b662d5c72c29903813eJake Slack
12603928aee4356845252ac6b662d5c72c29903813eJake Slack                    for (int j=0;j<vhosts.length;j++)
12703928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
12803928aee4356845252ac6b662d5c72c29903813eJake Slack                        String vhost=vhosts[j];
12903928aee4356845252ac6b662d5c72c29903813eJake Slack                        contexts=hosts.get(vhost);
13003928aee4356845252ac6b662d5c72c29903813eJake Slack                        contexts=LazyList.add(contexts,branches[b]);
13103928aee4356845252ac6b662d5c72c29903813eJake Slack                        hosts.put(vhost,contexts);
13203928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
13303928aee4356845252ac6b662d5c72c29903813eJake Slack                }
13403928aee4356845252ac6b662d5c72c29903813eJake Slack                else if (contexts instanceof Map)
13503928aee4356845252ac6b662d5c72c29903813eJake Slack                {
13603928aee4356845252ac6b662d5c72c29903813eJake Slack                    Map hosts=(Map)contexts;
13703928aee4356845252ac6b662d5c72c29903813eJake Slack                    contexts=hosts.get("*");
13803928aee4356845252ac6b662d5c72c29903813eJake Slack                    contexts= LazyList.add(contexts, branches[b]);
13903928aee4356845252ac6b662d5c72c29903813eJake Slack                    hosts.put("*",contexts);
14003928aee4356845252ac6b662d5c72c29903813eJake Slack                }
14103928aee4356845252ac6b662d5c72c29903813eJake Slack                else
14203928aee4356845252ac6b662d5c72c29903813eJake Slack                {
14303928aee4356845252ac6b662d5c72c29903813eJake Slack                    contexts= LazyList.add(contexts, branches[b]);
14403928aee4356845252ac6b662d5c72c29903813eJake Slack                    contextMap.put(contextPath, contexts);
14503928aee4356845252ac6b662d5c72c29903813eJake Slack                }
14603928aee4356845252ac6b662d5c72c29903813eJake Slack            }
14703928aee4356845252ac6b662d5c72c29903813eJake Slack        }
14803928aee4356845252ac6b662d5c72c29903813eJake Slack        _contextMap=contextMap;
14903928aee4356845252ac6b662d5c72c29903813eJake Slack
15003928aee4356845252ac6b662d5c72c29903813eJake Slack    }
15103928aee4356845252ac6b662d5c72c29903813eJake Slack
15203928aee4356845252ac6b662d5c72c29903813eJake Slack
15303928aee4356845252ac6b662d5c72c29903813eJake Slack
15403928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
15503928aee4356845252ac6b662d5c72c29903813eJake Slack    /*
15603928aee4356845252ac6b662d5c72c29903813eJake Slack     * @see org.eclipse.jetty.server.server.handler.HandlerCollection#setHandlers(org.eclipse.jetty.server.server.Handler[])
15703928aee4356845252ac6b662d5c72c29903813eJake Slack     */
15803928aee4356845252ac6b662d5c72c29903813eJake Slack    @Override
15903928aee4356845252ac6b662d5c72c29903813eJake Slack    public void setHandlers(Handler[] handlers)
16003928aee4356845252ac6b662d5c72c29903813eJake Slack    {
16103928aee4356845252ac6b662d5c72c29903813eJake Slack        _contextMap=null;
16203928aee4356845252ac6b662d5c72c29903813eJake Slack        super.setHandlers(handlers);
16303928aee4356845252ac6b662d5c72c29903813eJake Slack        if (isStarted())
16403928aee4356845252ac6b662d5c72c29903813eJake Slack            mapContexts();
16503928aee4356845252ac6b662d5c72c29903813eJake Slack    }
16603928aee4356845252ac6b662d5c72c29903813eJake Slack
16703928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
16803928aee4356845252ac6b662d5c72c29903813eJake Slack    @Override
16903928aee4356845252ac6b662d5c72c29903813eJake Slack    protected void doStart() throws Exception
17003928aee4356845252ac6b662d5c72c29903813eJake Slack    {
17103928aee4356845252ac6b662d5c72c29903813eJake Slack        mapContexts();
17203928aee4356845252ac6b662d5c72c29903813eJake Slack        super.doStart();
17303928aee4356845252ac6b662d5c72c29903813eJake Slack    }
17403928aee4356845252ac6b662d5c72c29903813eJake Slack
17503928aee4356845252ac6b662d5c72c29903813eJake Slack
17603928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
17703928aee4356845252ac6b662d5c72c29903813eJake Slack    /*
17803928aee4356845252ac6b662d5c72c29903813eJake Slack     * @see org.eclipse.jetty.server.server.Handler#handle(java.lang.String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
17903928aee4356845252ac6b662d5c72c29903813eJake Slack     */
18003928aee4356845252ac6b662d5c72c29903813eJake Slack    @Override
18103928aee4356845252ac6b662d5c72c29903813eJake Slack    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
18203928aee4356845252ac6b662d5c72c29903813eJake Slack    {
18303928aee4356845252ac6b662d5c72c29903813eJake Slack        Handler[] handlers = getHandlers();
18403928aee4356845252ac6b662d5c72c29903813eJake Slack        if (handlers==null || handlers.length==0)
18503928aee4356845252ac6b662d5c72c29903813eJake Slack	    return;
18603928aee4356845252ac6b662d5c72c29903813eJake Slack
18703928aee4356845252ac6b662d5c72c29903813eJake Slack	AsyncContinuation async = baseRequest.getAsyncContinuation();
18803928aee4356845252ac6b662d5c72c29903813eJake Slack	if (async.isAsync())
18903928aee4356845252ac6b662d5c72c29903813eJake Slack	{
19003928aee4356845252ac6b662d5c72c29903813eJake Slack	    ContextHandler context=async.getContextHandler();
19103928aee4356845252ac6b662d5c72c29903813eJake Slack	    if (context!=null)
19203928aee4356845252ac6b662d5c72c29903813eJake Slack	    {
19303928aee4356845252ac6b662d5c72c29903813eJake Slack	        context.handle(target,baseRequest,request, response);
19403928aee4356845252ac6b662d5c72c29903813eJake Slack	        return;
19503928aee4356845252ac6b662d5c72c29903813eJake Slack	    }
19603928aee4356845252ac6b662d5c72c29903813eJake Slack	}
19703928aee4356845252ac6b662d5c72c29903813eJake Slack
19803928aee4356845252ac6b662d5c72c29903813eJake Slack	// data structure which maps a request to a context; first-best match wins
19903928aee4356845252ac6b662d5c72c29903813eJake Slack	// { context path =>
20003928aee4356845252ac6b662d5c72c29903813eJake Slack	//     { virtual host => context }
20103928aee4356845252ac6b662d5c72c29903813eJake Slack	// }
20203928aee4356845252ac6b662d5c72c29903813eJake Slack	PathMap map = _contextMap;
20303928aee4356845252ac6b662d5c72c29903813eJake Slack	if (map!=null && target!=null && target.startsWith("/"))
20403928aee4356845252ac6b662d5c72c29903813eJake Slack	{
20503928aee4356845252ac6b662d5c72c29903813eJake Slack	    // first, get all contexts matched by context path
20603928aee4356845252ac6b662d5c72c29903813eJake Slack	    Object contexts = map.getLazyMatches(target);
20703928aee4356845252ac6b662d5c72c29903813eJake Slack
20803928aee4356845252ac6b662d5c72c29903813eJake Slack            for (int i=0; i<LazyList.size(contexts); i++)
20903928aee4356845252ac6b662d5c72c29903813eJake Slack            {
21003928aee4356845252ac6b662d5c72c29903813eJake Slack                // then, match against the virtualhost of each context
21103928aee4356845252ac6b662d5c72c29903813eJake Slack                Map.Entry entry = (Map.Entry)LazyList.get(contexts, i);
21203928aee4356845252ac6b662d5c72c29903813eJake Slack                Object list = entry.getValue();
21303928aee4356845252ac6b662d5c72c29903813eJake Slack
21403928aee4356845252ac6b662d5c72c29903813eJake Slack                if (list instanceof Map)
21503928aee4356845252ac6b662d5c72c29903813eJake Slack                {
21603928aee4356845252ac6b662d5c72c29903813eJake Slack                    Map hosts = (Map)list;
21703928aee4356845252ac6b662d5c72c29903813eJake Slack                    String host = normalizeHostname(request.getServerName());
21803928aee4356845252ac6b662d5c72c29903813eJake Slack
21903928aee4356845252ac6b662d5c72c29903813eJake Slack                    // explicitly-defined virtual hosts, most specific
22003928aee4356845252ac6b662d5c72c29903813eJake Slack                    list=hosts.get(host);
22103928aee4356845252ac6b662d5c72c29903813eJake Slack                    for (int j=0; j<LazyList.size(list); j++)
22203928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
22303928aee4356845252ac6b662d5c72c29903813eJake Slack                        Handler handler = (Handler)LazyList.get(list,j);
22403928aee4356845252ac6b662d5c72c29903813eJake Slack                        handler.handle(target,baseRequest, request, response);
22503928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (baseRequest.isHandled())
22603928aee4356845252ac6b662d5c72c29903813eJake Slack                            return;
22703928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
22803928aee4356845252ac6b662d5c72c29903813eJake Slack
22903928aee4356845252ac6b662d5c72c29903813eJake Slack                    // wildcard for one level of names
23003928aee4356845252ac6b662d5c72c29903813eJake Slack                    list=hosts.get("*."+host.substring(host.indexOf(".")+1));
23103928aee4356845252ac6b662d5c72c29903813eJake Slack                    for (int j=0; j<LazyList.size(list); j++)
23203928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
23303928aee4356845252ac6b662d5c72c29903813eJake Slack                        Handler handler = (Handler)LazyList.get(list,j);
23403928aee4356845252ac6b662d5c72c29903813eJake Slack                        handler.handle(target,baseRequest, request, response);
23503928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (baseRequest.isHandled())
23603928aee4356845252ac6b662d5c72c29903813eJake Slack                            return;
23703928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
23803928aee4356845252ac6b662d5c72c29903813eJake Slack
23903928aee4356845252ac6b662d5c72c29903813eJake Slack                    // no virtualhosts defined for the context, least specific
24003928aee4356845252ac6b662d5c72c29903813eJake Slack                    // will handle any request that does not match to a specific virtual host above
24103928aee4356845252ac6b662d5c72c29903813eJake Slack                    list=hosts.get("*");
24203928aee4356845252ac6b662d5c72c29903813eJake Slack                    for (int j=0; j<LazyList.size(list); j++)
24303928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
24403928aee4356845252ac6b662d5c72c29903813eJake Slack                        Handler handler = (Handler)LazyList.get(list,j);
24503928aee4356845252ac6b662d5c72c29903813eJake Slack                        handler.handle(target,baseRequest, request, response);
24603928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (baseRequest.isHandled())
24703928aee4356845252ac6b662d5c72c29903813eJake Slack                            return;
24803928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
24903928aee4356845252ac6b662d5c72c29903813eJake Slack                }
25003928aee4356845252ac6b662d5c72c29903813eJake Slack                else
25103928aee4356845252ac6b662d5c72c29903813eJake Slack                {
25203928aee4356845252ac6b662d5c72c29903813eJake Slack                    for (int j=0; j<LazyList.size(list); j++)
25303928aee4356845252ac6b662d5c72c29903813eJake Slack                    {
25403928aee4356845252ac6b662d5c72c29903813eJake Slack                        Handler handler = (Handler)LazyList.get(list,j);
25503928aee4356845252ac6b662d5c72c29903813eJake Slack                        handler.handle(target,baseRequest, request, response);
25603928aee4356845252ac6b662d5c72c29903813eJake Slack                        if (baseRequest.isHandled())
25703928aee4356845252ac6b662d5c72c29903813eJake Slack                            return;
25803928aee4356845252ac6b662d5c72c29903813eJake Slack                    }
25903928aee4356845252ac6b662d5c72c29903813eJake Slack                }
26003928aee4356845252ac6b662d5c72c29903813eJake Slack	    }
26103928aee4356845252ac6b662d5c72c29903813eJake Slack	}
26203928aee4356845252ac6b662d5c72c29903813eJake Slack	else
26303928aee4356845252ac6b662d5c72c29903813eJake Slack	{
26403928aee4356845252ac6b662d5c72c29903813eJake Slack            // This may not work in all circumstances... but then I think it should never be called
26503928aee4356845252ac6b662d5c72c29903813eJake Slack	    for (int i=0;i<handlers.length;i++)
26603928aee4356845252ac6b662d5c72c29903813eJake Slack	    {
26703928aee4356845252ac6b662d5c72c29903813eJake Slack		handlers[i].handle(target,baseRequest, request, response);
26803928aee4356845252ac6b662d5c72c29903813eJake Slack		if ( baseRequest.isHandled())
26903928aee4356845252ac6b662d5c72c29903813eJake Slack		    return;
27003928aee4356845252ac6b662d5c72c29903813eJake Slack	    }
27103928aee4356845252ac6b662d5c72c29903813eJake Slack	}
27203928aee4356845252ac6b662d5c72c29903813eJake Slack    }
27303928aee4356845252ac6b662d5c72c29903813eJake Slack
27403928aee4356845252ac6b662d5c72c29903813eJake Slack
27503928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
27603928aee4356845252ac6b662d5c72c29903813eJake Slack    /** Add a context handler.
27703928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param contextPath  The context path to add
27803928aee4356845252ac6b662d5c72c29903813eJake Slack     * @return the ContextHandler just added
27903928aee4356845252ac6b662d5c72c29903813eJake Slack     */
28003928aee4356845252ac6b662d5c72c29903813eJake Slack    public ContextHandler addContext(String contextPath,String resourceBase)
28103928aee4356845252ac6b662d5c72c29903813eJake Slack    {
28203928aee4356845252ac6b662d5c72c29903813eJake Slack        try
28303928aee4356845252ac6b662d5c72c29903813eJake Slack        {
28403928aee4356845252ac6b662d5c72c29903813eJake Slack            ContextHandler context = _contextClass.newInstance();
28503928aee4356845252ac6b662d5c72c29903813eJake Slack            context.setContextPath(contextPath);
28603928aee4356845252ac6b662d5c72c29903813eJake Slack            context.setResourceBase(resourceBase);
28703928aee4356845252ac6b662d5c72c29903813eJake Slack            addHandler(context);
28803928aee4356845252ac6b662d5c72c29903813eJake Slack            return context;
28903928aee4356845252ac6b662d5c72c29903813eJake Slack        }
29003928aee4356845252ac6b662d5c72c29903813eJake Slack        catch (Exception e)
29103928aee4356845252ac6b662d5c72c29903813eJake Slack        {
29203928aee4356845252ac6b662d5c72c29903813eJake Slack            LOG.debug(e);
29303928aee4356845252ac6b662d5c72c29903813eJake Slack            throw new Error(e);
29403928aee4356845252ac6b662d5c72c29903813eJake Slack        }
29503928aee4356845252ac6b662d5c72c29903813eJake Slack    }
29603928aee4356845252ac6b662d5c72c29903813eJake Slack
29703928aee4356845252ac6b662d5c72c29903813eJake Slack
29803928aee4356845252ac6b662d5c72c29903813eJake Slack
29903928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
30003928aee4356845252ac6b662d5c72c29903813eJake Slack    /**
30103928aee4356845252ac6b662d5c72c29903813eJake Slack     * @return The class to use to add new Contexts
30203928aee4356845252ac6b662d5c72c29903813eJake Slack     */
30303928aee4356845252ac6b662d5c72c29903813eJake Slack    public Class getContextClass()
30403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
30503928aee4356845252ac6b662d5c72c29903813eJake Slack        return _contextClass;
30603928aee4356845252ac6b662d5c72c29903813eJake Slack    }
30703928aee4356845252ac6b662d5c72c29903813eJake Slack
30803928aee4356845252ac6b662d5c72c29903813eJake Slack
30903928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
31003928aee4356845252ac6b662d5c72c29903813eJake Slack    /**
31103928aee4356845252ac6b662d5c72c29903813eJake Slack     * @param contextClass The class to use to add new Contexts
31203928aee4356845252ac6b662d5c72c29903813eJake Slack     */
31303928aee4356845252ac6b662d5c72c29903813eJake Slack    public void setContextClass(Class contextClass)
31403928aee4356845252ac6b662d5c72c29903813eJake Slack    {
31503928aee4356845252ac6b662d5c72c29903813eJake Slack        if (contextClass ==null || !(ContextHandler.class.isAssignableFrom(contextClass)))
31603928aee4356845252ac6b662d5c72c29903813eJake Slack            throw new IllegalArgumentException();
31703928aee4356845252ac6b662d5c72c29903813eJake Slack        _contextClass = contextClass;
31803928aee4356845252ac6b662d5c72c29903813eJake Slack    }
31903928aee4356845252ac6b662d5c72c29903813eJake Slack
32003928aee4356845252ac6b662d5c72c29903813eJake Slack    /* ------------------------------------------------------------ */
32103928aee4356845252ac6b662d5c72c29903813eJake Slack    private String normalizeHostname( String host )
32203928aee4356845252ac6b662d5c72c29903813eJake Slack    {
32303928aee4356845252ac6b662d5c72c29903813eJake Slack        if ( host == null )
32403928aee4356845252ac6b662d5c72c29903813eJake Slack            return null;
32503928aee4356845252ac6b662d5c72c29903813eJake Slack
32603928aee4356845252ac6b662d5c72c29903813eJake Slack        if ( host.endsWith( "." ) )
32703928aee4356845252ac6b662d5c72c29903813eJake Slack            return host.substring( 0, host.length() -1);
32803928aee4356845252ac6b662d5c72c29903813eJake Slack
32903928aee4356845252ac6b662d5c72c29903813eJake Slack        return host;
33003928aee4356845252ac6b662d5c72c29903813eJake Slack    }
33103928aee4356845252ac6b662d5c72c29903813eJake Slack
33203928aee4356845252ac6b662d5c72c29903813eJake Slack}
333