This is an automated email from the ASF dual-hosted git repository. davidb pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-installer-factory-feature.git commit 677a88f0a982d04ad9da817e9b4d785d4976191d Author: Carsten Ziegeler AuthorDate: Sat Feb 22 11:16:10 2020 +0100 Update to support multiple feature files per archive --- .../model/impl/FeatureModelInstallerPlugin.java | 230 +++++++++++++++++++++ .../model/impl/FeatureModelTaskFactory.java | 109 ---------- .../model/impl/FeatureModelTransformer.java | 126 ----------- .../model/impl/InstallFeatureModelTask.java | 8 +- .../model/impl/UninstallFeatureModelTask.java | 7 +- 5 files changed, 238 insertions(+), 242 deletions(-) diff --git a/src/main/java/org/apache/sling/installer/factory/model/impl/FeatureModelInstallerPlugin.java b/src/main/java/org/apache/sling/installer/factory/model/impl/FeatureModelInstallerPlugin.java new file mode 100644 index 0000000..69df21f --- /dev/null +++ b/src/main/java/org/apache/sling/installer/factory/model/impl/FeatureModelInstallerPlugin.java @@ -0,0 +1,230 @@ +/* + * 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.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; + +import org.apache.sling.feature.Feature; +import org.apache.sling.feature.io.archive.ArchiveReader; +import org.apache.sling.feature.io.artifacts.ArtifactManager; +import org.apache.sling.feature.io.artifacts.ArtifactManagerConfig; +import org.apache.sling.feature.io.json.FeatureJSONReader; +import org.apache.sling.feature.io.json.FeatureJSONWriter; +import org.apache.sling.installer.api.InstallableResource; +import org.apache.sling.installer.api.tasks.InstallTask; +import org.apache.sling.installer.api.tasks.InstallTaskFactory; +import org.apache.sling.installer.api.tasks.RegisteredResource; +import org.apache.sling.installer.api.tasks.ResourceState; +import org.apache.sling.installer.api.tasks.ResourceTransformer; +import org.apache.sling.installer.api.tasks.TaskResource; +import org.apache.sling.installer.api.tasks.TaskResourceGroup; +import org.apache.sling.installer.api.tasks.TransformationResult; +import org.apache.sling.jcr.api.SlingRepository; +import org.apache.sling.jcr.repoinit.JcrRepoInitOpsProcessor; +import org.apache.sling.repoinit.parser.RepoInitParser; +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.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.Designate; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This task factory processes model resources detected by + * the {@link FeatureModelTransformer}. + */ +@Component(service = { InstallTaskFactory.class, ResourceTransformer.class }) +@Designate(ocd = FeatureModelInstallerPlugin.Config.class) +public class FeatureModelInstallerPlugin implements InstallTaskFactory, ResourceTransformer { + + @ObjectClassDefinition(name = "Apache Sling Feature Model Installer", + description = "This component provides support for feature models to the OSGi installer") + public @interface Config { + + @AttributeDefinition(name = "Use Apache Maven", + description = "If enabled, missing artifacts from a feature are tried by invoking the mvn command") + boolean useMvn() default true; + + @AttributeDefinition(name = "Repository URLs", description = "Additional repository URLs to fetch artifacts") + String[] repositories(); + + @AttributeDefinition(name = "Classifier Patterns", description = "Patterns for selecting the features to handle based on the classifier. Without a configuration all features are handled.") + String[] classifierPatterns(); + } + + public static final String FILE_EXTENSION = ".json"; + + public static final String TYPE_FEATURE_MODEL = "featuremodel"; + + public static final String ATTR_MODEL = "feature"; + + public static final String ATTR_BASE_PATH = "path"; + + public static final String ATTR_ID = "featureId"; + + /** Logger. */ + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Reference + private SlingRepository repository; + + @Reference + private JcrRepoInitOpsProcessor repoInitProcessor; + + @Reference + private RepoInitParser repoInitParser; + + private final BundleContext bundleContext; + + private final ArtifactManager artifactManager; + + private final List classifierPatterns = new ArrayList<>(); + + @Activate + public FeatureModelInstallerPlugin(final BundleContext ctx, final Config config) throws IOException { + this.bundleContext = ctx; + final ArtifactManagerConfig amCfg = new ArtifactManagerConfig(); + amCfg.setUseMvn(config.useMvn()); + if (config.repositories() != null && config.repositories().length > 0) { + final List repos = new ArrayList<>(Arrays.asList(amCfg.getRepositoryUrls())); + for (final String r : config.repositories()) { + if (!r.trim().isEmpty()) { + repos.add(r); + } + } + amCfg.setRepositoryUrls(repos.toArray(new String[repos.size()])); + } + this.artifactManager = ArtifactManager.getArtifactManager(amCfg); + if (config.classifierPatterns() != null) { + for (final String text : config.classifierPatterns()) { + if (text != null && !text.trim().isEmpty()) { + classifierPatterns.add(text.trim()); + } + } + } + } + + @Override + public TransformationResult[] transform(final RegisteredResource resource) { + final List features = new ArrayList<>(); + File baseDir = null; + if (resource.getType().equals(InstallableResource.TYPE_FILE) && resource.getURL().endsWith(FILE_EXTENSION)) { + try (final Reader reader = new InputStreamReader(resource.getInputStream(), "UTF-8")) { + features.add(FeatureJSONReader.read(reader, resource.getURL())); + } catch (final IOException ioe) { + logger.info("Unable to read feature model from " + resource.getURL(), ioe); + } + } + if (resource.getType().equals(InstallableResource.TYPE_FILE) && resource.getURL().endsWith(".zip")) { + baseDir = this.bundleContext.getDataFile(""); + try (final InputStream is = resource.getInputStream()) { + features.addAll(ArchiveReader.read(is, null)); + } catch (final IOException ioe) { + logger.info("Unable to read feature model from " + resource.getURL(), ioe); + } + } + if (!features.isEmpty()) { + boolean error = false; + final List result = new ArrayList<>(); + for (final Feature feature : features) { + boolean select = this.classifierPatterns.isEmpty(); + if (!select) { + for (final String pattern : this.classifierPatterns) { + if (":".equals(pattern)) { + select = feature.getId().getClassifier() == null; + } else if (feature.getId().getClassifier() != null) { + select = Pattern.compile(pattern).matcher(feature.getId().getClassifier()).matches(); + } + + if (select) { + break; + } + } + } + + if (!select) { + continue; + } + + String featureJson = null; + try (final StringWriter sw = new StringWriter()) { + FeatureJSONWriter.write(sw, feature); + featureJson = sw.toString(); + } catch (final IOException ioe) { + logger.info("Unable to read feature model from " + resource.getURL(), ioe); + } + + if (featureJson != null) { + final TransformationResult tr = new TransformationResult(); + tr.setResourceType(TYPE_FEATURE_MODEL); + tr.setId(feature.getId().toMvnId()); + tr.setVersion(feature.getId().getOSGiVersion()); + + final Map attributes = new HashMap<>(); + attributes.put(ATTR_MODEL, featureJson); + attributes.put(ATTR_ID, feature.getId().toMvnId()); + if (baseDir != null) { + final File dir = new File(baseDir, feature.getId().toMvnName()); + attributes.put(ATTR_BASE_PATH, dir.getAbsolutePath()); + } + tr.setAttributes(attributes); + + result.add(tr); + } else { + error = true; + break; + } + } + if (!error) { + return result.toArray(new TransformationResult[result.size()]); + } + } + return null; + } + + @Override + public InstallTask createTask(final TaskResourceGroup group) { + final TaskResource rsrc = group.getActiveResource(); + if (!TYPE_FEATURE_MODEL.equals(rsrc.getType())) { + return null; + } + if (rsrc.getState() == ResourceState.UNINSTALL ) { + return new UninstallFeatureModelTask(group, bundleContext); + } + return new InstallFeatureModelTask(group, + this.repository, + this.repoInitProcessor, + this.repoInitParser, + this.bundleContext, this.artifactManager); + } +} diff --git a/src/main/java/org/apache/sling/installer/factory/model/impl/FeatureModelTaskFactory.java b/src/main/java/org/apache/sling/installer/factory/model/impl/FeatureModelTaskFactory.java deleted file mode 100644 index 60c1e76..0000000 --- a/src/main/java/org/apache/sling/installer/factory/model/impl/FeatureModelTaskFactory.java +++ /dev/null @@ -1,109 +0,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. - */ -package org.apache.sling.installer.factory.model.impl; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.apache.sling.feature.io.artifacts.ArtifactManager; -import org.apache.sling.feature.io.artifacts.ArtifactManagerConfig; -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.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.osgi.service.metatype.annotations.AttributeDefinition; -import org.osgi.service.metatype.annotations.Designate; -import org.osgi.service.metatype.annotations.ObjectClassDefinition; - -/** - * This task factory processes model resources detected by - * the {@link FeatureModelTransformer}. - */ -@Component(service = InstallTaskFactory.class) -@Designate(ocd = FeatureModelTaskFactory.Config.class) -public class FeatureModelTaskFactory implements InstallTaskFactory { - - @ObjectClassDefinition(name = "Apache Sling Feature Model Installer", - description = "This component provides support for feature models to the OSGi installer") - public @interface Config { - - @AttributeDefinition(name = "Use Apache Maven", - description = "If enabled, missing artifacts from a feature are tried by invoking the mvn command") - boolean useMvn() default true; - - @AttributeDefinition(name = "Repository URLs", description = "Additional repository URLs to fetch artifacts") - String[] repositories(); - } - - @Reference - private SlingRepository repository; - - @Reference - private JcrRepoInitOpsProcessor repoInitProcessor; - - @Reference - private RepoInitParser repoInitParser; - - private final BundleContext bundleContext; - - private final ArtifactManager artifactManager; - - @Activate - public FeatureModelTaskFactory(final BundleContext ctx, final Config config) throws IOException { - this.bundleContext = ctx; - final ArtifactManagerConfig amCfg = new ArtifactManagerConfig(); - amCfg.setUseMvn(config.useMvn()); - if (config.repositories() != null && config.repositories().length > 0) { - final List repos = new ArrayList<>(Arrays.asList(amCfg.getRepositoryUrls())); - for (final String r : config.repositories()) { - if (!r.trim().isEmpty()) { - repos.add(r); - } - } - amCfg.setRepositoryUrls(repos.toArray(new String[repos.size()])); - } - this.artifactManager = ArtifactManager.getArtifactManager(amCfg); - } - - @Override - public InstallTask createTask(final TaskResourceGroup group) { - final TaskResource rsrc = group.getActiveResource(); - if (!FeatureModelTransformer.TYPE_FEATURE_MODEL.equals(rsrc.getType())) { - return null; - } - if (rsrc.getState() == ResourceState.UNINSTALL ) { - return new UninstallFeatureModelTask(group, bundleContext); - } - return new InstallFeatureModelTask(group, - this.repository, - this.repoInitProcessor, - this.repoInitParser, - this.bundleContext, this.artifactManager); - } -} diff --git a/src/main/java/org/apache/sling/installer/factory/model/impl/FeatureModelTransformer.java b/src/main/java/org/apache/sling/installer/factory/model/impl/FeatureModelTransformer.java deleted file mode 100644 index 57b6b99..0000000 --- a/src/main/java/org/apache/sling/installer/factory/model/impl/FeatureModelTransformer.java +++ /dev/null @@ -1,126 +0,0 @@ -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.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringWriter; -import java.util.HashMap; -import java.util.Map; - -import org.apache.sling.feature.ArtifactId; -import org.apache.sling.feature.Feature; -import org.apache.sling.feature.io.archive.ArchiveReader; -import org.apache.sling.feature.io.json.FeatureJSONReader; -import org.apache.sling.feature.io.json.FeatureJSONWriter; -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.osgi.framework.BundleContext; -import org.osgi.service.component.annotations.Activate; -import org.osgi.service.component.annotations.Component; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This transformer detects a file with the ending ".feature" containing a - * feature model or a feature model archive ending in ".far" - */ -@Component(service = ResourceTransformer.class) -public class FeatureModelTransformer implements ResourceTransformer { - - public static final String FILE_EXTENSION = ".json"; - - public static final String TYPE_FEATURE_MODEL = "featuremodel"; - - public static final String ATTR_MODEL = "feature"; - - public static final String ATTR_BASE_PATH = "path"; - - public static final String ATTR_ID = "featureId"; - - /** Logger. */ - private final Logger logger = LoggerFactory.getLogger(this.getClass()); - - private final BundleContext bundleContext; - - @Activate - public FeatureModelTransformer(final BundleContext bc) { - this.bundleContext = bc; - } - - @Override - public TransformationResult[] transform(final RegisteredResource resource) { - Feature feature = null; - File baseDir = null; - if (resource.getType().equals(InstallableResource.TYPE_FILE) && resource.getURL().endsWith(FILE_EXTENSION)) { - try ( final Reader reader = new InputStreamReader(resource.getInputStream(), "UTF-8") ) { - feature = FeatureJSONReader.read(reader, resource.getURL()); - } catch ( final IOException ioe) { - logger.info("Unable to read feature model from " + resource.getURL(), ioe); - } - } - if (resource.getType().equals(InstallableResource.TYPE_FILE) - && resource.getURL().endsWith(".zip")) { - baseDir = this.bundleContext.getDataFile(""); - try ( final InputStream is = resource.getInputStream() ) { - - feature = ArchiveReader.read(is, new ArchiveReader.ArtifactConsumer() { - @Override - public void consume(final ArtifactId artifact, final InputStream is) throws IOException { - // nothing to do, install task does extraction - } - }); - } catch ( final IOException ioe) { - logger.info("Unable to read feature model from " + resource.getURL(), ioe); - } - } - if (feature != null) { - String featureJson = null; - try (final StringWriter sw = new StringWriter()) { - FeatureJSONWriter.write(sw, feature); - featureJson = sw.toString(); - } catch (final IOException ioe) { - logger.info("Unable to read feature model from " + resource.getURL(), ioe); - } - - if (featureJson != null) { - final TransformationResult tr = new TransformationResult(); - tr.setResourceType(TYPE_FEATURE_MODEL); - tr.setId(feature.getId().toMvnId()); - tr.setVersion(feature.getId().getOSGiVersion()); - - final Map attributes = new HashMap<>(); - attributes.put(ATTR_MODEL, featureJson); - attributes.put(ATTR_ID, feature.getId().toMvnId()); - if (baseDir != null) { - final File dir = new File(baseDir, feature.getId().toMvnName()); - attributes.put(ATTR_BASE_PATH, dir.getAbsolutePath()); - } - tr.setAttributes(attributes); - - return new TransformationResult[] { tr }; - } - } - return null; - } -} diff --git a/src/main/java/org/apache/sling/installer/factory/model/impl/InstallFeatureModelTask.java b/src/main/java/org/apache/sling/installer/factory/model/impl/InstallFeatureModelTask.java index 55f3f5c..3dde406 100644 --- a/src/main/java/org/apache/sling/installer/factory/model/impl/InstallFeatureModelTask.java +++ b/src/main/java/org/apache/sling/installer/factory/model/impl/InstallFeatureModelTask.java @@ -89,12 +89,12 @@ public class InstallFeatureModelTask extends AbstractFeatureModelTask { try { final TaskResource resource = this.getResource(); ctx.log("Installing {}", resource.getEntityId()); - final String featureJson = (String) resource.getAttribute(FeatureModelTransformer.ATTR_MODEL); + final String featureJson = (String) resource.getAttribute(FeatureModelInstallerPlugin.ATTR_MODEL); if (featureJson == null) { ctx.log("Unable to install feature model resource {} : no model found", resource); this.getResourceGroup().setFinishState(ResourceState.IGNORED); } else { - final String path = (String) resource.getAttribute(FeatureModelTransformer.ATTR_BASE_PATH); + final String path = (String) resource.getAttribute(FeatureModelInstallerPlugin.ATTR_BASE_PATH); final File baseDir = (path == null ? null : new File(path)); boolean success = false; @@ -140,7 +140,7 @@ public class InstallFeatureModelTask extends AbstractFeatureModelTask { final OsgiInstaller installer = this.getService(OsgiInstaller.class); if ( installer != null ) { installer.registerResources( - "model-" + resource.getAttribute(FeatureModelTransformer.ATTR_ID), + "model-" + resource.getAttribute(FeatureModelInstallerPlugin.ATTR_ID), result.resources.toArray(new InstallableResource[result.resources.size()])); } else { ctx.log("Unable to install feature model resource {} : unable to get OSGi installer", @@ -285,6 +285,6 @@ public class InstallFeatureModelTask extends AbstractFeatureModelTask { @Override public String getSortKey() { - return "30-" + getResource().getAttribute(FeatureModelTransformer.ATTR_ID); + return "30-" + getResource().getAttribute(FeatureModelInstallerPlugin.ATTR_ID); } } diff --git a/src/main/java/org/apache/sling/installer/factory/model/impl/UninstallFeatureModelTask.java b/src/main/java/org/apache/sling/installer/factory/model/impl/UninstallFeatureModelTask.java index ed437de..b584e6d 100644 --- a/src/main/java/org/apache/sling/installer/factory/model/impl/UninstallFeatureModelTask.java +++ b/src/main/java/org/apache/sling/installer/factory/model/impl/UninstallFeatureModelTask.java @@ -46,8 +46,9 @@ public class UninstallFeatureModelTask extends AbstractFeatureModelTask { } else { final TaskResource resource = this.getResource(); ctx.log("Uninstalling {}", resource.getEntityId()); - installer.registerResources("model-" + resource.getAttribute(FeatureModelTransformer.ATTR_ID), null); - final String path = (String)resource.getAttribute(FeatureModelTransformer.ATTR_BASE_PATH); + installer.registerResources("model-" + resource.getAttribute(FeatureModelInstallerPlugin.ATTR_ID), + null); + final String path = (String) resource.getAttribute(FeatureModelInstallerPlugin.ATTR_BASE_PATH); if ( path != null ) { final File dir = new File(path); deleteDirectory(dir); @@ -62,6 +63,6 @@ public class UninstallFeatureModelTask extends AbstractFeatureModelTask { @Override public String getSortKey() { - return "31-" + getResource().getAttribute(FeatureModelTransformer.ATTR_ID); + return "31-" + getResource().getAttribute(FeatureModelInstallerPlugin.ATTR_ID); } }