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 77348f23f181f339c9628b85c6b83466bff48184 Author: Carsten Ziegeler <[email protected]> AuthorDate: Sat Nov 12 15:13:35 2016 +0000 Add support for archives git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1769388 13f79535-47bb-0310-9956-ffa450edef68 --- pom.xml | 2 +- .../factory/model/impl/AbstractModelTask.java | 16 +- .../factory/model/impl/InstallModelTask.java | 218 ++++++++++++++------- .../factory/model/impl/ModelTransformer.java | 142 ++++++++------ .../factory/model/impl/UninstallModelTask.java | 11 +- 5 files changed, 256 insertions(+), 133 deletions(-) diff --git a/pom.xml b/pom.xml index 87fae4a..5a600d6 100644 --- a/pom.xml +++ b/pom.xml @@ -101,7 +101,7 @@ <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.provisioning.model</artifactId> - <version>1.7.0</version> + <version>1.7.1-SNAPSHOT</version> <scope>provided</scope> </dependency> </dependencies> 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 index 7fe3151..9f36b21 100644 --- 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 @@ -18,6 +18,7 @@ */ package org.apache.sling.installer.factory.model.impl; +import java.io.File; import java.util.HashMap; import java.util.Map; @@ -73,9 +74,16 @@ public abstract class AbstractModelTask extends InstallTask { return service; } - protected String getModelName() { - final String url = this.getResource().getURL(); - final int lastSlash = url.lastIndexOf('/'); - return lastSlash == -1 ? url : url.substring(lastSlash + 1); + protected void deleteDirectory(final File dir) { + if ( dir.exists() ) { + for(final File f : dir.listFiles()) { + if ( f.isDirectory() ) { + deleteDirectory(f); + } else { + f.delete(); + } + } + dir.delete(); + } } } 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 index 0cf2fac..063aefa 100644 --- 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 @@ -20,14 +20,17 @@ package org.apache.sling.installer.factory.model.impl; import java.io.File; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; 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.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -52,6 +55,7 @@ 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.ModelArchiveReader; import org.apache.sling.provisioning.model.io.ModelReader; import org.apache.sling.repoinit.parser.RepoInitParser; import org.apache.sling.repoinit.parser.RepoInitParsingException; @@ -90,55 +94,68 @@ public class InstallModelTask extends AbstractModelTask { try { final TaskResource resource = this.getResource(); final String modelTxt = (String) resource.getAttribute(ModelTransformer.ATTR_MODEL); - if ( modelTxt == null ) { + final Integer featureIndex = (Integer) resource.getAttribute(ModelTransformer.ATTR_FEATURE_INDEX); + final String name = (String) resource.getAttribute(ModelTransformer.ATTR_FEATURE_NAME); + if ( modelTxt == null || featureIndex == null || name == 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; - } + final String path = (String) resource.getAttribute(ModelTransformer.ATTR_BASE_PATH); + final File baseDir = (path == null ? null : new File(path)); + + boolean success = false; + try { + final Result result = this.transform(name, modelTxt, featureIndex, resource, baseDir); + 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; - // 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(); + } 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); + 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()])); + } else { + ctx.log("Unable to install model resource {} : unable to get OSGi installer", this.getResource()); + this.getResourceGroup().setFinishState(ResourceState.IGNORED); + return; + } } + this.getResourceGroup().setFinishState(ResourceState.INSTALLED); + success = true; + } + } finally { + if ( !success && baseDir != null ) { + this.deleteDirectory(baseDir); } } } @@ -152,17 +169,77 @@ public class InstallModelTask extends AbstractModelTask { public String repoinit; } - private Result transform(final String name, final String modelText) { + private Result transform(final String name, + final String modelText, + final int featureIndex, + final TaskResource rsrc, + final File baseDir) { + Model model = null; try ( final Reader reader = new StringReader(modelText)) { - final Model model = ModelUtility.getEffectiveModel(ModelReader.read(reader, name)); + model = ModelUtility.getEffectiveModel(ModelReader.read(reader, name)); + } catch ( final IOException ioe) { + logger.warn("Unable to read model file for feature " + name, ioe); + } + if ( model == null ) { + return null; + } + int index = 0; + final Iterator<Feature> iter = model.getFeatures().iterator(); + while ( iter.hasNext() ) { + iter.next(); + if ( index != featureIndex ) { + iter.remove(); + } + index++; + } - final List<ArtifactDescription> files = new ArrayList<>(); + if ( baseDir != null ) { + final List<Artifact> artifacts = new ArrayList<>(); + final Feature feature = model.getFeatures().get(0); + for(final RunMode rm : feature.getRunModes()) { + for(final ArtifactGroup group : rm.getArtifactGroups()) { + for(final Artifact a : group) { + artifacts.add(a); + } + } + } + + // extract artifacts + final byte[] buffer = new byte[1024*1024*256]; + + try ( final InputStream is = rsrc.getInputStream() ) { + ModelArchiveReader.read(is, new ModelArchiveReader.ArtifactConsumer() { + + @Override + public void consume(final Artifact artifact, final InputStream is) throws IOException { + if ( artifacts.contains(artifact) ) { + final File artifactFile = new File(baseDir, artifact.getRepositoryPath().replace('/', File.separatorChar)); + if ( !artifactFile.exists() ) { + artifactFile.getParentFile().mkdirs(); + try (final OutputStream os = new FileOutputStream(artifactFile)) { + int l = 0; + while ( (l = is.read(buffer)) > 0 ) { + os.write(buffer, 0, l); + } + } + } + } + } + }); + } catch ( final IOException ioe) { + logger.warn("Unable to extract artifacts from model " + name, ioe); + return null; + } + } - 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 List<ArtifactDescription> files = new ArrayList<>(); + + Map<Traceable, String> errors = collectArtifacts(model, files, baseDir); + if ( errors == null ) { + final Result result = new Result(); + for(final ArtifactDescription desc : files) { + if ( desc.artifactFile != null ) { + try { final InputStream is = new FileInputStream(desc.artifactFile); final String digest = String.valueOf(desc.artifactFile.lastModified()); // handle start level @@ -174,24 +251,26 @@ public class InstallModelTask extends AbstractModelTask { 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(); + } catch ( final IOException ioe ) { + logger.warn("Unable to read artifact " + desc.artifactFile, ioe); + return 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 result; } + logger.warn("Errors during parsing model file {} : {}", name, errors.values()); + return null; } @@ -202,7 +281,9 @@ public class InstallModelTask extends AbstractModelTask { public Section section; } - private Map<Traceable, String> collectArtifacts(final Model effectiveModel, final List<ArtifactDescription> files) { + private Map<Traceable, String> collectArtifacts(final Model effectiveModel, + final List<ArtifactDescription> files, + final File baseDir) { final RepositoryAccess repo = new RepositoryAccess(); final Map<Traceable, String> errors = new HashMap<>(); for(final Feature f : effectiveModel.getFeatures()) { @@ -221,7 +302,10 @@ public class InstallModelTask extends AbstractModelTask { if ( mode.isActive(this.activeRunModes) ) { for(final ArtifactGroup group : mode.getArtifactGroups()) { for(final Artifact artifact : group) { - final File file = repo.get(artifact); + File file = (baseDir == null ? null : new File(baseDir, artifact.getRepositoryPath().replace('/', File.separatorChar))); + if ( file == null || !file.exists() ) { + file = repo.get(artifact); + } if ( file == null ) { errors.put(artifact, "Artifact " + artifact.toMvnUrl() + " not found."); } else { @@ -248,6 +332,6 @@ public class InstallModelTask extends AbstractModelTask { @Override public String getSortKey() { - return "30-" + getModelName(); + return "30-" + getResource().getAttribute(ModelTransformer.ATTR_FEATURE_NAME); } } 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 index a2c9fa2..e9bd83b 100644 --- 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 @@ -18,27 +18,31 @@ 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.Collections; +import java.util.HashMap; 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.Artifact; 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.ModelArchiveReader; import org.apache.sling.provisioning.model.io.ModelReader; import org.apache.sling.provisioning.model.io.ModelWriter; +import org.osgi.framework.BundleContext; import org.osgi.framework.Version; +import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -54,78 +58,98 @@ public class ModelTransformer implements ResourceTransformer { public static final String ATTR_MODEL = "model"; + public static final String ATTR_FEATURE_INDEX = "feature"; + + public static final String ATTR_BASE_PATH = "path"; + + public static final String ATTR_FEATURE_NAME = "name"; + /** Logger. */ private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private BundleContext bundleContext; + + @Activate + private void activate(final BundleContext bc) { + this.bundleContext = bc; + } + @Override public TransformationResult[] transform(final RegisteredResource resource) { + Model model = null; + File baseDir = null; 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()); - } - + model = ModelReader.read(reader, resource.getURL()); } 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."); + if ( resource.getType().equals(InstallableResource.TYPE_FILE) && resource.getURL().endsWith(".mar") ) { + baseDir = this.bundleContext.getDataFile(""); + try ( final InputStream is = resource.getInputStream() ) { + + model = ModelArchiveReader.read(is, new ModelArchiveReader.ArtifactConsumer() { + @Override + public void consume(final Artifact artifact, final InputStream is) throws IOException { + // nothing to do, install task does extraction + } + }); + } catch ( final IOException ioe) { + logger.info("Unable to read model from " + resource.getURL(), ioe); } } - 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."); + if ( model != null ) { + Map<Traceable, String> errors = ModelUtility.validate(model); + if ( errors == null ) { + try { + final Model effectiveModel = ModelUtility.getEffectiveModel(model); + + errors = ModelUtility.validateIncludingVersion(effectiveModel); + if ( errors == null ) { + + String modelTxt = null; + try ( final StringWriter sw = new StringWriter()) { + ModelWriter.write(sw, effectiveModel); + modelTxt = sw.toString(); + } catch ( final IOException ioe) { + logger.info("Unable to read model from " + resource.getURL(), ioe); + } + + if ( modelTxt != null ) { + final TransformationResult[] result = new TransformationResult[effectiveModel.getFeatures().size()]; + int index = 0; + for(final Feature f : effectiveModel.getFeatures()) { + + final TransformationResult tr = new TransformationResult(); + tr.setResourceType(TYPE_PROV_MODEL); + tr.setId(f.getName()); + tr.setVersion(new Version(f.getVersion())); + + final Map<String, Object> attributes = new HashMap<>(); + attributes.put(ATTR_MODEL, modelTxt); + attributes.put(ATTR_FEATURE_INDEX, index); + attributes.put(ATTR_FEATURE_NAME, f.getName() + "-" + f.getVersion()); + if ( baseDir != null ) { + final File dir = new File(baseDir, f.getName() + "-" + f.getVersion()); + attributes.put(ATTR_BASE_PATH, dir.getAbsolutePath()); + } + tr.setAttributes(attributes); + + result[index] = tr; + index++; + } + return result; + } + } + } 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()); + } } - return null; } - } 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 index 682c64b..ecce2bf 100644 --- 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 @@ -18,6 +18,8 @@ */ package org.apache.sling.installer.factory.model.impl; +import java.io.File; + import org.apache.sling.installer.api.OsgiInstaller; import org.apache.sling.installer.api.tasks.InstallationContext; import org.apache.sling.installer.api.tasks.ResourceState; @@ -41,7 +43,12 @@ public class UninstallModelTask extends AbstractModelTask { if ( installer == null ) { ctx.log("Unable to get OSGi Installer service!"); } else { - installer.registerResources("model-" + getModelName(), null); + installer.registerResources("model-" + getResource().getAttribute(ModelTransformer.ATTR_FEATURE_NAME), null); + final String path = (String)this.getResource().getAttribute(ModelTransformer.ATTR_BASE_PATH); + if ( path != null ) { + final File dir = new File(path); + deleteDirectory(dir); + } this.getResourceGroup().setFinishState(ResourceState.UNINSTALLED); } } finally { @@ -51,6 +58,6 @@ public class UninstallModelTask extends AbstractModelTask { @Override public String getSortKey() { - return "31-" + getModelName(); + return "31-" + getResource().getAttribute(ModelTransformer.ATTR_FEATURE_NAME); } } -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
