You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:14:55 UTC

[sling-maven-launchpad-plugin] 12/49: SLING-1442 - adding start and stop goals to launchpad plugin

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag maven-launchpad-plugin-2.0.10
in repository https://gitbox.apache.org/repos/asf/sling-maven-launchpad-plugin.git

commit df85fd611eed2945f2608965dd2f0ac96831d3d5
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Mon Apr 12 17:36:43 2010 +0000

    SLING-1442 - adding start and stop goals to launchpad plugin
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/maven/maven-launchpad-plugin@933332 13f79535-47bb-0310-9956-ffa450edef68
---
 ...o.java => AbstractLaunchpadStartingPlugin.java} |  77 +------
 .../maven/projectsupport/ControlListener.java      | 212 +++++++++++++++++
 .../apache/sling/maven/projectsupport/RunMojo.java | 253 ++-------------------
 .../sling/maven/projectsupport/StartMojo.java      |  62 +++++
 .../sling/maven/projectsupport/StatusMojo.java     |  49 ++++
 .../sling/maven/projectsupport/StopMojo.java       |  49 ++++
 6 files changed, 401 insertions(+), 301 deletions(-)

diff --git a/src/main/java/org/apache/sling/maven/projectsupport/RunMojo.java b/src/main/java/org/apache/sling/maven/projectsupport/AbstractLaunchpadStartingPlugin.java
similarity index 77%
copy from src/main/java/org/apache/sling/maven/projectsupport/RunMojo.java
copy to src/main/java/org/apache/sling/maven/projectsupport/AbstractLaunchpadStartingPlugin.java
index 061ecd8..f94cb3f 100644
--- a/src/main/java/org/apache/sling/maven/projectsupport/RunMojo.java
+++ b/src/main/java/org/apache/sling/maven/projectsupport/AbstractLaunchpadStartingPlugin.java
@@ -1,19 +1,3 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with this
- * work for additional information regarding copyright ownership. The ASF
- * licenses this file to You 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.apache.sling.maven.projectsupport;
 
 import static org.apache.felix.framework.util.FelixConstants.*;
@@ -24,7 +8,6 @@ import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -49,13 +32,10 @@ import org.apache.sling.maven.projectsupport.bundlelist.v1_0_0.StartLevel;
 import org.osgi.framework.BundleException;
 
 /**
- * Run a Launchpad application.
- *
- * @goal run
- * @requiresDependencyResolution test
+ * @author justin
  *
  */
-public class RunMojo extends AbstractBundleListMojo implements Notifiable {
+public abstract class AbstractLaunchpadStartingPlugin extends AbstractBundleListMojo  implements Notifiable {
 
     /** Default log level setting if no set on command line (value is "INFO"). */
     private static final int DEFAULT_LOG_LEVEL = Logger.LOG_INFO;
@@ -173,39 +153,6 @@ public class RunMojo extends AbstractBundleListMojo implements Notifiable {
         }
     };
 
-    private Thread shutdown = new Thread() {
-        /**
-         * Called when the Java VM is being terminiated, for example because the
-         * KILL signal has been sent to the process. This method calls stop on
-         * the launched Sling instance to terminate the framework before
-         * returning.
-         */
-        @Override
-        public void run() {
-            getLog().info("Java VM is shutting down", null);
-            shutdown();
-        }
-
-        // ---------- Shutdown support for control listener and shutdown hook
-
-        void shutdown() {
-            // remove the shutdown hook, will fail if called from the
-            // shutdown hook itself. Otherwise this prevents shutdown
-            // from being called again
-            try {
-                Runtime.getRuntime().removeShutdownHook(this);
-            } catch (Throwable t) {
-                // don't care for problems removing the hook
-            }
-
-            // now really shutdown sling
-            if (sling != null) {
-                getLog().info("Stopping Sling", null);
-                sling.destroy();
-            }
-        }
-    };
-
     private Sling sling;
 
     /**
@@ -232,8 +179,6 @@ public class RunMojo extends AbstractBundleListMojo implements Notifiable {
      */
     @Override
     protected void executeWithArtifacts() throws MojoExecutionException, MojoFailureException {
-        Runtime.getRuntime().addShutdownHook(shutdown);
-
         try {
             final Map<String, String> props = new HashMap<String, String>();
 
@@ -280,21 +225,22 @@ public class RunMojo extends AbstractBundleListMojo implements Notifiable {
                 }
             }
 
-            // creating the instance launches the framework and we are done here
-            sling = new Sling(this, logger, resourceProvider, props);
-
-            // TODO this seems hacky!
-            while (sling != null) {
-                Thread.sleep(100);
-            }
+            sling = startSling(resourceProvider, props, logger);
 
         } catch (BundleException be) {
             getLog().error("Failed to Start OSGi framework", be);
-        } catch (InterruptedException e) {
         }
 
     }
 
+    protected abstract Sling startSling(ResourceProvider resourceProvider, Map<String, String> props, Logger logger) throws BundleException;
+
+    protected void stopSling() {
+        if (sling != null) {
+            sling.destroy();
+        }
+    }
+
     protected void initArtifactDefinitions(Properties dependencies) {
         if (jarWebSupport == null) {
             jarWebSupport = new ArtifactDefinition();
@@ -309,5 +255,4 @@ public class RunMojo extends AbstractBundleListMojo implements Notifiable {
     protected void initBundleList(BundleList bundleList) {
         bundleList.add(jarWebSupport.toBundle());
     }
-
 }
diff --git a/src/main/java/org/apache/sling/maven/projectsupport/ControlListener.java b/src/main/java/org/apache/sling/maven/projectsupport/ControlListener.java
new file mode 100644
index 0000000..dd60568
--- /dev/null
+++ b/src/main/java/org/apache/sling/maven/projectsupport/ControlListener.java
@@ -0,0 +1,212 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.apache.sling.maven.projectsupport;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.ConnectException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.UnknownHostException;
+
+import org.apache.maven.plugin.logging.Log;
+
+/**
+ * This class is adapted from org.apache.sling.launchpad.app.ControlListener.
+ */
+class ControlListener implements Runnable {
+    // command sent by the client to cause Sling to shutdown
+    static final String COMMAND_STOP = "stop";
+
+    // command sent by the client to check for the status of the server
+    static final String COMMAND_STATUS = "status";
+
+    // the response sent by the server if the command executed successfully
+    private static final String RESPONSE_OK = "OK";
+
+    // The default port to listen on and to connect to
+    private static final int DEFAULT_LISTEN_PORT = 63000;
+
+    /** The mojo */
+    private AbstractLaunchpadStartingPlugin mojo;
+
+    /** The log object */
+    private final Log log;
+
+    /** The socket address used for control communication */
+    private final SocketAddress socketAddress;
+
+    ControlListener(AbstractLaunchpadStartingPlugin mojo, Log log, String host, int port) {
+        this.mojo = mojo;
+        this.log = log;
+        this.socketAddress = getSocketAddress(host, port);
+    }
+
+    /**
+     * Implements the server side of the control connection starting a thread
+     * listening on the host and port configured on setup of this instance.
+     */
+    void listen() {
+        if (socketAddress != null) {
+            Thread listener = new Thread(this);
+            listener.setDaemon(true);
+            listener.setName("Sling Control Listener@" + socketAddress);
+            listener.start();
+        } else {
+            log.info("No socket address to listen to");
+        }
+    }
+
+    /**
+     * Implements the client side of the control connection sending the command
+     * to shutdown Sling.
+     */
+    void shutdownServer() {
+        sendCommand(COMMAND_STOP);
+    }
+
+    /**
+     * Implements the client side of the control connection sending the command
+     * to check whether Sling is active.
+     */
+    void statusServer() {
+        sendCommand(COMMAND_STATUS);
+    }
+
+    // ---------- Runnable interface
+
+    /**
+     * Implements the server thread receiving commands from clients and acting
+     * upon them.
+     */
+    public void run() {
+        ServerSocket server = null;
+        try {
+            server = new ServerSocket();
+            server.bind(socketAddress);
+            log.info("Sling Control Server started on " + socketAddress.toString());
+        } catch (IOException ioe) {
+            log.error("Failed to start Sling Control Server", ioe);
+            return;
+        }
+
+        try {
+            while (true) {
+
+                Socket s = server.accept();
+                try {
+                    String command = readLine(s);
+                    log.info(s.getRemoteSocketAddress() + ">" + command);
+
+                    if (COMMAND_STOP.equals(command)) {
+                        if (mojo != null) {
+                            mojo.stopSling();
+                        }
+                        writeLine(s, RESPONSE_OK);
+
+                        log.info("Sling shut down, exiting Java VM");
+                        System.exit(0);
+
+                    } else if (COMMAND_STATUS.equals(command)) {
+                        writeLine(s, RESPONSE_OK);
+
+                    } else {
+                        writeLine(s, "ERR:" + command);
+
+                    }
+                } finally {
+                    try {
+                        s.close();
+                    } catch (IOException ignore) {
+                    }
+                }
+            }
+        } catch (IOException ioe) {
+            log.error("Failure reading from client", ioe);
+        } finally {
+            try {
+                server.close();
+            } catch (IOException ignore) {
+            }
+        }
+    }
+
+    // ---------- socket support
+
+    private SocketAddress getSocketAddress(String host, int port) {
+        try {
+            if (port == -1) {
+                port = DEFAULT_LISTEN_PORT;
+            }
+
+            if (host != null) {
+                return new InetSocketAddress(host, port);
+            } else {
+
+                return new InetSocketAddress(InetAddress.getLocalHost(), port);
+            }
+        } catch (UnknownHostException uhe) {
+            log.error("Unknown host in '" + host + "': " + uhe.getMessage(), null);
+        }
+
+        return null;
+    }
+
+    private void sendCommand(String command) {
+        if (socketAddress != null) {
+            Socket socket = null;
+            try {
+                socket = new Socket();
+                socket.connect(socketAddress);
+                writeLine(socket, command);
+                String result = readLine(socket);
+                log.info("Sent '" + command + "' to " + socketAddress + ": " + result, null);
+            } catch (ConnectException ce) {
+                log.info("No Sling running at " + socketAddress, null);
+            } catch (IOException ioe) {
+                log.error("Failed sending '" + command + "' to " + socketAddress, ioe);
+            } finally {
+                if (socket != null) {
+                    try {
+                        socket.close();
+                    } catch (IOException ignore) {
+                    }
+                }
+            }
+        } else {
+            log.info("No socket address to send '" + command + "' to", null);
+        }
+    }
+
+    private String readLine(Socket socket) throws IOException {
+        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
+        return br.readLine();
+    }
+
+    private void writeLine(Socket socket, String line) throws IOException {
+        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), "UTF-8"));
+        bw.write(line);
+        bw.write("\r\n");
+        bw.flush();
+    }
+}
diff --git a/src/main/java/org/apache/sling/maven/projectsupport/RunMojo.java b/src/main/java/org/apache/sling/maven/projectsupport/RunMojo.java
index 061ecd8..248bd78 100644
--- a/src/main/java/org/apache/sling/maven/projectsupport/RunMojo.java
+++ b/src/main/java/org/apache/sling/maven/projectsupport/RunMojo.java
@@ -16,36 +16,11 @@
  */
 package org.apache.sling.maven.projectsupport;
 
-import static org.apache.felix.framework.util.FelixConstants.*;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
 import java.util.Map;
-import java.util.Properties;
 
 import org.apache.felix.framework.Logger;
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.shared.filtering.MavenFileFilter;
-import org.apache.maven.shared.filtering.MavenFilteringException;
-import org.apache.maven.shared.filtering.PropertyUtils;
 import org.apache.sling.launchpad.base.impl.ResourceProvider;
 import org.apache.sling.launchpad.base.impl.Sling;
-import org.apache.sling.launchpad.base.shared.Notifiable;
-import org.apache.sling.launchpad.base.shared.SharedConstants;
-import org.apache.sling.maven.projectsupport.bundlelist.v1_0_0.Bundle;
-import org.apache.sling.maven.projectsupport.bundlelist.v1_0_0.BundleList;
-import org.apache.sling.maven.projectsupport.bundlelist.v1_0_0.StartLevel;
 import org.osgi.framework.BundleException;
 
 /**
@@ -55,123 +30,9 @@ import org.osgi.framework.BundleException;
  * @requiresDependencyResolution test
  *
  */
-public class RunMojo extends AbstractBundleListMojo implements Notifiable {
-
-    /** Default log level setting if no set on command line (value is "INFO"). */
-    private static final int DEFAULT_LOG_LEVEL = Logger.LOG_INFO;
-
-    /** Mapping between log level numbers and names */
-    private static final String[] logLevels = { "FATAL", "ERROR", "WARN", "INFO", "DEBUG" };
-
-    /**
-     * The configuration property setting the port on which the HTTP service
-     * listens
-     */
-    private static final String PROP_PORT = "org.osgi.service.http.port";
-
-    /** Return the log level code for the string */
-    private static int toLogLevelInt(String level, int defaultLevel) {
-        for (int i = 0; i < logLevels.length; i++) {
-            if (logLevels[i].equalsIgnoreCase(level)) {
-                return i;
-            }
-        }
-
-        return defaultLevel;
-    }
-
-    /**
-     * @parameter expression="${http.port}" default-value="8080"
-     */
-    private int httpPort;
-
-    /**
-     * The definition of the package to be included to provide web support for
-     * JAR-packaged projects (i.e. pax-web).
-     *
-     * @parameter
-     */
-    private ArtifactDefinition jarWebSupport;
-
-    /**
-     * @parameter expression="${felix.log.level}"
-     */
-    private String logLevel;
-
-    /**
-     * @parameter expression="${propertiesFile}"
-     *            default-value="src/test/config/sling.properties"
-     */
-    private File propertiesFile;
+public class RunMojo extends AbstractLaunchpadStartingPlugin {
 
-    /**
-     * @component
-     */
-    private MavenFileFilter mavenFileFilter;
 
-    /**
-     * @parameter expression="${session}"
-     * @required
-     * @readonly
-     */
-    private MavenSession mavenSession;
-
-    private ResourceProvider resourceProvider = new ResourceProvider() {
-
-        @Override
-        public Iterator<String> getChildren(String path) {
-            if (path.equals("resources/bundles")) {
-                List<String> levels = new ArrayList<String>();
-                for (StartLevel level : getBundleList().getStartLevels()) {
-                    levels.add(String.valueOf(level.getLevel()) + "/");
-                }
-                return levels.iterator();
-            } else if (path.equals("resources/corebundles")) {
-                List<String> empty = Collections.emptyList();
-                return empty.iterator();
-            } else {
-                try {
-                    int i = Integer.parseInt(path);
-                    List<String> bundles = new ArrayList<String>();
-                    for (StartLevel level : getBundleList().getStartLevels()) {
-                        if (level.getLevel() == i) {
-                            for (Bundle bundle : level.getBundles()) {
-                                ArtifactDefinition d = new ArtifactDefinition(bundle, i);
-                                try {
-                                    Artifact artifact = getArtifact(d);
-                                    bundles.add(artifact.getFile().toURI().toURL().toExternalForm());
-                                } catch (Exception e) {
-                                    getLog().error("Unable to resolve artifact ", e);
-                                }
-                            }
-
-                            break;
-                        }
-                    }
-                    return bundles.iterator();
-
-                } catch (NumberFormatException e) {
-                    getLog().warn("un-handlable path " + path);
-                    return null;
-
-                }
-            }
-        }
-
-        @Override
-        public URL getResource(String path) {
-            if (path.endsWith(".properties")) {
-                return getClass().getResource("/" + path);
-            } else {
-                try {
-                    return new URL(path);
-                } catch (MalformedURLException e) {
-                    getLog().error("Expecting a real URL", e);
-                    return null;
-                }
-            }
-        }
-    };
 
     private Thread shutdown = new Thread() {
         /**
@@ -198,116 +59,38 @@ public class RunMojo extends AbstractBundleListMojo implements Notifiable {
                 // don't care for problems removing the hook
             }
 
-            // now really shutdown sling
-            if (sling != null) {
-                getLog().info("Stopping Sling", null);
-                sling.destroy();
-            }
+            stopSling();
         }
     };
 
-    private Sling sling;
-
-    /**
-     * @parameter expression="${sling.home}" default-value="sling"
-     */
-    private String slingHome;
-
-    /**
-     * @parameter default-value="true"
-     */
-    private boolean forceBundleLoad;
-
-    public void stopped() {
-        sling = null;
-    }
-
-    public void updated(File tmpFile) {
-        // TODO - should anything happen here?
-        getLog().info("File updated " + tmpFile.getAbsolutePath());
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected void executeWithArtifacts() throws MojoExecutionException, MojoFailureException {
+    protected Sling startSling(ResourceProvider resourceProvider, final Map<String, String> props, Logger logger)
+            throws BundleException {
         Runtime.getRuntime().addShutdownHook(shutdown);
 
-        try {
-            final Map<String, String> props = new HashMap<String, String>();
-
-            props.put(SharedConstants.SLING_HOME, slingHome);
+        // creating the instance launches the framework and we are done here
+        Sling mySling = new Sling(this, logger, resourceProvider, props) {
 
-            if (forceBundleLoad) {
-                props.put(SharedConstants.FORCE_PACKAGE_BUNDLE_LOADING, "true");
-            }
-
-            // set up and configure Felix Logger
-            int logLevelNum;
-            if (logLevel == null) {
-                logLevelNum = DEFAULT_LOG_LEVEL;
-            } else {
-                logLevelNum = toLogLevelInt(logLevel, DEFAULT_LOG_LEVEL);
-            }
-            props.put(LOG_LEVEL_PROP, String.valueOf(logLevelNum));
-            // Display port number on console, in case HttpService doesn't
-            getLog().info("HTTP server port: " + httpPort);
-            props.put(PROP_PORT, String.valueOf(httpPort));
-
-            // prevent tons of needless WARN from the framework
-            Logger logger = new Logger();
-            logger.setLogLevel(Logger.LOG_ERROR);
-
-            if (propertiesFile.exists()) {
-                File tmp = null;
-                try {
-                    tmp = File.createTempFile("sling", "props");
-                    mavenFileFilter.copyFile(propertiesFile, tmp, true, project, null, true, System
-                            .getProperty("file.encoding"), mavenSession);
-                    Properties loadedProps = PropertyUtils.loadPropertyFile(tmp, null);
-                    for (Object key : loadedProps.keySet()) {
-                        props.put((String) key, (String) loadedProps.get(key));
-                    }
-                } catch (IOException e) {
-                    throw new MojoExecutionException("Unable to create filtered properties file", e);
-                } catch (MavenFilteringException e) {
-                    throw new MojoExecutionException("Unable to create filtered properties file", e);
-                } finally {
-                    if (tmp != null) {
-                        tmp.delete();
-                    }
+            // overwrite the loadPropertiesOverride method to inject the
+            // mojo arguments unconditionally. These will not be persisted
+            // in any properties file, though
+            protected void loadPropertiesOverride(
+                    Map<String, String> properties) {
+                if (props != null) {
+                    properties.putAll(props);
                 }
             }
+        };
 
-            // creating the instance launches the framework and we are done here
-            sling = new Sling(this, logger, resourceProvider, props);
-
-            // TODO this seems hacky!
-            while (sling != null) {
+        // TODO this seems hacky!
+        try {
+            while (mySling != null) {
                 Thread.sleep(100);
             }
-
-        } catch (BundleException be) {
-            getLog().error("Failed to Start OSGi framework", be);
         } catch (InterruptedException e) {
         }
 
+        return mySling;
     }
 
-    protected void initArtifactDefinitions(Properties dependencies) {
-        if (jarWebSupport == null) {
-            jarWebSupport = new ArtifactDefinition();
-        }
-        jarWebSupport.initDefaults(dependencies.getProperty("jarWebSupport"));
-    }
-
-    /**
-     * Add the JAR Web Support bundle to the bundle list.
-     */
-    @Override
-    protected void initBundleList(BundleList bundleList) {
-        bundleList.add(jarWebSupport.toBundle());
-    }
 
 }
diff --git a/src/main/java/org/apache/sling/maven/projectsupport/StartMojo.java b/src/main/java/org/apache/sling/maven/projectsupport/StartMojo.java
new file mode 100644
index 0000000..7be272a
--- /dev/null
+++ b/src/main/java/org/apache/sling/maven/projectsupport/StartMojo.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.apache.sling.maven.projectsupport;
+
+import java.util.Map;
+
+import org.apache.felix.framework.Logger;
+import org.apache.sling.launchpad.base.impl.ResourceProvider;
+import org.apache.sling.launchpad.base.impl.Sling;
+import org.osgi.framework.BundleException;
+
+/**
+ * Start a Launchpad application.
+ *
+ * @goal start
+ * @requiresDependencyResolution test
+ *
+ */
+public class StartMojo extends AbstractLaunchpadStartingPlugin {
+
+    /**
+     * @parameter expression="${sling.control.port}" default-value="63000"
+     */
+    private int controlPort;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Sling startSling(ResourceProvider resourceProvider, final Map<String, String> props, Logger logger)
+            throws BundleException {
+        new ControlListener(this, getLog(), null, controlPort).listen();
+
+        return new Sling(this, logger, resourceProvider, props) {
+
+            // overwrite the loadPropertiesOverride method to inject the
+            // mojo arguments unconditionally. These will not be persisted
+            // in any properties file, though
+            protected void loadPropertiesOverride(
+                    Map<String, String> properties) {
+                if (props != null) {
+                    properties.putAll(props);
+                }
+            }
+        };
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/maven/projectsupport/StatusMojo.java b/src/main/java/org/apache/sling/maven/projectsupport/StatusMojo.java
new file mode 100644
index 0000000..95388e5
--- /dev/null
+++ b/src/main/java/org/apache/sling/maven/projectsupport/StatusMojo.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.apache.sling.maven.projectsupport;
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+
+/**
+ * Gets the status a running Launchpad standalone application.
+ *
+ * @goal status
+ * @requiresProject false
+ *
+ */
+public class StatusMojo extends AbstractMojo {
+
+    /**
+     * @parameter expression="${sling.control.port}" default-value="63000"
+     */
+    private int controlPort;
+
+    /**
+     * @parameter expression="${sling.control.host}" default-value="localhost"
+     */
+    private String controlHost;
+
+    /**
+     * {@inheritDoc}
+     */
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        new ControlListener(null, getLog(), controlHost, controlPort).statusServer();
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/maven/projectsupport/StopMojo.java b/src/main/java/org/apache/sling/maven/projectsupport/StopMojo.java
new file mode 100644
index 0000000..8fe3a8f
--- /dev/null
+++ b/src/main/java/org/apache/sling/maven/projectsupport/StopMojo.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership. The ASF
+ * licenses this file to You 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.apache.sling.maven.projectsupport;
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+
+/**
+ * Stop a running Launchpad standalone application.
+ *
+ * @goal stop
+ * @requiresProject false
+ *
+ */
+public class StopMojo extends AbstractMojo {
+
+    /**
+     * @parameter expression="${sling.control.port}" default-value="63000"
+     */
+    private int controlPort;
+
+    /**
+     * @parameter expression="${sling.control.host}" default-value="localhost"
+     */
+    private String controlHost;
+
+    /**
+     * {@inheritDoc}
+     */
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        new ControlListener(null, getLog(), controlHost, controlPort).shutdownServer();
+    }
+
+}

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.