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

org.wisdom.maven.mojos.InternalRunMojo Maven / Gradle / Ivy

The newest version!
/*
 * #%L
 * Wisdom-Framework
 * %%
 * Copyright (C) 2013 - 2014 Wisdom Framework
 * %%
 * 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.
 * #L%
 */
package org.wisdom.maven.mojos;

import org.apache.commons.exec.ProcessDestroyer;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
import org.codehaus.plexus.PlexusConstants;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.context.Context;
import org.codehaus.plexus.context.ContextException;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
import org.wisdom.maven.Watcher;
import org.wisdom.maven.pipeline.Pipeline;
import org.wisdom.maven.pipeline.Pipelines;
import org.wisdom.maven.pipeline.Watchers;
import org.wisdom.maven.utils.WisdomExecutor;

import java.io.File;

/**
 * The mojo launching the Wisdom server instance.
 * Do not use, this mojo is invoked automatically from {@code mvn wisdom:run}.
 */
@Mojo(name = "internal-run", threadSafe = false,
        // We need to use the TEST scope to let Surefire access its dependencies.
        requiresDependencyResolution = ResolutionScope.TEST,
        requiresProject = true
)
public class InternalRunMojo extends AbstractWisdomMojo implements Contextualizable {

    private Pipeline pipeline;

    /**
     * If set to {@literal true}, it does not collect transitive dependencies. This means that bundles that are
     * transitive dependencies of the current project won't be copied.
     */
    @Parameter(defaultValue = "false")
    private boolean excludeTransitive;

    /**
     * If set to {@literal false} (default), it enables the analysis and the collection of transitive webjars.
     */
    @Parameter(defaultValue = "false")
    private boolean excludeTransitiveWebJars;

    /**
     * Sets the debug port on which the remote debugger can be plugged.
     * If set to 0 the debug is disabled (default).
     */
    @Parameter(defaultValue = "${debug}")
    public int debug;

    /**
     * JVM arguments appended to the Java Command.
     * Arguments are given like: {@code mvn clean wisdom:run -DjvmArgs="-ea -Dfoo=bar"}
     */
    @Parameter(defaultValue = "${jvmArgs}")
    public String jvmArgs;

    /**
     * Enables the interactive mode of the launched server (shell prompt).
     * Be ware that exiting the framework must be done using the 'exit' command instead of 'CTRL+C'.
     */
    @Parameter(defaultValue = "${interactive}")
    private boolean interactive;

    /**
     * Enables the interactive mode of the launched server (shell prompt). This option is equivalent to {@literal
     * interactive}. Be ware that exiting the framework must be done using the 'exit' command instead of 'CTRL+C'.
     */
    @Parameter(defaultValue = "${shell}")
    private boolean shell;

    /**
     * Enables / disables the pom file monitoring.
     */
    @Parameter(defaultValue = "${pom.watching}")
    private boolean pomFileMonitoring = true;  //NOSONAR Cannot be a local variable, it's injected.


    /**
     * A parameter indicating that the current project is using the 'base runtime' instead of the 'full runtime'. This
     * option should only be used by components developed by Wisdom and being part of the 'full runtime'.
     * 

* This parameter is deprecated, used the "distribution" parameter instead. */ @Parameter @Deprecated boolean useBaseRuntime; /** * A parameter to select the Wisdom distribution to use. Are accepted a profile's name among: {base, equinox, * regular} (regular is the default distribution), or artifact coordinated given under the form: * GROUP_ID:ARTIFACT_ID:EXTENSION:CLASSIFIER:VERSION. If not set the regular distribution is used. */ @Parameter(defaultValue = "regular") String wisdomRuntime; /** * The dependency graph builder to use. */ @Component(hint = "default") private DependencyGraphBuilder dependencyGraphBuilder; /** * A parameter indicating whether or not we should remove from the bundle transitive copy some well-known * error-prone bundles. */ @Parameter(defaultValue = "true") public boolean useDefaultExclusions; /** * Configures the behavior of non-OSGi dependencies. */ @Parameter public Libraries libraries; //TODO Why do we have this field ? private PlexusContainer container; private ProcessController destroyer = new ProcessController(); /** * This method is called when the JVM is shutting down and notify all the waiting threads. */ private void unblock() { synchronized (this) { // This notify can be considered as 'naked', because it does not modify the current object state (the // object on which the synchronized is done). However in this very case, // it's normal. The wait-notify protocol is only used to block the thread until the JVM stops. notifyAll(); //NOSONAR } } /** * Execute method, initializes the watch pipeline. If the {@link #wisdomDirectory} * parameter is set then the execution of the wisdom server is skipped, * and keeps the thread alive until the shutdown of the JVM. Otherwise the wisdom server is * started. Before returning, the method cleans up the pipeline. * * @throws org.apache.maven.plugin.MojoExecutionException for init failures. */ @Override public void execute() throws MojoExecutionException { try { init(); } catch (ContextException e) { throw new MojoExecutionException("Cannot extract the watchers from the context", e); } if (wisdomDirectory != null) { getLog().info("Wisdom Directory set to " + wisdomDirectory.getAbsolutePath() + " - " + "skipping the execution of the wisdom server for " + project.getArtifactId()); // Here things are a bit tricky. As we are not going to start the Wisdom server, // the current thread is going to continue. We need to hold it and release it when // the JVM stops. For this purpose we register a shutdown hook that is going to // release the current thread we put in the waiting queue. This synchronization // protocol is quite safe, as only one thread can enter this block. // Register a shutdown hook that will unblock the execution when called. Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { /** * Calls the unblock method. */ @Override public void run() { unblock(); } })); /** * Entering a blocking block. * We are going to wait until the JVM shuts down. */ synchronized (this) { try { // Here again, it's an unconditional wait. There are no condition on which we are waiting, // we just hold the current thread until the JVM stops. wait(); //NOSONAR } catch (InterruptedException e) { getLog().warn("We were interrupted", e); } } } else { new WisdomExecutor().execute(this, shell || interactive, debug, jvmArgs, destroyer); } pipeline.shutdown(); } /** * Init method, expands the Wisdom Runtime zip and copies compile dependencies to the * application directory. If the {@link #wisdomDirectory} parameter is set then the expansion * of the zip is skipped. * * @throws org.apache.maven.plugin.MojoExecutionException if copy of dependencies fails. */ public void init() throws MojoExecutionException, ContextException { if (pomFileMonitoring) { Watchers.add(session, new PomWatcher()); } pipeline = Pipelines.watchers(session, basedir, this, pomFileMonitoring).watch(); } /** * The watcher responsible of stopping everything when the pom.xml file is changed. */ private class PomWatcher implements Watcher { /** * Checks that the given file is actually the 'pom.xml' file of the watched project. * * @param file is the file. * @return {@literal true} if the watcher is interested in being notified on an event * attached to the given file, {@literal false} otherwise. */ @Override public boolean accept(File file) { return file.equals(new File(project.getBasedir(), "pom.xml")); } /** * Does nothing. * * @param file is the file. * @return {@code true} */ @Override public boolean fileCreated(File file) { // Ignored event. return true; } /** * The 'pom.xml' file was updated. *

* It shutdowns the pipeline, kill the underlying Chameleon instance and exit the JVM with a special exit * code (20) instructing the parent process to relaunch Maven. * * @param file is the file. * @return {@literal false} */ @Override public boolean fileUpdated(File file) { getLog().warn("A change in the 'pom.xml' has been detected, in order to take such a change into account, " + "the Maven process is going to restart automatically. Don't forget to replug your debugger if you" + " are debugging the application."); pipeline.shutdown(); destroyer.stop(); return false; } /** * Does nothing. * * @param file the file * @return {@literal true} */ @Override public boolean fileDeleted(File file) { // Ignored event. return true; } } @Override public void contextualize(Context context) throws ContextException { container = (PlexusContainer) context.get(PlexusConstants.PLEXUS_KEY); } private class ProcessController implements ProcessDestroyer { Process process; @Override public boolean add(Process process) { if (this.process == null) { this.process = process; return true; } return false; } @Override public boolean remove(Process process) { if (this.process == process) { this.process = null; return true; } return false; } @Override public int size() { if (process != null) { return 1; } return 0; } public int stop() { if (process == null) { return 0; } try { process.destroy(); process.waitFor(); } catch (InterruptedException e) { //NOSONAR // Ignore it. } return process.exitValue(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy