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]>.
