View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2012 Sabre Holdings.
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  
20  package org.eclipse.jetty.ant;
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.net.MalformedURLException;
25  import java.util.ArrayList;
26  import java.util.Iterator;
27  import java.util.List;
28  
29  import org.eclipse.jetty.ant.types.Connector;
30  import org.eclipse.jetty.ant.types.ContextHandlers;
31  import org.eclipse.jetty.ant.utils.ServerProxy;
32  import org.eclipse.jetty.ant.utils.TaskLog;
33  import org.eclipse.jetty.security.LoginService;
34  import org.eclipse.jetty.server.Handler;
35  import org.eclipse.jetty.server.RequestLog;
36  import org.eclipse.jetty.server.Server;
37  import org.eclipse.jetty.server.ServerConnector;
38  import org.eclipse.jetty.server.ShutdownMonitor;
39  import org.eclipse.jetty.server.handler.ContextHandler;
40  import org.eclipse.jetty.server.handler.ContextHandlerCollection;
41  import org.eclipse.jetty.server.handler.DefaultHandler;
42  import org.eclipse.jetty.server.handler.HandlerCollection;
43  import org.eclipse.jetty.server.handler.RequestLogHandler;
44  import org.eclipse.jetty.util.Scanner;
45  import org.eclipse.jetty.util.resource.Resource;
46  import org.eclipse.jetty.xml.XmlConfiguration;
47  import org.xml.sax.SAXException;
48  
49  
50  
51  /**
52   * A proxy class for interaction with Jetty server object. Used to have some
53   * level of abstraction over standard Jetty classes.
54   */
55  public class ServerProxyImpl implements ServerProxy
56  {
57  
58      /** Proxied Jetty server object. */
59      private Server server;
60      
61      /** Temporary files directory. */
62      private File tempDirectory;
63      
64      /** Collection of context handlers (web application contexts). */
65      private ContextHandlerCollection contexts;
66  
67      /** Location of jetty.xml file. */
68      private File jettyXml;
69  
70      /** List of connectors. */
71      private List<Connector> connectors;
72  
73      /** Request logger. */
74      private RequestLog requestLog;
75  
76      /** User realms. */
77      private List<LoginService> loginServices;
78  
79      /** List of added web applications. */
80      private List<AntWebAppContext> webApplications = new ArrayList<AntWebAppContext>();
81  
82      /** other contexts to deploy */
83      private ContextHandlers contextHandlers;
84  
85      /** scan interval for changed files */
86      private int scanIntervalSecs;
87  
88      /** port to listen for stop command */
89      private int stopPort;
90  
91      /** security key for stop command */
92      private String stopKey;
93  
94      /** wait for all jetty threads to exit or continue */
95      private boolean daemon;
96  
97  
98      private boolean configured = false;
99  
100 
101     
102     /**
103      * WebAppScannerListener
104      *
105      * Handle notifications that files we are interested in have changed
106      * during execution.
107      * 
108      */
109     public static class WebAppScannerListener implements Scanner.BulkListener
110     {     
111         AntWebAppContext awc;
112 
113         public WebAppScannerListener (AntWebAppContext awc)
114         {
115             this.awc = awc;
116         }
117 
118         public void filesChanged(List<String> changedFileNames)
119         {
120             boolean isScanned = false;
121             try
122             {
123                 Iterator<String> itor = changedFileNames.iterator();
124                 while (!isScanned && itor.hasNext())
125                 {
126                     isScanned = awc.isScanned(Resource.newResource(itor.next()).getFile());
127                 }
128                 if (isScanned)
129                 {
130                     awc.stop();
131                     awc.start();
132                 }
133             }
134             catch (Exception e)
135             {
136                 TaskLog.log(e.getMessage());
137             }
138         }
139 
140     }
141 
142 
143     /**
144      * Default constructor. Creates a new Jetty server with a standard connector
145      * listening on a given port.
146      */
147     public ServerProxyImpl ()
148     {
149         server = new Server();
150         server.setStopAtShutdown(true);
151     }
152 
153    
154     public void addWebApplication(AntWebAppContext webApp)
155     {
156        webApplications.add(webApp);
157     }
158 
159     public int getStopPort()
160     {
161         return stopPort;
162     }
163 
164     public void setStopPort(int stopPort)
165     {
166         this.stopPort = stopPort;
167     }
168 
169     public String getStopKey()
170     {
171         return stopKey;
172     }
173 
174     public void setStopKey(String stopKey)
175     {
176         this.stopKey = stopKey;
177     }
178 
179     public File getJettyXml()
180     {
181         return jettyXml;
182     }
183 
184     public void setJettyXml(File jettyXml)
185     {
186         this.jettyXml = jettyXml;
187     }
188 
189     public List<Connector> getConnectors()
190     {
191         return connectors;
192     }
193 
194     public void setConnectors(List<Connector> connectors)
195     {
196         this.connectors = connectors;
197     }
198 
199     public RequestLog getRequestLog()
200     {
201         return requestLog;
202     }
203 
204     public void setRequestLog(RequestLog requestLog)
205     {
206         this.requestLog = requestLog;
207     }
208 
209     public List<LoginService> getLoginServices()
210     {
211         return loginServices;
212     }
213 
214     public void setLoginServices(List<LoginService> loginServices)
215     {
216         this.loginServices = loginServices;
217     }
218 
219     public List<AntWebAppContext> getWebApplications()
220     {
221         return webApplications;
222     }
223 
224     public void setWebApplications(List<AntWebAppContext> webApplications)
225     {
226         this.webApplications = webApplications;
227     }
228 
229     
230     public File getTempDirectory()
231     {
232         return tempDirectory;
233     }
234 
235 
236     public void setTempDirectory(File tempDirectory)
237     {
238         this.tempDirectory = tempDirectory;
239     }
240 
241 
242     /**
243      * @see org.eclipse.jetty.ant.utils.ServerProxy#start()
244      */
245     public void start()
246     {
247         try
248         {
249             configure();
250             
251             configureWebApps();
252             
253             server.start();
254          
255             System.setProperty("jetty.ant.server.port","" + ((ServerConnector)server.getConnectors()[0]).getLocalPort());
256             
257             String host = ((ServerConnector)server.getConnectors()[0]).getHost();
258             
259             if (host == null)
260             {
261                 System.setProperty("jetty.ant.server.host", "localhost");
262             }
263             else
264             {
265                 System.setProperty("jetty.ant.server.host", host);
266             }
267             
268             startScanners();
269             
270             TaskLog.log("Jetty AntTask Started");
271 
272             if (!daemon)
273                 server.join();
274         }
275         catch (InterruptedException e)
276         {
277             new RuntimeException(e);
278         }
279         catch (Exception e)
280         {
281             e.printStackTrace();
282             new RuntimeException(e);
283         }
284     }
285 
286 
287 
288   
289     /**
290      * @see org.eclipse.jetty.ant.utils.ServerProxy#getProxiedObject()
291      */
292     public Object getProxiedObject()
293     {
294         return server;
295     }
296 
297 
298     /**
299      * @return the daemon
300      */
301     public boolean isDaemon()
302     {
303         return daemon;
304     }
305 
306 
307     /**
308      * @param daemon the daemon to set
309      */
310     public void setDaemon(boolean daemon)
311     {       
312         this.daemon = daemon;
313     }
314 
315 
316     /**
317      * @return the contextHandlers
318      */
319     public ContextHandlers getContextHandlers()
320     {
321         return contextHandlers;
322     }
323 
324 
325     /**
326      * @param contextHandlers the contextHandlers to set
327      */
328     public void setContextHandlers (ContextHandlers contextHandlers)
329     {
330         this.contextHandlers = contextHandlers;
331     }
332 
333 
334     public int getScanIntervalSecs()
335     {
336         return scanIntervalSecs;
337     }
338 
339 
340     public void setScanIntervalSecs(int scanIntervalSecs)
341     {
342         this.scanIntervalSecs = scanIntervalSecs;
343     }
344     
345 
346     /**
347      * Configures Jetty server before adding any web applications to it.
348      */
349     private void configure()
350     {
351         if (configured)
352             return;
353         
354         configured = true;
355 
356         if(stopPort>0 && stopKey!=null)
357         {
358             ShutdownMonitor monitor = ShutdownMonitor.getInstance();
359             monitor.setPort(stopPort);
360             monitor.setKey(stopKey);
361             monitor.setExitVm(false);
362         }
363         
364         if (tempDirectory != null && !tempDirectory.exists())
365             tempDirectory.mkdirs();
366         
367         // Applies external configuration via jetty.xml
368         applyJettyXml();
369 
370         // Configures connectors for this server instance.
371         if (connectors != null)
372         {
373             for (Connector c:connectors)
374             {
375                 ServerConnector jc = new ServerConnector(server);
376 
377                 jc.setPort(c.getPort());
378                 jc.setIdleTimeout(c.getMaxIdleTime());
379 
380                 server.addConnector(jc);
381             }
382         }
383 
384         // Configures login services
385         if (loginServices != null)
386         {
387             for (LoginService ls:loginServices)
388             {
389                 server.addBean(ls);
390             }
391         }
392 
393         // Does not cache resources, to prevent Windows from locking files
394         Resource.setDefaultUseCaches(false);
395 
396         // Set default server handlers
397         configureHandlers();
398     }
399     
400     
401     /**
402      * 
403      */
404     private void configureHandlers()
405     {
406         RequestLogHandler requestLogHandler = new RequestLogHandler();
407         if (requestLog != null)
408             requestLogHandler.setRequestLog(requestLog);
409 
410         contexts = (ContextHandlerCollection) server
411                 .getChildHandlerByClass(ContextHandlerCollection.class);
412         if (contexts == null)
413         {
414             contexts = new ContextHandlerCollection();
415             HandlerCollection handlers = (HandlerCollection) server
416                     .getChildHandlerByClass(HandlerCollection.class);
417             if (handlers == null)
418             {
419                 handlers = new HandlerCollection();
420                 server.setHandler(handlers);
421                 handlers.setHandlers(new Handler[] { contexts, new DefaultHandler(),
422                         requestLogHandler });
423             }
424             else
425             {
426                 handlers.addHandler(contexts);
427             }
428         }
429         
430         //if there are any extra contexts to deploy
431         if (contextHandlers != null && contextHandlers.getContextHandlers() != null)
432         {
433             for (ContextHandler c:contextHandlers.getContextHandlers())
434                 contexts.addHandler(c);
435         }
436     }
437 
438 
439 
440     
441     /**
442      * Applies jetty.xml configuration to the Jetty server instance.
443      */
444     private void applyJettyXml()
445     {
446         if (jettyXml != null && jettyXml.exists())
447         {
448             TaskLog.log("Configuring jetty from xml configuration file = "
449                     + jettyXml.getAbsolutePath());
450             XmlConfiguration configuration;
451             try
452             {
453                 configuration = new XmlConfiguration(Resource.toURL(jettyXml));
454                 configuration.configure(server);
455             }
456             catch (MalformedURLException e)
457             {
458                 throw new RuntimeException(e);
459             }
460             catch (SAXException e)
461             {
462                 throw new RuntimeException(e);
463             }
464             catch (IOException e)
465             {
466                 throw new RuntimeException(e);
467             }
468             catch (Exception e)
469             {
470                 throw new RuntimeException(e);
471             }
472         }
473     }
474 
475     
476     /**
477      * Starts web applications' scanners.
478      */
479     private void startScanners() throws Exception
480     {
481         for (AntWebAppContext awc:webApplications)
482         {
483             if (scanIntervalSecs <= 0)
484                 return;
485 
486             List<File> scanList = awc.getScanFiles();
487  
488             TaskLog.log("Web application '" + awc + "': starting scanner at interval of "
489                     + scanIntervalSecs + " seconds.");
490             Scanner.Listener changeListener = new WebAppScannerListener(awc);
491             Scanner scanner = new Scanner();
492             scanner.setScanInterval(scanIntervalSecs);
493             scanner.addListener(changeListener);
494             scanner.setScanDirs(scanList);
495             scanner.setReportExistingFilesOnStartup(false);
496             scanner.start();
497         }  
498     }
499     
500     
501     /**
502      * 
503      */
504     private void configureWebApps()
505     {
506         for (AntWebAppContext awc:webApplications)
507         {
508             awc.setAttribute(AntWebAppContext.BASETEMPDIR, tempDirectory);
509             if (contexts != null)
510                 contexts.addHandler(awc);
511         }
512     }
513     
514 }