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

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

commit 87744a466de8c0955934568a0860dae75a8f572b
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Fri Sep 19 08:12:35 2014 +0000

    Add slingstart maven plugin
    
    git-svn-id: 
https://svn.apache.org/repos/asf/sling/trunk/tooling/maven/slingstart-maven-plugin@1626140
 13f79535-47bb-0310-9956-ffa450edef68
---
 .../maven/slingstart/AbstractSubsystemMojo.java    |  72 ++++
 .../maven/slingstart/AttachSlingSubsystem.java     |  69 ++++
 .../sling/maven/slingstart/BuildConstants.java     |  98 +++++
 .../slingstart/DependencyLifecycleParticipant.java | 194 ++++++++++
 .../sling/maven/slingstart/JarArchiverHelper.java  | 180 ++++++++++
 .../apache/sling/maven/slingstart/PackageMojo.java | 121 +++++++
 .../sling/maven/slingstart/PreparePackageMojo.java | 400 +++++++++++++++++++++
 .../sling/maven/slingstart/SubsystemUtils.java     | 179 +++++++++
 src/main/resources/META-INF/plexus/components.xml  |  95 +++++
 9 files changed, 1408 insertions(+)

diff --git 
a/src/main/java/org/apache/sling/maven/slingstart/AbstractSubsystemMojo.java 
b/src/main/java/org/apache/sling/maven/slingstart/AbstractSubsystemMojo.java
new file mode 100644
index 0000000..121ef2c
--- /dev/null
+++ b/src/main/java/org/apache/sling/maven/slingstart/AbstractSubsystemMojo.java
@@ -0,0 +1,72 @@
+/*
+ * 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.slingstart;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.MavenProjectHelper;
+import org.apache.sling.slingstart.model.SSMSubsystem;
+import org.apache.sling.slingstart.model.xml.XMLSSMModelReader;
+
+public abstract class AbstractSubsystemMojo extends AbstractMojo {
+
+    @Parameter(defaultValue="${basedir}/src/main/systems")
+    protected File systemsDirectory;
+
+    @Parameter(property = "project", readonly = true, required = true)
+    protected MavenProject project;
+
+    @Component
+    protected MavenProjectHelper projectHelper;
+
+    @Parameter(property = "session", readonly = true, required = true)
+    protected MavenSession mavenSession;
+
+    @Parameter(defaultValue="false")
+    protected boolean createWebapp;
+
+    /**
+     * Read the model prepared by the lifecycle plugin
+     */
+    protected SSMSubsystem readModel()
+    throws MojoExecutionException {
+        SSMSubsystem result = 
(SSMSubsystem)this.project.getContextValue(SSMSubsystem.class.getName());
+        if ( result == null ) {
+            try {
+                final String contents = 
(String)this.project.getContextValue(SSMSubsystem.class.getName() + "/text");
+                result = XMLSSMModelReader.read(new StringReader(contents));
+
+                this.project.setContextValue(SSMSubsystem.class.getName(), 
result);
+            } catch ( final IOException ioe) {
+                throw new MojoExecutionException("Unable to cache model", ioe);
+            }
+        }
+        return result;
+    }
+
+    protected File getTmpDir() {
+        return new File(this.project.getBuild().getDirectory(), 
"slingstart-tmp");
+    }
+}
diff --git 
a/src/main/java/org/apache/sling/maven/slingstart/AttachSlingSubsystem.java 
b/src/main/java/org/apache/sling/maven/slingstart/AttachSlingSubsystem.java
new file mode 100644
index 0000000..72a9687
--- /dev/null
+++ b/src/main/java/org/apache/sling/maven/slingstart/AttachSlingSubsystem.java
@@ -0,0 +1,69 @@
+/*
+ * 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.slingstart;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.sling.slingstart.model.SSMSubsystem;
+import org.apache.sling.slingstart.model.xml.XMLSSMModelWriter;
+
+/**
+ * Attaches the subsystem as a project artifact.
+ *
+ */
+@Mojo(
+        name = "attach-slingsubsystem",
+        defaultPhase = LifecyclePhase.PACKAGE,
+        requiresDependencyResolution = ResolutionScope.TEST,
+        threadSafe = true
+    )
+public class AttachSlingSubsystem extends AbstractSubsystemMojo {
+
+    @Override
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        final SSMSubsystem model = this.readModel();
+
+        final File outputFile = new 
File(this.project.getBuild().getDirectory() + File.separatorChar + 
"slingstart.xml");
+        outputFile.getParentFile().mkdirs();
+        Writer writer = null;
+        try {
+            writer = new FileWriter(outputFile);
+            XMLSSMModelWriter.write(writer, model);
+        } catch (IOException e) {
+            throw new MojoExecutionException("Unable to write model to " + 
outputFile, e);
+        } finally {
+            IOUtils.closeQuietly(writer);
+        }
+
+        // if this project is a partial bundle list, it's the main artifact
+        if ( 
project.getPackaging().equals(BuildConstants.PACKAGING_PARTIAL_SYSTEM) ) {
+            project.getArtifact().setFile(outputFile);
+        } else {
+            // otherwise attach it as an additional artifact
+            projectHelper.attachArtifact(project, BuildConstants.TYPE_XML, 
BuildConstants.CLASSIFIER_PARTIAL_SYSTEM, outputFile);
+        }
+    }
+}
diff --git 
a/src/main/java/org/apache/sling/maven/slingstart/BuildConstants.java 
b/src/main/java/org/apache/sling/maven/slingstart/BuildConstants.java
new file mode 100644
index 0000000..169bcdc
--- /dev/null
+++ b/src/main/java/org/apache/sling/maven/slingstart/BuildConstants.java
@@ -0,0 +1,98 @@
+/*
+ * 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.slingstart;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sling.slingstart.model.SSMRunMode;
+
+public abstract class BuildConstants {
+
+    // CONTEXTS
+    public static final String CONTEXT_GLOBAL = "slingstart:global";
+    public static final String CONTEXT_STANDALONE = "slingstart" + 
SSMRunMode.RUN_MODE_STANDALONE;
+    public static final String CONTEXT_WEBAPP = "slingstart" + 
SSMRunMode.RUN_MODE_WEBAPP;
+
+
+    // Types
+
+    public static final String TYPE_JAR = "jar";
+
+    public static final String TYPE_WAR = "war";
+
+    public static final String TYPE_POM = "pom";
+
+    public static final String TYPE_XML = "xml";
+
+    public static final String PACKAGING_PARTIAL_SYSTEM = "slingsubsystem";
+
+    public static final String PACKAGING_SLINGSTART = "slingstart";
+
+    // Classifiers
+
+    public static final String CLASSIFIER_PARTIAL_SYSTEM = "slingsubsystem";
+
+    public static final String CLASSIFIER_BASE = "base";
+
+    public static final String CLASSIFIER_APP = "app";
+
+    public static final String CLASSIFIER_WEBAPP = "webapp";
+
+    // Manifest attributes
+
+    public static final String ATTR_BUILT_BY = "Built-By";
+
+    public static final String ATTR_CREATED_BY = "Created-By";
+
+    public static final String ATTR_IMPLEMENTATION_VERSION = 
"Implementation-Version";
+
+    public static final String ATTR_IMPLEMENTATION_VENDOR = 
"Implementation-Vendor";
+
+    public static final String ATTR_IMPLEMENTATION_BUILD = 
"Implementation-Build";
+
+    public static final String ATTR_IMPLEMENTATION_VENDOR_ID = 
"Implementation-Vendor-Id";
+
+    public static final String ATTR_IMPLEMENTATION_TITLE = 
"Implementation-Title";
+
+    public static final String ATTR_SPECIFICATION_TITLE = 
"Specification-Title";
+
+    public static final String ATTR_SPECIFICATION_VENDOR = 
"Specification-Vendor";
+
+    public static final String ATTR_SPECIFICATION_VERSION = 
"Specification-Version";
+
+    public static final String ATTR_MAIN_CLASS = "Main-Class";
+
+    public static final String ATTR_VALUE_MAIN_CLASS = 
"org.apache.sling.launchpad.app.Main";
+
+    public static final List<String> ATTRS_EXCLUDES = new ArrayList<String>();
+    static {
+        ATTRS_EXCLUDES.add(ATTR_BUILT_BY);
+        ATTRS_EXCLUDES.add(ATTR_CREATED_BY);
+        ATTRS_EXCLUDES.add(ATTR_IMPLEMENTATION_VERSION);
+        ATTRS_EXCLUDES.add(ATTR_IMPLEMENTATION_VENDOR);
+        ATTRS_EXCLUDES.add(ATTR_IMPLEMENTATION_BUILD);
+        ATTRS_EXCLUDES.add(ATTR_IMPLEMENTATION_VENDOR_ID);
+        ATTRS_EXCLUDES.add(ATTR_IMPLEMENTATION_TITLE);
+        ATTRS_EXCLUDES.add(ATTR_SPECIFICATION_TITLE);
+        ATTRS_EXCLUDES.add(ATTR_SPECIFICATION_VENDOR);
+        ATTRS_EXCLUDES.add(ATTR_SPECIFICATION_VERSION);
+    }
+
+    // build constants
+    public static final String WEBAPP_OUTDIR = "slingstart-webapp";
+}
diff --git 
a/src/main/java/org/apache/sling/maven/slingstart/DependencyLifecycleParticipant.java
 
b/src/main/java/org/apache/sling/maven/slingstart/DependencyLifecycleParticipant.java
new file mode 100644
index 0000000..797d867
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/maven/slingstart/DependencyLifecycleParticipant.java
@@ -0,0 +1,194 @@
+/*
+ * 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.slingstart;
+
+import java.io.File;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.AbstractMavenLifecycleParticipant;
+import org.apache.maven.MavenExecutionException;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.DefaultArtifact;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.project.MavenProject;
+import org.apache.sling.slingstart.model.SSMArtifact;
+import org.apache.sling.slingstart.model.SSMRunMode;
+import org.apache.sling.slingstart.model.SSMStartLevel;
+import org.apache.sling.slingstart.model.SSMSubsystem;
+import org.apache.sling.slingstart.model.xml.XMLSSMModelWriter;
+import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.logging.Logger;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+
+/**
+ * Maven lifecycle participant which adds the artifacts of the model to the 
dependencies.
+ */
+@Component(role = AbstractMavenLifecycleParticipant.class)
+public class DependencyLifecycleParticipant extends 
AbstractMavenLifecycleParticipant {
+
+    private static final String PLUGIN_ID = "slingstart-maven-plugin";
+
+    private static final String PROVIDED = "provided";
+
+    @Requirement
+    private Logger log;
+
+    @Requirement
+    private ArtifactHandlerManager artifactHandlerManager;
+
+    /**
+     * Used to look up Artifacts in the remote repository.
+     *
+     */
+    @Requirement
+    private ArtifactResolver resolver;
+
+    @Override
+    public void afterProjectsRead(final MavenSession session) throws 
MavenExecutionException {
+        log.info("Searching for slingstart projects...");
+        try {
+            final Map<String, MavenProject> projectMap = new HashMap<String, 
MavenProject>();
+            for (final MavenProject project : session.getProjects()) {
+                projectMap.put(project.getGroupId() + ":" + 
project.getArtifactId() + ":" + project.getVersion(),
+                        project);
+            }
+
+            for (final MavenProject project : session.getProjects()) {
+                for (Plugin plugin : project.getBuild().getPlugins()) {
+                    if (plugin.getArtifactId().equals(PLUGIN_ID)) {
+                        addDependencies(artifactHandlerManager, resolver, log,
+                                session, project, plugin);
+                    }
+                }
+            }
+        } catch (final Exception e) {
+            throw new MavenExecutionException("Unable to determine 
plugin-based dependencies", e);
+        }
+    }
+
+    public static void addDependencies(final ArtifactHandlerManager 
artifactHandlerManager,
+            final ArtifactResolver resolver,
+            final Logger log,
+            final MavenSession session, final MavenProject project, final 
Plugin plugin)
+    throws Exception {
+        // check dependent projects first
+        final List<File> dependencies = new ArrayList<File>();
+        for(final Dependency d : project.getDependencies() ) {
+            if ( d.getType().equals(BuildConstants.PACKAGING_SLINGSTART)
+              || d.getType().equals(BuildConstants.PACKAGING_PARTIAL_SYSTEM)) {
+                final File modelXML = 
getSlingstartArtifact(artifactHandlerManager, resolver, project, session, d);
+                dependencies.add(modelXML);
+            }
+        }
+
+        final String directory = nodeValue((Xpp3Dom) plugin.getConfiguration(),
+                "systemsDirectory", new File(project.getBasedir(), 
"src/main/systems").getAbsolutePath());
+        final SSMSubsystem model = SubsystemUtils.readFullModel(new 
File(directory), dependencies, project, session, log);
+
+        final StringWriter w = new StringWriter();
+        XMLSSMModelWriter.write(w, model);
+        project.setContextValue(SSMSubsystem.class.getName() + "/text", 
w.toString());
+
+        // start with base artifact
+        final SSMArtifact base = SubsystemUtils.getBaseArtifact(model);
+        final String[] classifiers = new String[] {null, 
BuildConstants.CLASSIFIER_APP, BuildConstants.CLASSIFIER_WEBAPP};
+        for(final String c : classifiers) {
+            final Dependency dep = new Dependency();
+            dep.setGroupId(base.groupId);
+            dep.setArtifactId(base.artifactId);
+            dep.setVersion(model.getValue(base.version));
+            dep.setType(base.type);
+            dep.setClassifier(c);
+            if ( BuildConstants.CLASSIFIER_WEBAPP.equals(c) ) {
+                dep.setType(BuildConstants.TYPE_WAR);
+            }
+            dep.setScope(PROVIDED);
+
+            log.debug("- adding dependency " + dep);
+            project.getDependencies().add(dep);
+        }
+
+        addDependencies(model, log, project);
+    }
+
+    private static void addDependencies(final SSMSubsystem model, final Logger 
log, final MavenProject project) {
+        for(final SSMRunMode runMode : model.runModes) {
+            // skip base
+            if ( runMode.isRunMode(SSMRunMode.RUN_MODE_BASE) ) {
+                continue;
+            }
+            for(final SSMStartLevel sl : runMode.startLevels) {
+                for(final SSMArtifact a : sl.artifacts) {
+                    final Dependency dep = new Dependency();
+                    dep.setGroupId(a.groupId);
+                    dep.setArtifactId(a.artifactId);
+                    dep.setVersion(model.getValue(a.version));
+                    dep.setType(a.type);
+                    dep.setClassifier(a.classifier);
+                    dep.setScope(PROVIDED);
+
+                    log.debug("- adding dependency " + dep);
+                    project.getDependencies().add(dep);
+                }
+            }
+        }
+    }
+
+    private static File getSlingstartArtifact(final ArtifactHandlerManager 
artifactHandlerManager,
+            final ArtifactResolver resolver,
+            final MavenProject project,
+            final MavenSession session,
+            final Dependency d)
+    throws MavenExecutionException {
+        final Artifact prjArtifact = new DefaultArtifact(d.getGroupId(),
+                d.getArtifactId(),
+                VersionRange.createFromVersion(d.getVersion()),
+                Artifact.SCOPE_PROVIDED,
+                d.getType(),
+                d.getClassifier(),
+                artifactHandlerManager.getArtifactHandler(d.getType()));
+        try {
+            resolver.resolve(prjArtifact, 
project.getRemoteArtifactRepositories(), session.getLocalRepository());
+        } catch (final ArtifactResolutionException e) {
+            throw new MavenExecutionException("Unable to get artifact for " + 
d, e);
+        } catch (final ArtifactNotFoundException e) {
+            throw new MavenExecutionException("Unable to get artifact for " + 
d, e);
+        }
+        return prjArtifact.getFile();
+    }
+
+    private static String nodeValue(final Xpp3Dom config, final String name, 
final String defaultValue) {
+        final Xpp3Dom node = (config == null ? null : config.getChild(name));
+        if (node != null) {
+            return node.getValue();
+        } else {
+            return defaultValue;
+        }
+    }
+}
diff --git 
a/src/main/java/org/apache/sling/maven/slingstart/JarArchiverHelper.java 
b/src/main/java/org/apache/sling/maven/slingstart/JarArchiverHelper.java
new file mode 100644
index 0000000..9b70652
--- /dev/null
+++ b/src/main/java/org/apache/sling/maven/slingstart/JarArchiverHelper.java
@@ -0,0 +1,180 @@
+/*
+ * 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.slingstart;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.archiver.ArchiverException;
+import org.codehaus.plexus.archiver.jar.JarArchiver;
+import org.codehaus.plexus.archiver.jar.Manifest;
+import org.codehaus.plexus.archiver.jar.Manifest.Attribute;
+import org.codehaus.plexus.archiver.jar.ManifestException;
+
+public class JarArchiverHelper {
+
+    private final JarArchiver archiver;
+
+    private final MavenProject project;
+
+    public JarArchiverHelper(final JarArchiver archiver,
+                    final MavenProject project,
+                    final File destFile) throws MojoExecutionException {
+        this(archiver, project, destFile, null);
+    }
+
+    public JarArchiverHelper(final JarArchiver archiver,
+                    final MavenProject project,
+                    final File destFile,
+                    final java.util.jar.Manifest manifest) throws 
MojoExecutionException {
+        this.project = project;
+        this.archiver = archiver;
+        this.archiver.reset();
+        this.archiver.setDestFile(destFile);
+
+        this.createManifest(manifest);
+    }
+
+    /**
+     * Create a manifest
+     */
+    private void createManifest(final java.util.jar.Manifest manifest) throws 
MojoExecutionException {
+        // create a new manifest
+        final Manifest outManifest = new Manifest();
+
+        try {
+            boolean hasMain = false;
+
+            // copy entries from existing manifest
+            if ( manifest != null ) {
+                final Map<Object, Object> attrs = manifest.getMainAttributes();
+                for(final Map.Entry<Object, Object> entry : attrs.entrySet()) {
+                    final String key = entry.getKey().toString();
+                    if ( !BuildConstants.ATTRS_EXCLUDES.contains(key)) {
+                        final Attribute a = new Attribute(key, 
entry.getValue().toString());
+                        outManifest.addConfiguredAttribute(a);
+                    }
+                    if ( key.equals(BuildConstants.ATTR_MAIN_CLASS) ) {
+                        hasMain = true;
+                    }
+                }
+            }
+            outManifest.addConfiguredAttribute(new 
Attribute(BuildConstants.ATTR_IMPLEMENTATION_BUILD,
+                            project.getVersion()));
+            outManifest.addConfiguredAttribute(new 
Attribute(BuildConstants.ATTR_IMPLEMENTATION_VENDOR,
+                            project.getOrganization().getName()));
+            outManifest.addConfiguredAttribute(new 
Attribute(BuildConstants.ATTR_IMPLEMENTATION_VERSION,
+                            project.getVersion()));
+            outManifest.addConfiguredAttribute(new 
Attribute(BuildConstants.ATTR_CREATED_BY,
+                            project.getOrganization().getName()));
+            outManifest.addConfiguredAttribute(new 
Attribute(BuildConstants.ATTR_BUILT_BY,
+                            project.getOrganization().getName()));
+            outManifest.addConfiguredAttribute(new 
Attribute(BuildConstants.ATTR_IMPLEMENTATION_VENDOR_ID,
+                            project.getGroupId()));
+            outManifest.addConfiguredAttribute(new 
Attribute(BuildConstants.ATTR_IMPLEMENTATION_TITLE,
+                            project.getName()));
+            outManifest.addConfiguredAttribute(new 
Attribute(BuildConstants.ATTR_SPECIFICATION_TITLE,
+                            project.getName()));
+            outManifest.addConfiguredAttribute(new 
Attribute(BuildConstants.ATTR_SPECIFICATION_VENDOR,
+                            project.getOrganization().getName()));
+            outManifest.addConfiguredAttribute(new 
Attribute(BuildConstants.ATTR_SPECIFICATION_VERSION,
+                            project.getVersion()));
+
+            if ( archiver.getDestFile().getName().endsWith(".jar") && 
!hasMain) {
+                outManifest.addConfiguredAttribute(new 
Attribute(BuildConstants.ATTR_MAIN_CLASS,
+                                BuildConstants.ATTR_VALUE_MAIN_CLASS));
+            }
+
+            archiver.addConfiguredManifest(outManifest);
+        } catch (final ManifestException e) {
+            throw new MojoExecutionException("Unable to create manifest for " 
+ this.archiver.getDestFile(), e);
+        }
+    }
+
+    public void addDirectory(File directory, String prefix, String[] includes, 
String[] excludes)
+                    throws MojoExecutionException {
+        try {
+            archiver.addDirectory(directory, prefix, includes, excludes);
+        } catch (final ArchiverException ae) {
+            throw new MojoExecutionException("Unable to create archive for " + 
this.archiver.getDestFile(), ae);
+        }
+    }
+
+    public void addDirectory(File directory, String prefix) throws 
MojoExecutionException {
+        try {
+            archiver.addDirectory(directory, prefix);
+        } catch (final ArchiverException ae) {
+            throw new MojoExecutionException("Unable to create archive for " + 
this.archiver.getDestFile(), ae);
+        }
+    }
+
+    public void addDirectory(File directory, String[] includes, String[] 
excludes) throws MojoExecutionException {
+        try {
+            archiver.addDirectory(directory, includes, excludes);
+        } catch (final ArchiverException ae) {
+            throw new MojoExecutionException("Unable to create archive for " + 
this.archiver.getDestFile(), ae);
+        }
+    }
+
+    public void addDirectory(File directory) throws MojoExecutionException {
+        try {
+            archiver.addDirectory(directory);
+        } catch (final ArchiverException ae) {
+            throw new MojoExecutionException("Unable to create archive for " + 
this.archiver.getDestFile(), ae);
+        }
+    }
+
+    public void addFile(File arg0, String arg1, int arg2) throws 
MojoExecutionException {
+        try {
+            archiver.addFile(arg0, arg1, arg2);
+        } catch (final ArchiverException ae) {
+            throw new MojoExecutionException("Unable to create archive for " + 
this.archiver.getDestFile(), ae);
+        }
+    }
+
+    public void addFile(File inputFile, String destFileName) throws 
MojoExecutionException {
+        try {
+            archiver.addFile(inputFile, destFileName);
+        } catch (final ArchiverException ae) {
+            throw new MojoExecutionException("Unable to create archive for " + 
this.archiver.getDestFile(), ae);
+        }
+    }
+
+    public void createArchive() throws MojoExecutionException {
+        try {
+            archiver.createArchive();
+        } catch (final ArchiverException ae) {
+            throw new MojoExecutionException("Unable to create archive for " + 
this.archiver.getDestFile(), ae);
+        } catch (IOException e) {
+            throw new MojoExecutionException("Unable to create archive for " + 
this.archiver.getDestFile(), e);
+        }
+    }
+
+    public void addArtifacts(final Map<String, File> globalContentsMap, final 
String prefix)
+    throws MojoExecutionException {
+        for(final Map.Entry<String, File> entry : 
globalContentsMap.entrySet()) {
+            if ( entry.getValue().isFile() ) {
+                this.addFile(entry.getValue(), prefix + entry.getKey());
+            } else {
+                this.addDirectory(entry.getValue(), prefix);
+            }
+        }
+    }
+}
diff --git a/src/main/java/org/apache/sling/maven/slingstart/PackageMojo.java 
b/src/main/java/org/apache/sling/maven/slingstart/PackageMojo.java
new file mode 100644
index 0000000..0914d2a
--- /dev/null
+++ b/src/main/java/org/apache/sling/maven/slingstart/PackageMojo.java
@@ -0,0 +1,121 @@
+/*
+ * 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.slingstart;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Map;
+import java.util.jar.Manifest;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.codehaus.plexus.archiver.jar.JarArchiver;
+
+/**
+ * Initialize a Sling application project by extracting bundles into the 
correct
+ * locations.
+ */
+@Mojo(
+        name = "package",
+        defaultPhase = LifecyclePhase.PRE_INTEGRATION_TEST,
+        requiresDependencyResolution = ResolutionScope.TEST,
+        threadSafe = true
+    )
+public class PackageMojo extends AbstractSubsystemMojo {
+
+    private static final String[] EXCLUDES_MANIFEST = new String[] 
{"META-INF/MANIFEST.MF"};
+
+    /**
+     * The Jar archiver.
+     */
+    @Component(role = org.codehaus.plexus.archiver.Archiver.class, hint = 
"jar")
+    private JarArchiver jarArchiver;
+
+    @Override
+    public void execute() throws MojoExecutionException, MojoFailureException {
+
+        @SuppressWarnings("unchecked")
+        final Map<String, File> globalContentsMap = (Map<String, File>) 
this.project.getContextValue(BuildConstants.CONTEXT_GLOBAL);
+
+        this.packageStandaloneApp(globalContentsMap);
+        this.packageWebapp(globalContentsMap);
+    }
+
+    private void packageStandaloneApp(final Map<String, File> 
globalContentsMap) throws MojoExecutionException {
+        this.getLog().info("Packaging standalone jar...");
+
+        final File buildDirectory = new 
File(this.project.getBuild().getDirectory());
+        @SuppressWarnings("unchecked")
+        final Map<String, File> contentsMap = (Map<String, File>) 
this.project.getContextValue(BuildConstants.CONTEXT_STANDALONE);
+
+        final File buildOutputDirectory = new 
File(this.project.getBuild().getOutputDirectory());
+        final File manifestFile = new File(buildOutputDirectory, 
"META-INF/MANIFEST.MF");
+        FileInputStream fis = null;
+        try {
+            fis = new FileInputStream(manifestFile);
+            final Manifest mf = new Manifest(fis);
+
+            final File outputFile = new File(buildDirectory, 
this.project.getArtifactId() + "-" + this.project.getVersion() + ".jar");
+
+            final JarArchiverHelper helper = new 
JarArchiverHelper(jarArchiver, this.project, outputFile, mf);
+            helper.addDirectory(buildOutputDirectory, null, EXCLUDES_MANIFEST);
+
+            helper.addArtifacts(globalContentsMap, "");
+            helper.addArtifacts(contentsMap, "");
+
+            helper.createArchive();
+            if ( 
BuildConstants.PACKAGING_SLINGSTART.equals(project.getPackaging()) ) {
+                project.getArtifact().setFile(outputFile);
+            } else {
+                projectHelper.attachArtifact(project, BuildConstants.TYPE_JAR, 
BuildConstants.CLASSIFIER_APP, outputFile);
+            }
+        } catch ( final IOException ioe) {
+            throw new MojoExecutionException("Unable to create standalone 
jar", ioe);
+        } finally {
+            IOUtils.closeQuietly(fis);
+        }
+    }
+
+    private void packageWebapp(final Map<String, File> globalContentsMap) 
throws MojoExecutionException {
+        if ( this.createWebapp ) {
+            this.getLog().info("Packaging webapp...");
+
+            final File buildDirectory = new 
File(this.project.getBuild().getDirectory());
+            @SuppressWarnings("unchecked")
+            final Map<String, File> contentsMap = (Map<String, File>) 
this.project.getContextValue(BuildConstants.CONTEXT_WEBAPP);
+
+            final File buildOutputDirectory = new File(buildDirectory, 
BuildConstants.WEBAPP_OUTDIR);
+            final File outputFile = new File(buildDirectory, 
this.project.getArtifactId() + "-" + this.project.getVersion() + ".war");
+
+            final JarArchiverHelper helper = new 
JarArchiverHelper(this.jarArchiver, this.project, outputFile);
+            helper.addDirectory(buildOutputDirectory, null, EXCLUDES_MANIFEST);
+
+            helper.addArtifacts(globalContentsMap, "WEB-INF/");
+            helper.addArtifacts(contentsMap, "WEB-INF/");
+
+            helper.createArchive();
+
+            projectHelper.attachArtifact(project, BuildConstants.TYPE_WAR, 
BuildConstants.CLASSIFIER_WEBAPP, outputFile);
+        }
+    }
+}
diff --git 
a/src/main/java/org/apache/sling/maven/slingstart/PreparePackageMojo.java 
b/src/main/java/org/apache/sling/maven/slingstart/PreparePackageMojo.java
new file mode 100644
index 0000000..d595251
--- /dev/null
+++ b/src/main/java/org/apache/sling/maven/slingstart/PreparePackageMojo.java
@@ -0,0 +1,400 @@
+/*
+ * 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.slingstart;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.sling.slingstart.model.SSMArtifact;
+import org.apache.sling.slingstart.model.SSMConfiguration;
+import org.apache.sling.slingstart.model.SSMConstants;
+import org.apache.sling.slingstart.model.SSMRunMode;
+import org.apache.sling.slingstart.model.SSMStartLevel;
+import org.apache.sling.slingstart.model.SSMSubsystem;
+import org.codehaus.plexus.archiver.ArchiverException;
+import org.codehaus.plexus.archiver.UnArchiver;
+import org.codehaus.plexus.archiver.manager.ArchiverManager;
+import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
+import org.codehaus.plexus.util.FileUtils;
+
+/**
+ * Prepare the sling start applications.
+ */
+@Mojo(
+        name = "prepare-package",
+        defaultPhase = LifecyclePhase.PROCESS_SOURCES,
+        requiresDependencyResolution = ResolutionScope.TEST,
+        threadSafe = true
+    )
+public class PreparePackageMojo extends AbstractSubsystemMojo {
+
+    private static final String BASE_DESTINATION = "resources";
+
+    private static final String BOOT_DIRECTORY = "bundles";
+
+    private static final String ARTIFACTS_DIRECTORY = "install";
+
+    private static final String CONFIG_DIRECTORY = "config";
+
+    private static final String BOOTSTRAP_FILE = "sling_bootstrap.txt";
+
+    private static final String PROPERTIES_FILE = "sling_install.properties";
+
+    /**
+     * To look up Archiver/UnArchiver implementations
+     */
+    @Component
+    private ArchiverManager archiverManager;
+
+    @Override
+    public void execute() throws MojoExecutionException, MojoFailureException {
+        final SSMSubsystem model = this.readModel();
+
+        this.prepareGlobal(model);
+        this.prepareStandaloneApp(model);
+        this.prepareWebapp(model);
+    }
+
+    /**
+     * Prepare the global map for the artifacts.
+     */
+    private void prepareGlobal(final SSMSubsystem model) throws 
MojoExecutionException {
+        final Map<String, File> globalContentsMap = new HashMap<String, 
File>();
+        this.buildContentsMap(model, (String)null, globalContentsMap);
+
+        this.project.setContextValue(BuildConstants.CONTEXT_GLOBAL, 
globalContentsMap);
+    }
+
+    /**
+     * Prepare the standalone application.
+     */
+    private void prepareStandaloneApp(final SSMSubsystem model) throws 
MojoExecutionException {
+        final Map<String, File> contentsMap = new HashMap<String, File>();
+        this.project.setContextValue(BuildConstants.CONTEXT_STANDALONE, 
contentsMap);
+
+        // unpack base artifact and create settings
+        final File outputDir = new 
File(this.project.getBuild().getOutputDirectory());
+        unpackBaseArtifact(model, outputDir, SSMRunMode.RUN_MODE_STANDALONE);
+        this.buildSettings(model, SSMRunMode.RUN_MODE_STANDALONE, outputDir);
+        this.buildBootstrapFile(model, SSMRunMode.RUN_MODE_STANDALONE, 
outputDir);
+
+        this.buildContentsMap(model, SSMRunMode.RUN_MODE_STANDALONE, 
contentsMap);
+    }
+
+    /**
+     * Prepare the web application.
+     */
+    private void prepareWebapp(final SSMSubsystem model) throws 
MojoExecutionException {
+        if ( this.createWebapp ) {
+            final Map<String, File> contentsMap = new HashMap<String, File>();
+            this.project.setContextValue(BuildConstants.CONTEXT_WEBAPP, 
contentsMap);
+
+            // unpack base artifact and create settings
+            final File outputDir = new 
File(this.project.getBuild().getDirectory(), BuildConstants.WEBAPP_OUTDIR);
+            final File webappDir = new File(outputDir, "WEB-INF");
+            unpackBaseArtifact(model, outputDir, SSMRunMode.RUN_MODE_WEBAPP);
+
+            // check for web.xml
+            final SSMRunMode webappRM = 
model.getRunMode(SSMRunMode.RUN_MODE_WEBAPP);
+            if ( webappRM != null ) {
+                final SSMConfiguration webConfig = 
webappRM.getConfiguration(SSMConstants.CFG_WEB_XML);
+                if ( webConfig != null ) {
+                    final File webXML = new File(webappDir, "web.xml");
+                    try {
+                        FileUtils.fileWrite(webXML, webConfig.properties);
+                    } catch (final IOException e) {
+                        throw new MojoExecutionException("Unable to write 
configuration to " + webXML, e);
+                    }
+                }
+            }
+            this.buildSettings(model, SSMRunMode.RUN_MODE_WEBAPP, webappDir);
+            this.buildBootstrapFile(model, SSMRunMode.RUN_MODE_WEBAPP, 
outputDir);
+
+            this.buildContentsMap(model, SSMRunMode.RUN_MODE_WEBAPP, 
contentsMap);
+        }
+    }
+
+    /**
+     * Build a list of all artifacts.
+     */
+    private void buildContentsMap(final SSMSubsystem model, final String 
packageRunMode, final Map<String, File> contentsMap)
+    throws MojoExecutionException {
+        if ( packageRunMode == null ) {
+            // add base jar
+            final Artifact artifact = getBaseArtifact(model, null, 
BuildConstants.TYPE_JAR);
+            contentsMap.put(BASE_DESTINATION + "/"+ artifact.getArtifactId() + 
"." + artifact.getArtifactHandler().getExtension(), artifact.getFile());
+        }
+        for(final SSMRunMode runMode : model.runModes) {
+            if ( packageRunMode == null ) {
+                if ( runMode.isSpecial()
+                     && !runMode.isRunMode(SSMRunMode.RUN_MODE_BOOT)) {
+                    continue;
+                }
+                this.buildContentsMap(model, runMode, contentsMap);
+            } else {
+                if ( runMode.isRunMode(packageRunMode) ) {
+                    this.buildContentsMap(model, runMode, contentsMap);
+                }
+            }
+        }
+    }
+
+    /**
+     * Build a list of all artifacts from this run mode
+     */
+    private void buildContentsMap(final SSMSubsystem model, final SSMRunMode 
runMode, final Map<String, File> contentsMap)
+    throws MojoExecutionException{
+        for(final SSMStartLevel sl : runMode.startLevels) {
+            for(final SSMArtifact a : sl.artifacts) {
+                final Artifact artifact = 
SubsystemUtils.getArtifact(this.project, a.groupId, a.artifactId, 
model.getValue(a.version), a.type, a.classifier);
+                final File artifactFile = artifact.getFile();
+                contentsMap.put(getPathForArtifact(sl.level, 
artifactFile.getName(), runMode), artifactFile);
+            }
+        }
+
+        final File rootConfDir = new File(this.getTmpDir(), "global-config");
+        boolean hasConfig = false;
+        for(final SSMConfiguration config : runMode.configurations) {
+            // skip special configurations
+            if ( config.isSpecial() ) {
+                continue;
+            }
+            final String configPath = getPathForConfiguration(config, runMode);
+            final File configFile = new File(rootConfDir, configPath);
+            getLog().debug(String.format("Creating configuration at %s", 
configFile.getPath()));
+            configFile.getParentFile().mkdirs();
+            try {
+                FileUtils.fileWrite(configFile, config.properties);
+            } catch (final IOException e) {
+                throw new MojoExecutionException("Unable to write 
configuration to " + configFile, e);
+            }
+            hasConfig = true;
+        }
+        if ( hasConfig ) {
+            contentsMap.put(BASE_DESTINATION, rootConfDir);
+        }
+    }
+
+    /**
+     * Build the settings for the given packaging run mode
+     */
+    private void buildSettings(final SSMSubsystem model, final String 
packageRunMode, final File outputDir)
+    throws MojoExecutionException {
+        String settings = null;
+        final SSMRunMode baseRM = model.getRunMode(SSMRunMode.RUN_MODE_BASE);
+        if ( baseRM != null && baseRM.settings != null ) {
+            settings = baseRM.settings.properties + "\n";
+        } else {
+            settings = "";
+        }
+        final SSMRunMode bootRM = model.getRunMode(SSMRunMode.RUN_MODE_BOOT);
+        if ( bootRM != null && bootRM.settings != null ) {
+            settings = settings + bootRM.settings.properties + "\n";
+        }
+        final SSMRunMode packageRM = model.getRunMode(packageRunMode);
+        if ( packageRM != null && packageRM.settings != null ) {
+            settings = settings + packageRM.settings.properties;
+        }
+
+        if ( settings != null ) {
+            final File settingsFile = new File(outputDir, PROPERTIES_FILE);
+            getLog().debug(String.format("Creating settings at %s", 
settingsFile.getPath()));
+            try {
+                FileUtils.fileWrite(settingsFile, settings);
+            } catch ( final IOException ioe ) {
+                throw new MojoExecutionException("Unable to write properties 
file.", ioe);
+            }
+        }
+    }
+
+    /**
+     * Build the bootstrap file for the given packaging run mode
+     */
+    private void buildBootstrapFile(final SSMSubsystem model, final String 
packageRunMode, final File outputDir)
+    throws MojoExecutionException {
+        String bootstrapTxt = "";
+        final SSMRunMode baseRM = model.getRunMode(SSMRunMode.RUN_MODE_BASE);
+        if ( baseRM != null ) {
+            final SSMConfiguration c = 
baseRM.getConfiguration(SSMConstants.CFG_BOOTSTRAP);
+            if ( c != null ) {
+                bootstrapTxt = c.properties + "\n";
+            }
+        }
+        final SSMRunMode bootRM = model.getRunMode(SSMRunMode.RUN_MODE_BOOT);
+        if ( bootRM != null ) {
+            final SSMConfiguration c = 
bootRM.getConfiguration(SSMConstants.CFG_BOOTSTRAP);
+            if ( c != null ) {
+                bootstrapTxt = bootstrapTxt + c.properties;
+            }
+        }
+        final SSMRunMode packageRM = model.getRunMode(packageRunMode);
+        if ( packageRM != null ) {
+            final SSMConfiguration c = 
packageRM.getConfiguration(SSMConstants.CFG_BOOTSTRAP);
+            if ( c != null ) {
+                bootstrapTxt = bootstrapTxt + c.properties;
+            }
+        }
+
+        if ( bootstrapTxt != null ) {
+            final File file = new File(outputDir, BOOTSTRAP_FILE);
+            getLog().debug(String.format("Creating bootstrap file at %s", 
file.getPath()));
+            try {
+                FileUtils.fileWrite(file, bootstrapTxt);
+            } catch ( final IOException ioe ) {
+                throw new MojoExecutionException("Unable to write bootstrap 
file.", ioe);
+            }
+        }
+    }
+
+    /**
+     * Return the base artifact
+     */
+    private Artifact getBaseArtifact(final SSMSubsystem model, final String 
classifier, final String type) throws MojoExecutionException {
+        final SSMArtifact baseArtifact = SubsystemUtils.getBaseArtifact(model);
+
+        final Artifact a = SubsystemUtils.getArtifact(this.project, 
baseArtifact.groupId,
+                baseArtifact.artifactId,
+                model.getValue(baseArtifact.version),
+                type,
+                classifier);
+        if (a == null) {
+            throw new MojoExecutionException(
+                    String.format("Project doesn't have a base dependency of 
groupId %s and artifactId %s",
+                            baseArtifact.groupId, baseArtifact.artifactId));
+        }
+        return a;
+    }
+
+    /**
+     * Unpack the base artifact
+     */
+    private void unpackBaseArtifact(final SSMSubsystem model, final File 
outputDirectory, final String packageRunMode)
+     throws MojoExecutionException {
+        final String classifier;
+        final String type;
+        if ( SSMRunMode.RUN_MODE_STANDALONE.equals(packageRunMode) ) {
+            classifier = BuildConstants.CLASSIFIER_APP;
+            type = BuildConstants.TYPE_JAR;
+        } else {
+            classifier = BuildConstants.CLASSIFIER_WEBAPP;
+            type = BuildConstants.TYPE_WAR;
+        }
+        final Artifact artifact = this.getBaseArtifact(model, classifier, 
type);
+        unpack(artifact.getFile(), outputDirectory);
+    }
+
+    /**
+     * Unpack a file
+     */
+    private void unpack(final File source, final File destination)
+    throws MojoExecutionException {
+        getLog().debug("Unpacking " + source.getPath() + " to\n  " + 
destination.getPath());
+        try {
+            destination.mkdirs();
+
+            final UnArchiver unArchiver = 
archiverManager.getUnArchiver(source);
+
+            unArchiver.setSourceFile(source);
+            unArchiver.setDestDirectory(destination);
+
+            unArchiver.extract();
+        } catch (final NoSuchArchiverException e) {
+            throw new MojoExecutionException("Unable to find archiver for " + 
source.getPath(), e);
+        } catch (final ArchiverException e) {
+            throw new MojoExecutionException("Unable to unpack " + 
source.getPath(), e);
+        }
+    }
+
+    /**
+     * Get the relative path for an artifact.
+     */
+    private String getPathForArtifact(final int startLevel, final String 
artifactName, final SSMRunMode rm) {
+        final Set<String> runModesList = new TreeSet<String>();
+        if (rm.runModes != null ) {
+            for(final String mode : rm.runModes) {
+                runModesList.add(mode);
+            }
+        }
+        final String runModeExt;
+        if ( runModesList.size() == 0 || rm.isSpecial() ) {
+            runModeExt = "";
+        } else {
+            final StringBuilder sb = new StringBuilder();
+            for(final String n : runModesList ) {
+                sb.append('.');
+                sb.append(n);
+            }
+            runModeExt = sb.toString();
+        }
+
+        if ( rm.isRunMode(SSMRunMode.RUN_MODE_BOOT) ) {
+            return String.format("%s/%s/1/%s", BASE_DESTINATION, 
BOOT_DIRECTORY,
+                    artifactName);
+        }
+        return String.format("%s/%s%s/%s/%s", BASE_DESTINATION, 
ARTIFACTS_DIRECTORY,
+                runModeExt,
+                (startLevel == -1 ? 1 : startLevel),
+                artifactName);
+    }
+
+    /**
+     * Get the relative path for a configuration
+     */
+    private String getPathForConfiguration(final SSMConfiguration config, 
final SSMRunMode rm) {
+        final Set<String> runModesList = new TreeSet<String>();
+        if (rm.runModes != null ) {
+            for(final String mode : rm.runModes) {
+                runModesList.add(mode);
+            }
+        }
+        final String runModeExt;
+        if ( runModesList.size() == 0 || rm.isSpecial() ) {
+            runModeExt = "";
+        } else {
+            final StringBuilder sb = new StringBuilder();
+            boolean first = true;
+            for(final String n : runModesList ) {
+                if ( first ) {
+                    sb.append('/');
+                    first = false;
+                } else {
+                    sb.append('.');
+                }
+                sb.append(n);
+            }
+            runModeExt = sb.toString();
+        }
+
+        final String mainName = (config.factoryPid != null ? config.factoryPid 
: config.pid);
+        final String alias = (config.factoryPid != null ? "-" + config.pid : 
"");
+        return String.format("%s/%s%s/%s%s.cfg", BASE_DESTINATION, 
CONFIG_DIRECTORY,
+                runModeExt,
+                mainName,
+                alias);
+    }
+}
diff --git 
a/src/main/java/org/apache/sling/maven/slingstart/SubsystemUtils.java 
b/src/main/java/org/apache/sling/maven/slingstart/SubsystemUtils.java
new file mode 100644
index 0000000..d0c36ac
--- /dev/null
+++ b/src/main/java/org/apache/sling/maven/slingstart/SubsystemUtils.java
@@ -0,0 +1,179 @@
+/*
+ * 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.slingstart;
+
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.apache.sling.slingstart.model.SSMArtifact;
+import org.apache.sling.slingstart.model.SSMRunMode;
+import org.apache.sling.slingstart.model.SSMSubsystem;
+import org.apache.sling.slingstart.model.xml.XMLSSMModelReader;
+import org.codehaus.plexus.logging.Logger;
+
+public abstract class SubsystemUtils {
+
+    /**
+     * Read all model files from the directory in alphabetical order
+     * @param logger
+     */
+    private static SSMSubsystem readLocalModel(final File systemsDirectory, 
final MavenProject project, final MavenSession session, final Logger logger)
+    throws MojoExecutionException {
+        final SSMSubsystem result = new SSMSubsystem();
+        final List<String> candidates = new ArrayList<String>();
+        if ( systemsDirectory != null && systemsDirectory.exists() ) {
+            for(final File f : systemsDirectory.listFiles() ) {
+                if ( f.isFile() && f.getName().endsWith(".xml") && 
!f.getName().startsWith(".") ) {
+                    candidates.add(f.getName());
+                }
+            }
+            Collections.sort(candidates);
+        }
+        if ( candidates.size() == 0 ) {
+            throw new MojoExecutionException("No model files found in " + 
systemsDirectory);
+        }
+        for(final String name : candidates) {
+            logger.debug("Reading model " + name + " in project " + 
project.getId());
+            try {
+                final FileReader reader = new FileReader(new 
File(systemsDirectory, name));
+                try {
+                    final SSMSubsystem current = 
XMLSSMModelReader.read(reader);
+                    try {
+                        current.validate();
+                    } catch ( final IllegalStateException ise) {
+                        throw new MojoExecutionException("Invalid model at " + 
name, ise);
+                    }
+                    result.merge(current);
+                } finally {
+                    IOUtils.closeQuietly(reader);
+                }
+            } catch ( final IOException io) {
+                throw new MojoExecutionException("Unable to read " + name, io);
+            }
+        }
+
+        try {
+            result.validate();
+        } catch ( final IllegalStateException ise) {
+            throw new MojoExecutionException("Invalid assembled model", ise);
+        }
+
+        return result;
+    }
+
+    /**
+     * Read the full model
+     */
+    public static SSMSubsystem readFullModel(final File systemsDirectory,
+            final List<File> dependentModels,
+            final MavenProject project,
+            final MavenSession session,
+            final Logger logger)
+    throws MojoExecutionException {
+        try {
+            final SSMSubsystem localModel = readLocalModel(systemsDirectory, 
project, session, logger);
+
+            // check dependent models
+            SSMSubsystem depModel = null;
+            for(final File file : dependentModels) {
+                FileReader r = null;
+                try {
+                    r = new FileReader(file);
+                    if ( depModel == null ) {
+                        depModel = new SSMSubsystem();
+                    }
+                    final SSMSubsystem readModel = XMLSSMModelReader.read(r);
+                    try {
+                        readModel.validate();
+                    } catch ( final IllegalStateException ise) {
+                        throw new MojoExecutionException("Invalid model " + 
file, ise);
+                    }
+                    depModel.merge(readModel);
+                } finally {
+                    IOUtils.closeQuietly(r);
+                }
+            }
+            final SSMSubsystem result;
+            if ( depModel != null ) {
+                try {
+                    depModel.validate();
+                    depModel.merge(localModel);
+                    depModel.validate();
+                } catch ( final IllegalStateException ise) {
+                    throw new MojoExecutionException("Invalid model.", ise);
+                }
+                result = depModel;
+            } else {
+                result = localModel;
+            }
+            return result;
+        } catch ( final IOException ioe) {
+            throw new MojoExecutionException("Unable to cache model", ioe);
+        }
+    }
+
+    public static SSMArtifact getBaseArtifact(final SSMSubsystem model) throws 
MojoExecutionException {
+        // get base run mode
+        final SSMRunMode base = model.getRunMode(SSMRunMode.RUN_MODE_BASE);
+        if ( base == null ) {
+            throw new MojoExecutionException("No base run mode found.");
+        }
+        if ( base.startLevels.size() == 0 ) {
+            throw new MojoExecutionException("No base artifacts defined.");
+        }
+        if ( base.startLevels.size() > 1 ) {
+            throw new MojoExecutionException("Base run mode should only have a 
single start level.");
+        }
+        if ( base.startLevels.get(0).artifacts.size() != 1 ) {
+            throw new MojoExecutionException("Base run mode should contain 
exactly one artifact.");
+        }
+
+        return base.startLevels.get(0).artifacts.get(0);
+    }
+
+    /**
+     * Get a resolved Artifact from the coordinates provided
+     *
+     * @return the artifact, which has been resolved.
+     * @throws MojoExecutionException
+     */
+    public static Artifact getArtifact(final MavenProject project,
+            final String groupId, final String artifactId, final String 
version, final String type, final String classifier)
+    throws MojoExecutionException {
+        final Set<Artifact> artifacts = project.getDependencyArtifacts();
+        for(final Artifact artifact : artifacts) {
+            if ( artifact.getGroupId().equals(groupId)
+               && artifact.getArtifactId().equals(artifactId)
+               && artifact.getVersion().equals(version)
+               && artifact.getType().equals(type)
+               && ((classifier == null && artifact.getClassifier() == null) || 
(classifier != null && classifier.equals(artifact.getClassifier()))) ) {
+                return artifact;
+            }
+        }
+        return null;
+    }
+}
diff --git a/src/main/resources/META-INF/plexus/components.xml 
b/src/main/resources/META-INF/plexus/components.xml
new file mode 100644
index 0000000..8896896
--- /dev/null
+++ b/src/main/resources/META-INF/plexus/components.xml
@@ -0,0 +1,95 @@
+<!--
+ 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.
+-->
+<component-set>
+  <components>
+    <component>
+      <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
+      <role-hint>slingsubsystem</role-hint>
+      
<implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
+      <configuration>
+        <lifecycles>
+          <lifecycle>
+            <id>default</id>
+            <!-- START SNIPPET: bundle-lifecycle -->
+            <phases>
+              
<package>org.apache.sling:slingstart-maven-plugin:attach-slingsubsystem</package>
+              
<install>org.apache.maven.plugins:maven-install-plugin:install</install>
+              
<deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</deploy>
+            </phases>
+            <!-- END SNIPPET: bundle-lifecycle -->
+          </lifecycle>
+        </lifecycles>
+      </configuration>
+    </component>
+    <component>
+      <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>
+      <role-hint>slingstart</role-hint>
+      
<implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>
+      <configuration>
+        <lifecycles>
+          <lifecycle>
+            <id>default</id>
+            <!-- START SNIPPET: bundle-lifecycle -->
+            <phases>
+              
<process-sources>org.apache.sling:slingstart-maven-plugin:prepare-package</process-sources>
+              
<process-resources>org.apache.maven.plugins:maven-resources-plugin:resources</process-resources>
+              
<compile>org.apache.maven.plugins:maven-compiler-plugin:compile</compile>
+              <process-test-resources>
+                  
org.apache.maven.plugins:maven-resources-plugin:testResources,
+              </process-test-resources>
+              
<test-compile>org.apache.maven.plugins:maven-compiler-plugin:testCompile</test-compile>
+              <test>org.apache.maven.plugins:maven-surefire-plugin:test</test>
+              <package>
+                  
org.apache.sling:slingstart-maven-plugin:attach-slingsubsystem,
+                  org.apache.sling:slingstart-maven-plugin:package
+              </package>
+              
<install>org.apache.maven.plugins:maven-install-plugin:install</install>
+              
<deploy>org.apache.maven.plugins:maven-deploy-plugin:deploy</deploy>
+            </phases>
+            <!-- END SNIPPET: bundle-lifecycle -->
+          </lifecycle>
+        </lifecycles>
+      </configuration>
+    </component>
+    <component>
+      <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
+      <role-hint>slingsubsystem</role-hint>
+      
<implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
+      <configuration>
+        <type>slingsubsystem</type>
+        <includesDependencies>false</includesDependencies>
+        <language>xml</language>
+        <extension>xml</extension>
+        <addedToClasspath>false</addedToClasspath>
+      </configuration>
+    </component>
+    <component>
+      <role>org.apache.maven.artifact.handler.ArtifactHandler</role>
+      <role-hint>slingstart</role-hint>
+      
<implementation>org.apache.maven.artifact.handler.DefaultArtifactHandler</implementation>
+      <configuration>
+        <type>slingstart</type>
+        <includesDependencies>true</includesDependencies>
+        <language>java</language>
+        <extension>jar</extension>
+        <addedToClasspath>false</addedToClasspath>
+      </configuration>
+    </component>
+  </components>
+</component-set>

-- 
To stop receiving notification emails like this one, please contact
"[email protected]" <[email protected]>.

Reply via email to