]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/server/handler/ContextHandlerCollection.java
Merge remote-tracking branch 'origin/libs/scrypt/local'
[gigi.git] / lib / jetty / org / eclipse / jetty / server / handler / ContextHandlerCollection.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18
19 package org.eclipse.jetty.server.handler;
20
21 import java.io.IOException;
22
23 import javax.servlet.ServletException;
24 import javax.servlet.http.HttpServletRequest;
25 import javax.servlet.http.HttpServletResponse;
26
27 import org.eclipse.jetty.server.Handler;
28 import org.eclipse.jetty.server.HandlerContainer;
29 import org.eclipse.jetty.server.HttpChannelState;
30 import org.eclipse.jetty.server.Request;
31 import org.eclipse.jetty.util.ArrayTernaryTrie;
32 import org.eclipse.jetty.util.ArrayUtil;
33 import org.eclipse.jetty.util.Trie;
34 import org.eclipse.jetty.util.annotation.ManagedObject;
35 import org.eclipse.jetty.util.annotation.ManagedOperation;
36 import org.eclipse.jetty.util.log.Log;
37 import org.eclipse.jetty.util.log.Logger;
38
39 /* ------------------------------------------------------------ */
40 /** ContextHandlerCollection.
41  *
42  * This {@link org.eclipse.jetty.server.handler.HandlerCollection} is creates a
43  * {@link org.eclipse.jetty.http.PathMap} to it's contained handlers based
44  * on the context path and virtual hosts of any contained {@link org.eclipse.jetty.server.handler.ContextHandler}s.
45  * The contexts do not need to be directly contained, only children of the contained handlers.
46  * Multiple contexts may have the same context path and they are called in order until one
47  * handles the request.
48  *
49  */
50 @ManagedObject("Context Handler Collection")
51 public class ContextHandlerCollection extends HandlerCollection
52 {
53     private static final Logger LOG = Log.getLogger(ContextHandlerCollection.class);
54
55     private volatile Trie<ContextHandler[]> _contexts;
56     private Class<? extends ContextHandler> _contextClass = ContextHandler.class;
57
58     /* ------------------------------------------------------------ */
59     public ContextHandlerCollection()
60     {
61         super(true);
62     }
63
64
65     /* ------------------------------------------------------------ */
66     /**
67      * Remap the context paths.
68      */
69     @ManagedOperation("update the mapping of context path to context")
70     public void mapContexts()
71     {
72         int capacity=512;
73         
74         // Loop until we have a big enough trie to hold all the context paths
75         Trie<ContextHandler[]> trie;
76         loop: while(true)
77         {
78             trie=new ArrayTernaryTrie<>(false,capacity);
79
80             Handler[] branches = getHandlers();
81
82             // loop over each group of contexts
83             for (int b=0;branches!=null && b<branches.length;b++)
84             {
85                 Handler[] handlers=null;
86
87                 if (branches[b] instanceof ContextHandler)
88                 {
89                     handlers = new Handler[]{ branches[b] };
90                 }
91                 else if (branches[b] instanceof HandlerContainer)
92                 {
93                     handlers = ((HandlerContainer)branches[b]).getChildHandlersByClass(ContextHandler.class);
94                 }
95                 else
96                     continue;
97
98                 // for each context handler in a group
99                 for (int i=0;handlers!=null && i<handlers.length;i++)
100                 {
101                     ContextHandler handler=(ContextHandler)handlers[i];
102                     String contextPath=handler.getContextPath().substring(1);
103                     ContextHandler[] contexts=trie.get(contextPath);
104                     
105                     if (!trie.put(contextPath,ArrayUtil.addToArray(contexts,handler,ContextHandler.class)))
106                     {
107                         capacity+=512;
108                         continue loop;
109                     }
110                 }
111             }
112             
113             break;
114         }
115         
116         // Sort the contexts so those with virtual hosts are considered before those without
117         for (String ctx : trie.keySet())
118         {
119             ContextHandler[] contexts=trie.get(ctx);
120             ContextHandler[] sorted=new ContextHandler[contexts.length];
121             int i=0;
122             for (ContextHandler handler:contexts)
123                 if (handler.getVirtualHosts()!=null && handler.getVirtualHosts().length>0)
124                     sorted[i++]=handler;
125             for (ContextHandler handler:contexts)
126                 if (handler.getVirtualHosts()==null || handler.getVirtualHosts().length==0)
127                     sorted[i++]=handler;
128             trie.put(ctx,sorted);
129         }
130
131         //for (String ctx : trie.keySet())
132         //    System.err.printf("'%s'->%s%n",ctx,Arrays.asList(trie.get(ctx)));
133         _contexts=trie;
134     }
135
136
137     /* ------------------------------------------------------------ */
138     /*
139      * @see org.eclipse.jetty.server.server.handler.HandlerCollection#setHandlers(org.eclipse.jetty.server.server.Handler[])
140      */
141     @Override
142     public void setHandlers(Handler[] handlers)
143     {
144         super.setHandlers(handlers);
145         if (isStarted())
146             mapContexts();
147     }
148
149     /* ------------------------------------------------------------ */
150     @Override
151     protected void doStart() throws Exception
152     {
153         mapContexts();
154         super.doStart();
155     }
156
157
158     /* ------------------------------------------------------------ */
159     /*
160      * @see org.eclipse.jetty.server.server.Handler#handle(java.lang.String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, int)
161      */
162     @Override
163     public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
164     {
165         Handler[] handlers = getHandlers();
166         if (handlers==null || handlers.length==0)
167             return;
168
169         HttpChannelState async = baseRequest.getHttpChannelState();
170         if (async.isAsync())
171         {
172             ContextHandler context=async.getContextHandler();
173             if (context!=null)
174             {
175                 context.handle(target,baseRequest,request, response);
176                 return;
177             }
178         }
179
180         // data structure which maps a request to a context; first-best match wins
181         // { context path => [ context ] }
182         // }
183         if (target.startsWith("/"))
184         {
185             int limit = target.length()-1;
186
187             while (limit>=0)
188             {
189                 // Get best match
190                 ContextHandler[] contexts = _contexts.getBest(target,1,limit);
191                 if (contexts==null)
192                     break;
193
194                 int l=contexts[0].getContextPath().length();
195                 if (l==1 || target.length()==l || target.charAt(l)=='/')
196                 {
197                     for (ContextHandler handler : contexts)
198                     {
199                         handler.handle(target,baseRequest, request, response);
200                         if (baseRequest.isHandled())
201                             return;
202                     }
203                 }
204                 
205                 limit=l-2;
206             }
207         }
208         else
209         {
210             // This may not work in all circumstances... but then I think it should never be called
211             for (int i=0;i<handlers.length;i++)
212             {
213                 handlers[i].handle(target,baseRequest, request, response);
214                 if ( baseRequest.isHandled())
215                     return;
216             }
217         }
218     }
219
220
221     /* ------------------------------------------------------------ */
222     /** Add a context handler.
223      * @param contextPath  The context path to add
224      * @return the ContextHandler just added
225      */
226     public ContextHandler addContext(String contextPath,String resourceBase)
227     {
228         try
229         {
230             ContextHandler context = _contextClass.newInstance();
231             context.setContextPath(contextPath);
232             context.setResourceBase(resourceBase);
233             addHandler(context);
234             return context;
235         }
236         catch (Exception e)
237         {
238             LOG.debug(e);
239             throw new Error(e);
240         }
241     }
242
243
244
245     /* ------------------------------------------------------------ */
246     /**
247      * @return The class to use to add new Contexts
248      */
249     public Class<?> getContextClass()
250     {
251         return _contextClass;
252     }
253
254
255     /* ------------------------------------------------------------ */
256     /**
257      * @param contextClass The class to use to add new Contexts
258      */
259     public void setContextClass(Class<? extends ContextHandler> contextClass)
260     {
261         if (contextClass ==null || !(ContextHandler.class.isAssignableFrom(contextClass)))
262             throw new IllegalArgumentException();
263         _contextClass = contextClass;
264     }
265
266
267 }