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