1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.server.handler;
20
21 import java.io.IOException;
22 import java.util.Arrays;
23 import java.util.HashMap;
24 import java.util.HashSet;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.concurrent.ConcurrentHashMap;
28 import java.util.concurrent.ConcurrentMap;
29
30 import javax.servlet.ServletException;
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpServletResponse;
33
34 import org.eclipse.jetty.server.Handler;
35 import org.eclipse.jetty.server.HandlerContainer;
36 import org.eclipse.jetty.server.HttpChannelState;
37 import org.eclipse.jetty.server.Request;
38 import org.eclipse.jetty.util.ArrayTernaryTrie;
39 import org.eclipse.jetty.util.ArrayUtil;
40 import org.eclipse.jetty.util.Trie;
41 import org.eclipse.jetty.util.annotation.ManagedObject;
42 import org.eclipse.jetty.util.annotation.ManagedOperation;
43 import org.eclipse.jetty.util.log.Log;
44 import org.eclipse.jetty.util.log.Logger;
45
46
47
48
49
50
51
52
53
54
55
56
57 @ManagedObject("Context Handler Collection")
58 public class ContextHandlerCollection extends HandlerCollection
59 {
60 private static final Logger LOG = Log.getLogger(ContextHandlerCollection.class);
61
62 private final ConcurrentMap<ContextHandler,Handler> _contextBranches = new ConcurrentHashMap<>();
63 private volatile Trie<Map.Entry<String,Branch[]>> _pathBranches;
64 private Class<? extends ContextHandler> _contextClass = ContextHandler.class;
65
66
67 public ContextHandlerCollection()
68 {
69 super(true);
70 }
71
72
73
74
75
76
77 @ManagedOperation("update the mapping of context path to context")
78 public void mapContexts()
79 {
80 _contextBranches.clear();
81
82 if (getHandlers()==null)
83 {
84 _pathBranches=new ArrayTernaryTrie<>(false,16);
85 return;
86 }
87
88
89 Map<String,Branch[]> map = new HashMap<>();
90 for (Handler handler:getHandlers())
91 {
92 Branch branch=new Branch(handler);
93 for (String contextPath : branch.getContextPaths())
94 {
95 Branch[] branches=map.get(contextPath);
96 map.put(contextPath, ArrayUtil.addToArray(branches, branch, Branch.class));
97 }
98
99 for (ContextHandler context : branch.getContextHandlers())
100 _contextBranches.putIfAbsent(context, branch.getHandler());
101 }
102
103
104 for (Map.Entry<String,Branch[]> entry: map.entrySet())
105 {
106 Branch[] branches=entry.getValue();
107 Branch[] sorted=new Branch[branches.length];
108 int i=0;
109 for (Branch branch:branches)
110 if (branch.hasVirtualHost())
111 sorted[i++]=branch;
112 for (Branch branch:branches)
113 if (!branch.hasVirtualHost())
114 sorted[i++]=branch;
115 entry.setValue(sorted);
116 }
117
118
119 int capacity=512;
120 Trie<Map.Entry<String,Branch[]>> trie;
121 loop: while(true)
122 {
123 trie=new ArrayTernaryTrie<>(false,capacity);
124 for (Map.Entry<String,Branch[]> entry: map.entrySet())
125 {
126 if (!trie.put(entry.getKey().substring(1),entry))
127 {
128 capacity+=512;
129 continue loop;
130 }
131 }
132 break loop;
133 }
134
135
136 if (LOG.isDebugEnabled())
137 {
138 for (String ctx : trie.keySet())
139 LOG.debug("{}->{}",ctx,Arrays.asList(trie.get(ctx).getValue()));
140 }
141 _pathBranches=trie;
142 }
143
144
145
146
147
148 @Override
149 public void setHandlers(Handler[] handlers)
150 {
151 super.setHandlers(handlers);
152 if (isStarted())
153 mapContexts();
154 }
155
156
157 @Override
158 protected void doStart() throws Exception
159 {
160 mapContexts();
161 super.doStart();
162 }
163
164
165
166
167
168
169 @Override
170 public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
171 {
172 Handler[] handlers = getHandlers();
173 if (handlers==null || handlers.length==0)
174 return;
175
176 HttpChannelState async = baseRequest.getHttpChannelState();
177 if (async.isAsync())
178 {
179 ContextHandler context=async.getContextHandler();
180 if (context!=null)
181 {
182 Handler branch = _contextBranches.get(context);
183
184 if (branch==null)
185 context.handle(target,baseRequest,request, response);
186 else
187 branch.handle(target, baseRequest, request, response);
188 return;
189 }
190 }
191
192
193
194
195 if (target.startsWith("/"))
196 {
197 int limit = target.length()-1;
198
199 while (limit>=0)
200 {
201
202 Map.Entry<String,Branch[]> branches = _pathBranches.getBest(target,1,limit);
203
204
205 if (branches==null)
206 break;
207
208 int l=branches.getKey().length();
209 if (l==1 || target.length()==l || target.charAt(l)=='/')
210 {
211 for (Branch branch : branches.getValue())
212 {
213 branch.getHandler().handle(target,baseRequest, request, response);
214 if (baseRequest.isHandled())
215 return;
216 }
217 }
218
219 limit=l-2;
220 }
221 }
222 else
223 {
224
225 for (int i=0;i<handlers.length;i++)
226 {
227 handlers[i].handle(target,baseRequest, request, response);
228 if ( baseRequest.isHandled())
229 return;
230 }
231 }
232 }
233
234
235
236
237
238
239
240 public ContextHandler addContext(String contextPath,String resourceBase)
241 {
242 try
243 {
244 ContextHandler context = _contextClass.newInstance();
245 context.setContextPath(contextPath);
246 context.setResourceBase(resourceBase);
247 addHandler(context);
248 return context;
249 }
250 catch (Exception e)
251 {
252 LOG.debug(e);
253 throw new Error(e);
254 }
255 }
256
257
258
259
260
261
262
263 public Class<?> getContextClass()
264 {
265 return _contextClass;
266 }
267
268
269
270
271
272
273 public void setContextClass(Class<? extends ContextHandler> contextClass)
274 {
275 if (contextClass ==null || !(ContextHandler.class.isAssignableFrom(contextClass)))
276 throw new IllegalArgumentException();
277 _contextClass = contextClass;
278 }
279
280
281
282
283 private final static class Branch
284 {
285 private final Handler _handler;
286 private final ContextHandler[] _contexts;
287
288 Branch(Handler handler)
289 {
290 _handler=handler;
291
292 if (handler instanceof ContextHandler)
293 {
294 _contexts = new ContextHandler[]{(ContextHandler)handler};
295 }
296 else if (handler instanceof HandlerContainer)
297 {
298 Handler[] contexts=((HandlerContainer)handler).getChildHandlersByClass(ContextHandler.class);
299 _contexts = new ContextHandler[contexts.length];
300 System.arraycopy(contexts, 0, _contexts, 0, contexts.length);
301 }
302 else
303 _contexts = new ContextHandler[0];
304 }
305
306 Set<String> getContextPaths()
307 {
308 Set<String> set = new HashSet<String>();
309 for (ContextHandler context:_contexts)
310 set.add(context.getContextPath());
311 return set;
312 }
313
314 boolean hasVirtualHost()
315 {
316 for (ContextHandler context:_contexts)
317 if (context.getVirtualHosts()!=null && context.getVirtualHosts().length>0)
318 return true;
319 return false;
320 }
321
322 ContextHandler[] getContextHandlers()
323 {
324 return _contexts;
325 }
326
327 Handler getHandler()
328 {
329 return _handler;
330 }
331
332 @Override
333 public String toString()
334 {
335 return String.format("{%s,%s}",_handler,Arrays.asList(_contexts));
336 }
337 }
338
339
340 }