Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**
* Copyright (C) 2012-2018 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 ninja.maven;
import ninja.build.WatchAndRestartMachine;
import ninja.build.DelayedRestartTrigger;
import ninja.build.RunClassInSeparateJvmMachine;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import ninja.build.ArgumentTokenizer;
import ninja.standalone.NinjaJetty;
import ninja.standalone.AutoStandalone;
import ninja.standalone.Standalone;
import ninja.utils.NinjaConstant;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
/**
* Starts Ninja's SuperDevMode.
*/
@Mojo(name = "run",
requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME,
defaultPhase = LifecyclePhase.NONE,
threadSafe = true)
public class NinjaRunMojo extends AbstractMojo {
@Parameter(defaultValue = "${project}", readonly = true)
protected MavenProject project;
@Parameter(defaultValue = "${plugin.artifacts}", readonly = true)
protected List pluginArtifacts;
/**
* Skip execution of this plugin.
*/
@Parameter(property = "ninja.skip", defaultValue="false", required = true)
protected boolean skip;
/**
* Directory containing the build files.
*
* For webapps this is usually
* something like /User/username/workspace/project/target/classes
*/
@Parameter(property = "ninja.outputDirectory", defaultValue = "${project.build.outputDirectory}", required = true)
protected String buildOutputDirectory;
/**
* All directories to watch for changes.
*/
@Parameter(property = "ninja.watchDirs", required = false)
protected File[] watchDirs;
/**
* Watch all directories on runtime classpath of project. For single
* maven projects this usually will be identical to the buildOutputDirectory and this
* property is therefore redundant. However, for multi-module projects, all dependent
* project build output directories will be included (assuming you launched
* maven from parent project directory). A simple way to use this plugin and
* watch for changes across an entire multi-module project.
*/
@Parameter(property = "ninja.watchAllClassPathDirs", defaultValue = "false", required = true)
protected boolean watchAllClassPathDirs;
/**
* Watch all jars on runtime classpath of project. A simple way to monitor
* all transitive dependencies and trigger a restart if they change. Since
* Java's filesystem monitoring API only watches directories, this property
* adds the parent directory of where the jar is stored and also adds an
* include rule to always match that jar filename. If other files in the directory
* of jars on your classpath (unlikely if you're using maven in a normal manner),
* then just be cautious you'll want to add exclude rules to not include them.
*/
@Parameter(property = "ninja.watchAllClassPathJars", defaultValue = "false", required = true)
protected boolean watchAllClassPathJars;
/**
* Includes in Java regex format. Negative regex patterns are difficult to
* write, so include rules are processed before exclude rules. Positive
* matches shortcut the matching process and that file will be included.
*/
@Parameter(property = "ninja.includes", required = false)
protected List includes;
/**
* Exludes in Java regex format. If you want to exclude all
* freemarker templates use something like (.*)ftl.html$ for instance.
*/
@Parameter(property = "ninja.excludes", required = false)
protected List excludes;
/**
* Adds assets directory and freemarker templates to excluded files.
* These are loaded from the src directory in dev mode.
*
* Default excludes are:
* - "(.*)ftl\\.html$"
* - "File.pathSeparator + "assets" + File.separator"
*/
@Parameter(property = "ninja.useDefaultExcludes", defaultValue = "true", required = true)
protected boolean useDefaultExcludes;
/**
* Context path for SuperDevMode.
*/
@Parameter(property = "ninja.context", required = false)
protected String context;
@Deprecated
protected String contextPath;
/**
* Mode for SuperDevMode.
*/
@Parameter(property = "ninja.mode", defaultValue=NinjaConstant.MODE_DEV, required = false)
protected String mode;
/**
* Port for SuperDevMode (can also be set in conf/application.conf)
*/
@Parameter(property = "ninja.port", required = false)
protected Integer port;
/**
* SSL port for SuperDevMode (can also be set in conf/application.conf)
*/
@Parameter(property = "ninja.ssl.port", required = false)
protected Integer sslPort;
/**
* Main class to run in SuperDevMode. Defaults to default standalone class
* in Ninja.
*/
@Parameter(property = "ninja.mainClass", required = false)
protected String mainClass;
/**
* Extra arguments to pass to the forked JVM. If you keep your arguments
* fairly simple, they should be tokenized (split) correctly. Uses excellent
* DrJava ArgumentTokenizer class for splitting line into separate arguments.
*/
@Parameter(property = "ninja.jvmArgs", required = false)
protected String jvmArgs;
/**
* Amount of time to wait for file changes to settle down before triggering a
* restart in SuperDevMode.
*/
@Parameter(property = "ninja.settleDownMillis", defaultValue="500", required = false)
protected Long settleDownMillis;
@Override
public void execute() throws MojoExecutionException {
if (skip) {
getLog().info("Skip flag is on. Will not execute.");
return;
}
initMojoFromUserSubmittedParameters();
List classpathItems = new ArrayList<>();
alertAndStopExecutionIfDirectoryWithCompiledClassesOfThisProjectDoesNotExist(
buildOutputDirectory);
classpathItems.add(buildOutputDirectory);
for (org.apache.maven.artifact.Artifact artifact : project.getArtifacts()) {
classpathItems.add(artifact.getFile().toString());
}
List allArtifactsFromNinjaStandaloneInPlugin
= getAllArtifactsComingFromNinjaStandalone(pluginArtifacts);
for (Artifact artifact: allArtifactsFromNinjaStandaloneInPlugin) {
//only add once...
if (!classpathItems.contains(artifact.getFile().toString())) {
classpathItems.add(artifact.getFile().toString());
}
}
Set includesAsSet = new LinkedHashSet<>((includes != null ? includes : Collections.EMPTY_LIST));
Set excludesAsSet = new LinkedHashSet<>((excludes != null ? excludes : Collections.EMPTY_LIST));
// start building set of directories to recursively watch
Set directoriesToRecursivelyWatch = new LinkedHashSet<>();
// add only absolute paths so we can catch duplicates
// add buildOutputDirectory
directoriesToRecursivelyWatch.add(
FileSystems.getDefault().getPath(
buildOutputDirectory).toAbsolutePath());
// add any watch directories
if (this.watchDirs != null) {
for (File watchDir: this.watchDirs) {
directoriesToRecursivelyWatch.add(watchDir.toPath().toAbsolutePath());
}
}
// add stuff from classpath
for (org.apache.maven.artifact.Artifact artifact : project.getArtifacts()) {
File file = artifact.getFile();
if (file.isDirectory() && this.watchAllClassPathDirs) {
directoriesToRecursivelyWatch.add(file.toPath().toAbsolutePath());
}
else if (file.getName().endsWith(".jar") && this.watchAllClassPathJars) {
File parentDir = file.getParentFile();
Path parentPath = parentDir.toPath().toAbsolutePath();
// safe string for rules below (windows path must be escaped for
// use in regular expressions
String rulePrefix = parentDir.getAbsolutePath() + File.separator;
rulePrefix = rulePrefix.replace("\\", "\\\\");
// if not previously added then add an exclusion rule for everything in it
if (!directoriesToRecursivelyWatch.contains(parentPath)) {
excludesAsSet.add(rulePrefix + "(.*)$");
}
// we also need to add this jar with an inclusion rule so that we always match it
includesAsSet.add(rulePrefix + file.getName() + "$");
directoriesToRecursivelyWatch.add(parentPath);
}
}
// which standalone (works with -Dninja.standalone to maven OR in pom.xml)
String mainClassToRun = (mainClass != null ? mainClass : AutoStandalone.class.getCanonicalName());
getLog().info("------------------------------------------------------------------------");
getLog().info("Ninja will watch dirs:");
for (Path path : directoriesToRecursivelyWatch) {
getLog().info(" " + path);
}
getLog().info("");
getLog().info("Ninja will launch with:");
getLog().info(" context: " + (getContextPath() != null ? getContextPath() : ""));
getLog().info(" mode: " + mode);
getLog().info(" port: " + (port != null ? port : ""));
getLog().info(" ssl port: " + (sslPort != null ? sslPort : ""));
getLog().info(" mainClass: " + mainClassToRun);
getLog().info("extra jvmArgs: " + (jvmArgs != null ? jvmArgs : ""));
getLog().info("------------------------------------------------------------------------");
try {
//
// build dependencies, start them, and then watch
//
RunClassInSeparateJvmMachine machine = buildRunClassInSeparateJvmMachine(
"Standalone",
mainClassToRun,
classpathItems,
buildJvmArguments(),
project.getBasedir()
);
DelayedRestartTrigger restartTrigger = buildDelayedRestartTrigger(machine);
restartTrigger.setSettleDownMillis(settleDownMillis);
restartTrigger.start();
WatchAndRestartMachine watcher = buildWatchAndRestartMachine(
directoriesToRecursivelyWatch,
includesAsSet,
excludesAsSet,
restartTrigger);
// initial startup of machine
machine.restart();
watcher.run();
} catch (IOException e) {
getLog().error(e);
}
}
protected String getContextPath() {
if (this.context != null) {
return this.context;
} else {
return this.contextPath;
}
}
// so we can mock a fake one for unit testing
protected DelayedRestartTrigger buildDelayedRestartTrigger(RunClassInSeparateJvmMachine machine) {
return new DelayedRestartTrigger(machine);
}
protected WatchAndRestartMachine buildWatchAndRestartMachine(
Set directoriesToRecursivelyWatch,
Set includes,
Set excludes,
DelayedRestartTrigger restartTrigger) throws IOException {
return new WatchAndRestartMachine(
directoriesToRecursivelyWatch,
includes,
excludes,
restartTrigger);
}
// so we can mock a fake one for unit testing
protected RunClassInSeparateJvmMachine buildRunClassInSeparateJvmMachine(
String name,
String classNameWithMainToRun,
List classpath,
List jvmArguments,
File mavenBaseDir) {
return new RunClassInSeparateJvmMachine(
name,
classNameWithMainToRun,
classpath,
buildJvmArguments(),
mavenBaseDir
);
}
protected List buildJvmArguments() {
List jvmArguments = new ArrayList<>();
String systemPropertyDevMode
= "-D" + NinjaConstant.MODE_KEY_NAME + "=" + mode;
jvmArguments.add(systemPropertyDevMode);
if (port != null) {
String portSelection
= "-D" + Standalone.KEY_NINJA_PORT + "=" + port;
jvmArguments.add(portSelection);
}
if (sslPort != null) {
String sslPortSelection
= "-D" + Standalone.KEY_NINJA_SSL_PORT + "=" + sslPort;
jvmArguments.add(sslPortSelection);
}
if (getContextPath() != null) {
String contextPathSelection
= "-D" + Standalone.KEY_NINJA_CONTEXT_PATH + "=" + getContextPath();
jvmArguments.add(contextPathSelection);
}
if (jvmArgs != null) {
// use excellent DrJava library to tokenize arguments (do not keep tokens)
List tokenizedArgs = ArgumentTokenizer.tokenize(jvmArgs, false);
getLog().debug("JVM arguments tokenizer results:");
for (String s : tokenizedArgs) {
getLog().debug("argument: " + s + "");
}
jvmArguments.addAll(tokenizedArgs);
}
return jvmArguments;
}
protected void initMojoFromUserSubmittedParameters() {
if (useDefaultExcludes) {
excludes.addAll(
Arrays.asList(
NinjaMavenPluginConstants.DEFAULT_EXCLUDE_PATTERNS));
}
}
/**
* This might be a bit hacky. But just a little bit.
*
* We have to add ninja-standalone and all of its dependencies to
* the classpath, so that NinjaJetty can start.
*
* But we do not want the user to declare the dependencies inside his
* project pom.xml.
*
* Therefore we declare the dependency in this plugin pom.xml.
* But we do not want to include all of this plugin's dependencies in the
* classpath for NinjaJetty. Therefore this method filters everything and
* only adds dependencies (also transitive deps) that originate
* from ninja-standalone. That way we get all deps we need.
*
* @param artifacts A list of artifacts that will be filtered.
* @return All artifacts coming from artifactId "ninja-standalone"
* (including transitive dependencies)
*/
protected List getAllArtifactsComingFromNinjaStandalone(
List artifacts) {
List resultingArtifacts = new ArrayList<>();
for (Artifact artifact: artifacts) {
for (String dependencyTrail: artifact.getDependencyTrail()) {
// something like: org.ninjaframework:ninja-standalone:jar:2.5.2
if (dependencyTrail.contains(NinjaMavenPluginConstants.NINJA_STANDALONE_ARTIFACT_ID)) {
resultingArtifacts.add(artifact);
break;
}
}
}
return resultingArtifacts;
}
protected void alertAndStopExecutionIfDirectoryWithCompiledClassesOfThisProjectDoesNotExist(
String directoryWithCompiledClassesOfThisProject) throws MojoExecutionException {
File classesDir = null;
if (directoryWithCompiledClassesOfThisProject != null) {
classesDir = new File(directoryWithCompiledClassesOfThisProject);
}
if (classesDir == null || !classesDir.exists()) {
getLog().error("Directory with classes does not exist: " + directoryWithCompiledClassesOfThisProject);
getLog().error("Maybe running 'mvn compile' before running 'mvn ninja:run' helps :)");
// BAM!
//System.exit(1);
throw new MojoExecutionException("Directory with classes does not exist: " + directoryWithCompiledClassesOfThisProject);
}
}
}