Signed-off-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
Jan Bartel 2019-09-17 17:38:27 +10:00
parent 6e5af1cbee
commit 67343c5e0f
7 changed files with 593 additions and 99 deletions

View File

@ -30,6 +30,7 @@ import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
@ -409,6 +410,12 @@ public abstract class AbstractWebAppMojo extends AbstractMojo
@Parameter (defaultValue="${session}", required=true, readonly=true) @Parameter (defaultValue="${session}", required=true, readonly=true)
private MavenSession session; private MavenSession session;
/**
* Default supported project type is <code>war</code> packaging.
*/
@Parameter
protected List<String> supportedPackagings = Collections.singletonList("war");
/** /**
* List of deps that are wars * List of deps that are wars
*/ */
@ -426,34 +433,35 @@ public abstract class AbstractWebAppMojo extends AbstractMojo
protected List<File> providedJars; protected List<File> providedJars;
@Override @Override
public void execute() throws MojoExecutionException, MojoFailureException public void execute() throws MojoExecutionException, MojoFailureException
{ {
//Doesn't apply to non-webapp projects if (isPackagingSupported())
if ( !"war".equals( project.getPackaging() ) || skip )
return;
getLog().info("Configuring Jetty for project: " + this.project.getName());
if (skip)
{ {
getLog().info("Skipping Jetty start: jetty.skip==true"); if (skip)
return; {
} getLog().info("Skipping Jetty start: jetty.skip==true");
return;
}
if (isExcludedGoal(execution.getMojoDescriptor().getGoal())) if (isExcludedGoal(execution.getMojoDescriptor().getGoal()))
{ {
getLog().info("The goal \""+execution.getMojoDescriptor().getFullGoalName()+ getLog().info("The goal \""+execution.getMojoDescriptor().getFullGoalName()+
"\" is unavailable for this web app because of an <excludedGoal> configuration."); "\" is unavailable for this web app because of an <excludedGoal> configuration.");
return; return;
}
getLog().info("Configuring Jetty for project: " + getProjectName());
warPluginInfo = new WarPluginInfo(project);
configureSystemProperties();
augmentPluginClasspath();
PluginLog.setLog(getLog());
verifyPomConfiguration();
startJetty();
} }
else
warPluginInfo = new WarPluginInfo(project); getLog().info("Packaging type [" + project.getPackaging() + "] is unsupported");
configureSystemProperties();
augmentPluginClasspath();
PluginLog.setLog(getLog());
verifyPomConfiguration();
startJetty();
} }
@ -1078,9 +1086,25 @@ public abstract class AbstractWebAppMojo extends AbstractMojo
return excluded; return excluded;
} }
protected boolean isPackagingSupported()
{
if (!supportedPackagings.contains(project.getPackaging()))
return false;
return true;
}
protected String getProjectName()
{
String projectName = project.getName();
if (StringUtils.isBlank(projectName))
{
projectName = project.getGroupId() + ":" + project.getArtifactId();
}
return projectName;
}
protected void configureWebApp()
protected void configureWebApp ()
throws Exception throws Exception
{ {
if (webApp == null) if (webApp == null)
@ -1209,4 +1233,17 @@ public abstract class AbstractWebAppMojo extends AbstractMojo
return null; return null;
} }
/**
* Get a file into which to write output from jetty.
*/
protected File getJettyOutputFile (String name) throws Exception
{
File outputFile = new File(target, name);
if (outputFile.exists())
outputFile.delete();
outputFile.createNewFile();
return outputFile;
}
} }

View File

@ -0,0 +1,137 @@
//
// ========================================================================
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// 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.maven.plugin;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.eclipse.jetty.util.StringUtil;
/**
* <p>
* This goal is used to run Jetty with any pre-assembled war. This goal does not have
* to be used with a project of packaging type "war".
* </p>
* <p>
* You must configure the "webApp" element with the location of either a war file or
* an unpacked war that you wish to deploy - in either case, the webapp must be
* fully compiled and assembled as this goal does not do anything other than start
* jetty with the given webapp.
* </p>
* <p>
* This goal is designed to be bound to a build phase, and NOT to be run at the
* command line. It will not block waiting for jetty to execute, but rather continue
* execution.
* </p>
* <p>
* This goal is useful e.g. for launching a web app in Jetty as a target for unit-tested
* HTTP client components via binding to the test-integration build phase.
* </p>
*/
@Mojo(name = "newdeploy", requiresDependencyResolution = ResolutionScope.RUNTIME)
public class NewJettyDeployMojo extends AbstractWebAppMojo
{
protected JettyEmbedder embedder;
protected JettyForker forker;
protected JettyDistroForker distroForker;
protected Path war;
@Override
public void configureWebApp() throws Exception
{
if (StringUtil.isBlank(webApp.getWar()))
throw new MojoExecutionException("No war specified");
super.configureWebApp();
war = Paths.get(webApp.getWar());
getLog().info("War = "+war);
}
/**
* Start a jetty instance in process to run given war.
*/
@Override
public void startJettyEmbedded() throws MojoExecutionException
{
try
{
embedder = newJettyEmbedder();
embedder.setExitVm(false);
embedder.setStopAtShutdown(false);
embedder.start();
}
catch (Exception e)
{
throw new MojoExecutionException("Error starting jetty", e);
}
}
/**
* Fork a jetty instance to run the given war.
*/
@Override
public void startJettyForked() throws MojoExecutionException
{
try
{
forker = newJettyForker();
forker.setWaitForChild(false); //we never wait for child
forker.setJettyOutputFile(getJettyOutputFile("jetty-deploy.out"));
forker.start(); //forks jetty instance
}
catch (Exception e)
{
throw new MojoExecutionException("Error starting jetty", e);
}
}
/**
* Fork a jetty distro to run the given war.
*/
@Override
public void startJettyDistro() throws MojoExecutionException
{
try
{
distroForker = newJettyDistroForker();
distroForker.setWaitForChild(false); //never wait for child
distroForker.setJettyOutputFile(getJettyOutputFile("jetty-deploy.out"));
distroForker.start(); //forks a jetty distro
}
catch (Exception e)
{
throw new MojoExecutionException("Error starting jetty", e);
}
}
/**
*
*/
@Override
protected void verifyPomConfiguration() throws MojoExecutionException
{
//Do not verify the configuration of the webapp, as we are deploying
//a random war instead.
}
}

View File

@ -0,0 +1,56 @@
//
// ========================================================================
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// 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.maven.plugin;
import org.apache.maven.plugin.MojoExecutionException;
/**
*
*
*/
public class NewJettyEffectiveWebXml extends AbstractWebAppMojo
{
@Override
protected void startJettyEmbedded() throws MojoExecutionException
{
return; //not starting a full jetty
}
/**
*
*/
@Override
protected void startJettyForked() throws MojoExecutionException
{
return; //not starting jetty this way
}
/**
*
*/
@Override
protected void startJettyDistro() throws MojoExecutionException
{
return; //not starting jetty
}
}

View File

@ -19,7 +19,8 @@
package org.eclipse.jetty.maven.plugin; package org.eclipse.jetty.maven.plugin;
import java.io.File; import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
@ -31,6 +32,7 @@ import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.plugins.annotations.ResolutionScope;
import org.eclipse.jetty.util.PathWatcher; import org.eclipse.jetty.util.PathWatcher;
import org.eclipse.jetty.util.PathWatcher.PathWatchEvent; import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
import org.eclipse.jetty.util.StringUtil;
/** /**
* <p> * <p>
@ -48,15 +50,7 @@ import org.eclipse.jetty.util.PathWatcher.PathWatchEvent;
@Mojo( name = "newrun-war", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME) @Mojo( name = "newrun-war", requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
@Execute(phase = LifecyclePhase.PACKAGE) @Execute(phase = LifecyclePhase.PACKAGE)
public class NewJettyRunWarMojo extends AbstractWebAppMojo public class NewJettyRunWarMojo extends AbstractWebAppMojo
{ {
/**
* The location of the war file.
*
*/
@Parameter(defaultValue="${project.build.directory}/${project.build.finalName}.war", required = true)
private File war;
//Start of parameters only valid for runType=inprocess //Start of parameters only valid for runType=inprocess
/** /**
* The interval in seconds to pause before checking if changes * The interval in seconds to pause before checking if changes
@ -74,6 +68,7 @@ public class NewJettyRunWarMojo extends AbstractWebAppMojo
protected JettyEmbedder embedder; protected JettyEmbedder embedder;
protected JettyForker forker; protected JettyForker forker;
protected JettyDistroForker distroForker; protected JettyDistroForker distroForker;
protected Path war;
/** /**
@ -90,18 +85,25 @@ public class NewJettyRunWarMojo extends AbstractWebAppMojo
public void configureWebApp() throws Exception public void configureWebApp() throws Exception
{ {
super.configureWebApp(); super.configureWebApp();
webApp.setWar(war.getCanonicalPath()); if (StringUtil.isBlank(webApp.getWar()))
{
war = target.toPath().resolve(project.getBuild().getFinalName()+".war");
webApp.setWar(war.toFile().getAbsolutePath());
}
else
war = Paths.get(webApp.getWar());
getLog().info("War = "+war);
} }
/** /**
* * Start a jetty instance in process to run the built war.
*/ */
@Override @Override
public void startJettyEmbedded() throws MojoExecutionException public void startJettyEmbedded() throws MojoExecutionException
{ {
try try
{ {
//start jetty
embedder = newJettyEmbedder(); embedder = newJettyEmbedder();
embedder.setExitVm(true); embedder.setExitVm(true);
embedder.setStopAtShutdown(true); embedder.setStopAtShutdown(true);
@ -115,6 +117,47 @@ public class NewJettyRunWarMojo extends AbstractWebAppMojo
} }
} }
/**
* Fork a jetty instance to run the built war.
*/
@Override
public void startJettyForked() throws MojoExecutionException
{
try
{
forker = newJettyForker();
forker.setWaitForChild(true); //we run at the command line, echo child output and wait for it
startScanner();
forker.start(); //forks jetty instance
}
catch (Exception e)
{
throw new MojoExecutionException("Error starting jetty", e);
}
}
/**
* Deploy the built war to a jetty distro.
*/
@Override
public void startJettyDistro() throws MojoExecutionException
{
try
{
distroForker = newJettyDistroForker();
distroForker.setWaitForChild(true); //we always run at the command line, echo child output and wait for it
startScanner();
distroForker.start(); //forks a jetty distro
}
catch (Exception e)
{
throw new MojoExecutionException("Error starting jetty", e);
}
}
public void startScanner() public void startScanner()
throws Exception throws Exception
{ {
@ -149,57 +192,11 @@ public class NewJettyRunWarMojo extends AbstractWebAppMojo
cthread.start(); cthread.start();
} }
} }
/**
* Fork a jetty instance to run the war
*/
@Override
public void startJettyForked() throws MojoExecutionException
{
try
{
forker = newJettyForker();
forker.setWaitForChild(true); //we run at the command line, echo child output and wait for it
startScanner();
//TODO is it ok to start the scanner before we start jetty?
forker.start(); //forks jetty instance
}
catch (Exception e)
{
throw new MojoExecutionException("Error starting jetty", e);
}
}
/**
*
*/
@Override
public void startJettyDistro() throws MojoExecutionException
{
try
{
distroForker = newJettyDistroForker();
distroForker.setWaitForChild(true); //we always run at the command line, echo child output and wait for it
startScanner();
distroForker.start(); //forks a jetty distro
//TODO is it ok to start the scanner before we start jetty?
}
catch (Exception e)
{
throw new MojoExecutionException("Error starting jetty", e);
}
}
public void configureScanner() throws MojoExecutionException public void configureScanner() throws MojoExecutionException
{ {
scanner.watch(project.getFile().toPath()); scanner.watch(project.getFile().toPath());
scanner.watch(war.toPath()); scanner.watch(war);
scanner.addListener(new PathWatcher.EventListListener() scanner.addListener(new PathWatcher.EventListListener()
{ {
@ -303,5 +300,4 @@ public class NewJettyRunWarMojo extends AbstractWebAppMojo
} }
getLog().info("Restart completed."); getLog().info("Restart completed.");
} }
} }

View File

@ -19,8 +19,6 @@
package org.eclipse.jetty.maven.plugin; package org.eclipse.jetty.maven.plugin;
import java.io.File;
import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Execute; import org.apache.maven.plugins.annotations.Execute;
import org.apache.maven.plugins.annotations.LifecyclePhase; import org.apache.maven.plugins.annotations.LifecyclePhase;
@ -50,7 +48,8 @@ public class NewJettyStartMojo extends AbstractWebAppMojo
super.configureUnassembledWebApp(); super.configureUnassembledWebApp();
} }
/** Starts the webapp - without first compiling the classes - /**
* Starts the webapp - without first compiling the classes -
* in the same process as maven. * in the same process as maven.
*/ */
@Override @Override
@ -58,7 +57,6 @@ public class NewJettyStartMojo extends AbstractWebAppMojo
{ {
try try
{ {
//start jetty
JettyEmbedder jetty = newJettyEmbedder(); JettyEmbedder jetty = newJettyEmbedder();
jetty.setExitVm(false); jetty.setExitVm(false);
jetty.setStopAtShutdown(false); jetty.setStopAtShutdown(false);
@ -82,7 +80,7 @@ public class NewJettyStartMojo extends AbstractWebAppMojo
{ {
JettyForker jetty = newJettyForker(); JettyForker jetty = newJettyForker();
jetty.setWaitForChild(false); //we never wait for child jetty.setWaitForChild(false); //we never wait for child
jetty.setJettyOutputFile(getJettyOutputFile()); jetty.setJettyOutputFile(getJettyOutputFile("jetty-start.out"));
jetty.start(); //forks jetty instance jetty.start(); //forks jetty instance
} }
@ -103,7 +101,7 @@ public class NewJettyStartMojo extends AbstractWebAppMojo
{ {
JettyDistroForker jetty = newJettyDistroForker(); JettyDistroForker jetty = newJettyDistroForker();
jetty.setWaitForChild(false); //never wait for child jetty.setWaitForChild(false); //never wait for child
jetty.setJettyOutputFile(getJettyOutputFile()); jetty.setJettyOutputFile(getJettyOutputFile("jetty-start.out"));
jetty.start(); //forks a jetty distro jetty.start(); //forks a jetty distro
} }
catch (Exception e) catch (Exception e)
@ -111,13 +109,4 @@ public class NewJettyStartMojo extends AbstractWebAppMojo
throw new MojoExecutionException("Error starting jetty", e); throw new MojoExecutionException("Error starting jetty", e);
} }
} }
protected File getJettyOutputFile () throws Exception
{
File outputFile = new File(target, "jetty.out");
if (outputFile.exists())
outputFile.delete();
outputFile.createNewFile();
return outputFile;
}
} }

View File

@ -0,0 +1,115 @@
//
// ========================================================================
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// 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.maven.plugin;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.InetAddress;
import java.net.Socket;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
/**
* This goal stops a running instance of jetty.
*
* The <b>stopPort</b> and <b>stopKey</b> parameters can be used to
* configure which jetty to stop.
*/
@Mojo(name = "newstop")
public class NewJettyStopMojo extends AbstractWebAppMojo
{
/**
* Max time in seconds that the plugin will wait for confirmation that jetty has stopped.
*/
@Parameter
protected int stopWait;
@Override
protected void startJettyEmbedded() throws MojoExecutionException
{
//Does not start jetty
return;
}
@Override
protected void startJettyForked() throws MojoExecutionException
{
//Does not start jetty
return;
}
@Override
protected void startJettyDistro() throws MojoExecutionException
{
//Does not start jetty
return;
}
@Override
public void execute() throws MojoExecutionException, MojoFailureException
{
if (stopPort <= 0)
throw new MojoExecutionException("Please specify a valid port");
if (stopKey == null)
throw new MojoExecutionException("Please specify a valid stopKey");
String command = "forcestop";
try (Socket s = new Socket(InetAddress.getByName("127.0.0.1"), stopPort);)
{
OutputStream out = s.getOutputStream();
out.write((stopKey + "\r\n" + command + "\r\n").getBytes());
out.flush();
if (stopWait > 0)
{
s.setSoTimeout(stopWait * 1000);
s.getInputStream();
getLog().info("Waiting " + stopWait + " seconds for jetty to stop");
LineNumberReader lin = new LineNumberReader(new InputStreamReader(s.getInputStream()));
String response;
boolean stopped = false;
while (!stopped && ((response = lin.readLine()) != null))
{
if ("Stopped".equals(response))
{
stopped = true;
getLog().info("Server reports itself as stopped");
}
}
}
}
catch (ConnectException e)
{
getLog().info("Jetty not running!");
}
catch (Exception e)
{
getLog().error(e);
}
}
}

View File

@ -0,0 +1,164 @@
//
// ========================================================================
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// 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.maven.plugin;
import java.io.File;
import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.quickstart.QuickStartConfiguration;
import org.eclipse.jetty.quickstart.QuickStartConfiguration.Mode;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
/**
* Run enough of jetty in order to generate a quickstart file for a
* webapp.
*
*/
public class QuickStartGenerator
{
private File quickstartXml;
private JettyWebAppContext webApp;
private File webAppPropsFile;
private String contextXml;
private boolean prepared = false;
/**
* @return the webApp
*/
public JettyWebAppContext getWebApp()
{
return webApp;
}
/**
* @param webApp the webApp to set
*/
public void setWebApp(JettyWebAppContext webApp)
{
this.webApp = webApp;
}
/**
* @return the quickstartXml
*/
public File getQuickstartXml()
{
return quickstartXml;
}
/**
* @param quickstartXml the quickstartXml to set
*/
public void setQuickstartXml(File quickstartXml)
{
this.quickstartXml = quickstartXml;
}
public File getWebAppPropsFile()
{
return webAppPropsFile;
}
public void setWebAppPropsFile(File webAppPropsFile)
{
this.webAppPropsFile = webAppPropsFile;
}
public String getContextXml()
{
return contextXml;
}
public void setContextXml(String contextXml)
{
this.contextXml = contextXml;
}
private void prepareWebApp()
throws Exception
{
if (webApp == null)
webApp = new JettyWebAppContext();
//set the webapp up to do very little other than generate the quickstart-web.xml
webApp.addConfiguration(new MavenQuickStartConfiguration());
webApp.setAttribute(QuickStartConfiguration.MODE, Mode.GENERATE);
webApp.setAttribute(QuickStartConfiguration.QUICKSTART_WEB_XML, Resource.newResource(quickstartXml));
webApp.setCopyWebDir(false);
webApp.setCopyWebInf(false);
}
/**
* Run enough of jetty to generate a full quickstart xml file for the
* webapp. The tmp directory is persisted.
*/
public void generate()
throws Exception
{
if (quickstartXml == null)
throw new IllegalStateException ("No quickstart xml output file");
if (!prepared)
{
prepareWebApp();
prepared = true;
}
Server server = new Server();
//ensure handler structure enabled
ServerSupport.configureHandlers(server, null, null);
ServerSupport.configureDefaultConfigurationClasses(server);
//if our server has a thread pool associated we can do annotation scanning multithreaded,
//otherwise scanning will be single threaded
QueuedThreadPool tpool = server.getBean(QueuedThreadPool.class);
//add webapp to our fake server instance
ServerSupport.addWebApplication(server, webApp);
//leave everything unpacked for the forked process to use
webApp.setPersistTempDirectory(true);
try
{
if (tpool != null)
tpool.start();
else
webApp.setAttribute(AnnotationConfiguration.MULTI_THREADED, Boolean.FALSE.toString());
webApp.start(); //just enough to generate the quickstart
//save config of the webapp BEFORE we stop
if (webAppPropsFile != null)
WebAppPropertyConverter.toProperties(webApp, webAppPropsFile, contextXml);
}
finally
{
webApp.stop();
if (tpool != null)
tpool.stop();
}
}
}