1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.server;
15
16 import java.io.IOException;
17 import java.lang.reflect.Method;
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.Enumeration;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.ListIterator;
24
25 import javax.servlet.ServletException;
26 import javax.servlet.http.HttpServletRequest;
27 import javax.servlet.http.HttpServletResponse;
28
29 import org.eclipse.jetty.http.HttpGenerator;
30 import org.eclipse.jetty.http.HttpURI;
31 import org.eclipse.jetty.server.bio.SocketConnector;
32 import org.eclipse.jetty.server.handler.HandlerCollection;
33 import org.eclipse.jetty.server.handler.HandlerWrapper;
34 import org.eclipse.jetty.server.nio.SelectChannelConnector;
35 import org.eclipse.jetty.util.Attributes;
36 import org.eclipse.jetty.util.AttributesMap;
37 import org.eclipse.jetty.util.LazyList;
38 import org.eclipse.jetty.util.MultiException;
39 import org.eclipse.jetty.util.URIUtil;
40 import org.eclipse.jetty.util.component.Container;
41 import org.eclipse.jetty.util.component.LifeCycle;
42 import org.eclipse.jetty.util.log.Log;
43 import org.eclipse.jetty.util.thread.QueuedThreadPool;
44 import org.eclipse.jetty.util.thread.ThreadPool;
45
46
47
48
49
50
51
52
53
54
55 public class Server extends HandlerWrapper implements Attributes
56 {
57 private static ShutdownHookThread hookThread = new ShutdownHookThread();
58 private static String _version = (Server.class.getPackage()!=null && Server.class.getPackage().getImplementationVersion()!=null)
59 ?Server.class.getPackage().getImplementationVersion()
60 :"7.0.y.z-SNAPSHOT";
61
62 private ThreadPool _threadPool;
63 private Connector[] _connectors;
64 private Container _container=new Container();
65 private SessionIdManager _sessionIdManager;
66 private boolean _sendServerVersion = true;
67 private boolean _sendDateHeader = false;
68 private AttributesMap _attributes = new AttributesMap();
69 private List<Object> _dependentBeans=new ArrayList<Object>();
70 private int _graceful=0;
71
72
73 public Server()
74 {
75 setServer(this);
76 }
77
78
79
80
81
82 public Server(int port)
83 {
84 setServer(this);
85
86 Connector connector=new SelectChannelConnector();
87 connector.setPort(port);
88 setConnectors(new Connector[]{connector});
89 }
90
91
92
93 public static String getVersion()
94 {
95 return _version;
96 }
97
98
99
100
101
102 public Container getContainer()
103 {
104 return _container;
105 }
106
107
108 public boolean getStopAtShutdown()
109 {
110 return hookThread.contains(this);
111 }
112
113
114 public void setStopAtShutdown(boolean stop)
115 {
116 if (stop)
117 hookThread.add(this);
118 else
119 hookThread.remove(this);
120 }
121
122
123
124
125
126 public Connector[] getConnectors()
127 {
128 return _connectors;
129 }
130
131
132
133 public void addConnector(Connector connector)
134 {
135 setConnectors((Connector[])LazyList.addToArray(getConnectors(), connector, Connector.class));
136 }
137
138
139
140
141
142
143
144 public void removeConnector(Connector connector) {
145 setConnectors((Connector[])LazyList.removeFromArray (getConnectors(), connector));
146 }
147
148
149
150
151
152
153 public void setConnectors(Connector[] connectors)
154 {
155 if (connectors!=null)
156 {
157 for (int i=0;i<connectors.length;i++)
158 connectors[i].setServer(this);
159 }
160
161 _container.update(this, _connectors, connectors, "connector");
162 _connectors = connectors;
163 }
164
165
166
167
168
169 public ThreadPool getThreadPool()
170 {
171 return _threadPool;
172 }
173
174
175
176
177
178 public void setThreadPool(ThreadPool threadPool)
179 {
180 _container.update(this,_threadPool,threadPool, "threadpool",true);
181 _threadPool = threadPool;
182 }
183
184
185 protected void doStart() throws Exception
186 {
187 Log.info("jetty-"+_version);
188 HttpGenerator.setServerVersion(_version);
189 MultiException mex=new MultiException();
190
191 Iterator itor = _dependentBeans.iterator();
192 while (itor.hasNext())
193 {
194 try
195 {
196 Object o=itor.next();
197 if (o instanceof LifeCycle)
198 ((LifeCycle)o).start();
199 }
200 catch (Throwable e) {mex.add(e);}
201 }
202
203 if (_threadPool==null)
204 {
205 QueuedThreadPool tp=new QueuedThreadPool();
206 setThreadPool(tp);
207 }
208
209 if (_sessionIdManager!=null)
210 _sessionIdManager.start();
211
212 try
213 {
214 if (_threadPool instanceof LifeCycle)
215 ((LifeCycle)_threadPool).start();
216 }
217 catch(Throwable e) { mex.add(e);}
218
219 try
220 {
221 super.doStart();
222 }
223 catch(Throwable e)
224 {
225 Log.warn("Error starting handlers",e);
226 }
227
228 if (_connectors!=null)
229 {
230 for (int i=0;i<_connectors.length;i++)
231 {
232 try{_connectors[i].start();}
233 catch(Throwable e)
234 {
235 mex.add(e);
236 }
237 }
238 }
239 if (Log.isDebugEnabled())
240 Log.debug(dump());
241 mex.ifExceptionThrow();
242 }
243
244
245 protected void doStop() throws Exception
246 {
247 MultiException mex=new MultiException();
248
249 if (_graceful>0)
250 {
251 if (_connectors!=null)
252 {
253 for (int i=_connectors.length;i-->0;)
254 {
255 Log.info("Graceful shutdown {}",_connectors[i]);
256 try{_connectors[i].close();}catch(Throwable e){mex.add(e);}
257 }
258 }
259
260 Handler[] contexts = getChildHandlersByClass(Graceful.class);
261 for (int c=0;c<contexts.length;c++)
262 {
263 Graceful context=(Graceful)contexts[c];
264 Log.info("Graceful shutdown {}",context);
265 context.setShutdown(true);
266 }
267 Thread.sleep(_graceful);
268 }
269
270 if (_connectors!=null)
271 {
272 for (int i=_connectors.length;i-->0;)
273 try{_connectors[i].stop();}catch(Throwable e){mex.add(e);}
274 }
275
276 try {super.doStop(); } catch(Throwable e) { mex.add(e);}
277
278 if (_sessionIdManager!=null)
279 _sessionIdManager.stop();
280
281 try
282 {
283 if (_threadPool instanceof LifeCycle)
284 ((LifeCycle)_threadPool).stop();
285 }
286 catch(Throwable e){mex.add(e);}
287
288 if (!_dependentBeans.isEmpty())
289 {
290 ListIterator itor = _dependentBeans.listIterator(_dependentBeans.size());
291 while (itor.hasPrevious())
292 {
293 try
294 {
295 Object o =itor.previous();
296 if (o instanceof LifeCycle)
297 ((LifeCycle)o).stop();
298 }
299 catch (Throwable e) {mex.add(e);}
300 }
301 }
302
303 mex.ifExceptionThrow();
304 }
305
306
307
308
309
310
311
312 public void handle(HttpConnection connection) throws IOException, ServletException
313 {
314 final String target=connection.getRequest().getPathInfo();
315 final Request request=connection.getRequest();
316 final Response response=connection.getResponse();
317
318 if (Log.isDebugEnabled())
319 {
320 Log.debug("REQUEST "+target+" on "+connection);
321 handle(target, request, request, response);
322 Log.debug("RESPONSE "+target+" "+connection.getResponse().getStatus());
323 }
324 else
325 handle(target, request, request, response);
326 }
327
328
329
330
331
332
333
334 public void handleAsync(HttpConnection connection) throws IOException, ServletException
335 {
336 final AsyncRequest async = connection.getRequest().getAsyncRequest();
337 final AsyncRequest.AsyncEventState state = async.getAsyncEventState();
338
339 final Request baseRequest=connection.getRequest();
340 final String path=state.getPath();
341 if (path!=null)
342 {
343
344 baseRequest.setAttribute(AsyncContext.ASYNC_REQUEST_URI,baseRequest.getRequestURI());
345 baseRequest.setAttribute(AsyncContext.ASYNC_QUERY_STRING,baseRequest.getQueryString());
346
347 baseRequest.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH,state.getSuspendedContext().getContextPath());
348
349 final String contextPath=state.getServletContext().getContextPath();
350 HttpURI uri = new HttpURI(URIUtil.addPaths(contextPath,path));
351 baseRequest.setUri(uri);
352 baseRequest.setRequestURI(null);
353 baseRequest.setPathInfo(baseRequest.getRequestURI());
354 baseRequest.setQueryString(uri.getQuery());
355 }
356
357 final String target=baseRequest.getPathInfo();
358 final HttpServletRequest request=(HttpServletRequest)async.getRequest();
359 final HttpServletResponse response=(HttpServletResponse)async.getResponse();
360
361 if (Log.isDebugEnabled())
362 {
363 Log.debug("REQUEST "+target+" on "+connection);
364 handle(target, baseRequest, request, response);
365 Log.debug("RESPONSE "+target+" "+connection.getResponse().getStatus());
366 }
367 else
368 handle(target, baseRequest, request, response);
369 }
370
371
372
373
374 public void join() throws InterruptedException
375 {
376 getThreadPool().join();
377 }
378
379
380
381
382
383
384 public SessionIdManager getSessionIdManager()
385 {
386 return _sessionIdManager;
387 }
388
389
390
391
392
393
394 public void setSessionIdManager(SessionIdManager sessionIdManager)
395 {
396 _container.update(this,_sessionIdManager,sessionIdManager, "sessionIdManager",true);
397 _sessionIdManager = sessionIdManager;
398 }
399
400
401 public void setSendServerVersion (boolean sendServerVersion)
402 {
403 _sendServerVersion = sendServerVersion;
404 }
405
406
407 public boolean getSendServerVersion()
408 {
409 return _sendServerVersion;
410 }
411
412
413
414
415
416 public void setSendDateHeader(boolean sendDateHeader)
417 {
418 _sendDateHeader = sendDateHeader;
419 }
420
421
422 public boolean getSendDateHeader()
423 {
424 return _sendDateHeader;
425 }
426
427
428
429
430
431
432
433
434
435 public void addLifeCycle (LifeCycle c)
436 {
437 addBean(c);
438 }
439
440
441
442
443
444
445
446
447
448 public void addBean(Object o)
449 {
450 if (o == null)
451 return;
452
453 if (!_dependentBeans.contains(o))
454 {
455 _dependentBeans.add(o);
456 _container.addBean(o);
457 }
458
459 try
460 {
461 if (isStarted() && o instanceof LifeCycle)
462 ((LifeCycle)o).start();
463 }
464 catch (Exception e)
465 {
466 throw new RuntimeException (e);
467 }
468 }
469
470
471
472
473
474
475
476 public <T> List<T> getBeans(Class<T> clazz)
477 {
478 ArrayList<T> beans = new ArrayList<T>();
479 Iterator<?> iter = _dependentBeans.iterator();
480 while (iter.hasNext())
481 {
482 Object o = iter.next();
483 if (clazz.isInstance(o))
484 beans.add((T)o);
485 }
486 return beans;
487 }
488
489
490
491
492
493
494 public void removeLifeCycle (LifeCycle c)
495 {
496 removeBean(c);
497 }
498
499
500
501
502 public void removeBean (Object o)
503 {
504 if (o == null)
505 return;
506 _dependentBeans.remove(o);
507 _container.removeBean(o);
508 }
509
510
511
512
513
514
515
516
517
518
519
520 private static class ShutdownHookThread extends Thread
521 {
522 private boolean hooked = false;
523 private ArrayList servers = new ArrayList();
524
525
526
527
528
529
530 private void createShutdownHook()
531 {
532 if (!Boolean.getBoolean("JETTY_NO_SHUTDOWN_HOOK") && !hooked)
533 {
534 try
535 {
536 Method shutdownHook = java.lang.Runtime.class.getMethod("addShutdownHook", new Class[]
537 { java.lang.Thread.class});
538 shutdownHook.invoke(Runtime.getRuntime(), new Object[]
539 { this});
540 this.hooked = true;
541 }
542 catch (Exception e)
543 {
544 if (Log.isDebugEnabled())
545 Log.debug("No shutdown hook in JVM ", e);
546 }
547 }
548 }
549
550
551
552
553 public boolean add(Server server)
554 {
555 createShutdownHook();
556 return this.servers.add(server);
557 }
558
559
560
561
562 public boolean contains(Server server)
563 {
564 return this.servers.contains(server);
565 }
566
567
568
569
570 public boolean addAll(Collection c)
571 {
572 createShutdownHook();
573 return this.servers.addAll(c);
574 }
575
576
577
578
579 public void clear()
580 {
581 createShutdownHook();
582 this.servers.clear();
583 }
584
585
586
587
588 public boolean remove(Server server)
589 {
590 createShutdownHook();
591 return this.servers.remove(server);
592 }
593
594
595
596
597 public boolean removeAll(Collection c)
598 {
599 createShutdownHook();
600 return this.servers.removeAll(c);
601 }
602
603
604
605
606 public void run()
607 {
608 setName("Shutdown");
609 Log.info("Shutdown hook executing");
610 Iterator it = servers.iterator();
611 while (it.hasNext())
612 {
613 Server svr = (Server) it.next();
614 if (svr == null)
615 continue;
616 try
617 {
618 svr.stop();
619 }
620 catch (Exception e)
621 {
622 Log.warn(e);
623 }
624 Log.info("Shutdown hook complete");
625
626
627 try
628 {
629 Thread.sleep(1000);
630 }
631 catch (Exception e)
632 {
633 Log.warn(e);
634 }
635 }
636 }
637 }
638
639
640
641
642
643 public void clearAttributes()
644 {
645 _attributes.clearAttributes();
646 }
647
648
649
650
651
652 public Object getAttribute(String name)
653 {
654 return _attributes.getAttribute(name);
655 }
656
657
658
659
660
661 public Enumeration getAttributeNames()
662 {
663 return AttributesMap.getAttributeNamesCopy(_attributes);
664 }
665
666
667
668
669
670 public void removeAttribute(String name)
671 {
672 _attributes.removeAttribute(name);
673 }
674
675
676
677
678
679 public void setAttribute(String name, Object attribute)
680 {
681 _attributes.setAttribute(name, attribute);
682 }
683
684
685
686
687
688 public int getGracefulShutdown()
689 {
690 return _graceful;
691 }
692
693
694
695
696
697
698
699
700
701
702
703 public void setGracefulShutdown(int timeoutMS)
704 {
705 _graceful=timeoutMS;
706 }
707
708 public String toString()
709 {
710 return this.getClass().getName()+"@"+Integer.toHexString(hashCode());
711 }
712
713
714
715
716
717
718
719 public interface Graceful extends Handler
720 {
721 public void setShutdown(boolean shutdown);
722 }
723 }