View Javadoc

    1   //========================================================================
    2   //Copyright 2006 Mort Bay Consulting Pty. Ltd.
    3   //------------------------------------------------------------------------
    4   //Licensed under the Apache License, Version 2.0 (the "License");
    5   //you may not use this file except in compliance with the License.
    6   //You may obtain a copy of the License at
    7   //http://www.apache.org/licenses/LICENSE-2.0
    8   //Unless required by applicable law or agreed to in writing, software
    9   //distributed under the License is distributed on an "AS IS" BASIS,
    10  //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  //See the License for the specific language governing permissions and
    12  //limitations under the License.
    13  //========================================================================
    14
    15  package org.mortbay.jetty.handler;
    16
    17  import java.io.IOException;
    18  import java.util.HashMap;
    19  import java.util.Map;
    20
    21  import javax.servlet.ServletException;
    22  import javax.servlet.http.HttpServletRequest;
    23  import javax.servlet.http.HttpServletResponse;
    24
    25  import org.mortbay.jetty.Handler;
    26  import org.mortbay.jetty.HandlerContainer;
    27  import org.mortbay.jetty.HttpConnection;
    28  import org.mortbay.jetty.Request;
    29  import org.mortbay.jetty.servlet.PathMap;
    30  import org.mortbay.log.Log;
    31  import org.mortbay.util.LazyList;
    32
    33  /* ------------------------------------------------------------ */
    34  /** ContextHandlerCollection.
    35   *
    36   * This {@link org.mortbay.jetty.handler.HandlerCollection} is creates a
    37   * {@link org.mortbay.jetty.servlet.PathMap} to it's contained handlers based
    38   * on the context path and virtual hosts of any contained {@link org.mortbay.jetty.handler.ContextHandler}s.
    39   * The contexts do not need to be directly contained, only children of the contained handlers.
    40   * Multiple contexts may have the same context path and they are called in order until one
    41   * handles the request.
    42   *
    43   * @org.apache.xbean.XBean element="contexts"
    44   */
    45  public class ContextHandlerCollection extends HandlerCollection
    46  {
    47      private PathMap _contextMap;
    48      private Class _contextClass = ContextHandler.class;
    49
    50      /* ------------------------------------------------------------ */
    51      /**
    52       * Remap the context paths.
    53       */
    54      public void mapContexts()
    55      {
    56          PathMap contextMap = new PathMap();
    57          Handler[] branches = getHandlers();
    58
    59
    60          for (int b=0;branches!=null && b<branches.length;b++)
    61          {
    62              Handler[] handlers=null;
    63
    64              if (branches[b] instanceof ContextHandler)
    65              {
    66                  handlers = new Handler[]{ branches[b] };
    67              }
    68              else if (branches[b] instanceof HandlerContainer)
    69              {
    70                  handlers = ((HandlerContainer)branches[b]).getChildHandlersByClass(ContextHandler.class);
    71              }
    72              else
    73                  continue;
    74
    75              for (int i=0;i<handlers.length;i++)
    76              {
    77                  ContextHandler handler=(ContextHandler)handlers[i];
    78
    79                  String contextPath=handler.getContextPath();
    80
    81                  if (contextPath==null || contextPath.indexOf(',')>=0 || contextPath.startsWith("*"))
    82                      throw new IllegalArgumentException ("Illegal context spec:"+contextPath);
    83
    84                  if(!contextPath.startsWith("/"))
    85                      contextPath='/'+contextPath;
    86
    87                  if (contextPath.length()>1)
    88                  {
    89                      if (contextPath.endsWith("/"))
    90                          contextPath+="*";
    91                      else if (!contextPath.endsWith("/*"))
    92                          contextPath+="/*";
    93                  }
    94
    95                  Object contexts=contextMap.get(contextPath);
    96                  String[] vhosts=handler.getVirtualHosts();
    97
    98
    99                  if (vhosts!=null && vhosts.length>0)
    100                 {
    101                     Map hosts;
    102
    103                     if (contexts instanceof Map)
    104                         hosts=(Map)contexts;
    105                     else
    106                     {
    107                         hosts=new HashMap();
    108                         hosts.put("*",contexts);
    109                         contextMap.put(contextPath, hosts);
    110                     }
    111
    112                     for (int j=0;j<vhosts.length;j++)
    113                     {
    114                         String vhost=vhosts[j];
    115                         contexts=hosts.get(vhost);
    116                         contexts=LazyList.add(contexts,branches[b]);
    117                         hosts.put(vhost,contexts);
    118                     }
    119                 }
    120                 else if (contexts instanceof Map)
    121                 {
    122                     Map hosts=(Map)contexts;
    123                     contexts=hosts.get("*");
    124                     contexts= LazyList.add(contexts, branches[b]);
    125                     hosts.put("*",contexts);
    126                 }
    127                 else
    128                 {
    129                     contexts= LazyList.add(contexts, branches[b]);
    130                     contextMap.put(contextPath, contexts);
    131                 }
    132             }
    133         }
    134         _contextMap=contextMap;
    135
    136     }
    137
    138
    139
    140     /* ------------------------------------------------------------ */
    141     /*
    142      * @see org.mortbay.jetty.handler.HandlerCollection#setHandlers(org.mortbay.jetty.Handler[])
    143      */
    144     public void setHandlers(Handler[] handlers)
    145     {
    146         _contextMap=null;
    147         super.setHandlers(handlers);
    148         if (isStarted())
    149             mapContexts();
    150     }
    151
    152     /* ------------------------------------------------------------ */
    153     protected void doStart() throws Exception
    154     {
    155         mapContexts();
    156         super.doStart();
    157     }
    158
    159
    160     /* ------------------------------------------------------------ */
    161     /*
    162      * @see org.mortbay.jetty.Handler#handle(java.lang.String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
    163      */
    164     public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch) throws IOException, ServletException
    165     {
    166         Handler[] handlers = getHandlers();
    167         if (handlers==null || handlers.length==0)
    168 	    return;
    169
    170         Request base_request = HttpConnection.getCurrentConnection().getRequest();
    171
    172         // data structure which maps a request to a context
    173         // each match is called in turn until the request is handled
    174         // { context path =>
    175         //     { virtual host => context }
    176         // }
    177 	PathMap map = _contextMap;
    178 	if (map!=null && target!=null && target.startsWith("/"))
    179 	{
    180             // first, get all contexts matched by context path
    181 	    Object contexts = map.getLazyMatches(target);
    182
    183             for (int i=0; i<LazyList.size(contexts); i++)
    184             {
    185                 // then, match against the virtualhost of each context
    186                 Map.Entry entry = (Map.Entry)LazyList.get(contexts, i);
    187                 Object list = entry.getValue();
    188
    189                 if (list instanceof Map)
    190                 {
    191                     Map hosts = (Map)list;
    192                     String host = normalizeHostname(request.getServerName());
    193
    194                     // explicitly-defined virtual hosts, most specific
    195                     list=hosts.get(host);
    196                     for (int j=0; j<LazyList.size(list); j++)
    197                     {
    198                         Handler handler = (Handler)LazyList.get(list,j);
    199                         handler.handle(target,request, response, dispatch);
    200                         if (base_request.isHandled())
    201                             return;
    202                     }
    203
    204                     // wildcard for one level of names
    205                     list=hosts.get("*."+host.substring(host.indexOf(".")+1));
    206                     for (int j=0; j<LazyList.size(list); j++)
    207                     {
    208                         Handler handler = (Handler)LazyList.get(list,j);
    209                         handler.handle(target,request, response, dispatch);
    210                         if (base_request.isHandled())
    211                             return;
    212                     }
    213
    214                     // no virtualhosts defined for the context, least specific
    215                     // will handle any request that does not match to a specific virtual host above
    216                     list=hosts.get("*");
    217                     for (int j=0; j<LazyList.size(list); j++)
    218                     {
    219                         Handler handler = (Handler)LazyList.get(list,j);
    220                         handler.handle(target,request, response, dispatch);
    221                         if (base_request.isHandled())
    222                             return;
    223                     }
    224                 }
    225                 else
    226                 {
    227                     for (int j=0; j<LazyList.size(list); j++)
    228                     {
    229                         Handler handler = (Handler)LazyList.get(list,j);
    230                         handler.handle(target,request, response, dispatch);
    231                         if (base_request.isHandled())
    232                             return;
    233                     }
    234                 }
    235 	    }
    236 	}
    237 	else
    238 	{
    239             // This may not work in all circumstances... but then I think it should never be called
    240 	    for (int i=0;i<handlers.length;i++)
    241 	    {
    242 		handlers[i].handle(target,request, response, dispatch);
    243 		if ( base_request.isHandled())
    244 		    return;
    245 	    }
    246 	}
    247     }
    248
    249
    250     /* ------------------------------------------------------------ */
    251     /** Add a context handler.
    252      * @param contextPath  The context path to add
    253      * @return
    254      * @throws IllegalAccessException
    255      * @throws InstantiationException
    256      */
    257     public ContextHandler addContext(String contextPath,String resourceBase)
    258     {
    259         try
    260         {
    261             ContextHandler context = (ContextHandler)_contextClass.newInstance();
    262             context.setContextPath(contextPath);
    263             context.setResourceBase(resourceBase);
    264             addHandler(context);
    265             return context;
    266         }
    267         catch (Exception e)
    268         {
    269             Log.warn(e);
    270             throw new Error(e);
    271         }
    272     }
    273
    274
    275
    276     /* ------------------------------------------------------------ */
    277     /**
    278      * @return The class to use to add new Contexts
    279      */
    280     public Class getContextClass()
    281     {
    282         return _contextClass;
    283     }
    284
    285
    286     /* ------------------------------------------------------------ */
    287     /**
    288      * @param contextClass The class to use to add new Contexts
    289      */
    290     public void setContextClass(Class contextClass)
    291     {
    292         if (contextClass ==null || !(ContextHandler.class.isAssignableFrom(contextClass)))
    293             throw new IllegalArgumentException();
    294         _contextClass = contextClass;
    295     }
    296
    297     /* ------------------------------------------------------------ */
    298     private String normalizeHostname( String host )
    299     {
    300         if ( host == null )
    301             return null;
    302
    303         if ( host.endsWith( "." ) )
    304             return host.substring( 0, host.length() -1);
    305
    306         return host;
    307     }
    308
    309 }