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