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

org.mortbay.jetty.plugin.AbstractJettyMojo Maven / Gradle / Ivy

There is a newer version: 8.1.16.v20140903
Show newest version
//========================================================================
//$Id$
//Copyright 2000-2004 Mort Bay Consulting Pty. Ltd.
//------------------------------------------------------------------------
//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.mortbay.jetty.plugin;


import java.io.File;
import java.io.FileInputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.util.FileUtils;
import org.eclipse.jetty.security.LoginService;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.Server;
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.HandlerCollection;
import org.eclipse.jetty.util.Scanner;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.xml.XmlConfiguration;



/**
 * AbstractJettyMojo
 *
 *
 */
public abstract class AbstractJettyMojo extends AbstractMojo
{
  
    
    /**
     * Whether or not to include dependencies on the plugin's classpath with <scope>provided</scope>
     * Use WITH CAUTION as you may wind up with duplicate jars/classes.
     * 
     * @since jetty-7.5.2
     * @parameter  default-value="false"
     */
    protected boolean useProvidedScope;
    
    
    /**
     * List of goals that are NOT to be used
     * 
     * @since jetty-7.5.2
     * @parameter
     */
    protected String[] excludedGoals;
    

    
    /**
     * List of connectors to use. If none are configured
     * then the default is a single SelectChannelConnector at port 8080. You can
     * override this default port number by using the system property jetty.port
     * on the command line, eg:  mvn -Djetty.port=9999 jetty:run. Consider using instead
     * the <jettyXml> element to specify external jetty xml config file. 
     * 
     * @parameter 
     */
    protected Connector[] connectors;
    
    
    /**
     * List of other contexts to set up. Consider using instead
     * the <jettyXml> element to specify external jetty xml config file. 
     * Optional.
     * 
     * 
     * @parameter
     */
    protected ContextHandler[] contextHandlers;
    
    
    /**
     * List of security realms to set up. Consider using instead
     * the <jettyXml> element to specify external jetty xml config file. 
     * Optional.
     * 
     * 
     * @parameter
     */
    protected LoginService[] loginServices;
    


    /**
     * A RequestLog implementation to use for the webapp at runtime.
     * Consider using instead the <jettyXml> element to specify external jetty xml config file. 
     * Optional.
     * 
     *
     * @parameter
     */
    protected RequestLog requestLog;
    
    

    /**
     * An instance of org.eclipse.jetty.webapp.WebAppContext that represents the webapp.
     * Use any of its setters to configure the webapp. This is the preferred and most
     * flexible method of configuration, rather than using the (deprecated) individual
     * parameters like "tmpDirectory", "contextPath" etc.
     * 
     * @parameter alias="webAppConfig"
     */
    protected JettyWebAppContext webApp;



    /**
     * The context path for the webapp. Defaults to the
     * name of the webapp's artifact.
     *
     * @deprecated Use <webApp><contextPath> instead.
     * @parameter expression="/${project.artifactId}"
     * @required
     * @readonly
     */
    protected String contextPath;


    /**
     * The temporary directory to use for the webapp.
     * Defaults to target/tmp.  
     *
     * @deprecated Use %lt;webApp><tempDirectory> instead.
     * @parameter expression="${project.build.directory}/tmp"
     * @required
     * @readonly
     */
    protected File tmpDirectory;



    /**
     * The interval in seconds to scan the webapp for changes 
     * and restart the context if necessary. Ignored if reload
     * is enabled. Disabled by default.
     * 
     * @parameter expression="${jetty.scanIntervalSeconds}" default-value="0"
     * @required
     */
    protected int scanIntervalSeconds;
    
    
    /**
     * reload can be set to either 'automatic' or 'manual'
     *
     * if 'manual' then the context can be reloaded by a linefeed in the console
     * if 'automatic' then traditional reloading on changed files is enabled.
     * 
     * @parameter expression="${jetty.reload}" default-value="automatic"
     */
    protected String reload;
    
    /**
     * File containing system properties to be set before execution
     * 
     * Note that these properties will NOT override System properties
     * that have been set on the command line, by the JVM, or directly 
     * in the POM via systemProperties. Optional.
     * 
     * @parameter expression="${jetty.systemPropertiesFile}"
     */
    protected File systemPropertiesFile;

    /**
     * System properties to set before execution. 
     * Note that these properties will NOT override System properties 
     * that have been set on the command line or by the JVM. They WILL 
     * override System properties that have been set via systemPropertiesFile.
     * Optional.
     * @parameter
     */
    protected SystemProperties systemProperties;
    
    
    
    /**
     * Comma separated list of a jetty xml configuration files whose contents 
     * will be applied before any plugin configuration. Optional.
     * 
     * 
     * @parameter alias="jettyConfig"
     */
    protected String jettyXml;
    
    
    /**
     * Port to listen to stop jetty on executing -DSTOP.PORT=<stopPort> 
     * -DSTOP.KEY=<stopKey> -jar start.jar --stop
     * 
     * @parameter
     */
    protected int stopPort;
    
    /**
     * Key to provide when stopping jetty on executing java -DSTOP.KEY=<stopKey> 
     * -DSTOP.PORT=<stopPort> -jar start.jar --stop
     * 
     * @parameter
     */
    protected 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. *

* * @parameter expression="${jetty.daemon}" default-value="false" */ protected boolean daemon; /** * Skip this mojo execution. * * @parameter expression="${jetty.skip}" default-value="false" */ protected boolean skip; /** * Location of a context xml configuration file whose contents * will be applied to the webapp AFTER anything in <webApp>.Optional. * * * @parameter alias="webAppXml" */ protected String contextXml; /** * The maven project. * * @parameter expression="${project}" * @readonly */ protected MavenProject project; /** * The artifacts for the project. * * @parameter expression="${project.artifacts}" * @readonly */ protected Set projectArtifacts; /** * @parameter expression="${mojoExecution}" * @readonly */ private org.apache.maven.plugin.MojoExecution execution; /** * The artifacts for the plugin itself. * * @parameter expression="${plugin.artifacts}" * @readonly */ private List pluginArtifacts; /** * A wrapper for the Server object */ protected JettyServer server; /** * A scanner to check for changes to the webapp */ protected Scanner scanner; /** * List of files and directories to scan */ protected ArrayList scanList; /** * List of Listeners for the scanner */ protected ArrayList scannerListeners; /** * A scanner to check ENTER hits on the console */ protected Thread consoleScanner; public String PORT_SYSPROPERTY = "jetty.port"; public abstract void restartWebApp(boolean reconfigureScanner) throws Exception; public abstract void checkPomConfiguration() throws MojoExecutionException; public abstract void configureScanner () throws MojoExecutionException; public void execute() throws MojoExecutionException, MojoFailureException { getLog().info("Configuring Jetty for project: " + getProject().getName()); if (skip) { getLog().info("Skipping Jetty start: jetty.skip==true"); return; } if (isExcluded(execution.getMojoDescriptor().getGoal())) { getLog().info("The goal \""+execution.getMojoDescriptor().getFullGoalName()+ "\" has been made unavailable for this web application by an configuration."); return; } configurePluginClasspath(); PluginLog.setLog(getLog()); checkPomConfiguration(); startJetty(); } public void configurePluginClasspath() throws MojoExecutionException { //if we are configured to include the provided dependencies on the plugin's classpath //(which mimics being on jetty's classpath vs being on the webapp's classpath), we first //try and filter out ones that will clash with jars that are plugin dependencies, then //create a new classloader that we setup in the parent chain. if (useProvidedScope) { try { List provided = new ArrayList(); URL[] urls = null; for ( Iterator iter = projectArtifacts.iterator(); iter.hasNext(); ) { Artifact artifact = iter.next(); if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()) && !isPluginArtifact(artifact)) { provided.add(artifact.getFile().toURI().toURL()); if (getLog().isDebugEnabled()) { getLog().debug("Adding provided artifact: "+artifact);} } } if (!provided.isEmpty()) { urls = new URL[provided.size()]; provided.toArray(urls); URLClassLoader loader = new URLClassLoader(urls, getClass().getClassLoader()); Thread.currentThread().setContextClassLoader(loader); getLog().info("Plugin classpath augmented with provided dependencies: "+Arrays.toString(urls)); } } catch (MalformedURLException e) { throw new MojoExecutionException("Invalid url", e); } } } public boolean isPluginArtifact(Artifact artifact) { if (pluginArtifacts == null || pluginArtifacts.isEmpty()) return false; boolean isPluginArtifact = false; for (Iterator iter = pluginArtifacts.iterator(); iter.hasNext() && !isPluginArtifact; ) { Artifact pluginArtifact = iter.next(); if (getLog().isDebugEnabled()) { getLog().debug("Checking "+pluginArtifact);} if (pluginArtifact.getGroupId().equals(artifact.getGroupId()) && pluginArtifact.getArtifactId().equals(artifact.getArtifactId())) isPluginArtifact = true; } return isPluginArtifact; } public void finishConfigurationBeforeStart() throws Exception { HandlerCollection contexts = (HandlerCollection)server.getChildHandlerByClass(ContextHandlerCollection.class); if (contexts==null) contexts = (HandlerCollection)server.getChildHandlerByClass(HandlerCollection.class); for (int i=0; (this.contextHandlers != null) && (i < this.contextHandlers.length); i++) { contexts.addHandler(this.contextHandlers[i]); } } public void applyJettyXml() throws Exception { if (getJettyXmlFiles() == null) return; for ( File xmlFile : getJettyXmlFiles() ) { getLog().info( "Configuring Jetty from xml configuration file = " + xmlFile.getCanonicalPath() ); XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(xmlFile)); xmlConfiguration.configure(this.server); } } public void startJetty () throws MojoExecutionException { try { getLog().debug("Starting Jetty Server ..."); printSystemProperties(); this.server = new JettyServer(); setServer(this.server); //apply any config from a jetty.xml file first which is able to //be overwritten by config in the pom.xml applyJettyXml (); // if the user hasn't configured their project's pom to use a // different set of connectors, // use the default Connector[] connectors = this.server.getConnectors(); if (connectors == null|| connectors.length == 0) { //try using ones configured in pom this.server.setConnectors(this.connectors); connectors = this.server.getConnectors(); if (connectors == null || connectors.length == 0) { //if a SystemProperty -Djetty.port= has been supplied, use that as the default port this.connectors = new Connector[] { this.server.createDefaultConnector(System.getProperty(PORT_SYSPROPERTY, null)) }; this.server.setConnectors(this.connectors); } } //set up a RequestLog if one is provided if (this.requestLog != null) getServer().setRequestLog(this.requestLog); //set up the webapp and any context provided this.server.configureHandlers(); configureWebApplication(); this.server.addWebApplication(webApp); // set up security realms for (int i = 0; (this.loginServices != null) && i < this.loginServices.length; i++) { getLog().debug(this.loginServices[i].getClass().getName() + ": "+ this.loginServices[i].toString()); getServer().addBean(this.loginServices[i]); } //do any other configuration required by the //particular Jetty version finishConfigurationBeforeStart(); if(stopPort>0 && stopKey!=null) { ShutdownMonitor monitor = ShutdownMonitor.getInstance(); monitor.setPort(stopPort); monitor.setKey(stopKey); monitor.setExitVm(!daemon); } // start Jetty this.server.start(); getLog().info("Started Jetty Server"); // start the scanner thread (if necessary) on the main webapp configureScanner (); startScanner(); // start the new line scanner thread if necessary startConsoleScanner(); // keep the thread going if not in daemon mode if (!daemon ) { server.join(); } } catch (Exception e) { throw new MojoExecutionException("Failure", e); } finally { if (!daemon ) { getLog().info("Jetty server exiting."); } } } /** * Subclasses should invoke this to setup basic info * on the webapp * * @throws MojoExecutionException */ public void configureWebApplication () throws Exception { //As of jetty-7, you must use a element if (webApp == null) webApp = new JettyWebAppContext(); //Apply any context xml file to set up the webapp //CAUTION: if you've defined a element then the //context xml file can OVERRIDE those settings if (contextXml != null) { File file = FileUtils.getFile(contextXml); XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.toURL(file)); getLog().info("Applying context xml file "+contextXml); xmlConfiguration.configure(webApp); } //If no contextPath was specified, go with our default String cp = webApp.getContextPath(); if (cp == null || "".equals(cp)) { webApp.setContextPath((contextPath.startsWith("/") ? contextPath : "/"+ contextPath)); } //If no tmp directory was specified, and we have one, use it if (webApp.getTempDirectory() == null && tmpDirectory != null) { if (!tmpDirectory.exists()) tmpDirectory.mkdirs(); webApp.setTempDirectory(tmpDirectory); } getLog().info("Context path = " + webApp.getContextPath()); getLog().info("Tmp directory = "+ (webApp.getTempDirectory()== null? " determined at runtime": webApp.getTempDirectory())); getLog().info("Web defaults = "+(webApp.getDefaultsDescriptor()==null?" jetty default":webApp.getDefaultsDescriptor())); getLog().info("Web overrides = "+(webApp.getOverrideDescriptor()==null?" none":webApp.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() throws Exception { // 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 getLog().warn("scanIntervalSeconds is set to " + scanIntervalSeconds + " but will be IGNORED due to manual reloading"); return; } scanner = new Scanner(); scanner.setReportExistingFilesOnStartup(false); scanner.setScanInterval(getScanIntervalSeconds()); scanner.setScanDirs(getScanList()); scanner.setRecursive(true); List listeners = getScannerListeners(); Iterator itor = (listeners==null?null:listeners.iterator()); while (itor!=null && itor.hasNext()) scanner.addListener((Scanner.Listener)itor.next()); getLog().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() throws Exception { if ( "manual".equalsIgnoreCase( reload ) ) { getLog().info("Console reloading is ENABLED. Hit ENTER on the console to restart the context."); consoleScanner = new ConsoleScanner(this); consoleScanner.start(); } } private void printSystemProperties () { // print out which system properties were set up if (getLog().isDebugEnabled()) { if (systemProperties != null) { Iterator itor = systemProperties.getSystemProperties().iterator(); while (itor.hasNext()) { SystemProperty prop = (SystemProperty)itor.next(); getLog().debug("Property "+prop.getName()+"="+prop.getValue()+" was "+ (prop.isSet() ? "set" : "skipped")); } } } } /** * Try and find a jetty-web.xml file, using some * historical naming conventions if necessary. * @param webInfDir * @return the jetty web xml file */ 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; return null; } public Scanner getScanner () { return scanner; } public MavenProject getProject() { return this.project; } public void setProject(MavenProject project) { this.project = project; } public File getTmpDirectory() { return this.tmpDirectory; } public void setTmpDirectory(File tmpDirectory) { this.tmpDirectory = tmpDirectory; } /** * @return Returns the contextPath. */ public String getContextPath() { return this.contextPath; } public void setContextPath(String contextPath) { this.contextPath = contextPath; } /** * @return Returns the scanIntervalSeconds. */ public int getScanIntervalSeconds() { return this.scanIntervalSeconds; } public void setScanIntervalSeconds(int scanIntervalSeconds) { this.scanIntervalSeconds = scanIntervalSeconds; } /** * @return returns the path to the systemPropertiesFile */ public File getSystemPropertiesFile() { return this.systemPropertiesFile; } public void setSystemPropertiesFile(File file) throws Exception { this.systemPropertiesFile = file; FileInputStream propFile = new FileInputStream(systemPropertiesFile); Properties properties = new Properties(); properties.load(propFile); if (this.systemProperties == null ) this.systemProperties = new SystemProperties(); for (Enumeration keys = properties.keys(); keys.hasMoreElements(); ) { String key = (String)keys.nextElement(); if ( ! systemProperties.containsSystemProperty(key) ) { SystemProperty prop = new SystemProperty(); prop.setKey(key); prop.setValue(properties.getProperty(key)); this.systemProperties.setSystemProperty(prop); } } } public void setSystemProperties(SystemProperties systemProperties) { if (this.systemProperties == null) this.systemProperties = systemProperties; else { Iterator itor = systemProperties.getSystemProperties().iterator(); while (itor.hasNext()) { SystemProperty prop = (SystemProperty)itor.next(); this.systemProperties.setSystemProperty(prop); } } } public SystemProperties getSystemProperties () { return this.systemProperties; } public List getJettyXmlFiles() { if ( this.jettyXml == null ) { return null; } List jettyXmlFiles = new ArrayList(); if ( this.jettyXml.indexOf(',') == -1 ) { jettyXmlFiles.add( new File( this.jettyXml ) ); } else { String[] files = this.jettyXml.split(","); for ( String file : files ) { jettyXmlFiles.add( new File(file) ); } } return jettyXmlFiles; } public JettyServer getServer () { return this.server; } public void setServer (JettyServer server) { this.server = server; } public void setScanList (ArrayList list) { this.scanList = new ArrayList(list); } public ArrayList getScanList () { return this.scanList; } public void setScannerListeners (ArrayList listeners) { this.scannerListeners = new ArrayList(listeners); } public ArrayList getScannerListeners() { return this.scannerListeners; } public JettyWebAppContext getWebAppConfig() { return webApp; } public void setWebAppConfig(JettyWebAppContext webAppConfig) { this.webApp = webAppConfig; } public RequestLog getRequestLog() { return requestLog; } public void setRequestLog(RequestLog requestLog) { this.requestLog = requestLog; } public LoginService[] getLoginServices() { return loginServices; } public void setLoginServices(LoginService[] loginServices) { this.loginServices = loginServices; } public ContextHandler[] getContextHandlers() { return contextHandlers; } public void setContextHandlers(ContextHandler[] contextHandlers) { this.contextHandlers = contextHandlers; } public Connector[] getConnectors() { return connectors; } public void setConnectors(Connector[] connectors) { this.connectors = connectors; } public String getReload() { return reload; } public void setReload(String reload) { this.reload = reload; } public String getJettyConfig() { return jettyXml; } public void setJettyConfig(String jettyConfig) { this.jettyXml = jettyConfig; } public String getWebAppXml() { return contextXml; } public void setWebAppXml(String webAppXml) { this.contextXml = webAppXml; } public boolean isSkip() { return skip; } public void setSkip(boolean skip) { this.skip = skip; } public boolean isDaemon() { return daemon; } public void setDaemon(boolean daemon) { this.daemon = daemon; } public String getStopKey() { return stopKey; } public void setStopKey(String stopKey) { this.stopKey = stopKey; } public int getStopPort() { return stopPort; } public void setStopPort(int stopPort) { this.stopPort = stopPort; } public List getPluginArtifacts() { return pluginArtifacts; } public void setPluginArtifacts(List pluginArtifacts) { this.pluginArtifacts = pluginArtifacts; } public boolean isExcluded (String goal) { if (excludedGoals == null || goal == null) return false; goal = goal.trim(); if ("".equals(goal)) return false; boolean excluded = false; for (int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy