1
//========================================================================
2
//$Id: AbstractJettyMojo.java 4648 2009-02-24 08:56:03Z ayao $
3
//Copyright 2000-2004 Mort Bay Consulting Pty. Ltd.
4
//------------------------------------------------------------------------
5
//Licensed under the Apache License, Version 2.0 (the "License");
6
//you may not use this file except in compliance with the License.
7
//You may obtain a copy of the License at
8
//http://www.apache.org/licenses/LICENSE-2.0
9
//Unless required by applicable law or agreed to in writing, software
10
//distributed under the License is distributed on an "AS IS" BASIS,
11
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
//See the License for the specific language governing permissions and
13
//limitations under the License.
14
//========================================================================
17
package org.mortbay.jetty.plugin;
21
import java.io.FileInputStream;
22
import java.util.ArrayList;
23
import java.util.Enumeration;
24
import java.util.Iterator;
25
import java.util.List;
26
import java.util.Properties;
28
import org.apache.maven.plugin.AbstractMojo;
29
import org.apache.maven.plugin.MojoExecutionException;
30
import org.apache.maven.plugin.MojoFailureException;
31
import org.apache.maven.project.MavenProject;
32
import org.mortbay.jetty.Server;
33
import org.mortbay.jetty.plugin.util.ConsoleScanner;
34
import org.mortbay.jetty.plugin.util.JettyPluginServer;
35
import org.mortbay.jetty.plugin.util.PluginLog;
36
import org.mortbay.jetty.plugin.util.SystemProperties;
37
import org.mortbay.jetty.plugin.util.SystemProperty;
38
import org.mortbay.util.Scanner;
47
public abstract class AbstractJettyMojo extends AbstractMojo
50
* The proxy for the Server object
52
protected JettyPluginServer server;
56
* The "virtual" webapp created by the plugin
59
protected Jetty6PluginWebAppContext webAppConfig;
66
* @parameter expression="${executedProject}"
70
protected MavenProject project;
75
* The context path for the webapp. Defaults to the
76
* name of the webapp's artifact.
78
* @parameter expression="/${project.artifactId}"
81
protected String contextPath;
85
* The temporary directory to use for the webapp.
86
* Defaults to target/jetty-tmp
88
* @parameter expression="${project.build.directory}/work"
91
protected File tmpDirectory;
96
* A webdefault.xml file to use instead
97
* of the default for the webapp. Optional.
101
protected File webDefaultXml;
105
* A web.xml file to be applied AFTER
106
* the webapp's web.xml file. Useful for
107
* applying different build profiles, eg
108
* test, production etc. Optional.
111
protected File overrideWebXml;
114
* The interval in seconds to scan the webapp for changes
115
* and restart the context if necessary. Ignored if reload
116
* is enabled. Disabled by default.
118
* @parameter expression="${jetty.scanIntervalSeconds}" default-value="0"
121
protected int scanIntervalSeconds;
125
* reload can be set to either 'automatic' or 'manual'
127
* if 'manual' then the context can be reloaded by a linefeed in the console
128
* if 'automatic' then traditional reloading on changed files is enabled.
130
* @parameter expression="${jetty.reload}" default-value="automatic"
132
protected String reload;
135
* File containing system properties to be set before execution
137
* Note that these properties will NOT override System properties
138
* that have been set on the command line, by the JVM, or directly
139
* in the POM via systemProperties. Optional.
141
* @parameter expression="${jetty.systemPropertiesFile}"
143
protected File systemPropertiesFile;
146
* System properties to set before execution.
147
* Note that these properties will NOT override System properties
148
* that have been set on the command line or by the JVM. They WILL
149
* override System properties that have been set via systemPropertiesFile.
153
protected SystemProperties systemProperties;
158
* Location of a jetty xml configuration file whose contents
159
* will be applied before any plugin configuration. Optional.
162
protected File jettyConfig;
165
* Port to listen to stop jetty on executing -DSTOP.PORT=<stopPort>
166
* -DSTOP.KEY=<stopKey> -jar start.jar --stop
169
protected int stopPort;
172
* Key to provide when stopping jetty on executing java -DSTOP.KEY=<stopKey>
173
* -DSTOP.PORT=<stopPort> -jar start.jar --stop
176
protected String stopKey;
180
* Determines whether or not the server blocks when started. The default
181
* behavior (daemon = false) will cause the server to pause other processes
182
* while it continues to handle web requests. This is useful when starting the
183
* server with the intent to work with it interactively.
185
* Often, it is desirable to let the server start and continue running subsequent
186
* processes in an automated build environment. This can be facilitated by setting
189
* @parameter expression="${jetty.daemon}" default-value="false"
191
protected boolean daemon;
194
* A scanner to check for changes to the webapp
196
protected Scanner scanner;
199
* List of files and directories to scan
201
protected ArrayList scanList;
204
* List of Listeners for the scanner
206
protected ArrayList scannerListeners;
210
* A scanner to check ENTER hits on the console
212
protected Thread consoleScanner;
215
public String PORT_SYSPROPERTY = "jetty.port";
218
* @return Returns the realms configured in the pom
220
public abstract Object[] getConfiguredUserRealms();
223
* @return Returns the connectors configured in the pom
225
public abstract Object[] getConfiguredConnectors();
227
public abstract Object getConfiguredRequestLog();
230
public abstract void checkPomConfiguration() throws MojoExecutionException;
234
public abstract void configureScanner () throws MojoExecutionException;
237
public abstract void applyJettyXml () throws Exception;
241
* create a proxy that wraps a particular jetty version Server object
244
public abstract JettyPluginServer createServer() throws Exception;
247
public abstract void finishConfigurationBeforeStart() throws Exception;
250
public MavenProject getProject()
255
public File getTmpDirectory()
257
return this.tmpDirectory;
261
public File getWebDefaultXml()
263
return this.webDefaultXml;
266
public File getOverrideWebXml()
268
return this.overrideWebXml;
272
* @return Returns the contextPath.
274
public String getContextPath()
276
return this.contextPath;
280
* @return Returns the scanIntervalSeconds.
282
public int getScanIntervalSeconds()
284
return this.scanIntervalSeconds;
288
* @return returns the path to the systemPropertiesFile
290
public File getSystemPropertiesFile()
292
return this.systemPropertiesFile;
295
public void setSystemPropertiesFile(File file) throws Exception
297
this.systemPropertiesFile = file;
298
FileInputStream propFile = new FileInputStream(systemPropertiesFile);
299
Properties properties = new Properties();
300
properties.load(propFile);
302
if (this.systemProperties == null )
303
this.systemProperties = new SystemProperties();
305
for (Enumeration keys = properties.keys(); keys.hasMoreElements(); )
307
String key = (String)keys.nextElement();
308
if ( ! systemProperties.containsSystemProperty(key) )
310
SystemProperty prop = new SystemProperty();
312
prop.setValue(properties.getProperty(key));
314
this.systemProperties.setSystemProperty(prop);
320
public void setSystemProperties(SystemProperties systemProperties)
322
if (this.systemProperties == null)
323
this.systemProperties = systemProperties;
326
Iterator itor = systemProperties.getSystemProperties().iterator();
327
while (itor.hasNext())
329
SystemProperty prop = (SystemProperty)itor.next();
330
this.systemProperties.setSystemProperty(prop);
335
public File getJettyXmlFile ()
337
return this.jettyConfig;
341
public JettyPluginServer getServer ()
346
public void setServer (JettyPluginServer server)
348
this.server = server;
352
public void setScanList (ArrayList list)
354
this.scanList = new ArrayList(list);
357
public ArrayList getScanList ()
359
return this.scanList;
363
public void setScannerListeners (ArrayList listeners)
365
this.scannerListeners = new ArrayList(listeners);
368
public ArrayList getScannerListeners ()
370
return this.scannerListeners;
373
public Scanner getScanner ()
378
public void execute() throws MojoExecutionException, MojoFailureException
380
getLog().info("Configuring Jetty for project: " + getProject().getName());
381
PluginLog.setLog(getLog());
382
checkPomConfiguration();
387
public void startJetty () throws MojoExecutionException
391
getLog().debug("Starting Jetty Server ...");
393
printSystemProperties();
394
setServer(createServer());
396
//apply any config from a jetty.xml file first which is able to
397
//be overwritten by config in the pom.xml
400
JettyPluginServer plugin=getServer();
403
// if the user hasn't configured their project's pom to use a
404
// different set of connectors,
406
Object[] configuredConnectors = getConfiguredConnectors();
408
plugin.setConnectors(configuredConnectors);
409
Object[] connectors = plugin.getConnectors();
411
if (connectors == null|| connectors.length == 0)
413
//if a SystemProperty -Djetty.port=<portnum> has been supplied, use that as the default port
414
configuredConnectors = new Object[] { plugin.createDefaultConnector(System.getProperty(PORT_SYSPROPERTY, null)) };
415
plugin.setConnectors(configuredConnectors);
419
//set up a RequestLog if one is provided
420
if (getConfiguredRequestLog() != null)
421
getServer().setRequestLog(getConfiguredRequestLog());
423
//set up the webapp and any context provided
424
getServer().configureHandlers();
425
configureWebApplication();
426
getServer().addWebApplication(webAppConfig);
429
// set up security realms
430
Object[] configuredRealms = getConfiguredUserRealms();
431
for (int i = 0; (configuredRealms != null) && i < configuredRealms.length; i++)
432
getLog().debug(configuredRealms[i].getClass().getName() + ": "+ configuredRealms[i].toString());
434
plugin.setUserRealms(configuredRealms);
436
//do any other configuration required by the
437
//particular Jetty version
438
finishConfigurationBeforeStart();
443
getLog().info("Started Jetty Server");
445
if(stopPort>0 && stopKey!=null)
447
org.mortbay.jetty.plugin.util.Monitor monitor = new org.mortbay.jetty.plugin.util.Monitor(stopPort, stopKey, new Server[]{(Server)server.getProxiedObject()}, !daemon);
451
// start the scanner thread (if necessary) on the main webapp
455
// start the new line scanner thread if necessary
456
startConsoleScanner();
458
// keep the thread going if not in daemon mode
466
throw new MojoExecutionException("Failure", e);
472
getLog().info("Jetty server exiting.");
479
public abstract void restartWebApp(boolean reconfigureScanner) throws Exception;
482
* Subclasses should invoke this to setup basic info
485
* @throws MojoExecutionException
487
public void configureWebApplication () throws Exception
489
//use EITHER a <webAppConfig> element or the now deprecated <contextPath>, <tmpDirectory>, <webDefaultXml>, <overrideWebXml>
490
//way of doing things
491
if (webAppConfig == null)
493
webAppConfig = new Jetty6PluginWebAppContext();
494
webAppConfig.setContextPath((getContextPath().startsWith("/") ? getContextPath() : "/"+ getContextPath()));
495
if (getTmpDirectory() != null)
496
webAppConfig.setTempDirectory(getTmpDirectory());
497
if (getWebDefaultXml() != null)
498
webAppConfig.setDefaultsDescriptor(getWebDefaultXml().getCanonicalPath());
499
if (getOverrideWebXml() != null)
500
webAppConfig.setOverrideDescriptor(getOverrideWebXml().getCanonicalPath());
504
getLog().info("Context path = " + webAppConfig.getContextPath());
505
getLog().info("Tmp directory = "+ " determined at runtime");
506
getLog().info("Web defaults = "+(webAppConfig.getDefaultsDescriptor()==null?" jetty default":webAppConfig.getDefaultsDescriptor()));
507
getLog().info("Web overrides = "+(webAppConfig.getOverrideDescriptor()==null?" none":webAppConfig.getOverrideDescriptor()));
512
* Run a scanner thread on the given list of files and directories, calling
513
* stop/start on the given list of LifeCycle objects if any of the watched
517
private void startScanner()
520
// check if scanning is enabled
521
if (getScanIntervalSeconds() <= 0) return;
523
// check if reload is manual. It disables file scanning
524
if ( "manual".equalsIgnoreCase( reload ) )
526
// issue a warning if both scanIntervalSeconds and reload
528
getLog().warn("scanIntervalSeconds is set to " + scanIntervalSeconds + " but will be IGNORED due to manual reloading");
532
scanner = new Scanner();
533
scanner.setReportExistingFilesOnStartup(false);
534
scanner.setScanInterval(getScanIntervalSeconds());
535
scanner.setScanDirs(getScanList());
536
scanner.setRecursive(true);
537
List listeners = getScannerListeners();
538
Iterator itor = (listeners==null?null:listeners.iterator());
539
while (itor!=null && itor.hasNext())
540
scanner.addListener((Scanner.Listener)itor.next());
541
getLog().info("Starting scanner at interval of " + getScanIntervalSeconds()+ " seconds.");
546
* Run a thread that monitors the console input to detect ENTER hits.
548
protected void startConsoleScanner()
550
if ( "manual".equalsIgnoreCase( reload ) )
552
getLog().info("Console reloading is ENABLED. Hit ENTER on the console to restart the context.");
553
consoleScanner = new ConsoleScanner(this);
554
consoleScanner.start();
559
private void printSystemProperties ()
561
// print out which system properties were set up
562
if (getLog().isDebugEnabled())
564
if (systemProperties != null)
566
Iterator itor = systemProperties.getSystemProperties().iterator();
567
while (itor.hasNext())
569
SystemProperty prop = (SystemProperty)itor.next();
570
getLog().debug("Property "+prop.getName()+"="+prop.getValue()+" was "+ (prop.isSet() ? "set" : "skipped"));
577
* Try and find a jetty-web.xml file, using some
578
* historical naming conventions if necessary.
582
public File findJettyWebXmlFile (File webInfDir)
584
if (webInfDir == null)
586
if (!webInfDir.exists())
589
File f = new File (webInfDir, "jetty-web.xml");
593
//try some historical alternatives
594
f = new File (webInfDir, "web-jetty.xml");
597
f = new File (webInfDir, "jetty6-web.xml");