1 // ========================================================================
2 // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
3 // ------------------------------------------------------------------------
4 // All rights reserved. This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v1.0
6 // and Apache License v2.0 which accompanies this distribution.
7 // The Eclipse Public License is available at
8 // http://www.eclipse.org/legal/epl-v10.html
9 // The Apache License v2.0 is available at
10 // http://www.opensource.org/licenses/apache2.0.php
11 // You may elect to redistribute this code under either of these licenses.
12 // ========================================================================
13
14 package org.eclipse.jetty.server.handler;
15
16 import java.io.IOException;
17 import java.util.concurrent.CountDownLatch;
18
19 import javax.servlet.ServletException;
20 import javax.servlet.http.HttpServletRequest;
21 import javax.servlet.http.HttpServletResponse;
22
23 import org.eclipse.jetty.server.Handler;
24 import org.eclipse.jetty.server.Request;
25 import org.eclipse.jetty.server.Server;
26 import org.eclipse.jetty.util.LazyList;
27 import org.eclipse.jetty.util.MultiException;
28
29 /* ------------------------------------------------------------ */
30 /** A collection of handlers.
31 * <p>
32 * The default implementations calls all handlers in list order,
33 * regardless of the response status or exceptions. Derived implementation
34 * may alter the order or the conditions of calling the contained
35 * handlers.
36 * <p>
37 *
38 * @org.apache.xbean.XBean
39 */
40 public class HandlerCollection extends AbstractHandlerContainer
41 {
42 private final boolean _mutableWhenRunning;
43 private volatile Handler[] _handlers;
44 private boolean _parallelStart=true;
45
46 /* ------------------------------------------------------------ */
47 public HandlerCollection()
48 {
49 _mutableWhenRunning=false;
50 }
51
52 /* ------------------------------------------------------------ */
53 public HandlerCollection(boolean mutableWhenRunning)
54 {
55 _mutableWhenRunning=mutableWhenRunning;
56 }
57
58 /* ------------------------------------------------------------ */
59 /**
60 * @return Returns the handlers.
61 */
62 public Handler[] getHandlers()
63 {
64 return _handlers;
65 }
66
67 /* ------------------------------------------------------------ */
68 /**
69 *
70 * @param handlers The handlers to set.
71 */
72 public void setHandlers(Handler[] handlers)
73 {
74 if (!_mutableWhenRunning && isStarted())
75 throw new IllegalStateException(STARTED);
76
77 Handler [] old_handlers = _handlers==null?null:_handlers.clone();
78
79 if (getServer()!=null)
80 getServer().getContainer().update(this, old_handlers, handlers, "handler");
81
82 Server server = getServer();
83 MultiException mex = new MultiException();
84 for (int i=0;handlers!=null && i<handlers.length;i++)
85 {
86 if (handlers[i].getServer()!=server)
87 handlers[i].setServer(server);
88 }
89
90 // handlers is volatile
91 _handlers = handlers;
92
93 // stop old handlers
94 for (int i=0;old_handlers!=null && i<old_handlers.length;i++)
95 {
96 if (old_handlers[i]!=null)
97 {
98 try
99 {
100 if (old_handlers[i].isStarted())
101 old_handlers[i].stop();
102 }
103 catch (Throwable e)
104 {
105 mex.add(e);
106 }
107 }
108 }
109
110 mex.ifExceptionThrowRuntime();
111 }
112
113
114
115 /* ------------------------------------------------------------ */
116 /** Get the parrallelStart.
117 * @return true if the contained handlers are started in parallel.
118 */
119 public boolean isParallelStart()
120 {
121 return _parallelStart;
122 }
123
124
125
126 /* ------------------------------------------------------------ */
127 /** Set the parallelStart.
128 * @param parallelStart If true, contained handlers are started in parallel.
129 */
130 public void setParallelStart(boolean parallelStart)
131 {
132 this._parallelStart = parallelStart;
133 }
134
135
136 /* ------------------------------------------------------------ */
137 /**
138 * @see Handler#handle(String, Request, HttpServletRequest, HttpServletResponse)
139 */
140 public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
141 throws IOException, ServletException
142 {
143 if (_handlers!=null && isStarted())
144 {
145 MultiException mex=null;
146
147 for (int i=0;i<_handlers.length;i++)
148 {
149 try
150 {
151 _handlers[i].handle(target,baseRequest, request, response);
152 }
153 catch(IOException e)
154 {
155 throw e;
156 }
157 catch(RuntimeException e)
158 {
159 throw e;
160 }
161 catch(Exception e)
162 {
163 if (mex==null)
164 mex=new MultiException();
165 mex.add(e);
166 }
167 }
168 if (mex!=null)
169 {
170 if (mex.size()==1)
171 throw new ServletException(mex.getThrowable(0));
172 else
173 throw new ServletException(mex);
174 }
175
176 }
177 }
178
179 /* ------------------------------------------------------------ */
180 /*
181 * @see org.eclipse.jetty.server.server.handler.AbstractHandler#doStart()
182 */
183 @Override
184 protected void doStart() throws Exception
185 {
186 final MultiException mex=new MultiException();
187 if (_handlers!=null)
188 {
189 if (_parallelStart)
190 {
191 final CountDownLatch latch = new CountDownLatch(_handlers.length);
192 for (int i=0;i<_handlers.length;i++)
193 {
194 final int h=i;
195 getServer().getThreadPool().dispatch(
196 new Runnable()
197 {
198 public void run()
199 {
200 try{_handlers[h].start();}
201 catch(Throwable e){mex.add(e);}
202 finally{latch.countDown();}
203 }
204 }
205 );
206
207 }
208 latch.await();
209 }
210 else
211 {
212 for (int i=0;i<_handlers.length;i++)
213 {
214 try{_handlers[i].start();}
215 catch(Throwable e){mex.add(e);}
216 }
217 }
218 }
219 super.doStart();
220 mex.ifExceptionThrow();
221 }
222
223 /* ------------------------------------------------------------ */
224 /*
225 * @see org.eclipse.jetty.server.server.handler.AbstractHandler#doStop()
226 */
227 @Override
228 protected void doStop() throws Exception
229 {
230 MultiException mex=new MultiException();
231 try { super.doStop(); } catch(Throwable e){mex.add(e);}
232 if (_handlers!=null)
233 {
234 for (int i=_handlers.length;i-->0;)
235 try{_handlers[i].stop();}catch(Throwable e){mex.add(e);}
236 }
237 mex.ifExceptionThrow();
238 }
239
240 /* ------------------------------------------------------------ */
241 @Override
242 public void setServer(Server server)
243 {
244 if (isStarted())
245 throw new IllegalStateException(STARTED);
246
247 Server old_server=getServer();
248
249 super.setServer(server);
250
251 Handler[] h=getHandlers();
252 for (int i=0;h!=null && i<h.length;i++)
253 h[i].setServer(server);
254
255 if (server!=null && server!=old_server)
256 server.getContainer().update(this, null,_handlers, "handler");
257
258 }
259
260 /* ------------------------------------------------------------ */
261 /* Add a handler.
262 * This implementation adds the passed handler to the end of the existing collection of handlers.
263 * @see org.eclipse.jetty.server.server.HandlerContainer#addHandler(org.eclipse.jetty.server.server.Handler)
264 */
265 public void addHandler(Handler handler)
266 {
267 setHandlers((Handler[])LazyList.addToArray(getHandlers(), handler, Handler.class));
268 }
269
270 /* ------------------------------------------------------------ */
271 public void removeHandler(Handler handler)
272 {
273 Handler[] handlers = getHandlers();
274
275 if (handlers!=null && handlers.length>0 )
276 setHandlers((Handler[])LazyList.removeFromArray(handlers, handler));
277 }
278
279 /* ------------------------------------------------------------ */
280 @Override
281 protected Object expandChildren(Object list, Class byClass)
282 {
283 Handler[] handlers = getHandlers();
284 for (int i=0;handlers!=null && i<handlers.length;i++)
285 list=expandHandler(handlers[i], list, byClass);
286 return list;
287 }
288
289
290 }