All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.gradle.api.plugins.jetty.AbstractJettyRunTask Maven / Gradle / Ivy

There is a newer version: 8.11.1
Show newest version
/*
 * Copyright 2010 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.gradle.api.plugins.jetty;

import org.gradle.api.GradleException;
import org.gradle.api.internal.ConventionTask;
import org.gradle.api.plugins.jetty.internal.ConsoleScanner;
import org.gradle.api.plugins.jetty.internal.JettyPluginServer;
import org.gradle.api.plugins.jetty.internal.JettyPluginWebAppContext;
import org.gradle.api.plugins.jetty.internal.Monitor;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.TaskAction;
import org.gradle.internal.classpath.DefaultClassPath;
import org.gradle.internal.logging.progress.ProgressLogger;
import org.gradle.internal.logging.progress.ProgressLoggerFactory;
import org.mortbay.jetty.Connector;
import org.mortbay.jetty.RequestLog;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.security.UserRealm;
import org.mortbay.util.Scanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

/**
 * Base class for all tasks which deploy a web application to an embedded Jetty web container.
 *
 * @deprecated The Jetty plugin has been deprecated
 */
@Deprecated
public abstract class AbstractJettyRunTask extends ConventionTask {
    private final static Logger LOGGER = LoggerFactory.getLogger(AbstractJettyRunTask.class);

    private Iterable additionalRuntimeJars = new ArrayList();

    /**
     * The proxy for the Server object.
     */
    private JettyPluginServer server;

    /**
     * The "virtual" webapp created by the plugin.
     */
    private JettyPluginWebAppContext webAppConfig;

    /**
     * The context path for the webapp.
     */
    private String contextPath;

    /**
     * A webdefault.xml file to use instead of the default for the webapp. Optional.
     */
    private File webDefaultXml;

    /**
     * A web.xml file to be applied AFTER the webapp's web.xml file. Useful for applying different build profiles, eg test, production etc. Optional.
     */
    private File overrideWebXml;

    private int scanIntervalSeconds;

    protected String reload;

    /**
     * Location of a jetty XML configuration file whose contents will be applied before any plugin configuration. Optional.
     */
    private File jettyConfig;

    /**
     * Port to listen to stop jetty on.
     */
    private Integer stopPort;

    /**
     * Key to provide when stopping jetty.
     */
    private String stopKey;

    /**
     * 

Determines whether or not the server blocks when started. The default behavior (daemon = false) will cause the server to pause other processes while it continues to handle web requests. * This is useful when starting the server with the intent to work with it interactively.

Often, it is desirable to let the server start and continue running subsequent processes in an * automated build environment. This can be facilitated by setting daemon to true.

*/ private boolean daemon; private Integer httpPort; /** * List of connectors to use. If none are configured then we use a single SelectChannelConnector at port 8080 */ private Connector[] connectors; /** * List of security realms to set up. Optional. */ private UserRealm[] userRealms; /** * A RequestLog implementation to use for the webapp at runtime. Optional. */ private RequestLog requestLog; /** * A scanner to check for changes to the webapp. */ private Scanner scanner = new Scanner(); /** * List of Listeners for the scanner. */ protected List scannerListeners; /** * A scanner to check ENTER hits on the console. */ protected Thread consoleScanner; public static final String PORT_SYSPROPERTY = "jetty.port"; public abstract void validateConfiguration(); public abstract void configureScanner(); public abstract void applyJettyXml() throws Exception; /** * create a proxy that wraps a particular jetty version Server object. * * @return The Jetty Plugin Server */ public abstract JettyPluginServer createServer() throws Exception; public abstract void finishConfigurationBeforeStart() throws Exception; @TaskAction protected void start() { ClassLoader originalClassloader = Server.class.getClassLoader(); List additionalClasspath = new ArrayList(); for (File additionalRuntimeJar : getAdditionalRuntimeJars()) { additionalClasspath.add(additionalRuntimeJar); } URLClassLoader jettyClassloader = new URLClassLoader(new DefaultClassPath(additionalClasspath).getAsURLArray(), originalClassloader); try { Thread.currentThread().setContextClassLoader(jettyClassloader); startJetty(); } finally { Thread.currentThread().setContextClassLoader(originalClassloader); } } @Internal public JettyPluginServer getServer() { return this.server; } public void setServer(JettyPluginServer server) { this.server = server; } public void setScannerListeners(List listeners) { this.scannerListeners = new ArrayList(listeners); } @Internal public List getScannerListeners() { return this.scannerListeners; } @Internal public Scanner getScanner() { return scanner; } public void startJetty() { LOGGER.info("Configuring Jetty for " + getProject()); validateConfiguration(); startJettyInternal(); } public void startJettyInternal() { ProgressLoggerFactory progressLoggerFactory = getServices().get(ProgressLoggerFactory.class); ProgressLogger progressLogger = progressLoggerFactory.newOperation(AbstractJettyRunTask.class) .start("Start Jetty server", "Starting Jetty"); try { setServer(createServer()); applyJettyXml(); JettyPluginServer plugin = getServer(); Object[] configuredConnectors = getConnectors(); plugin.setConnectors(configuredConnectors); Object[] connectors = plugin.getConnectors(); if (connectors == null || connectors.length == 0) { configuredConnectors = new Object[]{plugin.createDefaultConnector(getHttpPort())}; plugin.setConnectors(configuredConnectors); } //set up a RequestLog if one is provided if (getRequestLog() != null) { getServer().setRequestLog(getRequestLog()); } //set up the webapp and any context provided getServer().configureHandlers(); configureWebApplication(); getServer().addWebApplication(webAppConfig); // set up security realms Object[] configuredRealms = getUserRealms(); for (int i = 0; (configuredRealms != null) && i < configuredRealms.length; i++) { LOGGER.debug(configuredRealms[i].getClass().getName() + ": " + configuredRealms[i].toString()); } plugin.setUserRealms(configuredRealms); //do any other configuration required by the //particular Jetty version finishConfigurationBeforeStart(); // start Jetty server.start(); if (getStopPort() != null && getStopPort() > 0 && getStopKey() != null) { Monitor monitor = new Monitor(getStopPort(), getStopKey(), (Server) server.getProxiedObject()); monitor.start(); } if (daemon) { return; } // start the scanner thread (if necessary) on the main webapp configureScanner(); startScanner(); // start the new line scanner thread if necessary startConsoleScanner(); } catch (Exception e) { throw new GradleException("Could not start the Jetty server.", e); } finally { progressLogger.completed(); } progressLogger = progressLoggerFactory.newOperation(AbstractJettyRunTask.class) .start("Run Jetty at http://localhost:" + getHttpPort() + "/" + getContextPath(), "Running at http://localhost:" + getHttpPort() + "/" + getContextPath()); try { // keep the thread going if not in daemon mode server.join(); } catch (Exception e) { throw new GradleException("Failed to wait for the Jetty server to stop.", e); } finally { progressLogger.completed(); } } public abstract void restartWebApp(boolean reconfigureScanner) throws Exception; /** * Subclasses should invoke this to setup basic info on the webapp. */ public void configureWebApplication() throws Exception { //use EITHER a element or the now deprecated , , //way of doing things if (webAppConfig == null) { webAppConfig = new JettyPluginWebAppContext(); } webAppConfig.setContextPath(getContextPath().startsWith("/") ? getContextPath() : "/" + getContextPath()); if (getTemporaryDir() != null) { webAppConfig.setTempDirectory(getTemporaryDir()); } if (getWebDefaultXml() != null) { webAppConfig.setDefaultsDescriptor(getWebDefaultXml().getCanonicalPath()); } if (getOverrideWebXml() != null) { webAppConfig.setOverrideDescriptor(getOverrideWebXml().getCanonicalPath()); } // Don't treat JCL or Log4j as system classes Set systemClasses = new LinkedHashSet(Arrays.asList(webAppConfig.getSystemClasses())); systemClasses.remove("org.apache.commons.logging."); systemClasses.remove("org.apache.log4j."); webAppConfig.setSystemClasses(systemClasses.toArray(new String[0])); webAppConfig.setParentLoaderPriority(false); LOGGER.info("Context path = " + webAppConfig.getContextPath()); LOGGER.info("Tmp directory = " + " determined at runtime"); LOGGER.info("Web defaults = " + (webAppConfig.getDefaultsDescriptor() == null ? " jetty default" : webAppConfig.getDefaultsDescriptor())); LOGGER.info("Web overrides = " + (webAppConfig.getOverrideDescriptor() == null ? " none" : webAppConfig.getOverrideDescriptor())); } /** * Run a scanner thread on the given list of files and directories, calling stop/start on the given list of LifeCycle objects if any of the watched files change. */ private void startScanner() { // check if scanning is enabled if (getScanIntervalSeconds() <= 0) { return; } // check if reload is manual. It disables file scanning if ("manual".equalsIgnoreCase(reload)) { // issue a warning if both scanIntervalSeconds and reload // are enabled LOGGER.warn("scanIntervalSeconds is set to " + scanIntervalSeconds + " but will be IGNORED due to manual reloading"); return; } scanner.setReportExistingFilesOnStartup(false); scanner.setScanInterval(getScanIntervalSeconds()); scanner.setRecursive(true); List listeners = getScannerListeners(); Iterator itor = listeners == null ? null : listeners.iterator(); while (itor != null && itor.hasNext()) { scanner.addListener((Scanner.Listener) itor.next()); } LOGGER.info("Starting scanner at interval of " + getScanIntervalSeconds() + " seconds."); scanner.start(); } /** * Run a thread that monitors the console input to detect ENTER hits. */ protected void startConsoleScanner() { if ("manual".equalsIgnoreCase(reload)) { LOGGER.info("Console reloading is ENABLED. Hit ENTER on the console to restart the context."); consoleScanner = new ConsoleScanner(this); consoleScanner.start(); } } /** * Try and find a jetty-web.xml file, using some historical naming conventions if necessary. * * @return File object to the location of the jetty-web.xml */ public File findJettyWebXmlFile(File webInfDir) { if (webInfDir == null) { return null; } if (!webInfDir.exists()) { return null; } File f = new File(webInfDir, "jetty-web.xml"); if (f.exists()) { return f; } //try some historical alternatives f = new File(webInfDir, "web-jetty.xml"); if (f.exists()) { return f; } f = new File(webInfDir, "jetty6-web.xml"); if (f.exists()) { return f; } return null; } @InputFile @Optional public File getWebDefaultXml() { return webDefaultXml; } public void setWebDefaultXml(File webDefaultXml) { this.webDefaultXml = webDefaultXml; } @InputFile @Optional public File getOverrideWebXml() { return overrideWebXml; } public void setOverrideWebXml(File overrideWebXml) { this.overrideWebXml = overrideWebXml; } /** * Returns the interval in seconds between scanning the web app for file changes. * If file changes are detected, the web app is reloaded. Only relevant * if {@code reload} is set to {@code "automatic"}. Defaults to {@code 0}, * which disables automatic reloading. */ @Internal public int getScanIntervalSeconds() { return scanIntervalSeconds; } /** * Sets the interval in seconds between scanning the web app for file changes. * If file changes are detected, the web app is reloaded. Only relevant * if {@code reload} is set to {@code "automatic"}. Defaults to {@code 0}, * which disables automatic reloading. */ public void setScanIntervalSeconds(int scanIntervalSeconds) { this.scanIntervalSeconds = scanIntervalSeconds; } /** * Returns the context path to use to deploy the web application. */ @Internal public String getContextPath() { return contextPath; } public void setContextPath(String contextPath) { this.contextPath = contextPath; } @Internal public JettyPluginWebAppContext getWebAppConfig() { return webAppConfig; } public void setWebAppConfig(JettyPluginWebAppContext webAppConfig) { this.webAppConfig = webAppConfig; } /** * Returns the reload mode, which is either {@code "automatic"} or {@code "manual"}. * *

In automatic mode, the web app is scanned for file changes every n seconds, where n is * determined by the {@code scanIntervalSeconds} property. (Note that {@code scanIntervalSeconds} * defaults to {@code 0}, which disables automatic reloading.) If files changes are * detected, the web app is reloaded. * *

In manual mode, the web app is reloaded whenever the Enter key is pressed. */ @Internal public String getReload() { return reload; } /** * Sets the reload mode, which is either {@code "automatic"} or {@code "manual"}. * *

In automatic mode, the web app is scanned for file changes every n seconds, where n is * determined by the {@code scanIntervalSeconds} property. (Note that {@code scanIntervalSeconds} * defaults to {@code 0}, which disables automatic reloading.) If files changes are * detected, the web app is reloaded. * *

In manual mode, the web app is reloaded whenever the Enter key is pressed. */ public void setReload(String reload) { this.reload = reload; } /** * Returns the jetty configuration file to use. When {@code null}, no configuration file is used. */ @InputFile @Optional public File getJettyConfig() { return jettyConfig; } public void setJettyConfig(File jettyConfig) { this.jettyConfig = jettyConfig; } /** * Returns the TCP port for Jetty to listen on for stop requests. */ @Internal public Integer getStopPort() { return stopPort; } public void setStopPort(Integer stopPort) { this.stopPort = stopPort; } /** * Returns the key to use to stop Jetty. */ @Internal public String getStopKey() { return stopKey; } public void setStopKey(String stopKey) { this.stopKey = stopKey; } /** * Specifies whether the Jetty server should run in the background. When {@code true}, this task completes as soon as the server has started. When {@code false}, this task blocks until the Jetty * server is stopped. */ @Internal public boolean isDaemon() { return daemon; } public void setDaemon(boolean daemon) { this.daemon = daemon; } /** * Returns the TCP port for Jetty to listen on for incoming HTTP requests. */ @Internal public Integer getHttpPort() { return httpPort; } public void setHttpPort(Integer httpPort) { this.httpPort = httpPort; } @Internal public Connector[] getConnectors() { return connectors; } public void setConnectors(Connector[] connectors) { this.connectors = connectors; } @Internal public UserRealm[] getUserRealms() { return userRealms; } public void setUserRealms(UserRealm[] userRealms) { this.userRealms = userRealms; } @Internal public RequestLog getRequestLog() { return requestLog; } public void setRequestLog(RequestLog requestLog) { this.requestLog = requestLog; } /** * Returns the classpath to make available to the web application. */ @Classpath public Iterable getAdditionalRuntimeJars() { return additionalRuntimeJars; } public void setAdditionalRuntimeJars(Iterable additionalRuntimeJars) { this.additionalRuntimeJars = additionalRuntimeJars; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy