You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2016/11/12 15:09:18 UTC
svn commit: r1769384 - in
/sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model:
ModelUtility.java io/ModelArchiveReader.java io/ModelArchiveWriter.java
io/package-info.java
Author: cziegeler
Date: Sat Nov 12 15:09:17 2016
New Revision: 1769384
URL: http://svn.apache.org/viewvc?rev=1769384&view=rev
Log:
SLING-6278 : Provide tooling to create an archive with the provisioning model and all artifacts
Added:
sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/ModelArchiveReader.java (with props)
sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/ModelArchiveWriter.java (with props)
Modified:
sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/ModelUtility.java
sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/package-info.java
Modified: sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/ModelUtility.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/ModelUtility.java?rev=1769384&r1=1769383&r2=1769384&view=diff
==============================================================================
--- sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/ModelUtility.java (original)
+++ sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/ModelUtility.java Sat Nov 12 15:09:17 2016
@@ -167,14 +167,14 @@ public abstract class ModelUtility {
for(final Feature feature : model.getFeatures() ) {
// validate feature
if ( feature.getName() == null || feature.getName().isEmpty() ) {
- errors.put(feature, "Name is required for a feature.");
+ addError(errors, feature, "Name is required for a feature.");
}
// version should be a valid version
if ( feature.getVersion() != null ) {
try {
new Version(feature.getVersion());
} catch ( final IllegalArgumentException iae) {
- errors.put(feature, "Version is not a valid version: " + feature.getVersion());
+ addError(errors, feature, "Version is not a valid version: " + feature.getVersion());
}
}
for(final RunMode runMode : feature.getRunModes()) {
@@ -193,12 +193,12 @@ public abstract class ModelUtility {
hasSpecial = 2;
} else {
hasSpecial = 2;
- errors.put(runMode, "Invalid modes " + Arrays.toString(rm));
+ addError(errors, runMode, "Invalid modes " + Arrays.toString(rm));
break;
}
} else {
hasSpecial++;
- errors.put(runMode, "Invalid modes " + Arrays.toString(rm));
+ addError(errors, runMode, "Invalid modes " + Arrays.toString(rm));
break;
}
@@ -212,7 +212,7 @@ public abstract class ModelUtility {
for(final ArtifactGroup sl : runMode.getArtifactGroups()) {
if ( sl.getStartLevel() < 0 ) {
- errors.put(sl, "Invalid start level " + sl.getStartLevel());
+ addError(errors, sl, "Invalid start level " + sl.getStartLevel());
}
for(final Artifact a : sl) {
String error = null;
@@ -229,7 +229,7 @@ public abstract class ModelUtility {
error = (error != null ? error + ", " : "") + "type missing";
}
if (error != null) {
- errors.put(a, error);
+ addError(errors, a, error);
}
}
}
@@ -246,12 +246,12 @@ public abstract class ModelUtility {
error = (error != null ? error + ", " : "") + "configuration properties missing";
}
if (error != null) {
- errors.put(c, error);
+ addError(errors, c, error);
}
}
}
}
- if ( errors.size() == 0 ) {
+ if ( errors.isEmpty()) {
return null;
}
return errors;
@@ -260,7 +260,7 @@ public abstract class ModelUtility {
/**
* Applies a set of variables to the given model.
* All variables that are referenced anywhere within the model are detected and passed to the given variable resolver.
- * The variable resolver may look up variables on it's own, or fallback to the variables already defined for the feature.
+ * The variable resolver may look up variables on it's own, or fall back to the variables already defined for the feature.
* All resolved variable values are collected and put to the "variables" section of the resulting model.
* @param model Original model
* @param resolver Variable resolver
@@ -346,4 +346,38 @@ public abstract class ModelUtility {
return versionUpdater.process(model);
}
+ /**
+ * Validates the model and checks that each feature has a valid version.
+ *
+ * This method first calls {@link #validate(Model)} and then checks
+ * that each feature has a version.
+ *
+ * @param model The model to validate
+ * @return A map with errors or {@code null} if valid.
+ * @since 1.9
+ */
+ public static Map<Traceable, String> validateIncludingVersion(final Model model) {
+ Map<Traceable, String> errors = validate(model);
+ for(final Feature feature : model.getFeatures()) {
+ if ( feature.getVersion() == null ) {
+ if ( errors == null ) {
+ errors = new HashMap<>();
+ }
+ addError(errors, feature, "Feature must have a version.");
+ }
+ }
+ return errors;
+ }
+
+ /**
+ * Add an error for the {@code Traceable} to the error map
+ * @param errors The map of errors
+ * @param object The traceable object
+ * @param error The error message
+ * @since 1.9
+ */
+ private static void addError(final Map<Traceable, String> errors, final Traceable object, final String error) {
+ String value = errors.get(object);
+ errors.put(object, (value == null ? error : value + " " + error));
+ }
}
Added: sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/ModelArchiveReader.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/ModelArchiveReader.java?rev=1769384&view=auto
==============================================================================
--- sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/ModelArchiveReader.java (added)
+++ sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/ModelArchiveReader.java Sat Nov 12 15:09:17 2016
@@ -0,0 +1,103 @@
+/*
+ * 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.provisioning.model.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+
+import org.apache.sling.provisioning.model.Artifact;
+import org.apache.sling.provisioning.model.Model;
+import org.apache.sling.provisioning.model.ModelUtility;
+
+/**
+ * The model archive reader can be used to read an archive based on a model
+ * The archive contains the model file and all artifacts.
+ * @since 1.3
+ */
+public class ModelArchiveReader {
+
+ public interface ArtifactConsumer {
+
+ /**
+ * Consume the artifact from the archive
+ * The input stream must not be closed by the consumer.
+ * @param artifact The artifact
+ * @param is The input stream for the artifact
+ * @throws IOException If the artifact can't be consumed
+ */
+ void consume(Artifact artifact, final InputStream is) throws IOException;
+ }
+
+ /**
+ * Read a model archive.
+ * The input stream is not closed. It is up to the caller to close the input stream.
+ * @param in The input stream to read from.
+ * @return The model
+ * @throws IOException If anything goes wrong
+ */
+ @SuppressWarnings("resource")
+ public static Model read(final InputStream in,
+ final ArtifactConsumer consumer)
+ throws IOException {
+ Model model = null;
+
+ final JarInputStream jis = new JarInputStream(in);
+
+ // check manifest
+ final Manifest manifest = jis.getManifest();
+ if ( manifest == null ) {
+ throw new IOException("Not a model archive - manifest is missing.");
+ }
+ // check manifest header
+ final String version = manifest.getMainAttributes().getValue(ModelArchiveWriter.MANIFEST_HEADER);
+ if ( version == null ) {
+ throw new IOException("Not a model archive - manifest header is missing.");
+ }
+ // validate manifest header
+ try {
+ final int number = Integer.valueOf(version);
+ if ( number < 1 || number > ModelArchiveWriter.ARCHIVE_VERSION ) {
+ throw new IOException("Not a model archive - invalid manifest header value: " + version);
+ }
+ } catch (final NumberFormatException nfe) {
+ throw new IOException("Not a model archive - invalid manifest header value: " + version);
+ }
+
+ // read contents
+ JarEntry entry = null;
+ while ( ( entry = jis.getNextJarEntry() ) != null ) {
+ if ( ModelArchiveWriter.MODEL_NAME.equals(entry.getName()) ) {
+ model = ModelUtility.getEffectiveModel(ModelReader.read(new InputStreamReader(jis, "UTF-8"), null));
+ } else if ( !entry.isDirectory() && entry.getName().startsWith(ModelArchiveWriter.ARTIFACTS_PREFIX) ) { // artifact
+ final Artifact artifact = Artifact.fromMvnUrl("mvn:" + entry.getName().substring(ModelArchiveWriter.ARTIFACTS_PREFIX.length()));
+ consumer.consume(artifact, jis);
+ }
+ jis.closeEntry();
+ }
+ if ( model == null ) {
+ throw new IOException("Not a model archive - model file is missing.");
+ }
+
+ // TODO - we could check whether all artifacts from the model are in the archive
+
+ return model;
+ }
+}
Propchange: sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/ModelArchiveReader.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/ModelArchiveReader.java
------------------------------------------------------------------------------
svn:keywords = author date id revision rev url
Added: sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/ModelArchiveWriter.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/ModelArchiveWriter.java?rev=1769384&view=auto
==============================================================================
--- sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/ModelArchiveWriter.java (added)
+++ sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/ModelArchiveWriter.java Sat Nov 12 15:09:17 2016
@@ -0,0 +1,137 @@
+/*
+ * 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.provisioning.model.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Map;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+
+import org.apache.sling.provisioning.model.Artifact;
+import org.apache.sling.provisioning.model.ArtifactGroup;
+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.Traceable;
+
+/**
+ * The model archive writer can be used to create an archive based on a model
+ * The archive contains the model file and all artifacts.
+ * @since 1.3
+ */
+public class ModelArchiveWriter {
+
+ /** The manifest header marking an archive as a model archive. */
+ public static final String MANIFEST_HEADER = "Model-Archive-Version";
+
+ /** Current support version of the model archive. */
+ public static final int ARCHIVE_VERSION = 1;
+
+ /** Default extension for model archives. */
+ public static final String DEFAULT_EXTENSION = "mar";
+
+ /** Model name. */
+ public static final String MODEL_NAME = "models/feature.model";
+
+ /** Artifacts prefix. */
+ public static final String ARTIFACTS_PREFIX = "artifacts/";
+
+ public interface ArtifactProvider {
+
+ /**
+ * Provide an input stream for the artifact.
+ * The input stream will be closed by the caller.
+ * @param artifact The artifact
+ * @return The input stream
+ * @throws IOException If the input stream can't be provided
+ */
+ InputStream getInputStream(Artifact artifact) throws IOException;
+ }
+
+ /**
+ * Create a model archive.
+ * The output stream will not be closed by this method. The caller
+ * must call {@link JarOutputStream#close()} or {@link JarOutputStream#finish()}
+ * on the return output stream. The caller can add additional files through
+ * the return stream.
+ *
+ * In order to create an archive for a model, each feature in the model must
+ * have a name and a version and the model must be valid, therefore {@link ModelUtility#validateIncludingVersion(Model)}
+ * is called first. If the model is invalid an {@code IOException} is thrown.
+ *
+ * @param out The output stream to write to
+ * @param model The model to write
+ * @param baseManifest Optional base manifest used for creating the manifest.
+ * @param provider The artifact provider
+ * @return The jar output stream.
+ * @throws IOException If anything goes wrong
+ */
+ public static JarOutputStream write(final OutputStream out,
+ final Model model,
+ final Manifest baseManifest,
+ final ArtifactProvider provider)
+ throws IOException {
+ // check model
+ final Map<Traceable, String> errors = ModelUtility.validate(model);
+ if ( errors != null ) {
+ throw new IOException("Model is not valid: " + errors);
+ }
+
+ // create manifest
+ final Manifest manifest = (baseManifest == null ? new Manifest() : new Manifest(baseManifest));
+ manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
+ manifest.getMainAttributes().putValue(MANIFEST_HEADER, String.valueOf(ARCHIVE_VERSION));
+
+ // create archive
+ final JarOutputStream jos = new JarOutputStream(out, manifest);
+
+ // write model first
+ final JarEntry entry = new JarEntry(MODEL_NAME);
+ jos.putNextEntry(entry);
+ final Writer writer = new OutputStreamWriter(jos, "UTF-8");
+ ModelWriter.write(writer, model);
+ writer.flush();
+ jos.closeEntry();
+
+ final byte[] buffer = new byte[1024*1024*256];
+ for(final Feature f : model.getFeatures() ) {
+ for(final RunMode rm : f.getRunModes()) {
+ for(final ArtifactGroup g : rm.getArtifactGroups()) {
+ for(final Artifact a : g) {
+ final JarEntry artifactEntry = new JarEntry(ARTIFACTS_PREFIX + a.getRepositoryPath());
+ jos.putNextEntry(artifactEntry);
+
+ try (final InputStream is = provider.getInputStream(a)) {
+ int l = 0;
+ while ( (l = is.read(buffer)) > 0 ) {
+ jos.write(buffer, 0, l);
+ }
+ }
+ jos.closeEntry();
+ }
+ }
+ }
+ }
+ return jos;
+ }
+}
Propchange: sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/ModelArchiveWriter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/ModelArchiveWriter.java
------------------------------------------------------------------------------
svn:keywords = author date id revision rev url
Modified: sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/package-info.java
URL: http://svn.apache.org/viewvc/sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/package-info.java?rev=1769384&r1=1769383&r2=1769384&view=diff
==============================================================================
--- sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/package-info.java (original)
+++ sling/trunk/tooling/support/provisioning-model/src/main/java/org/apache/sling/provisioning/model/io/package-info.java Sat Nov 12 15:09:17 2016
@@ -17,7 +17,7 @@
* under the License.
*/
-@org.osgi.annotation.versioning.Version("1.2")
+@org.osgi.annotation.versioning.Version("1.3")
package org.apache.sling.provisioning.model.io;