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