• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18 
19 package org.eclipse.jetty.server;
20 
21 import java.io.IOException;
22 import java.net.InetSocketAddress;
23 import java.util.Enumeration;
24 
25 import javax.servlet.AsyncContext;
26 import javax.servlet.ServletException;
27 import javax.servlet.http.HttpServletRequest;
28 import javax.servlet.http.HttpServletResponse;
29 
30 import org.eclipse.jetty.http.HttpGenerator;
31 import org.eclipse.jetty.http.HttpURI;
32 import org.eclipse.jetty.server.handler.HandlerWrapper;
33 import org.eclipse.jetty.server.nio.SelectChannelConnector;
34 import org.eclipse.jetty.util.Attributes;
35 import org.eclipse.jetty.util.AttributesMap;
36 import org.eclipse.jetty.util.LazyList;
37 import org.eclipse.jetty.util.MultiException;
38 import org.eclipse.jetty.util.TypeUtil;
39 import org.eclipse.jetty.util.URIUtil;
40 import org.eclipse.jetty.util.component.Container;
41 import org.eclipse.jetty.util.component.Destroyable;
42 import org.eclipse.jetty.util.component.LifeCycle;
43 import org.eclipse.jetty.util.log.Log;
44 import org.eclipse.jetty.util.log.Logger;
45 import org.eclipse.jetty.util.thread.QueuedThreadPool;
46 import org.eclipse.jetty.util.thread.ShutdownThread;
47 import org.eclipse.jetty.util.thread.ThreadPool;
48 
49 /* ------------------------------------------------------------ */
50 /** Jetty HTTP Servlet Server.
51  * This class is the main class for the Jetty HTTP Servlet server.
52  * It aggregates Connectors (HTTP request receivers) and request Handlers.
53  * The server is itself a handler and a ThreadPool.  Connectors use the ThreadPool methods
54  * to run jobs that will eventually call the handle method.
55  *
56  *  @org.apache.xbean.XBean  description="Creates an embedded Jetty web server"
57  */
58 public class Server extends HandlerWrapper implements Attributes
59 {
60     private static final Logger LOG = Log.getLogger(Server.class);
61 
62     private static final String __version;
63     static
64     {
65         if (Server.class.getPackage()!=null &&
66             "Eclipse.org - Jetty".equals(Server.class.getPackage().getImplementationVendor()) &&
67              Server.class.getPackage().getImplementationVersion()!=null)
68             __version=Server.class.getPackage().getImplementationVersion();
69         else
70             __version=System.getProperty("jetty.version","8.y.z-SNAPSHOT");
71     }
72 
73     private final Container _container=new Container();
74     private final AttributesMap _attributes = new AttributesMap();
75     private ThreadPool _threadPool;
76     private Connector[] _connectors;
77     private SessionIdManager _sessionIdManager;
78     private boolean _sendServerVersion = true; //send Server: header
79     private boolean _sendDateHeader = false; //send Date: header
80     private int _graceful=0;
81     private boolean _stopAtShutdown;
82     private boolean _dumpAfterStart=false;
83     private boolean _dumpBeforeStop=false;
84     private boolean _uncheckedPrintWriter=false;
85 
86 
87     /* ------------------------------------------------------------ */
Server()88     public Server()
89     {
90         setServer(this);
91     }
92 
93     /* ------------------------------------------------------------ */
94     /** Convenience constructor
95      * Creates server and a {@link SelectChannelConnector} at the passed port.
96      */
Server(int port)97     public Server(int port)
98     {
99         setServer(this);
100 
101         Connector connector=new SelectChannelConnector();
102         connector.setPort(port);
103         setConnectors(new Connector[]{connector});
104     }
105 
106     /* ------------------------------------------------------------ */
107     /** Convenience constructor
108      * Creates server and a {@link SelectChannelConnector} at the passed address.
109      */
Server(InetSocketAddress addr)110     public Server(InetSocketAddress addr)
111     {
112         setServer(this);
113 
114         Connector connector=new SelectChannelConnector();
115         connector.setHost(addr.getHostName());
116         connector.setPort(addr.getPort());
117         setConnectors(new Connector[]{connector});
118     }
119 
120 
121     /* ------------------------------------------------------------ */
getVersion()122     public static String getVersion()
123     {
124         return __version;
125     }
126 
127     /* ------------------------------------------------------------ */
128     /**
129      * @return Returns the container.
130      */
getContainer()131     public Container getContainer()
132     {
133         return _container;
134     }
135 
136     /* ------------------------------------------------------------ */
getStopAtShutdown()137     public boolean getStopAtShutdown()
138     {
139         return _stopAtShutdown;
140     }
141 
142     /* ------------------------------------------------------------ */
setStopAtShutdown(boolean stop)143     public void setStopAtShutdown(boolean stop)
144     {
145         //if we now want to stop
146         if (stop)
147         {
148             //and we weren't stopping before
149             if (!_stopAtShutdown)
150             {
151                 //only register to stop if we're already started (otherwise we'll do it in doStart())
152                 if (isStarted())
153                     ShutdownThread.register(this);
154             }
155         }
156         else
157             ShutdownThread.deregister(this);
158 
159         _stopAtShutdown=stop;
160     }
161 
162     /* ------------------------------------------------------------ */
163     /**
164      * @return Returns the connectors.
165      */
getConnectors()166     public Connector[] getConnectors()
167     {
168         return _connectors;
169     }
170 
171     /* ------------------------------------------------------------ */
addConnector(Connector connector)172     public void addConnector(Connector connector)
173     {
174         setConnectors((Connector[])LazyList.addToArray(getConnectors(), connector, Connector.class));
175     }
176 
177     /* ------------------------------------------------------------ */
178     /**
179      * Conveniance method which calls {@link #getConnectors()} and {@link #setConnectors(Connector[])} to
180      * remove a connector.
181      * @param connector The connector to remove.
182      */
removeConnector(Connector connector)183     public void removeConnector(Connector connector) {
184         setConnectors((Connector[])LazyList.removeFromArray (getConnectors(), connector));
185     }
186 
187     /* ------------------------------------------------------------ */
188     /** Set the connectors for this server.
189      * Each connector has this server set as it's ThreadPool and its Handler.
190      * @param connectors The connectors to set.
191      */
setConnectors(Connector[] connectors)192     public void setConnectors(Connector[] connectors)
193     {
194         if (connectors!=null)
195         {
196             for (int i=0;i<connectors.length;i++)
197                 connectors[i].setServer(this);
198         }
199 
200         _container.update(this, _connectors, connectors, "connector");
201         _connectors = connectors;
202     }
203 
204     /* ------------------------------------------------------------ */
205     /**
206      * @return Returns the threadPool.
207      */
getThreadPool()208     public ThreadPool getThreadPool()
209     {
210         return _threadPool;
211     }
212 
213     /* ------------------------------------------------------------ */
214     /**
215      * @param threadPool The threadPool to set.
216      */
setThreadPool(ThreadPool threadPool)217     public void setThreadPool(ThreadPool threadPool)
218     {
219         if (_threadPool!=null)
220             removeBean(_threadPool);
221         _container.update(this, _threadPool, threadPool, "threadpool",false);
222         _threadPool = threadPool;
223         if (_threadPool!=null)
224             addBean(_threadPool);
225     }
226 
227     /**
228      * @return true if {@link #dumpStdErr()} is called after starting
229      */
isDumpAfterStart()230     public boolean isDumpAfterStart()
231     {
232         return _dumpAfterStart;
233     }
234 
235     /**
236      * @param dumpAfterStart true if {@link #dumpStdErr()} is called after starting
237      */
setDumpAfterStart(boolean dumpAfterStart)238     public void setDumpAfterStart(boolean dumpAfterStart)
239     {
240         _dumpAfterStart = dumpAfterStart;
241     }
242 
243     /**
244      * @return true if {@link #dumpStdErr()} is called before stopping
245      */
isDumpBeforeStop()246     public boolean isDumpBeforeStop()
247     {
248         return _dumpBeforeStop;
249     }
250 
251     /**
252      * @param dumpBeforeStop true if {@link #dumpStdErr()} is called before stopping
253      */
setDumpBeforeStop(boolean dumpBeforeStop)254     public void setDumpBeforeStop(boolean dumpBeforeStop)
255     {
256         _dumpBeforeStop = dumpBeforeStop;
257     }
258 
259 
260 
261     /* ------------------------------------------------------------ */
262     @Override
doStart()263     protected void doStart() throws Exception
264     {
265         if (getStopAtShutdown())
266         {
267             ShutdownThread.register(this);
268         }
269 
270         ShutdownMonitor.getInstance().start(); // initialize
271 
272         LOG.info("jetty-"+__version);
273         HttpGenerator.setServerVersion(__version);
274 
275         MultiException mex=new MultiException();
276 
277         if (_threadPool==null)
278             setThreadPool(new QueuedThreadPool());
279 
280         try
281         {
282             super.doStart();
283         }
284         catch(Throwable e)
285         {
286             mex.add(e);
287         }
288 
289         if (_connectors!=null && mex.size()==0)
290         {
291             for (int i=0;i<_connectors.length;i++)
292             {
293                 try{_connectors[i].start();}
294                 catch(Throwable e)
295                 {
296                     mex.add(e);
297                 }
298             }
299         }
300 
301         if (isDumpAfterStart())
302             dumpStdErr();
303 
304         mex.ifExceptionThrow();
305     }
306 
307     /* ------------------------------------------------------------ */
308     @Override
doStop()309     protected void doStop() throws Exception
310     {
311         if (isDumpBeforeStop())
312             dumpStdErr();
313 
314         MultiException mex=new MultiException();
315 
316         if (_graceful>0)
317         {
318             if (_connectors!=null)
319             {
320                 for (int i=_connectors.length;i-->0;)
321                 {
322                     LOG.info("Graceful shutdown {}",_connectors[i]);
323                     try{_connectors[i].close();}catch(Throwable e){mex.add(e);}
324                 }
325             }
326 
327             Handler[] contexts = getChildHandlersByClass(Graceful.class);
328             for (int c=0;c<contexts.length;c++)
329             {
330                 Graceful context=(Graceful)contexts[c];
331                 LOG.info("Graceful shutdown {}",context);
332                 context.setShutdown(true);
333             }
334             Thread.sleep(_graceful);
335         }
336 
337         if (_connectors!=null)
338         {
339             for (int i=_connectors.length;i-->0;)
340                 try{_connectors[i].stop();}catch(Throwable e){mex.add(e);}
341         }
342 
343         try {super.doStop(); } catch(Throwable e) { mex.add(e);}
344 
345         mex.ifExceptionThrow();
346 
347         if (getStopAtShutdown())
348             ShutdownThread.deregister(this);
349     }
350 
351     /* ------------------------------------------------------------ */
352     /* Handle a request from a connection.
353      * Called to handle a request on the connection when either the header has been received,
354      * or after the entire request has been received (for short requests of known length), or
355      * on the dispatch of an async request.
356      */
handle(AbstractHttpConnection connection)357     public void handle(AbstractHttpConnection connection) throws IOException, ServletException
358     {
359         final String target=connection.getRequest().getPathInfo();
360         final Request request=connection.getRequest();
361         final Response response=connection.getResponse();
362 
363         if (LOG.isDebugEnabled())
364         {
365             LOG.debug("REQUEST "+target+" on "+connection);
366             handle(target, request, request, response);
367             LOG.debug("RESPONSE "+target+"  "+connection.getResponse().getStatus()+" handled="+request.isHandled());
368         }
369         else
370             handle(target, request, request, response);
371     }
372 
373     /* ------------------------------------------------------------ */
374     /* Handle a request from a connection.
375      * Called to handle a request on the connection when either the header has been received,
376      * or after the entire request has been received (for short requests of known length), or
377      * on the dispatch of an async request.
378      */
handleAsync(AbstractHttpConnection connection)379     public void handleAsync(AbstractHttpConnection connection) throws IOException, ServletException
380     {
381         final AsyncContinuation async = connection.getRequest().getAsyncContinuation();
382         final AsyncContinuation.AsyncEventState state = async.getAsyncEventState();
383 
384         final Request baseRequest=connection.getRequest();
385         final String path=state.getPath();
386 
387         if (path!=null)
388         {
389             // this is a dispatch with a path
390             final String contextPath=state.getServletContext().getContextPath();
391             HttpURI uri = new HttpURI(URIUtil.addPaths(contextPath,path));
392             baseRequest.setUri(uri);
393             baseRequest.setRequestURI(null);
394             baseRequest.setPathInfo(baseRequest.getRequestURI());
395             if (uri.getQuery()!=null)
396                 baseRequest.mergeQueryString(uri.getQuery()); //we have to assume dispatch path and query are UTF8
397         }
398 
399         final String target=baseRequest.getPathInfo();
400         final HttpServletRequest request=(HttpServletRequest)async.getRequest();
401         final HttpServletResponse response=(HttpServletResponse)async.getResponse();
402 
403         if (LOG.isDebugEnabled())
404         {
405             LOG.debug("REQUEST "+target+" on "+connection);
406             handle(target, baseRequest, request, response);
407             LOG.debug("RESPONSE "+target+"  "+connection.getResponse().getStatus());
408         }
409         else
410             handle(target, baseRequest, request, response);
411 
412     }
413 
414 
415     /* ------------------------------------------------------------ */
join()416     public void join() throws InterruptedException
417     {
418         getThreadPool().join();
419     }
420 
421     /* ------------------------------------------------------------ */
422     /* ------------------------------------------------------------ */
423     /**
424      * @return Returns the sessionIdManager.
425      */
getSessionIdManager()426     public SessionIdManager getSessionIdManager()
427     {
428         return _sessionIdManager;
429     }
430 
431     /* ------------------------------------------------------------ */
432     /* ------------------------------------------------------------ */
433     /**
434      * @param sessionIdManager The sessionIdManager to set.
435      */
setSessionIdManager(SessionIdManager sessionIdManager)436     public void setSessionIdManager(SessionIdManager sessionIdManager)
437     {
438         if (_sessionIdManager!=null)
439             removeBean(_sessionIdManager);
440         _container.update(this, _sessionIdManager, sessionIdManager, "sessionIdManager",false);
441         _sessionIdManager = sessionIdManager;
442         if (_sessionIdManager!=null)
443             addBean(_sessionIdManager);
444     }
445 
446     /* ------------------------------------------------------------ */
setSendServerVersion(boolean sendServerVersion)447     public void setSendServerVersion (boolean sendServerVersion)
448     {
449         _sendServerVersion = sendServerVersion;
450     }
451 
452     /* ------------------------------------------------------------ */
getSendServerVersion()453     public boolean getSendServerVersion()
454     {
455         return _sendServerVersion;
456     }
457 
458     /* ------------------------------------------------------------ */
459     /**
460      * @param sendDateHeader
461      */
setSendDateHeader(boolean sendDateHeader)462     public void setSendDateHeader(boolean sendDateHeader)
463     {
464         _sendDateHeader = sendDateHeader;
465     }
466 
467     /* ------------------------------------------------------------ */
getSendDateHeader()468     public boolean getSendDateHeader()
469     {
470         return _sendDateHeader;
471     }
472 
473     /* ------------------------------------------------------------ */
474     /**
475      */
476     @Deprecated
getMaxCookieVersion()477     public int getMaxCookieVersion()
478     {
479         return 1;
480     }
481 
482     /* ------------------------------------------------------------ */
483     /**
484      */
485     @Deprecated
setMaxCookieVersion(int maxCookieVersion)486     public void setMaxCookieVersion(int maxCookieVersion)
487     {
488     }
489 
490     /* ------------------------------------------------------------ */
491     /**
492      * Add a LifeCycle object to be started/stopped
493      * along with the Server.
494      * @deprecated Use {@link #addBean(Object)}
495      * @param c
496      */
497     @Deprecated
addLifeCycle(LifeCycle c)498     public void addLifeCycle (LifeCycle c)
499     {
500         addBean(c);
501     }
502 
503     /* ------------------------------------------------------------ */
504     /**
505      * Add an associated bean.
506      * The bean will be added to the servers {@link Container}
507      * and if it is a {@link LifeCycle} instance, it will be
508      * started/stopped along with the Server. Any beans that are also
509      * {@link Destroyable}, will be destroyed with the server.
510      * @param o the bean object to add
511      */
512     @Override
addBean(Object o)513     public boolean addBean(Object o)
514     {
515         if (super.addBean(o))
516         {
517             _container.addBean(o);
518             return true;
519         }
520         return false;
521     }
522 
523     /**
524      * Remove a LifeCycle object to be started/stopped
525      * along with the Server
526      * @deprecated Use {@link #removeBean(Object)}
527      */
528     @Deprecated
removeLifeCycle(LifeCycle c)529     public void removeLifeCycle (LifeCycle c)
530     {
531         removeBean(c);
532     }
533 
534     /* ------------------------------------------------------------ */
535     /**
536      * Remove an associated bean.
537      */
538     @Override
removeBean(Object o)539     public boolean removeBean (Object o)
540     {
541         if (super.removeBean(o))
542         {
543             _container.removeBean(o);
544             return true;
545         }
546         return false;
547     }
548 
549     /* ------------------------------------------------------------ */
550     /*
551      * @see org.eclipse.util.AttributesMap#clearAttributes()
552      */
clearAttributes()553     public void clearAttributes()
554     {
555         _attributes.clearAttributes();
556     }
557 
558     /* ------------------------------------------------------------ */
559     /*
560      * @see org.eclipse.util.AttributesMap#getAttribute(java.lang.String)
561      */
getAttribute(String name)562     public Object getAttribute(String name)
563     {
564         return _attributes.getAttribute(name);
565     }
566 
567     /* ------------------------------------------------------------ */
568     /*
569      * @see org.eclipse.util.AttributesMap#getAttributeNames()
570      */
getAttributeNames()571     public Enumeration getAttributeNames()
572     {
573         return AttributesMap.getAttributeNamesCopy(_attributes);
574     }
575 
576     /* ------------------------------------------------------------ */
577     /*
578      * @see org.eclipse.util.AttributesMap#removeAttribute(java.lang.String)
579      */
removeAttribute(String name)580     public void removeAttribute(String name)
581     {
582         _attributes.removeAttribute(name);
583     }
584 
585     /* ------------------------------------------------------------ */
586     /*
587      * @see org.eclipse.util.AttributesMap#setAttribute(java.lang.String, java.lang.Object)
588      */
setAttribute(String name, Object attribute)589     public void setAttribute(String name, Object attribute)
590     {
591         _attributes.setAttribute(name, attribute);
592     }
593 
594     /* ------------------------------------------------------------ */
595     /**
596      * @return the graceful
597      */
getGracefulShutdown()598     public int getGracefulShutdown()
599     {
600         return _graceful;
601     }
602 
603     /* ------------------------------------------------------------ */
604     /**
605      * Set graceful shutdown timeout.  If set, the internal <code>doStop()</code> method will not immediately stop the
606      * server. Instead, all {@link Connector}s will be closed so that new connections will not be accepted
607      * and all handlers that implement {@link Graceful} will be put into the shutdown mode so that no new requests
608      * will be accepted, but existing requests can complete.  The server will then wait the configured timeout
609      * before stopping.
610      * @param timeoutMS the milliseconds to wait for existing request to complete before stopping the server.
611      *
612      */
setGracefulShutdown(int timeoutMS)613     public void setGracefulShutdown(int timeoutMS)
614     {
615         _graceful=timeoutMS;
616     }
617 
618     /* ------------------------------------------------------------ */
619     @Override
toString()620     public String toString()
621     {
622         return this.getClass().getName()+"@"+Integer.toHexString(hashCode());
623     }
624 
625     /* ------------------------------------------------------------ */
626     @Override
dump(Appendable out,String indent)627     public void dump(Appendable out,String indent) throws IOException
628     {
629         dumpThis(out);
630         dump(out,indent,TypeUtil.asList(getHandlers()),getBeans(),TypeUtil.asList(_connectors));
631     }
632 
633 
634     /* ------------------------------------------------------------ */
isUncheckedPrintWriter()635     public boolean isUncheckedPrintWriter()
636     {
637         return _uncheckedPrintWriter;
638     }
639 
640     /* ------------------------------------------------------------ */
setUncheckedPrintWriter(boolean unchecked)641     public void setUncheckedPrintWriter(boolean unchecked)
642     {
643         _uncheckedPrintWriter=unchecked;
644     }
645 
646 
647     /* ------------------------------------------------------------ */
648     /* A handler that can be gracefully shutdown.
649      * Called by doStop if a {@link #setGracefulShutdown} period is set.
650      * TODO move this somewhere better
651      */
652     public interface Graceful extends Handler
653     {
setShutdown(boolean shutdown)654         public void setShutdown(boolean shutdown);
655     }
656 
657     /* ------------------------------------------------------------ */
main(String...args)658     public static void main(String...args) throws Exception
659     {
660         System.err.println(getVersion());
661     }
662 }
663