// // ======================================================================== // Copyright (c) 1995-2012 Sabre Holdings. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // and Apache License v2.0 which accompanies this distribution. // // The Eclipse Public License is available at // http://www.eclipse.org/legal/epl-v10.html // // The Apache License v2.0 is available at // http://www.opensource.org/licenses/apache2.0.php // // You may elect to redistribute this code under either of these licenses. // ======================================================================== // package org.eclipse.jetty.ant; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.jetty.ant.types.Connector; import org.eclipse.jetty.ant.types.ContextHandlers; import org.eclipse.jetty.ant.utils.ServerProxy; import org.eclipse.jetty.ant.utils.TaskLog; import org.eclipse.jetty.security.LoginService; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.RequestLog; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.server.ShutdownMonitor; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.RequestLogHandler; import org.eclipse.jetty.util.Scanner; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.xml.XmlConfiguration; import org.xml.sax.SAXException; /** * A proxy class for interaction with Jetty server object. Used to have some * level of abstraction over standard Jetty classes. */ public class ServerProxyImpl implements ServerProxy { /** Proxied Jetty server object. */ private Server server; /** Temporary files directory. */ private File tempDirectory; /** Collection of context handlers (web application contexts). */ private ContextHandlerCollection contexts; /** Location of jetty.xml file. */ private File jettyXml; /** List of connectors. */ private List<Connector> connectors; /** Request logger. */ private RequestLog requestLog; /** User realms. */ private List<LoginService> loginServices; /** List of added web applications. */ private List<AntWebAppContext> webApplications = new ArrayList<AntWebAppContext>(); /** other contexts to deploy */ private ContextHandlers contextHandlers; /** scan interval for changed files */ private int scanIntervalSecs; /** port to listen for stop command */ private int stopPort; /** security key for stop command */ private String stopKey; /** wait for all jetty threads to exit or continue */ private boolean daemon; private boolean configured = false; /** * WebAppScannerListener * * Handle notifications that files we are interested in have changed * during execution. * */ public static class WebAppScannerListener implements Scanner.BulkListener { AntWebAppContext awc; public WebAppScannerListener (AntWebAppContext awc) { this.awc = awc; } public void filesChanged(List<String> changedFileNames) { boolean isScanned = false; try { Iterator<String> itor = changedFileNames.iterator(); while (!isScanned && itor.hasNext()) { isScanned = awc.isScanned(Resource.newResource(itor.next()).getFile()); } if (isScanned) { awc.stop(); awc.start(); } } catch (Exception e) { TaskLog.log(e.getMessage()); } } } /** * Default constructor. Creates a new Jetty server with a standard connector * listening on a given port. */ public ServerProxyImpl () { server = new Server(); server.setStopAtShutdown(true); } public void addWebApplication(AntWebAppContext webApp) { webApplications.add(webApp); } public int getStopPort() { return stopPort; } public void setStopPort(int stopPort) { this.stopPort = stopPort; } public String getStopKey() { return stopKey; } public void setStopKey(String stopKey) { this.stopKey = stopKey; } public File getJettyXml() { return jettyXml; } public void setJettyXml(File jettyXml) { this.jettyXml = jettyXml; } public List<Connector> getConnectors() { return connectors; } public void setConnectors(List<Connector> connectors) { this.connectors = connectors; } public RequestLog getRequestLog() { return requestLog; } public void setRequestLog(RequestLog requestLog) { this.requestLog = requestLog; } public List<LoginService> getLoginServices() { return loginServices; } public void setLoginServices(List<LoginService> loginServices) { this.loginServices = loginServices; } public List<AntWebAppContext> getWebApplications() { return webApplications; } public void setWebApplications(List<AntWebAppContext> webApplications) { this.webApplications = webApplications; } public File getTempDirectory() { return tempDirectory; } public void setTempDirectory(File tempDirectory) { this.tempDirectory = tempDirectory; } /** * @see org.eclipse.jetty.ant.utils.ServerProxy#start() */ public void start() { try { configure(); configureWebApps(); server.start(); System.setProperty("jetty.ant.server.port","" + ((ServerConnector)server.getConnectors()[0]).getLocalPort()); String host = ((ServerConnector)server.getConnectors()[0]).getHost(); if (host == null) { System.setProperty("jetty.ant.server.host", "localhost"); } else { System.setProperty("jetty.ant.server.host", host); } startScanners(); TaskLog.log("Jetty AntTask Started"); if (!daemon) server.join(); } catch (InterruptedException e) { new RuntimeException(e); } catch (Exception e) { e.printStackTrace(); new RuntimeException(e); } } /** * @see org.eclipse.jetty.ant.utils.ServerProxy#getProxiedObject() */ public Object getProxiedObject() { return server; } /** * @return the daemon */ public boolean isDaemon() { return daemon; } /** * @param daemon the daemon to set */ public void setDaemon(boolean daemon) { this.daemon = daemon; } /** * @return the contextHandlers */ public ContextHandlers getContextHandlers() { return contextHandlers; } /** * @param contextHandlers the contextHandlers to set */ public void setContextHandlers (ContextHandlers contextHandlers) { this.contextHandlers = contextHandlers; } public int getScanIntervalSecs() { return scanIntervalSecs; } public void setScanIntervalSecs(int scanIntervalSecs) { this.scanIntervalSecs = scanIntervalSecs; } /** * Configures Jetty server before adding any web applications to it. */ private void configure() { if (configured) return; configured = true; if(stopPort>0 && stopKey!=null) { ShutdownMonitor monitor = ShutdownMonitor.getInstance(); monitor.setPort(stopPort); monitor.setKey(stopKey); monitor.setExitVm(false); } if (tempDirectory != null && !tempDirectory.exists()) tempDirectory.mkdirs(); // Applies external configuration via jetty.xml applyJettyXml(); // Configures connectors for this server instance. if (connectors != null) { for (Connector c:connectors) { ServerConnector jc = new ServerConnector(server); jc.setPort(c.getPort()); jc.setIdleTimeout(c.getMaxIdleTime()); server.addConnector(jc); } } // Configures login services if (loginServices != null) { for (LoginService ls:loginServices) { server.addBean(ls); } } // Does not cache resources, to prevent Windows from locking files Resource.setDefaultUseCaches(false); // Set default server handlers configureHandlers(); } /** * */ private void configureHandlers() { RequestLogHandler requestLogHandler = new RequestLogHandler(); if (requestLog != null) requestLogHandler.setRequestLog(requestLog); contexts = (ContextHandlerCollection) server .getChildHandlerByClass(ContextHandlerCollection.class); if (contexts == null) { contexts = new ContextHandlerCollection(); HandlerCollection handlers = (HandlerCollection) server .getChildHandlerByClass(HandlerCollection.class); if (handlers == null) { handlers = new HandlerCollection(); server.setHandler(handlers); handlers.setHandlers(new Handler[] { contexts, new DefaultHandler(), requestLogHandler }); } else { handlers.addHandler(contexts); } } //if there are any extra contexts to deploy if (contextHandlers != null && contextHandlers.getContextHandlers() != null) { for (ContextHandler c:contextHandlers.getContextHandlers()) contexts.addHandler(c); } } /** * Applies jetty.xml configuration to the Jetty server instance. */ private void applyJettyXml() { if (jettyXml != null && jettyXml.exists()) { TaskLog.log("Configuring jetty from xml configuration file = " + jettyXml.getAbsolutePath()); XmlConfiguration configuration; try { configuration = new XmlConfiguration(Resource.toURL(jettyXml)); configuration.configure(server); } catch (MalformedURLException e) { throw new RuntimeException(e); } catch (SAXException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } catch (Exception e) { throw new RuntimeException(e); } } } /** * Starts web applications' scanners. */ private void startScanners() throws Exception { for (AntWebAppContext awc:webApplications) { if (scanIntervalSecs <= 0) return; List<File> scanList = awc.getScanFiles(); TaskLog.log("Web application '" + awc + "': starting scanner at interval of " + scanIntervalSecs + " seconds."); Scanner.Listener changeListener = new WebAppScannerListener(awc); Scanner scanner = new Scanner(); scanner.setScanInterval(scanIntervalSecs); scanner.addListener(changeListener); scanner.setScanDirs(scanList); scanner.setReportExistingFilesOnStartup(false); scanner.start(); } } /** * */ private void configureWebApps() { for (AntWebAppContext awc:webApplications) { awc.setAttribute(AntWebAppContext.BASETEMPDIR, tempDirectory); if (contexts != null) contexts.addHandler(awc); } } }