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 	PathMap map = _contextMap;
172 	if (map!=null && target!=null && target.startsWith("/"))
173 	{
174 	    Object contexts = map.getLazyMatches(target);
175 
176             for (int i=0; i<LazyList.size(contexts); i++)
177             {
178                 Map.Entry entry = (Map.Entry)LazyList.get(contexts, i);
179                 Object list = entry.getValue();
180 
181                 if (list instanceof Map)
182                 {
183                     Map hosts = (Map)list;
184                     list=hosts.get(request.getServerName());
185                     for (int j=0; j<LazyList.size(list); j++)
186                     {
187                         Handler handler = (Handler)LazyList.get(list,j);
188                         handler.handle(target,request, response, dispatch);
189                         if (base_request.isHandled())
190                             return;
191                     }
192                     list=hosts.get("*");
193                     for (int j=0; j<LazyList.size(list); j++)
194                     {
195                         Handler handler = (Handler)LazyList.get(list,j);
196                         handler.handle(target,request, response, dispatch);
197                         if (base_request.isHandled())
198                             return;
199                     }
200                 }
201                 else
202                 {
203                     for (int j=0; j<LazyList.size(list); j++)
204                     {
205                         Handler handler = (Handler)LazyList.get(list,j);
206                         handler.handle(target,request, response, dispatch);
207                         if (base_request.isHandled())
208                             return;
209                     }
210                 }
211 	    }
212 	}
213 	else
214 	{
215             // This may not work in all circumstances... but then I think it should never be called
216 	    for (int i=0;i<handlers.length;i++)
217 	    {
218 		handlers[i].handle(target,request, response, dispatch);
219 		if ( base_request.isHandled())
220 		    return;
221 	    }
222 	}
223     }
224     
225     
226     /* ------------------------------------------------------------ */
227     /** Add a context handler.
228      * @param contextPath  The context path to add
229      * @return
230      * @throws IllegalAccessException 
231      * @throws InstantiationException 
232      */
233     public ContextHandler addContext(String contextPath,String resourceBase) 
234     {
235         try
236         {
237             ContextHandler context = (ContextHandler)_contextClass.newInstance();
238             context.setContextPath(contextPath);
239             context.setResourceBase(resourceBase);
240             addHandler(context);
241             return context;
242         }
243         catch (Exception e)
244         {
245             Log.warn(e);
246             throw new Error(e);
247         }
248     }
249 
250 
251 
252     /* ------------------------------------------------------------ */
253     /**
254      * @return The class to use to add new Contexts
255      */
256     public Class getContextClass()
257     {
258         return _contextClass;
259     }
260 
261 
262     /* ------------------------------------------------------------ */
263     /**
264      * @param contextClass The class to use to add new Contexts
265      */
266     public void setContextClass(Class contextClass)
267     {
268         if (contextClass ==null || !(ContextHandler.class.isAssignableFrom(contextClass)))
269             throw new IllegalArgumentException();
270         _contextClass = contextClass;
271     }
272     
273     
274 }