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