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

rombert pushed a commit to branch master
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-installer-factory-model.git

commit 140e18def3257952ab11dd90dcfa1b3190cb9793
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Fri Nov 11 06:09:36 2016 +0000

    Add prototype of a installer support for provisioning models
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1769248 
13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            | 109 +++++++++
 .../factory/model/impl/AbstractModelTask.java      |  81 +++++++
 .../factory/model/impl/InstallModelTask.java       | 253 +++++++++++++++++++++
 .../factory/model/impl/ModelTaskFactory.java       |  86 +++++++
 .../factory/model/impl/ModelTransformer.java       | 131 +++++++++++
 .../factory/model/impl/RepositoryAccess.java       | 145 ++++++++++++
 .../factory/model/impl/UninstallModelTask.java     |  56 +++++
 7 files changed, 861 insertions(+)

diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..87fae4a
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>sling</artifactId>
+        <version>29</version>
+        <relativePath/>
+    </parent>
+
+    <artifactId>org.apache.sling.installer.factory.model</artifactId>
+    <version>0.1.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <name>Apache Sling Installer Provisioning Model Support</name>
+    <description> 
+        Provides support for the provisioning model to the Apache Sling OSGi 
installer
+    </description>
+
+    <properties>
+        <sling.java.version>8</sling.java.version>
+    </properties>
+
+    <scm>
+        
<connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/installer/factories/model</connection>
+        <developerConnection> 
scm:svn:https://svn.apache.org/repos/asf/sling/trunk/installer/factories/model</developerConnection>
+        
<url>http://svn.apache.org/viewvc/sling/trunk/installer/factories/model</url>
+    </scm>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.jcr</groupId>
+            <artifactId>jcr</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.installer.core</artifactId>
+            <version>3.8.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.jcr.api</artifactId>
+            <version>2.4.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.jcr.repoinit</artifactId>
+            <version>1.1.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.repoinit.parser</artifactId>
+            <version>1.1.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.settings</artifactId>
+            <version>1.2.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.provisioning.model</artifactId>
+            <version>1.7.0</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git 
a/src/main/java/org/apache/sling/installer/factory/model/impl/AbstractModelTask.java
 
b/src/main/java/org/apache/sling/installer/factory/model/impl/AbstractModelTask.java
new file mode 100644
index 0000000..7fe3151
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/installer/factory/model/impl/AbstractModelTask.java
@@ -0,0 +1,81 @@
+/*
+ * 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.installer.factory.model.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.installer.api.tasks.InstallTask;
+import org.apache.sling.installer.api.tasks.TaskResourceGroup;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract class for the tasks.
+ */
+public abstract class AbstractModelTask extends InstallTask {
+
+    /** Logger. */
+    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    private final BundleContext bundleContext;
+
+    private final Map<ServiceReference<?>, Object> services = new HashMap<>();
+
+    public AbstractModelTask(final TaskResourceGroup group,
+            final BundleContext bundleContext) {
+        super(group);
+        this.bundleContext = bundleContext;
+    }
+
+    protected void cleanup() {
+        for(final ServiceReference<?> r : this.services.keySet()) {
+            this.bundleContext.ungetService(r);
+        }
+        this.services.clear();
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <T> T getService(final Class<T> type) {
+        T service = null;
+        final ServiceReference<T> reference = 
this.bundleContext.getServiceReference(type);
+        if ( reference != null ) {
+            service = (T)this.services.get(reference);
+            if ( service == null ) {
+                service = this.bundleContext.getService(reference);
+                if ( service != null ) {
+                    this.services.put(reference, service);
+                } else {
+                }
+            }
+        }
+        if ( service == null ) {
+            logger.error("Unable to get OSGi service " + type.getName());
+        }
+        return service;
+    }
+
+    protected String getModelName() {
+        final String url = this.getResource().getURL();
+        final int lastSlash = url.lastIndexOf('/');
+        return lastSlash == -1 ? url : url.substring(lastSlash + 1);
+    }
+}
diff --git 
a/src/main/java/org/apache/sling/installer/factory/model/impl/InstallModelTask.java
 
b/src/main/java/org/apache/sling/installer/factory/model/impl/InstallModelTask.java
new file mode 100644
index 0000000..0cf2fac
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/installer/factory/model/impl/InstallModelTask.java
@@ -0,0 +1,253 @@
+/*
+ * 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.installer.factory.model.impl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.sling.installer.api.InstallableResource;
+import org.apache.sling.installer.api.OsgiInstaller;
+import org.apache.sling.installer.api.tasks.InstallationContext;
+import org.apache.sling.installer.api.tasks.ResourceState;
+import org.apache.sling.installer.api.tasks.TaskResource;
+import org.apache.sling.installer.api.tasks.TaskResourceGroup;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.jcr.repoinit.JcrRepoInitOpsProcessor;
+import org.apache.sling.provisioning.model.Artifact;
+import org.apache.sling.provisioning.model.ArtifactGroup;
+import org.apache.sling.provisioning.model.Configuration;
+import org.apache.sling.provisioning.model.Feature;
+import org.apache.sling.provisioning.model.Model;
+import org.apache.sling.provisioning.model.ModelUtility;
+import org.apache.sling.provisioning.model.RunMode;
+import org.apache.sling.provisioning.model.Section;
+import org.apache.sling.provisioning.model.Traceable;
+import org.apache.sling.provisioning.model.io.ModelReader;
+import org.apache.sling.repoinit.parser.RepoInitParser;
+import org.apache.sling.repoinit.parser.RepoInitParsingException;
+import org.apache.sling.repoinit.parser.operations.Operation;
+import org.osgi.framework.BundleContext;
+
+/**
+ * This task installs model resources.
+ */
+public class InstallModelTask extends AbstractModelTask {
+
+    private final Set<String> activeRunModes;
+
+    private final SlingRepository repository;
+
+    private final JcrRepoInitOpsProcessor repoInitProcessor;
+
+    private final RepoInitParser repoInitParser;
+
+    public InstallModelTask(final TaskResourceGroup group,
+            final Set<String> runModes,
+            final SlingRepository repository,
+            final JcrRepoInitOpsProcessor repoInitProcessor,
+            final RepoInitParser repoInitParser,
+            final BundleContext bundleContext) {
+        super(group, bundleContext);
+        this.activeRunModes = runModes;
+        this.repository = repository;
+        this.repoInitProcessor = repoInitProcessor;
+        this.repoInitParser = repoInitParser;
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public void execute(final InstallationContext ctx) {
+        try {
+            final TaskResource resource = this.getResource();
+            final String modelTxt = (String) 
resource.getAttribute(ModelTransformer.ATTR_MODEL);
+            if ( modelTxt == null ) {
+                ctx.log("Unable to install model resource {} : no model 
found", this.getResource());
+                this.getResourceGroup().setFinishState(ResourceState.IGNORED);
+            } else {
+                final String name = this.getModelName();
+                final Result result = this.transform(name, modelTxt);
+                if ( result == null ) {
+                    ctx.log("Unable to install model resource {} : unable to 
create resources", this.getResource());
+                    
this.getResourceGroup().setFinishState(ResourceState.IGNORED);
+                } else {
+                    // repo init first
+                    if ( result.repoinit != null ) {
+                        List<Operation> ops = null;
+                        try ( final Reader r = new 
StringReader(result.repoinit) ) {
+                            ops = this.repoInitParser.parse(r);
+                        } catch (final IOException | RepoInitParsingException 
e) {
+                            logger.error("Unable to parse repoinit block.", e);
+                            ctx.log("Unable to install model resource {} : 
unable parse repoinit block.", this.getResource());
+                            
this.getResourceGroup().setFinishState(ResourceState.IGNORED);
+                            return;
+                        }
+
+                        // login admin is required for repo init
+                        Session session = null;
+                        try {
+                            session = 
this.repository.loginAdministrative(null);
+                            this.repoInitProcessor.apply(session, ops);
+                            session.save();
+                        } catch ( final RepositoryException re) {
+                            logger.error("Unable to process repoinit block.", 
re);
+                            ctx.log("Unable to install model resource {} : 
unable to process repoinit block.", this.getResource());
+                            
this.getResourceGroup().setFinishState(ResourceState.IGNORED);
+                            return;
+
+                        } finally {
+                            if ( session != null ) {
+                                session.logout();
+                            }
+                        }
+                    }
+                    if ( !result.resources.isEmpty() ) {
+                        final OsgiInstaller installer = 
this.getService(OsgiInstaller.class);
+                        if ( installer != null ) {
+                            installer.registerResources("model-" + name, 
result.resources.toArray(new InstallableResource[result.resources.size()]));
+                            
this.getResourceGroup().setFinishState(ResourceState.INSTALLED);
+                        } else {
+                            ctx.log("Unable to install model resource {} : 
unable to get OSGi installer", this.getResource());
+                            
this.getResourceGroup().setFinishState(ResourceState.IGNORED);
+                        }
+                    }
+                }
+            }
+        } finally {
+            this.cleanup();
+        }
+    }
+
+    public static final class Result {
+        public final List<InstallableResource> resources = new ArrayList<>();
+        public String repoinit;
+    }
+
+    private Result transform(final String name, final String modelText) {
+        try ( final Reader reader = new StringReader(modelText)) {
+            final Model model = 
ModelUtility.getEffectiveModel(ModelReader.read(reader, name));
+
+            final List<ArtifactDescription> files = new ArrayList<>();
+
+            Map<Traceable, String> errors = collectArtifacts(model, files);
+            if ( errors == null ) {
+                final Result result = new Result();
+                for(final ArtifactDescription desc : files) {
+                    if ( desc.artifactFile != null ) {
+                        final InputStream is = new 
FileInputStream(desc.artifactFile);
+                        final String digest = 
String.valueOf(desc.artifactFile.lastModified());
+                        // handle start level
+                        final Dictionary<String, Object> dict = new 
Hashtable<String, Object>();
+                        if ( desc.startLevel > 0 ) {
+                            dict.put(InstallableResource.BUNDLE_START_LEVEL, 
desc.startLevel);
+                        }
+                        dict.put(InstallableResource.RESOURCE_URI_HINT, 
desc.artifactFile.toURI().toString());
+
+                        result.resources.add(new InstallableResource("/" + 
desc.artifactFile.getName(), is, dict, digest,
+                                                              
InstallableResource.TYPE_FILE, null));
+                    } else if ( desc.cfg != null ) {
+                        final String id = (desc.cfg.getFactoryPid() != null ? 
desc.cfg.getFactoryPid() + "-" + desc.cfg.getPid() : desc.cfg.getPid());
+                        result.resources.add(new InstallableResource("/" + id 
+ ".config",
+                                null,
+                                desc.cfg.getProperties(),
+                                null,
+                                InstallableResource.TYPE_CONFIG, null));
+
+                    } else if ( desc.section != null ) {
+                        result.repoinit = desc.section.getContents();
+                    }
+                }
+                return result;
+            }
+            logger.warn("Errors during parsing model file {} : {}", name, 
errors.values());
+        } catch ( final IOException ioe) {
+            logger.warn("Unable to read potential model file " + name, ioe);
+        }
+        return null;
+    }
+
+    private static class ArtifactDescription {
+        public int startLevel;
+        public File artifactFile;
+        public Configuration cfg;
+        public Section section;
+    }
+
+    private Map<Traceable, String> collectArtifacts(final Model 
effectiveModel, final List<ArtifactDescription> files) {
+        final RepositoryAccess repo = new RepositoryAccess();
+        final Map<Traceable, String> errors = new HashMap<>();
+        for(final Feature f : effectiveModel.getFeatures()) {
+            if ( f.isSpecial() ) {
+                continue;
+            }
+            for(final Section section : f.getAdditionalSections()) {
+                final ArtifactDescription desc = new ArtifactDescription();
+                desc.section = section;
+                files.add(desc);
+            }
+            for(final RunMode mode : f.getRunModes()) {
+                if ( mode.isSpecial() ) {
+                    continue;
+                }
+                if ( mode.isActive(this.activeRunModes) ) {
+                    for(final ArtifactGroup group : mode.getArtifactGroups()) {
+                        for(final Artifact artifact : group) {
+                            final File file = repo.get(artifact);
+                            if ( file == null ) {
+                                errors.put(artifact, "Artifact " + 
artifact.toMvnUrl() + " not found.");
+                            } else {
+                                final ArtifactDescription desc = new 
ArtifactDescription();
+                                desc.artifactFile = file;
+                                desc.startLevel = group.getStartLevel();
+                                files.add(desc);
+                            }
+                        }
+                    }
+                    for(final Configuration cfg : mode.getConfigurations() ) {
+                        if ( cfg.isSpecial() ) {
+                            continue;
+                        }
+                        final ArtifactDescription desc = new 
ArtifactDescription();
+                        desc.cfg = cfg;
+                        files.add(desc);
+                    }
+                }
+            }
+        }
+        return errors.isEmpty() ? null : errors;
+    }
+
+    @Override
+    public String getSortKey() {
+        return "30-" + getModelName();
+    }
+}
diff --git 
a/src/main/java/org/apache/sling/installer/factory/model/impl/ModelTaskFactory.java
 
b/src/main/java/org/apache/sling/installer/factory/model/impl/ModelTaskFactory.java
new file mode 100644
index 0000000..dfff035
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/installer/factory/model/impl/ModelTaskFactory.java
@@ -0,0 +1,86 @@
+/*
+ * 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.installer.factory.model.impl;
+
+
+import org.apache.sling.installer.api.tasks.InstallTask;
+import org.apache.sling.installer.api.tasks.InstallTaskFactory;
+import org.apache.sling.installer.api.tasks.ResourceState;
+import org.apache.sling.installer.api.tasks.TaskResource;
+import org.apache.sling.installer.api.tasks.TaskResourceGroup;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.jcr.repoinit.JcrRepoInitOpsProcessor;
+import org.apache.sling.repoinit.parser.RepoInitParser;
+import org.apache.sling.settings.SlingSettingsService;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This task factory process model resources detected by
+ * the {@link ModelTransformer}.
+ */
+@Component(service = InstallTaskFactory.class)
+public class ModelTaskFactory implements InstallTaskFactory {
+
+    /** Logger. */
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    @Reference
+    private SlingSettingsService settings;
+
+    @Reference
+    private SlingRepository repository;
+
+    @Reference
+    private JcrRepoInitOpsProcessor repoInitProcessor;
+
+    @Reference
+    private RepoInitParser repoInitParser;
+
+    private BundleContext bundleContext;
+
+    @Activate
+    private void activate(final BundleContext ctx) {
+        this.bundleContext = ctx;
+    }
+
+    @Override
+    public InstallTask createTask(final TaskResourceGroup group) {
+        final TaskResource rsrc = group.getActiveResource();
+        if ( !ModelTransformer.TYPE_PROV_MODEL.equals(rsrc.getType()) ) {
+            return null;
+        }
+        if (rsrc.getState() == ResourceState.UNINSTALL ) {
+            logger.info("Uninstalling {}", rsrc.getEntityId());
+
+            return new UninstallModelTask(group, bundleContext);
+        }
+        logger.info("Installing {}", rsrc.getEntityId());
+        return new InstallModelTask(group,
+                this.settings.getRunModes(),
+                this.repository,
+                this.repoInitProcessor,
+                this.repoInitParser,
+                this.bundleContext);
+    }
+}
diff --git 
a/src/main/java/org/apache/sling/installer/factory/model/impl/ModelTransformer.java
 
b/src/main/java/org/apache/sling/installer/factory/model/impl/ModelTransformer.java
new file mode 100644
index 0000000..a2c9fa2
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/installer/factory/model/impl/ModelTransformer.java
@@ -0,0 +1,131 @@
+package org.apache.sling.installer.factory.model.impl;/*
+ * 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.
+ */
+
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.util.Collections;
+import java.util.Map;
+
+import org.apache.sling.installer.api.InstallableResource;
+import org.apache.sling.installer.api.tasks.RegisteredResource;
+import org.apache.sling.installer.api.tasks.ResourceTransformer;
+import org.apache.sling.installer.api.tasks.TransformationResult;
+import org.apache.sling.provisioning.model.Configuration;
+import org.apache.sling.provisioning.model.Feature;
+import org.apache.sling.provisioning.model.Model;
+import org.apache.sling.provisioning.model.ModelUtility;
+import org.apache.sling.provisioning.model.RunMode;
+import org.apache.sling.provisioning.model.Section;
+import org.apache.sling.provisioning.model.Traceable;
+import org.apache.sling.provisioning.model.io.ModelReader;
+import org.apache.sling.provisioning.model.io.ModelWriter;
+import org.osgi.framework.Version;
+import org.osgi.service.component.annotations.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This transformer detects a file with the ending ".model" containing
+ * a provisioning model.
+ */
+@Component(service = ResourceTransformer.class)
+public class ModelTransformer implements ResourceTransformer {
+
+    public static final String TYPE_PROV_MODEL = "provisioningmodel";
+
+    public static final String ATTR_MODEL = "model";
+
+    /** Logger. */
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    @Override
+    public TransformationResult[] transform(final RegisteredResource resource) 
{
+        if ( resource.getType().equals(InstallableResource.TYPE_FILE) && 
resource.getURL().endsWith(".model") ) {
+            try ( final Reader reader = new 
InputStreamReader(resource.getInputStream(), "UTF-8") ) {
+                final Model model = ModelReader.read(reader, 
resource.getURL());
+
+                Map<Traceable, String> errors = ModelUtility.validate(model);
+                if ( errors == null ) {
+                    try {
+                        final Model effectiveModel = 
ModelUtility.getEffectiveModel(model);
+
+                        errors = validate(effectiveModel);
+                        if ( errors == null ) {
+
+                            final Feature f = 
effectiveModel.getFeatures().get(0);
+                            final TransformationResult tr = new 
TransformationResult();
+                            tr.setId(f.getName());
+                            tr.setResourceType(TYPE_PROV_MODEL);
+                            tr.setVersion(new Version(f.getVersion()));
+
+                            try ( final StringWriter sw = new StringWriter()) {
+                                ModelWriter.write(sw, effectiveModel);
+                                
tr.setAttributes(Collections.singletonMap(ATTR_MODEL, (Object)sw.toString()));
+                            }
+                            return new TransformationResult[] {tr};
+                        }
+                    } catch ( final IllegalArgumentException iae ) {
+                        errors = Collections.singletonMap((Traceable)model, 
iae.getMessage());
+                    }
+                }
+                if ( errors != null ) {
+                    logger.warn("Errors during parsing model at {} : {}", 
resource.getURL(), errors.values());
+                }
+
+            } catch ( final IOException ioe) {
+                logger.info("Unable to read model from " + resource.getURL(), 
ioe);
+            }
+        }
+        return null;
+    }
+
+    private Map<Traceable, String> validate(final Model effectiveModel) {
+        if ( effectiveModel.getFeatures().size() != 1 ) {
+            return Collections.singletonMap((Traceable)effectiveModel, "Model 
should only contain a single feature.");
+        }
+        final Feature feature = effectiveModel.getFeatures().get(0);
+        if ( feature.isSpecial() ) {
+            return Collections.singletonMap((Traceable)feature, "Feature must 
not be special.");
+        }
+        if ( feature.getVersion() == null ) {
+            return Collections.singletonMap((Traceable)feature, "Feature must 
have a version.");
+        }
+        for(final Section section : feature.getAdditionalSections()) {
+            if ( !"repoinit".equals(section.getName()) ) {
+                return Collections.singletonMap((Traceable)section, 
"Additional section not supported.");
+            }
+        }
+        for(final RunMode mode : feature.getRunModes()) {
+            if ( mode.isSpecial() ) {
+                return Collections.singletonMap((Traceable)mode, "RunMode must 
not be special.");
+            }
+            for(final Configuration cfg : mode.getConfigurations()) {
+                if ( cfg.isSpecial() ) {
+                    return Collections.singletonMap((Traceable)cfg, 
"Configuration must not be special.");
+                }
+            }
+        }
+
+        return null;
+    }
+
+}
diff --git 
a/src/main/java/org/apache/sling/installer/factory/model/impl/RepositoryAccess.java
 
b/src/main/java/org/apache/sling/installer/factory/model/impl/RepositoryAccess.java
new file mode 100644
index 0000000..68792cf
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/installer/factory/model/impl/RepositoryAccess.java
@@ -0,0 +1,145 @@
+/*
+ * 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.installer.factory.model.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.ProcessBuilder.Redirect;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.sling.provisioning.model.Artifact;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Helper class for getting maven artifacts.
+ *
+ * It is a simple class assuming that the mvn command is installed
+ * and that the .m2 directory is in the home directory of the current
+ * user.
+ */
+public class RepositoryAccess {
+
+    /**
+     * A logger.
+     */
+    private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    /**
+     * The .m2 directory.
+     */
+    private final String repoHome;
+
+    /**
+     * Create a new instance.
+     */
+    public RepositoryAccess() {
+        this.repoHome = System.getProperty("user.home") + "/.m2/repository/";
+    }
+
+    /**
+     * Get the file for an artifact
+     * @param artifact The artifact
+     * @return The file or {@code null}
+     */
+    public File get(final Artifact artifact) {
+
+        final File artifactFile = this.getArtifact(artifact);
+
+        if ( artifactFile == null ) {
+            return null;
+        }
+        logger.info("Responding for {} with {}", artifact, artifactFile);
+        return artifactFile;
+    }
+
+    private File getArtifact(final Artifact artifact) {
+        logger.info("Requesting {}", artifact);
+
+        final String filePath = 
(this.repoHome.concat(artifact.getRepositoryPath())).replace('/', 
File.separatorChar);
+        logger.info("Trying to fetch artifact from {}", filePath);
+        final File f = new File(filePath);
+        if ( !f.exists() || !f.isFile() || !f.canRead() ) {
+            logger.info("Trying to download {}", artifact.getRepositoryPath());
+            try {
+                this.downloadArtifact(artifact);
+            } catch ( final IOException ioe ) {
+                logger.debug("Error downloading file.", ioe);
+            }
+            if ( !f.exists() || !f.isFile() || !f.canRead() ) {
+                logger.info("Artifact not found {}", artifact);
+
+                return null;
+            }
+        }
+        return f;
+    }
+
+    /**
+     * Download artifact from maven
+     * @throws IOException
+     */
+    private void downloadArtifact(final Artifact artifact) throws IOException {
+        // create fake pom
+        final Path dir = Files.createTempDirectory(null);
+        final List<String> lines = new ArrayList<String>();
+        lines.add("<project xmlns=\"http://maven.apache.org/POM/4.0.0\"; 
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"; 
xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/maven-v4_0_0.xsd\";>");
+        lines.add("    <modelVersion>4.0.0</modelVersion>");
+        lines.add("    <groupId>org.apache.sling</groupId>");
+        lines.add("    <artifactId>temp-artifact</artifactId>");
+        lines.add("    <version>1-SNAPSHOT</version>");
+        lines.add("    <dependencies>");
+        lines.add("        <dependency>");
+        lines.add("            <groupId>" + artifact.getGroupId() + 
"</groupId>");
+        lines.add("            <artifactId>" + artifact.getArtifactId() + 
"</artifactId>");
+        lines.add("            <version>" + artifact.getVersion() + 
"</version>");
+        if ( artifact.getClassifier() != null ) {
+            lines.add("            <classifier>" + artifact.getClassifier() + 
"</classifier>");
+        }
+        if ( !"bundle".equals(artifact.getType()) && 
!"jar".equals(artifact.getType()) ) {
+            lines.add("            <type>" + artifact.getType() + "</type>");
+        }
+        lines.add("            <scope>provided</scope>");
+        lines.add("        </dependency>");
+        lines.add("    </dependencies>");
+        lines.add("</project>");
+        logger.info("Writing pom to {}", dir);
+        Files.write(dir.resolve("pom.xml"), lines);
+
+        final File output = dir.resolve("output.txt").toFile();
+        final File error = dir.resolve("error.txt").toFile();
+
+        // invoke maven
+        logger.info("Invoking maven...");
+        final ProcessBuilder pb = new ProcessBuilder("mvn", "verify");
+        pb.directory(dir.toFile());
+        pb.redirectOutput(Redirect.to(output));
+        pb.redirectError(Redirect.to(error));
+
+        final Process p = pb.start();
+        try {
+            p.waitFor();
+        } catch (final InterruptedException e) {
+            Thread.currentThread().interrupt();
+        }
+    }
+}
\ No newline at end of file
diff --git 
a/src/main/java/org/apache/sling/installer/factory/model/impl/UninstallModelTask.java
 
b/src/main/java/org/apache/sling/installer/factory/model/impl/UninstallModelTask.java
new file mode 100644
index 0000000..682c64b
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/installer/factory/model/impl/UninstallModelTask.java
@@ -0,0 +1,56 @@
+/*
+ * 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.installer.factory.model.impl;
+
+import org.apache.sling.installer.api.OsgiInstaller;
+import org.apache.sling.installer.api.tasks.InstallationContext;
+import org.apache.sling.installer.api.tasks.ResourceState;
+import org.apache.sling.installer.api.tasks.TaskResourceGroup;
+import org.osgi.framework.BundleContext;
+
+/**
+ * This task uninstalls model resources.
+ */
+public class UninstallModelTask extends AbstractModelTask {
+
+    public UninstallModelTask(final TaskResourceGroup group,
+            final BundleContext bundleContext) {
+        super(group, bundleContext);
+    }
+
+    @Override
+    public void execute(final InstallationContext ctx) {
+        try {
+            final OsgiInstaller installer = 
this.getService(OsgiInstaller.class);
+            if ( installer == null ) {
+                ctx.log("Unable to get OSGi Installer service!");
+            } else {
+                installer.registerResources("model-" + getModelName(), null);
+                
this.getResourceGroup().setFinishState(ResourceState.UNINSTALLED);
+            }
+        } finally {
+            this.cleanup();
+        }
+    }
+
+    @Override
+    public String getSortKey() {
+        return "31-" + getModelName();
+    }
+}

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

Reply via email to