org.gradle.api.plugins.jetty.JettyRun Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-api Show documentation
Show all versions of gradle-api Show documentation
Gradle 6.9.1 API redistribution.
/*
* Copyright 2009 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 com.google.common.collect.Sets;
import org.gradle.api.InvalidUserDataException;
import org.gradle.api.file.ConfigurableFileTree;
import org.gradle.api.file.FileCollection;
import org.gradle.api.plugins.jetty.internal.Jetty6PluginServer;
import org.gradle.api.plugins.jetty.internal.JettyPluginServer;
import org.gradle.api.tasks.InputDirectory;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OrderSensitive;
import org.mortbay.jetty.Handler;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.handler.ContextHandler;
import org.mortbay.jetty.handler.ContextHandlerCollection;
import org.mortbay.jetty.handler.HandlerCollection;
import org.mortbay.resource.Resource;
import org.mortbay.resource.ResourceCollection;
import org.mortbay.util.Scanner;
import org.mortbay.xml.XmlConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
/**
* Deploys an exploded web application to an embedded Jetty web container. Does not require that the web application
* be assembled into a war, saving time during the development cycle.
*
* Once started, the web container can be configured to run continuously, scanning for changes in the project and
* automatically performing a hot redeploy when necessary. This allows the developer to concentrate on coding changes to
* the project using their IDE of choice and have those changes immediately and transparently reflected in the running
* web container, eliminating development time that is wasted on rebuilding, reassembling and redeploying.
*
* @deprecated The Jetty plugin has been deprecated
*/
@Deprecated
public class JettyRun extends AbstractJettyRunTask {
private static final Logger LOGGER = LoggerFactory.getLogger(JettyRun.class);
/**
* List of other contexts to set up. Optional.
*/
private ContextHandler[] contextHandlers;
/**
* The location of a jetty-env.xml file. Optional.
*/
private File jettyEnvXml;
/**
* The location of the web.xml file. If not set then it is assumed it is in ${basedir}/src/main/webapp/WEB-INF
*/
private File webXml;
/**
* Root directory for all HTML/JSP etc files.
*/
private File webAppSourceDirectory;
/**
* List of files or directories to additionally periodically scan for changes. Optional.
*/
private File[] scanTargets;
/**
* List of directories with ant-style <include> and <exclude> patterns for extra targets to periodically
* scan for changes. Can be used instead of, or in conjunction with <scanTargets>.Optional.
*/
private ScanTargetPattern[] scanTargetPatterns;
/**
* jetty-env.xml as a File.
*/
private File jettyEnvXmlFile;
/**
* List of files on the classpath for the webapp.
*/
private List classPathFiles;
/**
* Extra scan targets as a list.
*/
private Set extraScanTargets;
private FileCollection classpath;
public void validateConfiguration() {
// check the location of the static content/jsps etc
try {
if ((getWebAppSourceDirectory() == null) || !getWebAppSourceDirectory().exists()) {
throw new InvalidUserDataException("Webapp source directory "
+ (getWebAppSourceDirectory() == null ? "null" : getWebAppSourceDirectory().getCanonicalPath())
+ " does not exist");
} else {
LOGGER.info("Webapp source directory = " + getWebAppSourceDirectory().getCanonicalPath());
}
} catch (IOException e) {
throw new InvalidUserDataException("Webapp source directory does not exist", e);
}
// check reload mechanic
if (!"automatic".equalsIgnoreCase(reload) && !"manual".equalsIgnoreCase(reload)) {
throw new InvalidUserDataException("invalid reload mechanic specified, must be 'automatic' or 'manual'");
} else {
LOGGER.info("Reload Mechanic: " + reload);
}
// get the web.xml file if one has been provided, otherwise assume it is in the webapp src directory
if (getWebXml() == null) {
setWebXml(new File(new File(getWebAppSourceDirectory(), "WEB-INF"), "web.xml"));
}
LOGGER.info("web.xml file = " + getWebXml());
//check if a jetty-env.xml location has been provided, if so, it must exist
if (getJettyEnvXml() != null) {
setJettyEnvXmlFile(jettyEnvXml);
try {
if (!getJettyEnvXmlFile().exists()) {
throw new InvalidUserDataException("jetty-env.xml file does not exist at location " + jettyEnvXml);
} else {
LOGGER.info(" jetty-env.xml = " + getJettyEnvXmlFile().getCanonicalPath());
}
} catch (IOException e) {
throw new InvalidUserDataException("jetty-env.xml does not exist");
}
}
setExtraScanTargets(new ArrayList());
if (scanTargets != null) {
for (File scanTarget : scanTargets) {
LOGGER.info("Added extra scan target:" + scanTarget);
getExtraScanTargets().add(scanTarget);
}
}
if (scanTargetPatterns != null) {
for (ScanTargetPattern scanTargetPattern : scanTargetPatterns) {
ConfigurableFileTree files = getProject().fileTree(scanTargetPattern.getDirectory());
files.include(scanTargetPattern.getIncludes());
files.exclude(scanTargetPattern.getExcludes());
Set currentTargets = getExtraScanTargets();
if (currentTargets != null && !currentTargets.isEmpty()) {
currentTargets.addAll(files.getFiles());
} else {
setExtraScanTargets(files.getFiles());
}
}
}
}
public void configureWebApplication() throws Exception {
super.configureWebApplication();
setClassPathFiles(setUpClassPath());
if (getWebAppConfig().getWebXmlFile() == null) {
getWebAppConfig().setWebXmlFile(getWebXml());
}
if (getWebAppConfig().getJettyEnvXmlFile() == null) {
getWebAppConfig().setJettyEnvXmlFile(getJettyEnvXmlFile());
}
if (getWebAppConfig().getClassPathFiles() == null) {
getWebAppConfig().setClassPathFiles(getClassPathFiles());
}
if (getWebAppConfig().getWar() == null) {
getWebAppConfig().setWar(getWebAppSourceDirectory().getCanonicalPath());
}
LOGGER.info("Webapp directory = " + getWebAppSourceDirectory().getCanonicalPath());
getWebAppConfig().configure();
}
public void configureScanner() {
// start the scanner thread (if necessary) on the main webapp
List scanList = new ArrayList();
scanList.add(getWebXml());
if (getJettyEnvXmlFile() != null) {
scanList.add(getJettyEnvXmlFile());
}
File jettyWebXmlFile = findJettyWebXmlFile(new File(getWebAppSourceDirectory(), "WEB-INF"));
if (jettyWebXmlFile != null) {
scanList.add(jettyWebXmlFile);
}
scanList.addAll(getExtraScanTargets());
scanList.add(getProject().getBuildFile());
scanList.addAll(getClassPathFiles());
getScanner().setScanDirs(scanList);
List listeners = new ArrayList();
listeners.add(new Scanner.BulkListener() {
public void filesChanged(List changes) {
try {
boolean reconfigure = changes.contains(getProject().getBuildFile().getCanonicalPath());
restartWebApp(reconfigure);
} catch (Exception e) {
LOGGER.error("Error reconfiguring/restarting webapp after change in watched files", e);
}
}
});
setScannerListeners(listeners);
}
public void restartWebApp(boolean reconfigureScanner) throws Exception {
LOGGER.info("restarting " + getWebAppConfig());
LOGGER.debug("Stopping webapp ...");
getWebAppConfig().stop();
LOGGER.debug("Reconfiguring webapp ...");
validateConfiguration();
configureWebApplication();
// check if we need to reconfigure the scanner
if (reconfigureScanner) {
LOGGER.info("Reconfiguring scanner ...");
List scanList = new ArrayList();
scanList.add(getWebXml());
if (getJettyEnvXmlFile() != null) {
scanList.add(getJettyEnvXmlFile());
}
scanList.addAll(getExtraScanTargets());
scanList.add(getProject().getBuildFile());
scanList.addAll(getClassPathFiles());
getScanner().setScanDirs(scanList);
}
LOGGER.debug("Restarting webapp ...");
getWebAppConfig().start();
LOGGER.info("Restart completed at " + new Date().toString());
}
@Internal
private Set getDependencyFiles() {
List overlays = new ArrayList();
Set dependencies = getClasspath().getFiles();
LOGGER.debug("Adding dependencies {} for WEB-INF/lib ", dependencies);
//todo incorporate overlays when our resolved dependencies provide type information
// if (artifact.getType().equals("war")) {
// try {
// Resource r = Resource.newResource("jar:" + artifact.getFile().toURL().toString() + "!/");
// overlays.add(r);
// getExtraScanTargets().add(artifact.getFile());
// }
// catch (Exception e) {
// throw new RuntimeException(e);
// }
// continue;
// }
if (!overlays.isEmpty()) {
try {
Resource resource = getWebAppConfig().getBaseResource();
ResourceCollection rc = new ResourceCollection();
if (resource == null) {
// nothing configured, so we automagically enable the overlays
int size = overlays.size() + 1;
Resource[] resources = new Resource[size];
resources[0] = Resource.newResource(getWebAppSourceDirectory().toURI().toURL());
for (int i = 1; i < size; i++) {
resources[i] = overlays.get(i - 1);
LOGGER.info("Adding overlay: " + resources[i]);
}
rc.setResources(resources);
} else {
if (resource instanceof ResourceCollection) {
// there was a preconfigured ResourceCollection ... append the artifact wars
Resource[] old = ((ResourceCollection) resource).getResources();
int size = old.length + overlays.size();
Resource[] resources = new Resource[size];
System.arraycopy(old, 0, resources, 0, old.length);
for (int i = old.length; i < size; i++) {
resources[i] = overlays.get(i - old.length);
LOGGER.info("Adding overlay: " + resources[i]);
}
rc.setResources(resources);
} else {
// baseResource was already configured w/c could be src/main/webapp
if (!resource.isDirectory() && String.valueOf(resource.getFile()).endsWith(".war")) {
// its a war
resource = Resource.newResource("jar:" + resource.getURL().toString() + "!/");
}
int size = overlays.size() + 1;
Resource[] resources = new Resource[size];
resources[0] = resource;
for (int i = 1; i < size; i++) {
resources[i] = overlays.get(i - 1);
LOGGER.info("Adding overlay: " + resources[i]);
}
rc.setResources(resources);
}
}
getWebAppConfig().setBaseResource(rc);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return dependencies;
}
private List setUpClassPath() {
List classPathFiles = new ArrayList();
classPathFiles.addAll(getDependencyFiles());
if (LOGGER.isDebugEnabled()) {
for (File classPathFile : classPathFiles) {
LOGGER.debug("classpath element: " + classPathFile.getName());
}
}
return classPathFiles;
}
public void finishConfigurationBeforeStart() throws Exception {
Handler[] handlers = getConfiguredContextHandlers();
org.gradle.api.plugins.jetty.internal.JettyPluginServer plugin = getServer();
Server server = (Server) plugin.getProxiedObject();
HandlerCollection contexts = (HandlerCollection) server.getChildHandlerByClass(ContextHandlerCollection.class);
if (contexts == null) {
contexts = (HandlerCollection) server.getChildHandlerByClass(HandlerCollection.class);
}
for (int i = 0; (handlers != null) && (i < handlers.length); i++) {
contexts.addHandler(handlers[i]);
}
}
public void applyJettyXml() throws Exception {
if (getJettyConfig() == null) {
return;
}
LOGGER.info("Configuring Jetty from xml configuration file = " + getJettyConfig());
XmlConfiguration xmlConfiguration = new XmlConfiguration(getJettyConfig().toURI().toURL());
xmlConfiguration.configure(getServer().getProxiedObject());
}
public JettyPluginServer createServer() {
return new Jetty6PluginServer();
}
@InputFile
@Optional
public File getJettyEnvXml() {
return jettyEnvXml;
}
public void setJettyEnvXml(File jettyEnvXml) {
this.jettyEnvXml = jettyEnvXml;
}
/**
* Returns the {@code web.xml} file to use. When {@code null}, no {@code web.xml} file is used.
*/
@Internal("See webXmlIfExists")
public File getWebXml() {
return webXml;
}
// Workaround for non-existent web.xml passed to this task
@Optional @InputFile
protected File getWebXmlIfExists() {
File webXml = getWebXml();
if (webXml != null && webXml.exists()) {
return webXml;
} else {
return null;
}
}
public void setWebXml(File webXml) {
this.webXml = webXml;
}
/**
* Returns the directory containing the web application source files.
*/
@InputDirectory
public File getWebAppSourceDirectory() {
return webAppSourceDirectory;
}
public void setWebAppSourceDirectory(File webAppSourceDirectory) {
this.webAppSourceDirectory = webAppSourceDirectory;
}
@Internal
public File[] getScanTargets() {
return scanTargets;
}
public void setScanTargets(File[] scanTargets) {
this.scanTargets = scanTargets;
}
@Internal
public Set getExtraScanTargets() {
return extraScanTargets;
}
public void setExtraScanTargets(Iterable extraScanTargets) {
this.extraScanTargets = Sets.newLinkedHashSet(extraScanTargets);
}
@InputFile
@Optional
public File getJettyEnvXmlFile() {
return jettyEnvXmlFile;
}
public void setJettyEnvXmlFile(File jettyEnvXmlFile) {
this.jettyEnvXmlFile = jettyEnvXmlFile;
}
@Internal
public List getClassPathFiles() {
return classPathFiles;
}
public void setClassPathFiles(List classPathFiles) {
this.classPathFiles = classPathFiles;
}
@Internal
public ScanTargetPattern[] getScanTargetPatterns() {
return scanTargetPatterns;
}
public void setScanTargetPatterns(ScanTargetPattern[] scanTargetPatterns) {
this.scanTargetPatterns = scanTargetPatterns;
}
@Internal
public ContextHandler[] getConfiguredContextHandlers() {
return this.contextHandlers;
}
public void setContextHandlers(ContextHandler[] contextHandlers) {
this.contextHandlers = contextHandlers;
}
/**
* Returns the classpath for the web application.
*/
@OrderSensitive
@InputFiles
public FileCollection getClasspath() {
return classpath;
}
/**
* Set the classpath for the web application.
*/
public void setClasspath(FileCollection classpath) {
this.classpath = classpath;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy