You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ss...@apache.org on 2017/05/29 16:05:48 UTC

svn commit: r1796657 - in /sling/trunk/tooling/maven/maven-sling-plugin: ./ src/main/java/org/apache/sling/maven/bundlesupport/ src/main/java/org/apache/sling/maven/bundlesupport/deploy/ src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/...

Author: sseifert
Date: Mon May 29 16:05:47 2017
New Revision: 1796657

URL: http://svn.apache.org/viewvc?rev=1796657&view=rev
Log:
SLING-6917 Maven Sling Plugin: Deploy fsresource bundles on fsmount goal if required
refactor bundle upload logic to separate classes to make them reusable

Added:
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/BundleDeploymentMethod.java   (with props)
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/DeployContext.java   (with props)
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/DeployMethod.java   (with props)
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/FelixPostDeployMethod.java   (with props)
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/IntermediateUrisExtractor.java   (with props)
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/MkColMethod.java   (with props)
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/SlingPostDeployMethod.java   (with props)
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/WebDavPutDeployMethod.java   (with props)
    sling/trunk/tooling/maven/maven-sling-plugin/src/test/java/org/apache/sling/maven/bundlesupport/deploy/
    sling/trunk/tooling/maven/maven-sling-plugin/src/test/java/org/apache/sling/maven/bundlesupport/deploy/method/
    sling/trunk/tooling/maven/maven-sling-plugin/src/test/java/org/apache/sling/maven/bundlesupport/deploy/method/IntermediateUrisExtractorTest.java   (with props)
Removed:
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/IntermediateUrisExtractor.java
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/MkColMethod.java
    sling/trunk/tooling/maven/maven-sling-plugin/src/test/java/org/apache/sling/maven/bundlesupport/IntermediateUrisExtractorTest.java
Modified:
    sling/trunk/tooling/maven/maven-sling-plugin/README.txt
    sling/trunk/tooling/maven/maven-sling-plugin/pom.xml
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/AbstractBundleInstallMojo.java
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/AbstractFsMountMojo.java
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/BundleInstallFileMojo.java
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/BundleUninstallMojo.java
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/FsMountMojo.java
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/FsUnMountMojo.java
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/GenerateAdapterMetadataMojo.java
    sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/ValidationMojo.java

Modified: sling/trunk/tooling/maven/maven-sling-plugin/README.txt
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/README.txt?rev=1796657&r1=1796656&r2=1796657&view=diff
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/README.txt (original)
+++ sling/trunk/tooling/maven/maven-sling-plugin/README.txt Mon May 29 16:05:47 2017
@@ -5,16 +5,16 @@ Maven Plugin supporting various Sling De
 Getting Started
 ===============
 
-This component uses a Maven 2 (http://maven.apache.org/) build
+This component uses a Maven 3 (http://maven.apache.org/) build
 environment. It requires a Java 5 JDK (or higher) and Maven (http://maven.apache.org/)
 2.0.7 or later. We recommend to use the latest Maven version.
 
-If you have Maven 2 installed, you can compile and
+If you have Maven 3 installed, you can compile and
 package the jar using the following command:
 
     mvn package
 
-See the Maven 2 documentation for other build features.
+See the Maven 3 documentation for other build features.
 
 The latest source code for this component is available in the
 Subversion (http://subversion.tigris.org/) source repository of

Modified: sling/trunk/tooling/maven/maven-sling-plugin/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/pom.xml?rev=1796657&r1=1796656&r2=1796657&view=diff
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/pom.xml (original)
+++ sling/trunk/tooling/maven/maven-sling-plugin/pom.xml Mon May 29 16:05:47 2017
@@ -172,7 +172,20 @@
         <dependency>
             <groupId>org.apache.maven</groupId>
             <artifactId>maven-plugin-api</artifactId>
-            <version>2.0</version>
+            <version>3.0.4</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-artifact</artifactId>
+            <version>3.0.4</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.maven</groupId>
+            <artifactId>maven-compat</artifactId>
+            <version>3.0.4</version>
+            <scope>compile</scope>
         </dependency>
         <dependency>
             <groupId>org.apache.maven</groupId>
@@ -202,6 +215,11 @@
         </dependency>        
 
         <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
             <version>15.0</version>

Modified: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/AbstractBundleInstallMojo.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/AbstractBundleInstallMojo.java?rev=1796657&r1=1796656&r2=1796657&view=diff
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/AbstractBundleInstallMojo.java (original)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/AbstractBundleInstallMojo.java Mon May 29 16:05:47 2017
@@ -18,27 +18,13 @@
  */
 package org.apache.sling.maven.bundlesupport;
 
-import static org.apache.sling.maven.bundlesupport.JsonSupport.JSON_MIME_TYPE;
-
 import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.httpclient.HttpException;
-import org.apache.commons.httpclient.HttpStatus;
-import org.apache.commons.httpclient.methods.FileRequestEntity;
-import org.apache.commons.httpclient.methods.HeadMethod;
-import org.apache.commons.httpclient.methods.PostMethod;
-import org.apache.commons.httpclient.methods.PutMethod;
-import org.apache.commons.httpclient.methods.multipart.FilePart;
-import org.apache.commons.httpclient.methods.multipart.FilePartSource;
-import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
-import org.apache.commons.httpclient.methods.multipart.Part;
-import org.apache.commons.httpclient.methods.multipart.StringPart;
+
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugins.annotations.Parameter;
 import org.apache.maven.project.MavenProject;
+import org.apache.sling.maven.bundlesupport.deploy.BundleDeploymentMethod;
+import org.apache.sling.maven.bundlesupport.deploy.DeployContext;
 import org.apache.sling.maven.bundlesupport.fsresource.SlingInitialContentMounter;
 
 abstract class AbstractBundleInstallMojo extends AbstractBundlePostMojo {
@@ -54,22 +40,6 @@ abstract class AbstractBundleInstallMojo
     protected boolean usePut;
 
     /**
-     * Possible methodologies for deploying (installing and uninstalling)
-     * bundles from the remote server.
-     * Use camel-case values because those are used when you configure the plugin (and uppercase with separators "_" just looks ugly in that context)
-     */
-    enum BundleDeploymentMethod {
-        /** Via POST to Felix Web Console */
-        WebConsole,
-
-        /** Via WebDAV */
-        WebDAV,
-
-        /** Via POST to Sling directly */
-        SlingPostServlet;
-    }
-
-    /**
      * Bundle deployment method. One of the following three values are allowed
      * <ol>
      *  <li><strong>WebConsole</strong>, uses the <a href="http://felix.apache.org/documentation/subprojects/apache-felix-web-console/web-console-restful-api.html#post-requests">
@@ -135,15 +105,6 @@ abstract class AbstractBundleInstallMojo
 
     protected abstract String getBundleFileName() throws MojoExecutionException;
 
-    /**
-     * Returns the URL with the filename appended to it.
-     * @param targetURL the original requested targetURL to append fileName to
-     * @param fileName the name of the file to append to the targetURL.
-     */
-    protected String getURLWithFilename(String targetURL, String fileName) {
-        return targetURL + (targetURL.endsWith("/") ? "" : "/") + fileName;
-    }
-
     @Override
     public void execute() throws MojoExecutionException {
 
@@ -171,21 +132,14 @@ abstract class AbstractBundleInstallMojo
             "Installing Bundle " + bundleName + "(" + bundleFile + ") to "
                 + targetURL + " via " + deploymentMethod);
 
-
-        switch (deploymentMethod) {
-        case SlingPostServlet:
-            postToSling(targetURL, bundleFile);
-            break;
-        case WebConsole:
-            postToFelix(targetURL, bundleFile);
-            break;
-        case WebDAV:
-            putViaWebDav(targetURL, bundleFile);
-            break;
-        // sanity check to make sure it gets handled in some fashion
-        default:
-            throw new MojoExecutionException("Unrecognized BundleDeployMethod " + deploymentMethod);
-        }
+        deploymentMethod.execute().deploy(targetURL, bundleFile, bundleName, new DeployContext()
+                .log(getLog())
+                .httpClient(getHttpClient())
+                .failOnError(failOnError)
+                .bundleStartLevel(bundleStartLevel)
+                .bundleStart(bundleStart)
+                .mimeType(mimeType)
+                .refreshPackages(refreshPackages));
 
         if ( mountByFS ) {
             configure(getConsoleTargetURL(), bundleFile);
@@ -213,230 +167,4 @@ abstract class AbstractBundleInstallMojo
         }
     }
 
-    /**
-     * Install the bundle via POST to the Felix Web Console
-     * @param targetURL the URL to the Felix Web Console Bundles listing
-     * @param file the file to POST
-     * @throws MojoExecutionException
-     * @see <a href="http://felix.apache.org/documentation/subprojects/apache-felix-web-console/web-console-restful-api.html#post-requests">Webconsole RESTful API</a>
-     * @see <a href="https://github.com/apache/felix/blob/trunk/webconsole/src/main/java/org/apache/felix/webconsole/internal/core/BundlesServlet.java">BundlesServlet@Github</a>
-     */
-    protected void postToFelix(String targetURL, File file)
-            throws MojoExecutionException {
-
-        // append pseudo path after root URL to not get redirected for nothing
-        final PostMethod filePost = new PostMethod(targetURL + "/install");
-
-        try {
-            // set referrer
-            filePost.setRequestHeader("referer", "about:blank");
-
-            List<Part> partList = new ArrayList<Part>();
-            partList.add(new StringPart("action", "install"));
-            partList.add(new StringPart("_noredir_", "_noredir_"));
-            partList.add(new FilePart("bundlefile", new FilePartSource(
-                file.getName(), file)));
-            partList.add(new StringPart("bundlestartlevel", bundleStartLevel));
-
-            if (bundleStart) {
-                partList.add(new StringPart("bundlestart", "start"));
-            }
-
-            if (refreshPackages) {
-                partList.add(new StringPart("refreshPackages", "true"));
-            }
-
-            Part[] parts = partList.toArray(new Part[partList.size()]);
-
-            filePost.setRequestEntity(new MultipartRequestEntity(parts,
-                filePost.getParams()));
-
-            int status = getHttpClient().executeMethod(filePost);
-            if (status == HttpStatus.SC_OK) {
-                getLog().info("Bundle installed");
-            } else {
-                String msg = "Installation failed, cause: "
-                    + HttpStatus.getStatusText(status);
-                if (failOnError) {
-                    throw new MojoExecutionException(msg);
-                } else {
-                    getLog().error(msg);
-                }
-            }
-        } catch (Exception ex) {
-            throw new MojoExecutionException("Installation on " + targetURL
-                + " failed, cause: " + ex.getMessage(), ex);
-        } finally {
-            filePost.releaseConnection();
-        }
-    }
-
-    /**
-     * Perform the operation via POST to SlingPostServlet
-     * @param targetURL the URL of the Sling instance to post the file to.
-     * @param file the file being interacted with the POST to Sling.
-     * @throws MojoExecutionException
-     */
-    protected void postToSling(String targetURL, File file) throws MojoExecutionException {
-
-        /* truncate off trailing slash as this has special behaviorisms in
-         * the SlingPostServlet around created node name conventions */
-        if (targetURL.endsWith("/")) {
-            targetURL = targetURL.substring(0, targetURL.length()-1);
-        }
-        // append pseudo path after root URL to not get redirected for nothing
-        final PostMethod filePost = new PostMethod(targetURL);
-
-        try {
-
-            Part[] parts = new Part[2];
-            // Add content type to force the configured mimeType value
-            parts[0] = new FilePart("*", new FilePartSource(
-                file.getName(), file), mimeType, null);
-            // Add TypeHint to have jar be uploaded as file (not as resource)
-            parts[1] = new StringPart("*@TypeHint", "nt:file");
-
-            /* Request JSON response from Sling instead of standard HTML, to
-             * reduce the payload size (if the PostServlet supports it). */
-            filePost.setRequestHeader("Accept", JSON_MIME_TYPE);
-            filePost.setRequestEntity(new MultipartRequestEntity(parts,
-                filePost.getParams()));
-
-            int status = getHttpClient().executeMethod(filePost);
-            // SlingPostServlet may return 200 or 201 on creation, accept both
-            if (status == HttpStatus.SC_OK || status == HttpStatus.SC_CREATED) {
-                getLog().info("Bundle installed");
-            } else {
-                String msg = "Installation failed, cause: "
-                    + HttpStatus.getStatusText(status);
-                if (failOnError) {
-                    throw new MojoExecutionException(msg);
-                } else {
-                    getLog().error(msg);
-                }
-            }
-        } catch (Exception ex) {
-            throw new MojoExecutionException("Installation on " + targetURL
-                + " failed, cause: " + ex.getMessage(), ex);
-        } finally {
-            filePost.releaseConnection();
-        }
-    }
-
-    /**
-     * Puts the file via PUT (leveraging WebDAV). Creates the intermediate folders as well.
-     * @param targetURL
-     * @param file
-     * @throws MojoExecutionException
-     * @see <a href="https://tools.ietf.org/html/rfc4918#section-9.7.1">RFC 4918</a>
-     */
-    protected void putViaWebDav(String targetURL, File file) throws MojoExecutionException {
-
-        boolean success = false;
-        int status;
-
-        try {
-            status = performPut(targetURL, file);
-            if (status >= 200 && status < 300) {
-                success = true;
-            } else if (status == HttpStatus.SC_CONFLICT) {
-
-                getLog().debug("Bundle not installed due missing parent folders. Attempting to create parent structure.");
-                createIntermediaryPaths(targetURL);
-
-                getLog().debug("Re-attempting bundle install after creating parent folders.");
-                status = performPut(targetURL, file);
-                if (status >= 200 && status < 300) {
-                    success = true;
-                }
-            }
-
-            if (!success) {
-                String msg = "Installation failed, cause: "
-                    + HttpStatus.getStatusText(status);
-                if (failOnError) {
-                    throw new MojoExecutionException(msg);
-                } else {
-                    getLog().error(msg);
-                }
-            }
-        } catch (Exception ex) {
-            throw new MojoExecutionException("Installation on " + targetURL
-                + " failed, cause: " + ex.getMessage(), ex);
-        }
-    }
-
-    private int performPut(String targetURL, File file) throws HttpException, IOException {
-        PutMethod filePut = new PutMethod(getURLWithFilename(targetURL, file.getName()));
-        try {
-            filePut.setRequestEntity(new FileRequestEntity(file, mimeType));
-            return getHttpClient().executeMethod(filePut);
-        } finally {
-            filePut.releaseConnection();
-        }
-    }
-
-    private int performHead(String uri) throws HttpException, IOException {
-        HeadMethod head = new HeadMethod(uri);
-        try {
-            return getHttpClient().executeMethod(head);
-        } finally {
-            head.releaseConnection();
-        }
-    }
-
-    private int performMkCol(String uri) throws IOException {
-        MkColMethod mkCol = new MkColMethod(uri);
-        try {
-            return getHttpClient().executeMethod(mkCol);
-        } finally {
-            mkCol.releaseConnection();
-        }
-    }
-
-    private void createIntermediaryPaths(String targetURL) throws HttpException, IOException, MojoExecutionException {
-        // extract all intermediate URIs (longest one first)
-        List<String> intermediateUris = IntermediateUrisExtractor.extractIntermediateUris(targetURL);
-
-        // 1. go up to the node in the repository which exists already (HEAD request towards the root node)
-        String existingIntermediateUri = null;
-        // go through all intermediate URIs (longest first)
-        for (String intermediateUri : intermediateUris) {
-            // until one is existing
-            int result = performHead(intermediateUri) ;
-            if (result == HttpStatus.SC_OK) {
-                existingIntermediateUri = intermediateUri;
-                break;
-            } else if (result != HttpStatus.SC_NOT_FOUND) {
-                throw new MojoExecutionException("Failed getting intermediate path at " + intermediateUri + "."
-                        + " Reason: " + HttpStatus.getStatusText(result));
-            }
-        }
-
-        if (existingIntermediateUri == null) {
-            throw new MojoExecutionException(
-                    "Could not find any intermediate path up until the root of " + targetURL + ".");
-        }
-
-        // 2. now create from that level on each intermediate node individually towards the target path
-        int startOfInexistingIntermediateUri = intermediateUris.indexOf(existingIntermediateUri);
-        if (startOfInexistingIntermediateUri == -1) {
-            throw new IllegalStateException(
-                    "Could not find intermediate uri " + existingIntermediateUri + " in the list");
-        }
-
-        for (int index = startOfInexistingIntermediateUri - 1; index >= 0; index--) {
-            // use MKCOL to create the intermediate paths
-            String intermediateUri = intermediateUris.get(index);
-            int result = performMkCol(intermediateUri);
-            if (result == HttpStatus.SC_CREATED || result == HttpStatus.SC_OK) {
-                getLog().debug("Intermediate path at " + intermediateUri + " successfully created");
-                continue;
-            } else {
-                throw new MojoExecutionException("Failed creating intermediate path at '" + intermediateUri + "'."
-                        + " Reason: " + HttpStatus.getStatusText(result));
-            }
-        }
-    }
-
 }

Modified: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/AbstractFsMountMojo.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/AbstractFsMountMojo.java?rev=1796657&r1=1796656&r2=1796657&view=diff
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/AbstractFsMountMojo.java (original)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/AbstractFsMountMojo.java Mon May 29 16:05:47 2017
@@ -67,6 +67,9 @@ abstract class AbstractFsMountMojo exten
     public void execute() throws MojoExecutionException, MojoFailureException {
         String targetUrl = getConsoleTargetURL();
         
+        // ensure required bundles are installed
+        ensureBundlesInstalled(targetUrl);
+        
         // check for Sling-Initial-Content
         File bundleFile = new File(bundleFileName);
         if (bundleFile.exists()) {
@@ -97,7 +100,6 @@ abstract class AbstractFsMountMojo exten
         getLog().info("No Bundle with initial content or FileVault content package found - skipping.");
     }
 
-    @SuppressWarnings("unchecked")
     private File detectJcrRootFile() {
         List<Resource> resources = project.getResources();
         if (resources != null) {
@@ -112,7 +114,6 @@ abstract class AbstractFsMountMojo exten
         return null;
     }
 
-    @SuppressWarnings("unchecked")
     private File detectFilterXmlFile() {
         List<Resource> resources = project.getResources();
         if (resources != null) {
@@ -145,11 +146,14 @@ abstract class AbstractFsMountMojo exten
         }
         return null;
     }
-
+    
     protected abstract void configureSlingInitialContent(final String targetUrl, final File bundleFile)
             throws MojoExecutionException;
 
     protected abstract void configureFileVaultXml(final String targetUrl, final File jcrRootFile, final File filterXmlFile)
             throws MojoExecutionException;
+    
+    protected abstract void ensureBundlesInstalled(final String targetUrl)
+            throws MojoExecutionException;
 
 }
\ No newline at end of file

Modified: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/BundleInstallFileMojo.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/BundleInstallFileMojo.java?rev=1796657&r1=1796656&r2=1796657&view=diff
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/BundleInstallFileMojo.java (original)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/BundleInstallFileMojo.java Mon May 29 16:05:47 2017
@@ -21,7 +21,6 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.factory.ArtifactFactory;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
@@ -97,8 +96,9 @@ public class BundleInstallFileMojo exten
     @Parameter(property = "sling.repoUrl")
     private String repositoryUrl;
 
+    @SuppressWarnings("deprecation")
     @Component
-    private ArtifactFactory artifactFactory;
+    private org.apache.maven.artifact.factory.ArtifactFactory artifactFactory;
 
     @Component
     private ArtifactResolver artifactResolver;
@@ -126,7 +126,7 @@ public class BundleInstallFileMojo exten
         return fileName;
     }
 
-    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @SuppressWarnings({ "rawtypes", "unchecked", "deprecation" })
     private String resolveBundleFileFromArtifact() throws MojoExecutionException {
         if (artifactId == null && artifact == null) {
             return null;

Modified: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/BundleUninstallMojo.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/BundleUninstallMojo.java?rev=1796657&r1=1796656&r2=1796657&view=diff
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/BundleUninstallMojo.java (original)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/BundleUninstallMojo.java Mon May 29 16:05:47 2017
@@ -18,19 +18,13 @@
  */
 package org.apache.sling.maven.bundlesupport;
 
-import static org.apache.sling.maven.bundlesupport.JsonSupport.JSON_MIME_TYPE;
-
 import java.io.File;
 
-import org.apache.commons.httpclient.HttpStatus;
-import org.apache.commons.httpclient.methods.DeleteMethod;
-import org.apache.commons.httpclient.methods.PostMethod;
-import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
-import org.apache.commons.httpclient.methods.multipart.Part;
-import org.apache.commons.httpclient.methods.multipart.StringPart;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.sling.maven.bundlesupport.deploy.BundleDeploymentMethod;
+import org.apache.sling.maven.bundlesupport.deploy.DeployContext;
 import org.apache.sling.maven.bundlesupport.fsresource.SlingInitialContentMounter;
 
 /**
@@ -78,97 +72,11 @@ public class BundleUninstallMojo extends
 
         configure(targetURL, bundleFile);
 
-        switch (deployMethod) {
-        case SlingPostServlet:
-            postToSling(targetURL, bundleFile);
-            break;
-        case WebConsole:
-            postToFelix(targetURL, bundleName);
-            break;
-        case WebDAV:
-            deleteViaWebDav(targetURL, bundleFile);
-            break;
-        // sanity check to make sure it gets handled in some fashion
-        default:
-            throw new MojoExecutionException("Unrecognized BundleDeployMethod " + deployMethod);
-        }
-    }
-
-    protected void deleteViaWebDav(String targetURL, File file)
-        throws MojoExecutionException {
-
-        final DeleteMethod delete = new DeleteMethod(getURLWithFilename(targetURL, file.getName()));
-
-        try {
-
-            int status = getHttpClient().executeMethod(delete);
-            if (status >= 200 && status < 300) {
-                getLog().info("Bundle uninstalled");
-            } else {
-                getLog().error(
-                    "Uninstall failed, cause: "
-                        + HttpStatus.getStatusText(status));
-            }
-        } catch (Exception ex) {
-            throw new MojoExecutionException("Uninstall from " + targetURL
-                + " failed, cause: " + ex.getMessage(), ex);
-        } finally {
-            delete.releaseConnection();
-        }
-    }
-
-    @Override
-    protected void postToSling(String targetURL, File file)
-        throws MojoExecutionException {
-        final PostMethod post = new PostMethod(getURLWithFilename(targetURL, file.getName()));
-
-        try {
-            // Add SlingPostServlet operation flag for deleting the content
-            Part[] parts = new Part[1];
-            parts[0] = new StringPart(":operation", "delete");
-            post.setRequestEntity(new MultipartRequestEntity(parts,
-                    post.getParams()));
-
-            // Request JSON response from Sling instead of standard HTML
-            post.setRequestHeader("Accept", JSON_MIME_TYPE);
-
-            int status = getHttpClient().executeMethod(post);
-            if (status == HttpStatus.SC_OK) {
-                getLog().info("Bundle uninstalled");
-            } else {
-                getLog().error(
-                    "Uninstall failed, cause: "
-                        + HttpStatus.getStatusText(status));
-            }
-        } catch (Exception ex) {
-            throw new MojoExecutionException("Uninstall from " + targetURL
-                + " failed, cause: " + ex.getMessage(), ex);
-        } finally {
-            post.releaseConnection();
-        }
-    }
-
-    protected void postToFelix(String targetURL, String symbolicName)
-    throws MojoExecutionException {
-        final PostMethod post = new PostMethod(targetURL + "/bundles/" + symbolicName);
-        post.addParameter("action", "uninstall");
-
-        try {
-
-            int status = getHttpClient().executeMethod(post);
-            if (status == HttpStatus.SC_OK) {
-                getLog().info("Bundle uninstalled");
-            } else {
-                getLog().error(
-                    "Uninstall failed, cause: "
-                        + HttpStatus.getStatusText(status));
-            }
-        } catch (Exception ex) {
-            throw new MojoExecutionException("Uninstall from " + targetURL
-                + " failed, cause: " + ex.getMessage(), ex);
-        } finally {
-            post.releaseConnection();
-        }
+        deployMethod.execute().undeploy(targetURL, bundleFile, bundleName, new DeployContext()
+                .log(getLog())
+                .httpClient(getHttpClient())
+                .failOnError(failOnError)
+                .mimeType(mimeType));
     }
 
     @Override

Modified: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/FsMountMojo.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/FsMountMojo.java?rev=1796657&r1=1796656&r2=1796657&view=diff
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/FsMountMojo.java (original)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/FsMountMojo.java Mon May 29 16:05:47 2017
@@ -18,9 +18,30 @@
 package org.apache.sling.maven.bundlesupport;
 
 import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
 
+import javax.json.JsonArray;
+import javax.json.JsonException;
+import javax.json.JsonObject;
+
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.CharEncoding;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
+import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
+import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
 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.repository.RepositorySystem;
+import org.apache.sling.maven.bundlesupport.deploy.BundleDeploymentMethod;
+import org.apache.sling.maven.bundlesupport.deploy.DeployContext;
 import org.apache.sling.maven.bundlesupport.fsresource.FileVaultXmlMounter;
 import org.apache.sling.maven.bundlesupport.fsresource.SlingInitialContentMounter;
 
@@ -30,6 +51,48 @@ import org.apache.sling.maven.bundlesupp
  */
 @Mojo(name = "fsmount", requiresProject = true)
 public class FsMountMojo extends AbstractFsMountMojo {
+    
+    private static final String FS_BUNDLE_GROUP_ID = "org.apache.sling"; 
+    private static final String FS_BUNDLE_ARTIFACT_ID = "org.apache.sling.fsresource"; 
+    private static final String FS_BUNDLE_SYMBOLIC_NAME = FS_BUNDLE_ARTIFACT_ID; 
+    
+    /**
+     * Bundle deployment method. One of the following three values are allowed
+     * <ol>
+     *  <li><strong>WebConsole</strong>, uses the <a href="http://felix.apache.org/documentation/subprojects/apache-felix-web-console/web-console-restful-api.html#post-requests">
+     *  Felix Web Console REST API</a> for deployment (HTTP POST). This is the default. 
+     *  Make sure that {@link #slingUrl} points to the Felix Web Console in that case.</li>
+     *  <li><strong>WebDAV</strong>, uses <a href="https://sling.apache.org/documentation/development/repository-based-development.html">
+     *  WebDAV</a> for deployment (HTTP PUT). Make sure that {@link #slingUrl} points to the entry path of 
+     *  the Sling WebDAV bundle (usually below regular Sling root URL). Issues a HTTP Delete for the uninstall goal.
+     *  <li><strong>SlingPostServlet</strong>, uses the
+     *  <a href="https://sling.apache.org/documentation/bundles/manipulating-content-the-slingpostservlet-servlets-post.html">Sling Post Servlet</a> for deployment (HTTP POST).
+     *  Make sure that {@link #slingUrl} points a path which is handled by the Sling POST Servlet (usually below regular Sling root URL).</li>
+     * </ol>
+     * 
+     * This has precedence over the deprecated parameter {@link #usePut}.
+     */
+    @Parameter(property="sling.deploy.method", required = true, defaultValue = "WebConsole")
+    private BundleDeploymentMethod deploymentMethod;
+    
+    /**
+     * Deploy <code>org.apache.sling.fsresource</code> to Sling instance bundle when it is not deployed already.
+     */
+    @Parameter(required = true, defaultValue = "true")
+    private boolean deployFsResourceBundle;
+    
+    /**
+     * Minimum version of <code>org.apache.sling.fsresource</code> bundle. If an older version is installed this version is deployed. 
+     */
+    @Parameter(required = true, defaultValue = "2.1.2")
+    private String minimumFsResourceVersion;
+
+    @Component
+    private RepositorySystem repository;
+    @Parameter(property = "localRepository", required = true, readonly = true)
+    private ArtifactRepository localRepository;
+    @Parameter(property = "project.remoteArtifactRepositories", required = true, readonly = true)
+    private java.util.List<ArtifactRepository> remoteRepositories;
 
     @Override
     protected void configureSlingInitialContent(final String targetUrl, final File bundleFile) throws MojoExecutionException {
@@ -41,4 +104,95 @@ public class FsMountMojo extends Abstrac
         new FileVaultXmlMounter(getLog(), getHttpClient(), project).mount(targetUrl, jcrRootFile, filterXmlFile);
     }
 
+    @Override
+    protected void ensureBundlesInstalled(String targetUrl) throws MojoExecutionException {
+        if (!deployFsResourceBundle) {
+            return;
+        }
+        
+        boolean deployRequired = false;       
+        String fsBundleVersion = getFsResourceBundleInstalledVersion(targetUrl);
+        if (StringUtils.isBlank(fsBundleVersion)) {
+            deployRequired = true;
+        }
+        else {
+            DefaultArtifactVersion deployedVersion = new DefaultArtifactVersion(fsBundleVersion);
+            DefaultArtifactVersion requiredVersion = new DefaultArtifactVersion(minimumFsResourceVersion);
+            deployRequired = (deployedVersion.compareTo(requiredVersion) < 0);
+        }
+        if (!deployRequired) {
+            getLog().info("Bundle " + FS_BUNDLE_SYMBOLIC_NAME + " " + fsBundleVersion + " already installed, skipping deployment.");
+            return;
+        }
+        
+        getLog().info("Deploying bundle " + FS_BUNDLE_SYMBOLIC_NAME + " " + minimumFsResourceVersion + " ...");
+        
+        File file = getArtifactFile(FS_BUNDLE_GROUP_ID, FS_BUNDLE_ARTIFACT_ID, minimumFsResourceVersion, "jar");
+        deploymentMethod.execute().deploy(targetUrl, file, FS_BUNDLE_SYMBOLIC_NAME, new DeployContext()
+                .log(getLog())
+                .httpClient(getHttpClient())
+                .failOnError(failOnError));
+    }
+
+    /**
+     * Get version of fsresource bundle that is installed in the instance.
+     * @param targetUrl Target URL
+     * @return Version number or null if non installed
+     * @throws MojoExecutionException
+     */
+    public String getFsResourceBundleInstalledVersion(final String targetUrl) throws MojoExecutionException {
+        final String getUrl = targetUrl + "/bundles/" + FS_BUNDLE_SYMBOLIC_NAME + ".json";
+        final GetMethod get = new GetMethod(getUrl);
+
+        try {
+            final int status = getHttpClient().executeMethod(get);
+            if ( status == 200 ) {                
+                final String jsonText;
+                try (InputStream jsonResponse = get.getResponseBodyAsStream()) {
+                    jsonText = IOUtils.toString(jsonResponse, CharEncoding.UTF_8);
+                }
+                try {
+                    JsonObject response = JsonSupport.parseObject(jsonText);
+                    JsonArray data = response.getJsonArray("data");
+                    if (data.size() > 0) {
+                        JsonObject bundleData = data.getJsonObject(0);
+                        return bundleData.getString("version");
+                    }
+                    
+                } catch (JsonException ex) {
+                    throw new MojoExecutionException("Reading bundle data from " + getUrl
+                            + " failed, cause: " + ex.getMessage(), ex);
+                }
+            }
+        }
+        catch (HttpException ex) {
+            throw new MojoExecutionException("Reading bundle data from " + getUrl
+                    + " failed, cause: " + ex.getMessage(), ex);
+        }
+        catch (IOException ex) {
+            throw new MojoExecutionException("Reading bundle data from " + getUrl
+                    + " failed, cause: " + ex.getMessage(), ex);
+        }
+        finally {
+            get.releaseConnection();
+        }
+        // no version detected, bundle is not installed
+        return null;
+    }
+   
+    private File getArtifactFile(String groupId, String artifactId, String version, String type)
+            throws MojoExecutionException {
+        Artifact artifactObject = repository.createArtifact(groupId, artifactId, version, type);
+        ArtifactResolutionRequest request = new ArtifactResolutionRequest();
+        request.setArtifact(artifactObject);
+        request.setLocalRepository(localRepository);
+        request.setRemoteRepositories(remoteRepositories);
+        ArtifactResolutionResult result = repository.resolve(request);
+        if (result.isSuccess()) {
+            return artifactObject.getFile();
+        } else {
+            throw new MojoExecutionException("Unable to download artifact: " + artifactObject.toString());
+        }
+    }
+   
 }
\ No newline at end of file

Modified: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/FsUnMountMojo.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/FsUnMountMojo.java?rev=1796657&r1=1796656&r2=1796657&view=diff
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/FsUnMountMojo.java (original)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/FsUnMountMojo.java Mon May 29 16:05:47 2017
@@ -41,4 +41,9 @@ public class FsUnMountMojo extends Abstr
         new FileVaultXmlMounter(getLog(), getHttpClient(), project).unmount(targetUrl, jcrRootFile, filterXmlFile);
     }
 
-}
\ No newline at end of file
+    @Override
+    protected void ensureBundlesInstalled(String targetUrl) throws MojoExecutionException {
+        // nothing to do on uninstall
+    }
+
+}

Modified: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/GenerateAdapterMetadataMojo.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/GenerateAdapterMetadataMojo.java?rev=1796657&r1=1796656&r2=1796657&view=diff
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/GenerateAdapterMetadataMojo.java (original)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/GenerateAdapterMetadataMojo.java Mon May 29 16:05:47 2017
@@ -162,7 +162,6 @@ public class GenerateAdapterMetadataMojo
     private void addResource() {
         final String ourRsrcPath = this.outputDirectory.getAbsolutePath();
         boolean found = false;
-        @SuppressWarnings("unchecked")
         final Iterator<Resource> rsrcIterator = this.project.getResources().iterator();
         while (!found && rsrcIterator.hasNext()) {
             final Resource rsrc = rsrcIterator.next();

Modified: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/ValidationMojo.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/ValidationMojo.java?rev=1796657&r1=1796656&r2=1796657&view=diff
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/ValidationMojo.java (original)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/ValidationMojo.java Mon May 29 16:05:47 2017
@@ -70,7 +70,6 @@ public class ValidationMojo extends Abst
             getLog().info("Validation is skipped.");
             return;
         }
-        @SuppressWarnings("unchecked")
         final Iterator<Resource> rsrcIterator = this.project.getResources().iterator();
         while ( rsrcIterator.hasNext() ) {
             final Resource rsrc = rsrcIterator.next();

Added: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/BundleDeploymentMethod.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/BundleDeploymentMethod.java?rev=1796657&view=auto
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/BundleDeploymentMethod.java (added)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/BundleDeploymentMethod.java Mon May 29 16:05:47 2017
@@ -0,0 +1,58 @@
+/*
+ * 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.bundlesupport.deploy;
+
+import org.apache.sling.maven.bundlesupport.deploy.method.FelixPostDeployMethod;
+import org.apache.sling.maven.bundlesupport.deploy.method.SlingPostDeployMethod;
+import org.apache.sling.maven.bundlesupport.deploy.method.WebDavPutDeployMethod;
+
+/**
+ * Possible methodologies for deploying (installing and uninstalling)
+ * bundles from the remote server.
+ * Use camel-case values because those are used when you configure the plugin (and uppercase with separators "_" just looks ugly in that context)
+ */
+public enum BundleDeploymentMethod {
+    
+    /**
+     * Via POST to Felix Web Console
+     */
+    WebConsole(new FelixPostDeployMethod()),
+
+    /**
+     * Via WebDAV
+     */
+    WebDAV(new WebDavPutDeployMethod()),
+
+    /**
+     * Via POST to Sling directly
+     */
+    SlingPostServlet(new SlingPostDeployMethod());
+    
+    
+    private final DeployMethod deployMethod;
+
+    private BundleDeploymentMethod(DeployMethod deployMethod) {
+        this.deployMethod = deployMethod;
+    }
+    
+    public DeployMethod execute() {
+        return deployMethod;
+    }
+
+}

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/BundleDeploymentMethod.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/BundleDeploymentMethod.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon May 29 16:05:47 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/BundleDeploymentMethod.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/DeployContext.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/DeployContext.java?rev=1796657&view=auto
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/DeployContext.java (added)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/DeployContext.java Mon May 29 16:05:47 2017
@@ -0,0 +1,84 @@
+/*
+ * 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.bundlesupport.deploy;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.maven.plugin.logging.Log;
+
+public final class DeployContext {
+    
+    private Log log;
+    private HttpClient httpClient;
+    private boolean failOnError = true;
+    private String bundleStartLevel = "20";
+    private boolean bundleStart = true;
+    private String mimeType = "application/java-archive";
+    private boolean refreshPackages = true;
+    
+    public Log getLog() {
+        return log;
+    }
+    public DeployContext log(Log log) {
+        this.log = log;
+        return this;
+    }
+    public HttpClient getHttpClient() {
+        return httpClient;
+    }
+    public DeployContext httpClient(HttpClient httpClient) {
+        this.httpClient = httpClient;
+        return this;
+    }
+    public boolean isFailOnError() {
+        return failOnError;
+    }
+    public DeployContext failOnError(boolean failOnError) {
+        this.failOnError = failOnError;
+        return this;
+    }
+    public String getBundleStartLevel() {
+        return bundleStartLevel;
+    }
+    public DeployContext bundleStartLevel(String bundleStartLevel) {
+        this.bundleStartLevel = bundleStartLevel;
+        return this;
+    }
+    public boolean isBundleStart() {
+        return bundleStart;
+    }
+    public DeployContext bundleStart(boolean bundleStart) {
+        this.bundleStart = bundleStart;
+        return this;
+    }
+    public String getMimeType() {
+        return mimeType;
+    }
+    public DeployContext mimeType(String mimeType) {
+        this.mimeType = mimeType;
+        return this;
+    }
+    public boolean isRefreshPackages() {
+        return refreshPackages;
+    }
+    public DeployContext refreshPackages(boolean refreshPackages) {
+        this.refreshPackages = refreshPackages;
+        return this;
+    }
+
+}

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/DeployContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/DeployContext.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon May 29 16:05:47 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/DeployContext.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/DeployMethod.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/DeployMethod.java?rev=1796657&view=auto
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/DeployMethod.java (added)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/DeployMethod.java Mon May 29 16:05:47 2017
@@ -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.bundlesupport.deploy;
+
+import java.io.File;
+
+import org.apache.maven.plugin.MojoExecutionException;
+
+/**
+ * Deploys/installs and undeploys/uninstalls bundles on a Sling instance.
+ */
+public interface DeployMethod {
+
+    /**
+     * Deploy/install a bundle on a Sling instance.
+     * @param targetURL Target URL
+     * @param file Bundle file
+     * @param bundleSymbolicName Bundle symbolic name
+     * @param context Deploy context parameters
+     * @throws MojoExecutionException Mojo execution execution
+     */
+    void deploy(String targetURL, File file, String bundleSymbolicName, DeployContext context) throws MojoExecutionException;
+    
+    /**
+     * Undeploy/uninstall a bundle on a Sling instance.
+     * @param targetURL Target URL
+     * @param file Bundle file
+     * @param context Deploy context parameters
+     * @throws MojoExecutionException Mojo execution execution
+     */
+    void undeploy(String targetURL, File file, String bundleSymbolicName, DeployContext context) throws MojoExecutionException;
+    
+}

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/DeployMethod.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/DeployMethod.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon May 29 16:05:47 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/DeployMethod.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/FelixPostDeployMethod.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/FelixPostDeployMethod.java?rev=1796657&view=auto
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/FelixPostDeployMethod.java (added)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/FelixPostDeployMethod.java Mon May 29 16:05:47 2017
@@ -0,0 +1,111 @@
+/*
+ * 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.bundlesupport.deploy.method;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.multipart.FilePart;
+import org.apache.commons.httpclient.methods.multipart.FilePartSource;
+import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
+import org.apache.commons.httpclient.methods.multipart.Part;
+import org.apache.commons.httpclient.methods.multipart.StringPart;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.sling.maven.bundlesupport.deploy.DeployContext;
+import org.apache.sling.maven.bundlesupport.deploy.DeployMethod;
+
+public class FelixPostDeployMethod implements DeployMethod {
+
+    @Override
+    public void deploy(String targetURL, File file, String bundleSymbolicName, DeployContext context) throws MojoExecutionException {
+
+        // append pseudo path after root URL to not get redirected for nothing
+        final PostMethod filePost = new PostMethod(targetURL + "/install");
+
+        try {
+            // set referrer
+            filePost.setRequestHeader("referer", "about:blank");
+
+            List<Part> partList = new ArrayList<Part>();
+            partList.add(new StringPart("action", "install"));
+            partList.add(new StringPart("_noredir_", "_noredir_"));
+            partList.add(new FilePart("bundlefile", new FilePartSource(
+                file.getName(), file)));
+            partList.add(new StringPart("bundlestartlevel", context.getBundleStartLevel()));
+
+            if (context.isBundleStart()) {
+                partList.add(new StringPart("bundlestart", "start"));
+            }
+
+            if (context.isRefreshPackages()) {
+                partList.add(new StringPart("refreshPackages", "true"));
+            }
+
+            Part[] parts = partList.toArray(new Part[partList.size()]);
+
+            filePost.setRequestEntity(new MultipartRequestEntity(parts,
+                filePost.getParams()));
+
+            int status = context.getHttpClient().executeMethod(filePost);
+            if (status == HttpStatus.SC_OK) {
+                context.getLog().info("Bundle installed");
+            } else {
+                String msg = "Installation failed, cause: "
+                    + HttpStatus.getStatusText(status);
+                if (context.isFailOnError()) {
+                    throw new MojoExecutionException(msg);
+                } else {
+                    context.getLog().error(msg);
+                }
+            }
+        } catch (Exception ex) {
+            throw new MojoExecutionException("Installation on " + targetURL
+                + " failed, cause: " + ex.getMessage(), ex);
+        } finally {
+            filePost.releaseConnection();
+        }
+    }
+
+    @Override
+    public void undeploy(String targetURL, File file, String bundleSymbolicName, DeployContext context) throws MojoExecutionException {
+        final PostMethod post = new PostMethod(targetURL + "/bundles/" + bundleSymbolicName);
+        post.addParameter("action", "uninstall");
+
+        try {
+
+            int status = context.getHttpClient().executeMethod(post);
+            if (status == HttpStatus.SC_OK) {
+                context.getLog().info("Bundle uninstalled");
+            } else {
+                context.getLog().error(
+                    "Uninstall failed, cause: "
+                        + HttpStatus.getStatusText(status));
+            }
+        } catch (Exception ex) {
+            throw new MojoExecutionException("Uninstall from " + targetURL
+                + " failed, cause: " + ex.getMessage(), ex);
+        } finally {
+            post.releaseConnection();
+        }
+    }
+
+}

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/FelixPostDeployMethod.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/FelixPostDeployMethod.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon May 29 16:05:47 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/FelixPostDeployMethod.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/IntermediateUrisExtractor.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/IntermediateUrisExtractor.java?rev=1796657&view=auto
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/IntermediateUrisExtractor.java (added)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/IntermediateUrisExtractor.java Mon May 29 16:05:47 2017
@@ -0,0 +1,74 @@
+/*
+ * 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.bundlesupport.deploy.method;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper which extracts intermediate URIs from an URI 
+ */
+final class IntermediateUrisExtractor {
+
+    private IntermediateUrisExtractor() {
+        // static methods only
+    }
+
+    /**
+     * Extracts a list of intermediate paths from an URL.
+     * 
+     * <p>For instance, <tt>http://localhost:8080/apps/slingshot/install</tt> would have the following intermediate
+     * paths:
+     * <ol>
+     *   <li>http://localhost:8080/apps</li>
+     *   <li>http://localhost:8080/apps/slingshot</li>
+     *   <li>http://localhost:8080/apps/slingshot/install</li>
+     * </ol>
+     * </p>
+     * 
+     * @param url the url to extract paths from
+     * @return the intermediate paths, possibly empty
+     */
+    public static List<String> extractIntermediateUris(String url) {
+        
+        List<String> paths = new ArrayList<String>();
+        
+        URI uri = URI.create(url);
+        String path = uri.getPath();
+        
+        StringBuilder accu = new StringBuilder();
+        for ( String segment : path.split("/") ) {
+
+            // ensure we have a trailing slash to join with the next segment
+            if ( accu.length() == 0 || accu.charAt(accu.length() - 1) != '/') {
+                accu.append('/');
+            }
+            
+            accu.append(segment);
+            
+            // don't add the root segment ( / ) 
+            if ( segment.length() != 0 ) {
+                paths.add(0, uri.resolve(accu.toString()).toString());
+            }
+            
+        }
+        
+        return paths;
+    }
+    
+}

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/IntermediateUrisExtractor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/IntermediateUrisExtractor.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon May 29 16:05:47 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/IntermediateUrisExtractor.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/MkColMethod.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/MkColMethod.java?rev=1796657&view=auto
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/MkColMethod.java (added)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/MkColMethod.java Mon May 29 16:05:47 2017
@@ -0,0 +1,43 @@
+/*
+ * 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.bundlesupport.deploy.method;
+
+import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
+
+/**
+ * Implements the WebDAV MKCOL method
+ * 
+ * @see <a href="http://www.webdav.org/specs/rfc4918.html#METHOD_MKCOL">RFC 4918, $9.3</a>
+ *
+ */
+final class MkColMethod extends EntityEnclosingMethod {
+
+    /**
+     * Constructor specifying a URI.
+     *
+     * @param uri either an absolute or relative URI
+     */
+    public MkColMethod(String uri) {
+        super(uri);
+    }
+    
+    @Override
+    public String getName() {
+        return "MKCOL";
+    }
+
+}

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/MkColMethod.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/MkColMethod.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon May 29 16:05:47 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/MkColMethod.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/SlingPostDeployMethod.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/SlingPostDeployMethod.java?rev=1796657&view=auto
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/SlingPostDeployMethod.java (added)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/SlingPostDeployMethod.java Mon May 29 16:05:47 2017
@@ -0,0 +1,123 @@
+/*
+ * 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.bundlesupport.deploy.method;
+
+import static org.apache.sling.maven.bundlesupport.JsonSupport.JSON_MIME_TYPE;
+
+import java.io.File;
+
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.multipart.FilePart;
+import org.apache.commons.httpclient.methods.multipart.FilePartSource;
+import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
+import org.apache.commons.httpclient.methods.multipart.Part;
+import org.apache.commons.httpclient.methods.multipart.StringPart;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.sling.maven.bundlesupport.deploy.DeployContext;
+import org.apache.sling.maven.bundlesupport.deploy.DeployMethod;
+
+public class SlingPostDeployMethod implements DeployMethod {
+
+    @Override
+    public void deploy(String targetURL, File file, String bundleSymbolicName, DeployContext context) throws MojoExecutionException {
+        /* truncate off trailing slash as this has special behaviorisms in
+         * the SlingPostServlet around created node name conventions */
+        if (targetURL.endsWith("/")) {
+            targetURL = targetURL.substring(0, targetURL.length()-1);
+        }
+        // append pseudo path after root URL to not get redirected for nothing
+        final PostMethod filePost = new PostMethod(targetURL);
+
+        try {
+
+            Part[] parts = new Part[2];
+            // Add content type to force the configured mimeType value
+            parts[0] = new FilePart("*", new FilePartSource(
+                file.getName(), file), context.getMimeType(), null);
+            // Add TypeHint to have jar be uploaded as file (not as resource)
+            parts[1] = new StringPart("*@TypeHint", "nt:file");
+
+            /* Request JSON response from Sling instead of standard HTML, to
+             * reduce the payload size (if the PostServlet supports it). */
+            filePost.setRequestHeader("Accept", JSON_MIME_TYPE);
+            filePost.setRequestEntity(new MultipartRequestEntity(parts,
+                filePost.getParams()));
+
+            int status = context.getHttpClient().executeMethod(filePost);
+            // SlingPostServlet may return 200 or 201 on creation, accept both
+            if (status == HttpStatus.SC_OK || status == HttpStatus.SC_CREATED) {
+                context.getLog().info("Bundle installed");
+            } else {
+                String msg = "Installation failed, cause: "
+                    + HttpStatus.getStatusText(status);
+                if (context.isFailOnError()) {
+                    throw new MojoExecutionException(msg);
+                } else {
+                    context.getLog().error(msg);
+                }
+            }
+        } catch (Exception ex) {
+            throw new MojoExecutionException("Installation on " + targetURL
+                + " failed, cause: " + ex.getMessage(), ex);
+        } finally {
+            filePost.releaseConnection();
+        }
+    }
+
+    @Override
+    public void undeploy(String targetURL, File file, String bundleSymbolicName, DeployContext context) throws MojoExecutionException {
+        final PostMethod post = new PostMethod(getURLWithFilename(targetURL, file.getName()));
+
+        try {
+            // Add SlingPostServlet operation flag for deleting the content
+            Part[] parts = new Part[1];
+            parts[0] = new StringPart(":operation", "delete");
+            post.setRequestEntity(new MultipartRequestEntity(parts,
+                    post.getParams()));
+
+            // Request JSON response from Sling instead of standard HTML
+            post.setRequestHeader("Accept", JSON_MIME_TYPE);
+
+            int status = context.getHttpClient().executeMethod(post);
+            if (status == HttpStatus.SC_OK) {
+                context.getLog().info("Bundle uninstalled");
+            } else {
+                context.getLog().error(
+                    "Uninstall failed, cause: "
+                        + HttpStatus.getStatusText(status));
+            }
+        } catch (Exception ex) {
+            throw new MojoExecutionException("Uninstall from " + targetURL
+                + " failed, cause: " + ex.getMessage(), ex);
+        } finally {
+            post.releaseConnection();
+        }
+    }
+
+    /**
+     * Returns the URL with the filename appended to it.
+     * @param targetURL the original requested targetURL to append fileName to
+     * @param fileName the name of the file to append to the targetURL.
+     */
+    private String getURLWithFilename(String targetURL, String fileName) {
+        return targetURL + (targetURL.endsWith("/") ? "" : "/") + fileName;
+    }
+    
+}

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/SlingPostDeployMethod.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/SlingPostDeployMethod.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon May 29 16:05:47 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/SlingPostDeployMethod.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/WebDavPutDeployMethod.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/WebDavPutDeployMethod.java?rev=1796657&view=auto
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/WebDavPutDeployMethod.java (added)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/WebDavPutDeployMethod.java Mon May 29 16:05:47 2017
@@ -0,0 +1,177 @@
+/*
+ * 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.bundlesupport.deploy.method;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.httpclient.methods.DeleteMethod;
+import org.apache.commons.httpclient.methods.FileRequestEntity;
+import org.apache.commons.httpclient.methods.HeadMethod;
+import org.apache.commons.httpclient.methods.PutMethod;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.sling.maven.bundlesupport.deploy.DeployContext;
+import org.apache.sling.maven.bundlesupport.deploy.DeployMethod;
+
+public class WebDavPutDeployMethod implements DeployMethod {
+
+    @Override
+    public void deploy(String targetURL, File file, String bundleSymbolicName, DeployContext context) throws MojoExecutionException {
+        boolean success = false;
+        int status;
+
+        try {
+            status = performPut(targetURL, file, context);
+            if (status >= 200 && status < 300) {
+                success = true;
+            } else if (status == HttpStatus.SC_CONFLICT) {
+
+                context.getLog().debug("Bundle not installed due missing parent folders. Attempting to create parent structure.");
+                createIntermediaryPaths(targetURL, context);
+
+                context.getLog().debug("Re-attempting bundle install after creating parent folders.");
+                status = performPut(targetURL, file, context);
+                if (status >= 200 && status < 300) {
+                    success = true;
+                }
+            }
+
+            if (!success) {
+                String msg = "Installation failed, cause: "
+                    + HttpStatus.getStatusText(status);
+                if (context.isFailOnError()) {
+                    throw new MojoExecutionException(msg);
+                } else {
+                    context.getLog().error(msg);
+                }
+            }
+        } catch (Exception ex) {
+            throw new MojoExecutionException("Installation on " + targetURL
+                + " failed, cause: " + ex.getMessage(), ex);
+        }
+    }
+
+    @Override
+    public void undeploy(String targetURL, File file, String bundleSymbolicName, DeployContext context) throws MojoExecutionException {
+        final DeleteMethod delete = new DeleteMethod(getURLWithFilename(targetURL, file.getName()));
+
+        try {
+
+            int status = context.getHttpClient().executeMethod(delete);
+            if (status >= 200 && status < 300) {
+                context.getLog().info("Bundle uninstalled");
+            } else {
+                context.getLog().error(
+                    "Uninstall failed, cause: "
+                        + HttpStatus.getStatusText(status));
+            }
+        } catch (Exception ex) {
+            throw new MojoExecutionException("Uninstall from " + targetURL
+                + " failed, cause: " + ex.getMessage(), ex);
+        } finally {
+            delete.releaseConnection();
+        }
+    }
+
+    private int performPut(String targetURL, File file, DeployContext context) throws HttpException, IOException {
+        PutMethod filePut = new PutMethod(getURLWithFilename(targetURL, file.getName()));
+        try {
+            filePut.setRequestEntity(new FileRequestEntity(file, context.getMimeType()));
+            return context.getHttpClient().executeMethod(filePut);
+        } finally {
+            filePut.releaseConnection();
+        }
+    }
+
+    private int performHead(String uri, DeployContext context) throws HttpException, IOException {
+        HeadMethod head = new HeadMethod(uri);
+        try {
+            return context.getHttpClient().executeMethod(head);
+        } finally {
+            head.releaseConnection();
+        }
+    }
+
+    private int performMkCol(String uri, DeployContext context) throws IOException {
+        MkColMethod mkCol = new MkColMethod(uri);
+        try {
+            return context.getHttpClient().executeMethod(mkCol);
+        } finally {
+            mkCol.releaseConnection();
+        }
+    }
+
+    private void createIntermediaryPaths(String targetURL, DeployContext context) throws HttpException, IOException, MojoExecutionException {
+        // extract all intermediate URIs (longest one first)
+        List<String> intermediateUris = IntermediateUrisExtractor.extractIntermediateUris(targetURL);
+
+        // 1. go up to the node in the repository which exists already (HEAD request towards the root node)
+        String existingIntermediateUri = null;
+        // go through all intermediate URIs (longest first)
+        for (String intermediateUri : intermediateUris) {
+            // until one is existing
+            int result = performHead(intermediateUri, context) ;
+            if (result == HttpStatus.SC_OK) {
+                existingIntermediateUri = intermediateUri;
+                break;
+            } else if (result != HttpStatus.SC_NOT_FOUND) {
+                throw new MojoExecutionException("Failed getting intermediate path at " + intermediateUri + "."
+                        + " Reason: " + HttpStatus.getStatusText(result));
+            }
+        }
+
+        if (existingIntermediateUri == null) {
+            throw new MojoExecutionException(
+                    "Could not find any intermediate path up until the root of " + targetURL + ".");
+        }
+
+        // 2. now create from that level on each intermediate node individually towards the target path
+        int startOfInexistingIntermediateUri = intermediateUris.indexOf(existingIntermediateUri);
+        if (startOfInexistingIntermediateUri == -1) {
+            throw new IllegalStateException(
+                    "Could not find intermediate uri " + existingIntermediateUri + " in the list");
+        }
+
+        for (int index = startOfInexistingIntermediateUri - 1; index >= 0; index--) {
+            // use MKCOL to create the intermediate paths
+            String intermediateUri = intermediateUris.get(index);
+            int result = performMkCol(intermediateUri, context);
+            if (result == HttpStatus.SC_CREATED || result == HttpStatus.SC_OK) {
+                context.getLog().debug("Intermediate path at " + intermediateUri + " successfully created");
+                continue;
+            } else {
+                throw new MojoExecutionException("Failed creating intermediate path at '" + intermediateUri + "'."
+                        + " Reason: " + HttpStatus.getStatusText(result));
+            }
+        }
+    }
+
+    /**
+     * Returns the URL with the filename appended to it.
+     * @param targetURL the original requested targetURL to append fileName to
+     * @param fileName the name of the file to append to the targetURL.
+     */
+    private String getURLWithFilename(String targetURL, String fileName) {
+        return targetURL + (targetURL.endsWith("/") ? "" : "/") + fileName;
+    }
+    
+}

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/WebDavPutDeployMethod.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/WebDavPutDeployMethod.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon May 29 16:05:47 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/main/java/org/apache/sling/maven/bundlesupport/deploy/method/WebDavPutDeployMethod.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sling/trunk/tooling/maven/maven-sling-plugin/src/test/java/org/apache/sling/maven/bundlesupport/deploy/method/IntermediateUrisExtractorTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/maven/maven-sling-plugin/src/test/java/org/apache/sling/maven/bundlesupport/deploy/method/IntermediateUrisExtractorTest.java?rev=1796657&view=auto
==============================================================================
--- sling/trunk/tooling/maven/maven-sling-plugin/src/test/java/org/apache/sling/maven/bundlesupport/deploy/method/IntermediateUrisExtractorTest.java (added)
+++ sling/trunk/tooling/maven/maven-sling-plugin/src/test/java/org/apache/sling/maven/bundlesupport/deploy/method/IntermediateUrisExtractorTest.java Mon May 29 16:05:47 2017
@@ -0,0 +1,58 @@
+/*
+ * 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.bundlesupport.deploy.method;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.sling.maven.bundlesupport.deploy.method.IntermediateUrisExtractor;
+import org.junit.Test;
+
+public class IntermediateUrisExtractorTest {
+    
+    @Test
+    public void extractPaths() {
+
+        doTest("http://localhost:8080/apps/slingshot/install", 
+                Arrays.asList("http://localhost:8080/apps/slingshot/install", "http://localhost:8080/apps/slingshot", "http://localhost:8080/apps" ));
+    }
+    
+    private void doTest(String input, List<String> expectedOutput) {
+
+        List<String> paths = IntermediateUrisExtractor.extractIntermediateUris(input);
+        
+        assertThat(paths, equalTo(expectedOutput));
+    }
+
+    @Test
+    public void extractPaths_trailingSlash() {
+        
+        doTest("http://localhost:8080/apps/slingshot/install/", 
+                Arrays.asList("http://localhost:8080/apps/slingshot/install", "http://localhost:8080/apps/slingshot", "http://localhost:8080/apps" ));
+    }
+
+    @Test
+    public void extractPaths_empty() {
+        
+        doTest("http://localhost:8080", Collections.<String> emptyList());
+    }
+
+}

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/test/java/org/apache/sling/maven/bundlesupport/deploy/method/IntermediateUrisExtractorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/test/java/org/apache/sling/maven/bundlesupport/deploy/method/IntermediateUrisExtractorTest.java
------------------------------------------------------------------------------
--- svn:keywords (added)
+++ svn:keywords Mon May 29 16:05:47 2017
@@ -0,0 +1 @@
+LastChangedDate LastChangedRevision LastChangedBy HeadURL Id Author

Propchange: sling/trunk/tooling/maven/maven-sling-plugin/src/test/java/org/apache/sling/maven/bundlesupport/deploy/method/IntermediateUrisExtractorTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain