You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:57:18 UTC
[sling-org-apache-sling-provisioning-model] 22/34: Refactor model
and add basic read/write test
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to annotated tag org.apache.sling.provisioning.model-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-provisioning-model.git
commit 4b98c32d19fc98161211fa6c411d12ee929c9acb
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Wed Oct 1 16:03:47 2014 +0000
Refactor model and add basic read/write test
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/tooling/support/slingstart-model@1628749 13f79535-47bb-0310-9956-ffa450edef68
---
pom.xml | 4 +
.../apache/sling/provisioning/model/Artifact.java | 2 +-
.../sling/provisioning/model/ArtifactGroup.java | 17 +--
.../model/{Traceable.java => Commentable.java} | 26 +---
.../sling/provisioning/model/Configuration.java | 2 +-
.../apache/sling/provisioning/model/Feature.java | 16 +-
.../apache/sling/provisioning/model/ItemList.java | 50 +++++++
.../sling/provisioning/model/KeyValueMap.java | 55 +++++++
.../org/apache/sling/provisioning/model/Model.java | 4 +-
.../sling/provisioning/model/ModelUtility.java | 20 +--
.../apache/sling/provisioning/model/RunMode.java | 18 ++-
.../apache/sling/provisioning/model/Traceable.java | 25 +---
.../sling/provisioning/model/io/ModelReader.java | 166 +++++++++------------
.../sling/provisioning/model/io/ModelWriter.java | 86 +++++------
.../apache/sling/provisioning/model/io/IOTest.java | 75 ++++++++++
src/test/resources/boot.txt | 40 +++++
src/test/resources/example.txt | 64 ++++++++
src/test/resources/main.txt | 104 +++++++++++++
src/test/resources/oak.txt | 19 +++
19 files changed, 560 insertions(+), 233 deletions(-)
diff --git a/pom.xml b/pom.xml
index 46f9477..8d212a2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,5 +64,9 @@
<version>1.2.8</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
</dependencies>
</project>
diff --git a/src/main/java/org/apache/sling/provisioning/model/Artifact.java b/src/main/java/org/apache/sling/provisioning/model/Artifact.java
index bb5d844..432c4bf 100644
--- a/src/main/java/org/apache/sling/provisioning/model/Artifact.java
+++ b/src/main/java/org/apache/sling/provisioning/model/Artifact.java
@@ -25,7 +25,7 @@ import java.util.Map;
* In addition, the classifier and type can be specified as well.
* An artifact can have any metadata.
*/
-public class Artifact extends Traceable {
+public class Artifact extends Commentable {
private final String groupId;
private final String artifactId;
diff --git a/src/main/java/org/apache/sling/provisioning/model/ArtifactGroup.java b/src/main/java/org/apache/sling/provisioning/model/ArtifactGroup.java
index 0d0ccf9..8cb3550 100644
--- a/src/main/java/org/apache/sling/provisioning/model/ArtifactGroup.java
+++ b/src/main/java/org/apache/sling/provisioning/model/ArtifactGroup.java
@@ -16,20 +16,16 @@
*/
package org.apache.sling.provisioning.model;
-import java.util.ArrayList;
-import java.util.List;
/**
* A artifact group holds a set of artifacts.
* A valid start level is positive, start level 0 means the default OSGi start level.
*/
-public class ArtifactGroup extends Traceable
+public class ArtifactGroup extends ItemList<Artifact>
implements Comparable<ArtifactGroup> {
private final int level;
- private final List<Artifact> artifacts = new ArrayList<Artifact>();
-
public ArtifactGroup(final int level) {
this.level = level;
}
@@ -38,20 +34,17 @@ public class ArtifactGroup extends Traceable
return this.level;
}
- public List<Artifact> getArtifacts() {
- return this.artifacts;
- }
-
/**
* Search an artifact with the same groupId, artifactId, version, type and classifier.
* Version is not considered.
*/
public Artifact search(final Artifact template) {
Artifact found = null;
- for(final Artifact current : this.artifacts) {
+ for(final Artifact current : this) {
if ( current.getGroupId().equals(template.getGroupId())
&& current.getArtifactId().equals(template.getArtifactId())
- && current.getClassifier().equals(template.getClassifier())
+ && ((current.getClassifier() == null && template.getClassifier() == null)
+ || (current.getClassifier().equals(template.getClassifier()) ))
&& current.getType().equals(template.getType()) ) {
found = current;
break;
@@ -73,7 +66,7 @@ public class ArtifactGroup extends Traceable
@Override
public String toString() {
return "ArtifactGroup [level=" + level
- + ", artifacts=" + artifacts
+ + ", artifacts=" + this.items
+ ( this.getLocation() != null ? ", location=" + this.getLocation() : "")
+ "]";
}
diff --git a/src/main/java/org/apache/sling/provisioning/model/Traceable.java b/src/main/java/org/apache/sling/provisioning/model/Commentable.java
similarity index 67%
copy from src/main/java/org/apache/sling/provisioning/model/Traceable.java
copy to src/main/java/org/apache/sling/provisioning/model/Commentable.java
index 4345ab5..b966a91 100644
--- a/src/main/java/org/apache/sling/provisioning/model/Traceable.java
+++ b/src/main/java/org/apache/sling/provisioning/model/Commentable.java
@@ -20,33 +20,12 @@ package org.apache.sling.provisioning.model;
* A traceable has a comment and a location.
* Both are optional.
*/
-public abstract class Traceable {
-
- /** The location. */
- private String location;
+public abstract class Commentable extends Traceable {
/** The comment. */
private String comment;
/**
- * Get the location.
- * The location might be the location of the model file or any other
- * means identifying where the object is defined.
- * @return The location or {@code null}.
- */
- public String getLocation() {
- return this.location;
- }
-
- /**
- * Set the location.
- * @param value The new location.
- */
- public void setLocation(final String value) {
- this.location = value;
- }
-
- /**
* Get the comment.
* @return The comment or {@code null}.
*/
@@ -64,8 +43,7 @@ public abstract class Traceable {
@Override
public String toString() {
- return "SSMTraceable [location=" + location + ", comment=" + comment
- + "]";
+ return "Commentable [location=" + this.getLocation() + ", comment=" + comment + "]";
}
}
diff --git a/src/main/java/org/apache/sling/provisioning/model/Configuration.java b/src/main/java/org/apache/sling/provisioning/model/Configuration.java
index 67535ce..b317a14 100644
--- a/src/main/java/org/apache/sling/provisioning/model/Configuration.java
+++ b/src/main/java/org/apache/sling/provisioning/model/Configuration.java
@@ -23,7 +23,7 @@ import java.util.Hashtable;
/**
* Configuration
*/
-public class Configuration extends Traceable {
+public class Configuration extends Commentable {
private final String pid;
diff --git a/src/main/java/org/apache/sling/provisioning/model/Feature.java b/src/main/java/org/apache/sling/provisioning/model/Feature.java
index 480e1b8..f333888 100644
--- a/src/main/java/org/apache/sling/provisioning/model/Feature.java
+++ b/src/main/java/org/apache/sling/provisioning/model/Feature.java
@@ -19,9 +19,7 @@ package org.apache.sling.provisioning.model;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
/**
@@ -30,14 +28,14 @@ import java.util.Map;
* - run modes
*/
public class Feature
- extends Traceable
+ extends Commentable
implements Comparable<Feature> {
/** All run modes. */
private final List<RunMode> runModes = new ArrayList<RunMode>();
/** Variables. */
- private final Map<String, String> variables = new HashMap<String, String>();
+ private final KeyValueMap<String> variables = new KeyValueMap<String>();
private final String name;
@@ -68,7 +66,7 @@ public class Feature
* Get all variables
* @return The set of variables
*/
- public Map<String, String> getVariables() {
+ public KeyValueMap<String> getVariables() {
return this.variables;
}
@@ -122,4 +120,12 @@ public class Feature
return this.name.compareTo(o.name);
}
+ @Override
+ public String toString() {
+ return "Feature [runModes=" + runModes + ", variables=" + variables
+ + ", name=" + name
+ + ( this.getLocation() != null ? ", location=" + this.getLocation() : "")
+ + "]";
+ }
+
}
diff --git a/src/main/java/org/apache/sling/provisioning/model/ItemList.java b/src/main/java/org/apache/sling/provisioning/model/ItemList.java
new file mode 100644
index 0000000..85ea138
--- /dev/null
+++ b/src/main/java/org/apache/sling/provisioning/model/ItemList.java
@@ -0,0 +1,50 @@
+/*
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+public class ItemList<T>
+ extends Commentable
+ implements Iterable<T> {
+
+ protected final List<T> items = new ArrayList<T>();
+
+ public void add(final T item) {
+ this.items.add(item);
+ }
+
+ public void remove(final T item) {
+ this.items.remove(item);
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return this.items.iterator();
+ }
+
+ public boolean isEmpty() {
+ return this.items.isEmpty();
+ }
+
+ @Override
+ public String toString() {
+ return items.toString();
+ }
+}
diff --git a/src/main/java/org/apache/sling/provisioning/model/KeyValueMap.java b/src/main/java/org/apache/sling/provisioning/model/KeyValueMap.java
new file mode 100644
index 0000000..aa6598c
--- /dev/null
+++ b/src/main/java/org/apache/sling/provisioning/model/KeyValueMap.java
@@ -0,0 +1,55 @@
+/*
+ * 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;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public class KeyValueMap<T>
+ extends Commentable
+ implements Iterable<Map.Entry<String, T>> {
+
+ private final Map<String, T> properties = new HashMap<String, T>();
+
+ public T get(final String key) {
+ return this.properties.get(key);
+ }
+
+ public void put(final String key, final T value) {
+ this.properties.put(key, value);
+ }
+
+ public void putAll(final KeyValueMap<T> map) {
+ this.properties.putAll(map.properties);
+ }
+
+ @Override
+ public Iterator<Entry<String, T>> iterator() {
+ return this.properties.entrySet().iterator();
+ }
+
+ public boolean isEmpty() {
+ return this.properties.isEmpty();
+ }
+
+ @Override
+ public String toString() {
+ return properties.toString();
+ }
+}
diff --git a/src/main/java/org/apache/sling/provisioning/model/Model.java b/src/main/java/org/apache/sling/provisioning/model/Model.java
index 5ce2a55..ee80611 100644
--- a/src/main/java/org/apache/sling/provisioning/model/Model.java
+++ b/src/main/java/org/apache/sling/provisioning/model/Model.java
@@ -69,8 +69,6 @@ public class Model extends Traceable {
@Override
public String toString() {
- return "Model [features=" + features
- + ( this.getLocation() != null ? ", location=" + this.getLocation() : "")
- + "]";
+ return "Model [features=" + features + "]";
}
}
diff --git a/src/main/java/org/apache/sling/provisioning/model/ModelUtility.java b/src/main/java/org/apache/sling/provisioning/model/ModelUtility.java
index 3188d1c..d42f727 100644
--- a/src/main/java/org/apache/sling/provisioning/model/ModelUtility.java
+++ b/src/main/java/org/apache/sling/provisioning/model/ModelUtility.java
@@ -55,12 +55,12 @@ public abstract class ModelUtility {
for(final ArtifactGroup group : runMode.getArtifactGroups()) {
final ArtifactGroup baseGroup = baseRunMode.getOrCreateArtifactGroup(group.getLevel());
- for(final Artifact artifact : group.getArtifacts()) {
+ for(final Artifact artifact : group) {
final Artifact found = baseGroup.search(artifact);
if ( found != null ) {
- baseGroup.getArtifacts().remove(found);
+ baseGroup.remove(found);
}
- baseGroup.getArtifacts().add(artifact);
+ baseGroup.add(artifact);
}
}
@@ -75,7 +75,7 @@ public abstract class ModelUtility {
}
// settings
- for(final Map.Entry<String, String> entry : runMode.getSettings().entrySet() ) {
+ for(final Map.Entry<String, String> entry : runMode.getSettings() ) {
baseRunMode.getSettings().put(entry.getKey(), entry.getValue());
}
}
@@ -109,8 +109,6 @@ public abstract class ModelUtility {
*/
public static Model getEffectiveModel(final Model model, final VariableResolver resolver) {
final Model result = new Model();
- result.setComment(model.getComment());
- result.setLocation(model.getLocation());
for(final Feature feature : model.getFeatures()) {
final Feature newFeature = result.getOrCreateFeature(feature.getName());
@@ -121,15 +119,13 @@ public abstract class ModelUtility {
for(final RunMode runMode : feature.getRunModes()) {
final RunMode newRunMode = newFeature.getOrCreateRunMode(runMode.getRunModes());
- newRunMode.setComment(runMode.getComment());
- newRunMode.setLocation(runMode.getLocation());
for(final ArtifactGroup group : runMode.getArtifactGroups()) {
final ArtifactGroup newGroup = newRunMode.getOrCreateArtifactGroup(group.getLevel());
newGroup.setComment(group.getComment());
newGroup.setLocation(group.getLocation());
- for(final Artifact artifact : group.getArtifacts()) {
+ for(final Artifact artifact : group) {
final Artifact newArtifact = new Artifact(replace(feature, artifact.getGroupId(), resolver),
replace(feature, artifact.getArtifactId(), resolver),
replace(feature, artifact.getVersion(), resolver),
@@ -138,7 +134,7 @@ public abstract class ModelUtility {
newArtifact.setComment(artifact.getComment());
newArtifact.setLocation(artifact.getLocation());
- newGroup.getArtifacts().add(newArtifact);
+ newGroup.add(newArtifact);
}
}
@@ -201,7 +197,7 @@ public abstract class ModelUtility {
newRunMode.getConfigurations().add(newConfig);
}
- for(final Map.Entry<String, String> entry : runMode.getSettings().entrySet() ) {
+ for(final Map.Entry<String, String> entry : runMode.getSettings() ) {
newRunMode.getSettings().put(entry.getKey(), replace(feature, entry.getValue(), resolver));
}
}
@@ -284,7 +280,7 @@ public abstract class ModelUtility {
if ( sl.getLevel() < 0 ) {
errors.put(sl, "Invalid start level " + sl.getLevel());
}
- for(final Artifact a : sl.getArtifacts()) {
+ for(final Artifact a : sl) {
String error = null;
if ( a.getGroupId() == null || a.getGroupId().isEmpty() ) {
error = "groupId missing";
diff --git a/src/main/java/org/apache/sling/provisioning/model/RunMode.java b/src/main/java/org/apache/sling/provisioning/model/RunMode.java
index 677abaf..72a8b23 100644
--- a/src/main/java/org/apache/sling/provisioning/model/RunMode.java
+++ b/src/main/java/org/apache/sling/provisioning/model/RunMode.java
@@ -19,9 +19,7 @@ package org.apache.sling.provisioning.model;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.Set;
/**
@@ -43,9 +41,9 @@ public class RunMode
private final List<ArtifactGroup> groups = new ArrayList<ArtifactGroup>();
- private final List<Configuration> configurations = new ArrayList<Configuration>();
+ private final ItemList<Configuration> configurations = new ItemList<Configuration>();
- private final Map<String, String> settings = new HashMap<String, String>();
+ private final KeyValueMap<String> settings = new KeyValueMap<String>();
public RunMode(final String[] runModes) {
this.runModes = getSortedRunModesArray(runModes);
@@ -153,7 +151,7 @@ public class RunMode
return null;
}
- public Configuration getOrCreateConfiguration(final String pid, final String factoryPid) {
+ public Configuration getConfiguration(final String pid, final String factoryPid) {
Configuration found = null;
for(final Configuration current : this.configurations) {
if ( factoryPid == null ) {
@@ -168,6 +166,11 @@ public class RunMode
}
}
}
+ return found;
+ }
+
+ public Configuration getOrCreateConfiguration(final String pid, final String factoryPid) {
+ Configuration found = getConfiguration(pid, factoryPid);
if ( found == null ) {
found = new Configuration(pid, factoryPid);
this.configurations.add(found);
@@ -179,11 +182,11 @@ public class RunMode
return this.groups;
}
- public List<Configuration> getConfigurations() {
+ public ItemList<Configuration> getConfigurations() {
return this.configurations;
}
- public Map<String, String> getSettings() {
+ public KeyValueMap<String> getSettings() {
return this.settings;
}
@@ -209,7 +212,6 @@ public class RunMode
return "RunMode [runModes=" + Arrays.toString(runModes) + ", groups="
+ groups + ", configurations=" + configurations + ", settings="
+ settings
- + ( this.getLocation() != null ? ", location=" + this.getLocation() : "")
+ "]";
}
diff --git a/src/main/java/org/apache/sling/provisioning/model/Traceable.java b/src/main/java/org/apache/sling/provisioning/model/Traceable.java
index 4345ab5..d4ced41 100644
--- a/src/main/java/org/apache/sling/provisioning/model/Traceable.java
+++ b/src/main/java/org/apache/sling/provisioning/model/Traceable.java
@@ -17,17 +17,13 @@
package org.apache.sling.provisioning.model;
/**
- * A traceable has a comment and a location.
- * Both are optional.
+ * A traceable has an optional location.
*/
public abstract class Traceable {
/** The location. */
private String location;
- /** The comment. */
- private String comment;
-
/**
* Get the location.
* The location might be the location of the model file or any other
@@ -46,26 +42,9 @@ public abstract class Traceable {
this.location = value;
}
- /**
- * Get the comment.
- * @return The comment or {@code null}.
- */
- public String getComment() {
- return this.comment;
- }
-
- /**
- * Set the comment.
- * @param value The new comment.
- */
- public void setComment(final String value) {
- this.comment = value;
- }
-
@Override
public String toString() {
- return "SSMTraceable [location=" + location + ", comment=" + comment
- + "]";
+ return "Traceable [location=" + location + "]";
}
}
diff --git a/src/main/java/org/apache/sling/provisioning/model/io/ModelReader.java b/src/main/java/org/apache/sling/provisioning/model/io/ModelReader.java
index c3833df..948f3e6 100644
--- a/src/main/java/org/apache/sling/provisioning/model/io/ModelReader.java
+++ b/src/main/java/org/apache/sling/provisioning/model/io/ModelReader.java
@@ -25,31 +25,32 @@ import java.util.Map;
import org.apache.sling.provisioning.model.Artifact;
import org.apache.sling.provisioning.model.ArtifactGroup;
+import org.apache.sling.provisioning.model.Commentable;
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.ModelConstants;
import org.apache.sling.provisioning.model.RunMode;
-import org.apache.sling.provisioning.model.Traceable;
public class ModelReader {
private enum CATEGORY {
- NONE(null),
- FEATURE("feature"),
- VARIABLES("variables"),
- GLOBAL("global"),
- RUN_MODE("runMode"),
- ARTIFACTS("artifacts"),
- SETTINGS("settings"),
- CONFIGURATIONS("configurations"),
- CONFIG(null);
+ NONE(null, null),
+ FEATURE("feature", new String[] {"name"}),
+ VARIABLES("variables", null),
+ ARTIFACTS("artifacts", new String[] {"runModes", "startLevel"}),
+ SETTINGS("settings", new String[] {"runModes"}),
+ CONFIGURATIONS("configurations", new String[] {"runModes"}),
+ CONFIG(null, null);
public final String name;
- private CATEGORY(final String n) {
+ public final String[] parameters;
+
+ private CATEGORY(final String n, final String[] p) {
this.name = n;
+ this.parameters = p;
}
}
@@ -64,9 +65,6 @@ public class ModelReader {
return mr.readModel(reader);
}
- /** Is this a single feature model? */
- private boolean isSingleFeature = false;
-
private CATEGORY mode = CATEGORY.NONE;
private final Model model = new Model();
@@ -101,16 +99,18 @@ public class ModelReader {
lineNumberReader = new LineNumberReader(reader);
String line;
while ( (line = lineNumberReader.readLine()) != null ) {
+ // trim the line
line = line.trim();
+
// ignore empty line
if ( line.isEmpty() ) {
checkConfig();
continue;
}
+
// comment?
if ( line.startsWith("#") ) {
checkConfig();
- mode = CATEGORY.NONE;
final String c = line.substring(1).trim();
if ( comment == null ) {
comment = c;
@@ -122,8 +122,9 @@ public class ModelReader {
if ( global ) {
global = false;
- model.setComment(comment);
- comment = null;
+ if ( !line.startsWith("[feature ") ) {
+ throw new IOException(exceptionPrefix + " Model file must start with a feature category.");
+ }
}
if ( line.startsWith("[") ) {
@@ -149,22 +150,16 @@ public class ModelReader {
Map<String, String> parameters = Collections.emptyMap();
if (line.charAt(pos) != ']') {
final String parameterLine = line.substring(pos + 1, line.length() - 1).trim();
- parameters = parseParameters(parameterLine);
+ parameters = parseParameters(parameterLine, this.mode.parameters);
}
switch ( this.mode ) {
case NONE : break; // this can never happen
case CONFIG : break; // this can never happen
- case FEATURE : if ( this.isSingleFeature ) {
- throw new IOException(exceptionPrefix + "Single feature model allows only one feature.");
- }
- final String name = parameters.get("name");
+ case FEATURE : final String name = parameters.get("name");
if ( name == null ) {
throw new IOException(exceptionPrefix + "Feature name missing in line " + this.lineNumberReader.getLineNumber() + ": " + line);
}
- if ( parameters.size() > 1 ) {
- throw new IOException(exceptionPrefix + "Unknown feature parameters in line " + this.lineNumberReader.getLineNumber() + ": " + line);
- }
if ( model.findFeature(name) != null ) {
throw new IOException(exceptionPrefix + "Duplicate feature in line " + this.lineNumberReader.getLineNumber() + ": " + line);
}
@@ -174,45 +169,16 @@ public class ModelReader {
this.artifactGroup = null;
break;
case VARIABLES : checkFeature();
+ this.init(this.feature.getVariables());
break;
- case RUN_MODE : checkFeature();
- final String names = parameters.get("names");
- if ( names == null ) {
- throw new IOException(exceptionPrefix + "Run mode names missing in line " + this.lineNumberReader.getLineNumber() + ": " + line);
- }
- if ( parameters.size() > 1 ) {
- throw new IOException(exceptionPrefix + "Unknown run mode parameters in line " + this.lineNumberReader.getLineNumber() + ": " + line);
- }
- final String[] rm = names.split(",");
- if ( this.feature.getRunMode(rm) != null ) {
- throw new IOException(exceptionPrefix + "Duplicate run mode in line " + this.lineNumberReader.getLineNumber() + ": " + line);
- }
- this.runMode = this.feature.getOrCreateRunMode(rm);
- this.init(this.runMode);
- this.artifactGroup = null;
- break;
- case GLOBAL : checkFeature();
- if ( !parameters.isEmpty() ) {
- throw new IOException(exceptionPrefix + "Unknown global parameters in line " + this.lineNumberReader.getLineNumber() + ": " + line);
- }
- if ( this.feature.getRunMode(null) != null ) {
- throw new IOException(exceptionPrefix + "Duplicate global run mode in line " + this.lineNumberReader.getLineNumber() + ": " + line);
- }
- this.runMode = this.feature.getOrCreateRunMode(null);
- this.init(this.runMode);
- this.artifactGroup = null;
- break;
case SETTINGS: checkFeature();
- checkRunMode();
+ checkRunMode(parameters);
+ this.init(this.runMode.getSettings());
break;
case ARTIFACTS: checkFeature();
- checkRunMode();
- String level = parameters.get("startLevel");
- if ( (level == null && !parameters.isEmpty())
- || (level != null && parameters.size() > 1 ) ) {
- throw new IOException(exceptionPrefix + "Unknown artifacts parameters in line " + this.lineNumberReader.getLineNumber() + ": " + line);
- }
+ checkRunMode(parameters);
int startLevel = 0;
+ String level = parameters.get("startLevel");
if ( level != null ) {
try {
startLevel = Integer.valueOf(level);
@@ -227,7 +193,8 @@ public class ModelReader {
this.init(this.artifactGroup);
break;
case CONFIGURATIONS: checkFeature();
- checkRunMode();
+ checkRunMode(parameters);
+ this.init(this.runMode.getConfigurations());
break;
}
} else {
@@ -239,27 +206,22 @@ public class ModelReader {
case SETTINGS : final String[] settings = parseProperty(line);
runMode.getSettings().put(settings[0], settings[1]);
break;
- case FEATURE:
- case RUN_MODE:
- case GLOBAL:
- case ARTIFACTS : this.checkFeature();
- this.checkRunMode();
- if ( this.artifactGroup == null ) {
- this.artifactGroup = this.runMode.getOrCreateArtifactGroup(0);
- }
- String artifactUrl = line;
+ case FEATURE: this.runMode = this.feature.getOrCreateRunMode(null);
+ this.artifactGroup = this.runMode.getOrCreateArtifactGroup(0);
+ // no break, we continue with ARTIFACT
+ case ARTIFACTS : String artifactUrl = line;
Map<String, String> parameters = Collections.emptyMap();
if ( line.endsWith("]") ) {
final int startPos = line.indexOf("[");
if ( startPos != -1 ) {
artifactUrl = line.substring(0, startPos).trim();
- parameters = parseParameters(line.substring(startPos + 1, line.length() - 1).trim());
+ parameters = parseParameters(line.substring(startPos + 1, line.length() - 1).trim(), null);
}
}
try {
final Artifact artifact = Artifact.fromMvnUrl("mvn:" + artifactUrl);
this.init(artifact);
- this.artifactGroup.getArtifacts().add(artifact);
+ this.artifactGroup.add(artifact);
artifact.getMetadata().putAll(parameters);
} catch ( final IllegalArgumentException iae) {
throw new IOException(exceptionPrefix + iae.getMessage() + " in line " + this.lineNumberReader.getLineNumber(), iae);
@@ -271,14 +233,10 @@ public class ModelReader {
final int startPos = line.indexOf("[");
if ( startPos != -1 ) {
configId = line.substring(0, startPos).trim();
- cfgPars = parseParameters(line.substring(startPos + 1, line.length() - 1).trim());
+ cfgPars = parseParameters(line.substring(startPos + 1, line.length() - 1).trim(), new String[] {"format"});
}
}
String format = cfgPars.get("format");
- if ( (format == null && !cfgPars.isEmpty())
- || (format != null && cfgPars.size() > 1 ) ) {
- throw new IOException(exceptionPrefix + "Unknown configuration parameters in line " + this.lineNumberReader.getLineNumber() + ": " + line);
- }
if ( format != null ) {
if ( !ModelConstants.CFG_FORMAT_FELIX_CA.equals(format)
&& !ModelConstants.CFG_FORMAT_PROPERTIES.equals(format) ) {
@@ -287,15 +245,23 @@ public class ModelReader {
} else {
format = ModelConstants.CFG_FORMAT_FELIX_CA;
}
+ final String pid;
+ final String factoryPid;
final int factoryPos = configId.indexOf('-');
if ( factoryPos == -1 ) {
+ pid = configId;
+ factoryPid = null;
config = new Configuration(configId, null);
} else {
- config = new Configuration(configId.substring(factoryPos + 1), configId.substring(0, factoryPos));
+ pid = configId.substring(factoryPos + 1);
+ factoryPid = configId.substring(0, factoryPos);
+ }
+ if ( runMode.getConfiguration(pid, factoryPid) != null ) {
+ throw new IOException(exceptionPrefix + "Duplicate configuration in line " + this.lineNumberReader.getLineNumber());
}
+ config = runMode.getOrCreateConfiguration(pid, factoryPid);
this.init(config);
config.getProperties().put(ModelConstants.CFG_UNPROCESSED_FORMAT, format);
- runMode.getConfigurations().add(config);
configBuilder = new StringBuilder();
mode = CATEGORY.CONFIG;
break;
@@ -318,30 +284,26 @@ public class ModelReader {
*/
private void checkFeature() throws IOException {
if ( feature == null ) {
- if ( model.getLocation() == null ) {
- throw new IOException(exceptionPrefix + "No preceding feature definition in line " + this.lineNumberReader.getLineNumber());
- }
- final int beginPos = model.getLocation().replace('\\', '/').lastIndexOf("/");
- String newName = model.getLocation().substring(beginPos + 1);
- final int endPos = newName.lastIndexOf('.');
- if ( endPos != -1 ) {
- newName = newName.substring(0, endPos);
- }
- this.isSingleFeature = true;
- feature = model.getOrCreateFeature(newName);
+ throw new IOException(exceptionPrefix + "No preceding feature definition in line " + this.lineNumberReader.getLineNumber());
}
}
/**
* Check for a run mode object
*/
- private void checkRunMode() throws IOException {
- if ( runMode == null ) {
- runMode = this.feature.getOrCreateRunMode(null);
+ private void checkRunMode(final Map<String, String> parameters) throws IOException {
+ String[] runModes = null;
+ final String rmDef = parameters.get("runModes");
+ if ( rmDef != null ) {
+ runModes = rmDef.split(",");
+ for(int i=0; i<runModes.length; i++) {
+ runModes[i] = runModes[i].trim();
+ }
}
+ runMode = this.feature.getOrCreateRunMode(runModes);
}
- private void init(final Traceable traceable) {
+ private void init(final Commentable traceable) {
traceable.setComment(this.comment);
this.comment = null;
final String number = String.valueOf(this.lineNumberReader.getLineNumber());
@@ -377,7 +339,7 @@ public class ModelReader {
return new String[] {key, value};
}
- private Map<String, String> parseParameters(final String line) throws IOException {
+ private Map<String, String> parseParameters(final String line, final String[] allowedParameters) throws IOException {
final Map<String, String>parameters = new HashMap<String, String>();
final String[] keyValuePairs = line.split(" ");
for(String kv : keyValuePairs) {
@@ -387,7 +349,21 @@ public class ModelReader {
if ( sep == -1 ) {
throw new IOException(exceptionPrefix + "Invalid parameter definition in line " + this.lineNumberReader.getLineNumber() + ": " + line);
}
- parameters.put(kv.substring(0, sep).trim(), kv.substring(sep + 1).trim());
+ final String key = kv.substring(0, sep).trim();
+ parameters.put(key, kv.substring(sep + 1).trim());
+
+ if ( allowedParameters != null ) {
+ boolean found = false;
+ for(final String allowed : allowedParameters) {
+ if ( key.equals(allowed) ) {
+ found = true;
+ break;
+ }
+ }
+ if ( !found ) {
+ throw new IOException(exceptionPrefix + "Invalid parameter " + key + " in line " + this.lineNumberReader.getLineNumber());
+ }
+ }
}
}
return parameters;
diff --git a/src/main/java/org/apache/sling/provisioning/model/io/ModelWriter.java b/src/main/java/org/apache/sling/provisioning/model/io/ModelWriter.java
index 4b023f0..09c8423 100644
--- a/src/main/java/org/apache/sling/provisioning/model/io/ModelWriter.java
+++ b/src/main/java/org/apache/sling/provisioning/model/io/ModelWriter.java
@@ -27,22 +27,22 @@ import java.util.Map;
import org.apache.felix.cm.file.ConfigurationHandler;
import org.apache.sling.provisioning.model.Artifact;
import org.apache.sling.provisioning.model.ArtifactGroup;
+import org.apache.sling.provisioning.model.Commentable;
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.ModelConstants;
import org.apache.sling.provisioning.model.RunMode;
-import org.apache.sling.provisioning.model.Traceable;
/**
* Simple writer for the a model
*/
public class ModelWriter {
- private static void writeComment(final PrintWriter pw, final Traceable traceable)
+ private static void writeComment(final PrintWriter pw, final Commentable commentable)
throws IOException {
- if ( traceable.getComment() != null ) {
- final LineNumberReader lnr = new LineNumberReader(new StringReader(traceable.getComment()));
+ if ( commentable.getComment() != null ) {
+ final LineNumberReader lnr = new LineNumberReader(new StringReader(commentable.getComment()));
try {
String line = null;
while ( (line = lnr.readLine()) != null ) {
@@ -55,6 +55,22 @@ public class ModelWriter {
}
}
+ private static void writeRunMode(final PrintWriter pw, final RunMode runMode) {
+ final String[] rm = runMode.getRunModes();
+ if ( rm != null && rm.length > 0 ) {
+ pw.print(" runModes=");
+ boolean first = true;
+ for(final String mode : rm) {
+ if ( first ) {
+ first = false;
+ } else {
+ pw.print(",");
+ }
+ pw.print(mode);
+ }
+ }
+ }
+
/**
* Writes the model to the writer.
* The writer is not closed.
@@ -66,8 +82,6 @@ public class ModelWriter {
throws IOException {
final PrintWriter pw = new PrintWriter(writer);
- writeComment(pw, model);
-
// features
for(final Feature feature : model.getFeatures()) {
writeComment(pw, feature);
@@ -78,8 +92,9 @@ public class ModelWriter {
// variables
if ( !feature.getVariables().isEmpty() ) {
+ writeComment(pw, feature.getVariables());
pw.println("[variables]");
- for(final Map.Entry<String, String> entry : feature.getVariables().entrySet()) {
+ for(final Map.Entry<String, String> entry : feature.getVariables()) {
pw.print(" ");
pw.print(entry.getKey());
pw.print("=");
@@ -90,43 +105,14 @@ public class ModelWriter {
// run modes
for(final RunMode runMode : feature.getRunModes()) {
- // skip empty run mode
- if ( runMode.getConfigurations().isEmpty() && runMode.getSettings().isEmpty() ) {
- boolean hasArtifacts = false;
- for(final ArtifactGroup sl : runMode.getArtifactGroups()) {
- if ( !sl.getArtifacts().isEmpty() ) {
- hasArtifacts = true;
- break;
- }
- }
- if ( !hasArtifacts ) {
- continue;
- }
- }
- writeComment(pw, runMode);
- final String[] runModes = runMode.getRunModes();
- if ( runModes == null || runModes.length == 0 ) {
- pw.println("[global]");
- } else {
- pw.print("[runMode names=");
- boolean first = true;
- for(final String mode : runModes) {
- if ( first ) {
- first = false;
- } else {
- pw.print(",");
- }
- pw.print(mode);
- }
- pw.println("]");
- }
- pw.println();
-
// settings
if ( !runMode.getSettings().isEmpty() ) {
- pw.println("[settings]");
+ writeComment(pw, runMode.getSettings());
+ pw.print("[settings");
+ writeRunMode(pw, runMode);
+ pw.println("]");
- for(final Map.Entry<String, String> entry : runMode.getSettings().entrySet()) {
+ for(final Map.Entry<String, String> entry : runMode.getSettings()) {
pw.print(" ");
pw.print(entry.getKey());
pw.print("=");
@@ -138,7 +124,7 @@ public class ModelWriter {
// artifact groups
for(final ArtifactGroup group : runMode.getArtifactGroups()) {
// skip empty groups
- if ( group.getArtifacts().isEmpty() ) {
+ if ( group.isEmpty() ) {
continue;
}
writeComment(pw, group);
@@ -147,11 +133,12 @@ public class ModelWriter {
pw.print(" startLevel=");
pw.print(String.valueOf(group.getLevel()));
}
+ writeRunMode(pw, runMode);
pw.println("]");
pw.println();
// artifacts
- for(final Artifact ad : group.getArtifacts()) {
+ for(final Artifact ad : group) {
writeComment(pw, ad);
pw.print(" ");
pw.print(ad.toMvnUrl().substring(4));
@@ -160,26 +147,27 @@ public class ModelWriter {
for(final Map.Entry<String, String> entry : ad.getMetadata().entrySet()) {
if ( first ) {
first = false;
- pw.print("{ ");
+ pw.print(" { ");
} else {
pw.print(", ");
}
pw.print(entry.getKey());
pw.print("=");
- pw.println(entry.getValue());
+ pw.print(entry.getValue());
}
pw.print("}");
}
pw.println();
}
- if ( !group.getArtifacts().isEmpty() ) {
- pw.println();
- }
+ pw.println();
}
// configurations
if ( !runMode.getConfigurations().isEmpty() ) {
- pw.println("[configurations]");
+ writeComment(pw, runMode.getConfigurations());
+ pw.print("[configurations");
+ writeRunMode(pw, runMode);
+ pw.println("]");
for(final Configuration config : runMode.getConfigurations()) {
writeComment(pw, config);
final String raw = (String)config.getProperties().get(ModelConstants.CFG_UNPROCESSED);
diff --git a/src/test/java/org/apache/sling/provisioning/model/io/IOTest.java b/src/test/java/org/apache/sling/provisioning/model/io/IOTest.java
new file mode 100644
index 0000000..313f9d4
--- /dev/null
+++ b/src/test/java/org/apache/sling/provisioning/model/io/IOTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Map;
+
+import org.apache.sling.provisioning.model.Model;
+import org.apache.sling.provisioning.model.ModelUtility;
+import org.apache.sling.provisioning.model.Traceable;
+import org.junit.Test;
+
+public class IOTest {
+
+ /**
+ * Not really a unit test...but better than nothing
+ */
+ @Test public void testReadWrite() throws Exception {
+ final Model result = new Model();
+ final String[] candidates = new String[] {"boot.txt", "example.txt", "main.txt", "oak.txt"};
+
+ for(final String name : candidates) {
+ final Reader reader = new InputStreamReader(this.getClass().getResourceAsStream("/" + name), "UTF-8");
+ try {
+ final Model current = ModelReader.read(reader, name);
+ final Map<Traceable, String> errors = ModelUtility.validate(current);
+ if (errors != null ) {
+ throw new Exception("Invalid model at " + name + " : " + errors);
+ }
+ ModelUtility.merge(result, current);
+ } finally {
+ reader.close();
+ }
+ }
+
+ final Map<Traceable, String> errors = ModelUtility.validate(result);
+ if (errors != null ) {
+ throw new Exception("Invalid assembled model : " + errors);
+ }
+
+ // write the complete model
+ StringWriter writer = new StringWriter();
+ try {
+ ModelWriter.write(writer, result);
+ } finally {
+ writer.close();
+ }
+
+ // and read it again
+ StringReader reader = new StringReader(writer.toString());
+ final Model readModel = ModelReader.read(reader, "memory");
+ reader.close();
+ final Map<Traceable, String> readErrors = ModelUtility.validate(readModel);
+ if (readErrors != null ) {
+ throw new Exception("Invalid read model : " + readErrors);
+ }
+ }
+}
diff --git a/src/test/resources/boot.txt b/src/test/resources/boot.txt
new file mode 100644
index 0000000..7f08d39
--- /dev/null
+++ b/src/test/resources/boot.txt
@@ -0,0 +1,40 @@
+# The :launchpad feature defines Sling's launchpad version
+# Only a single artifact is allowed within this feature.
+#
+[feature name=:launchpad]
+ org.apache.sling/org.apache.sling.launchpad.base/4.4.1-2.5.2/jar
+
+
+# The :boot feature contains all things to bootstrap the installation.
+#
+[feature name=:boot]
+
+# additional entries for sling.properties
+# ---------------------------------------
+# jackrabbit and oak run modes are mutually exclusive,
+# and cannot be changed after the first startup
+[settings]
+ sling.run.mode.install.options=jackrabbit,oak
+
+[artifacts]
+ org.slf4j/slf4j-api/1.7.6/jar
+ org.apache.sling/org.apache.sling.commons.log/4.0.0/jar
+ org.apache.sling/org.apache.sling.commons.logservice/1.0.2/jar
+ org.slf4j/jcl-over-slf4j/1.7.6/jar
+ org.slf4j/log4j-over-slf4j/1.7.6/jar
+ org.apache.sling/org.apache.sling.settings/1.3.2/jar
+ org.apache.sling/org.apache.sling.fragment.xml/1.0.2/jar
+ org.apache.sling/org.apache.sling.fragment.transaction/1.0.0/jar
+ org.apache.sling/org.apache.sling.javax.activation/0.1.0/jar
+ org.apache.sling/org.apache.sling.fragment.ws/${ws.version}/jar
+ org.apache.sling/org.apache.sling.launchpad.installer/1.2.0/jar
+ org.apache.sling/org.apache.sling.installer.core/3.5.4/jar
+ org.apache.sling/org.apache.sling.installer.provider.file/1.0.4/jar
+ org.apache.felix/org.apache.felix.configadmin/1.6.0/jar
+ org.apache.felix/org.apache.felix.eventadmin/1.4.2/jar
+
+# Add an a servlet implementation for the standalone case
+[artifacts startLevel=5 runModes=:standalone]
+ org.apache.felix/org.apache.felix.http.api/2.3.0/jar
+ org.apache.felix/org.apache.felix.http.servlet-api/1.0.0/jar
+ org.apache.felix/org.apache.felix.http.jetty/2.3.0/jar
diff --git a/src/test/resources/example.txt b/src/test/resources/example.txt
new file mode 100644
index 0000000..0153cd3
--- /dev/null
+++ b/src/test/resources/example.txt
@@ -0,0 +1,64 @@
+# This is a feature description
+#
+# A feature consists of variables and run mode dependent artifacts.
+#
+[feature name=example]
+# The variables are global and can be used within artifact definitions, configurations,
+# and settings.
+#
+# Variables
+[variables]
+ ws.version=1.0.2
+
+# Settings, artifacts and configurations belong to a run mode. If none is specified
+# the default run mode is used. The same goes with the start level for artifacts
+# Framework properties
+[settings]
+ sling.options=jackrabbit,oak
+
+[artifacts]
+ commons-io/commons-io/1.4/jar
+ commons-fileupload/commons-fileupload/1.3.1/jar
+ commons-collections/commons-collections/3.2.1/jar
+ commons-codec/commons-codec/1.9/jar
+ commons-lang/commons-lang/2.6/jar
+ org.apache.commons/commons-math/2.2/jar
+# Artifacts can have additional information like a SHA1 etc.
+#
+ org.apache.commons/commons-math/2.2/jar [sha1=2353750701ABE]
+
+# A start level can be specified
+[artifacts startLevel=5]
+ org.apache.sling/org.apache.sling.extensions.webconsolebranding/1.0.0/jar
+ org.apache.sling/org.apache.sling.extensions.webconsolesecurityprovider/1.0.0/jar
+
+# And now the configurations section
+# A configuration ends with an empty line and all configurations use the Apache Felix
+# ConfigAdmin format.
+#
+[configurations]
+# A plain configuration
+org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStoreService
+ name="Default\ NodeStore"
+ repository.home="sling/oak/repository"
+
+# A factory configuration with the alias error
+org.apache.sling.log.LoggerFactory-error
+ name="Test"
+ value="Hallo"
+
+# A configuration using properties format:
+org.apache.sling.another.config [format=properties]
+ test=A
+ value=5
+
+
+
+# Now artifacts, configurations and settings can be specified. All of them belong to
+# the previous runMode definition
+#
+[artifacts startLevel=15 runModes=jackrabbit]
+ org.apache.derby/derby/10.5.3.0_1/jar
+ org.apache.sling/org.apache.sling.jcr.jackrabbit.server/2.1.3-SNAPSHOT/jar
+
+
diff --git a/src/test/resources/main.txt b/src/test/resources/main.txt
new file mode 100644
index 0000000..1afbc3f
--- /dev/null
+++ b/src/test/resources/main.txt
@@ -0,0 +1,104 @@
+[feature name=main]
+
+[variables]
+ ws.version=1.0.2
+
+[artifacts]
+ commons-io/commons-io/1.4/jar
+ commons-fileupload/commons-fileupload/1.3.1/jar
+ commons-collections/commons-collections/3.2.1/jar
+ commons-codec/commons-codec/1.9/jar
+ commons-lang/commons-lang/2.6/jar
+ org.apache.commons/commons-math/2.2/jar
+ commons-pool/commons-pool/1.6/jar
+ org.apache.servicemix.bundles/org.apache.servicemix.bundles.concurrent/1.3.4_1/jar
+ org.apache.geronimo.bundles/commons-httpclient/3.1_1/jar
+ org.apache.sling/org.apache.sling.commons.osgi/2.2.2/jar
+ org.apache.sling/org.apache.sling.commons.mime/2.1.8/jar
+ org.apache.sling/org.apache.sling.commons.classloader/1.3.2/jar
+ org.apache.sling/org.apache.sling.commons.compiler/2.2.0/jar
+ org.apache.sling/org.apache.sling.commons.scheduler/2.4.4/jar
+ org.apache.sling/org.apache.sling.commons.threads/3.2.0/jar
+ org.apache.sling/org.apache.sling.discovery.api/1.0.0/jar
+ org.apache.sling/org.apache.sling.discovery.support/1.0.0/jar
+ org.apache.sling/org.apache.sling.discovery.impl/1.0.10/jar
+ org.apache.sling/org.apache.sling.event/3.3.14/jar
+ org.apache.sling/org.apache.sling.api/2.8.0/jar
+ org.apache.sling/org.apache.sling.serviceusermapper/1.0.2/jar
+ org.apache.sling/org.apache.sling.resourceresolver/1.1.3-SNAPSHOT/jar
+ org.apache.sling/org.apache.sling.auth.core/1.2.0/jar
+ org.apache.sling/org.apache.sling.engine/2.3.5-SNAPSHOT/jar
+ org.apache.sling/org.apache.sling.auth.openid/1.0.4/jar
+ org.apache.sling/org.apache.sling.auth.form/1.0.6/jar
+ org.apache.sling/org.apache.sling.auth.selector/1.0.6/jar
+ org.apache.sling/org.apache.sling.adapter/2.1.1-SNAPSHOT/jar
+ org.apache.sling/org.apache.sling.servlets.resolver/2.3.2/jar
+ org.apache.sling/org.apache.sling.servlets.get/2.1.10/jar
+ org.apache.sling/org.apache.sling.servlets.post/2.3.6/jar
+ org.apache.sling/org.apache.sling.jcr.contentloader/2.1.8/jar
+ org.apache.sling/org.apache.sling.jcr.resource/2.3.8/jar
+ org.apache.sling/org.apache.sling.jcr.classloader/3.2.1-SNAPSHOT/jar
+ org.apache.sling/org.apache.sling.bundleresource.impl/2.2.0/jar
+ org.apache.sling/org.apache.sling.fsresource/1.1.4/jar
+ org.apache.sling/org.apache.sling.launchpad.content/2.0.8/jar
+ org.apache.sling/org.apache.sling.scripting.api/2.1.6/jar
+ org.apache.sling/org.apache.sling.scripting.core/2.0.27-SNAPSHOT/jar
+ org.apache.sling/org.apache.sling.scripting.javascript/2.0.12/jar
+ org.apache.sling/org.apache.sling.scripting.jsp/2.1.4/jar
+ org.apache.sling/org.apache.sling.scripting.jsp.taglib/2.2.2/jar
+ org.apache.geronimo.bundles/jstl/1.2_1/jar
+ org.apache.sling/org.apache.sling.models.api/1.1.0/jar
+ org.apache.sling/org.apache.sling.models.impl/1.1.0/jar
+ org.apache.felix/org.apache.felix.http.whiteboard/2.2.0/jar
+ org.apache.sling/org.apache.sling.installer.console/1.0.0/jar
+ org.apache.sling/org.apache.sling.installer.factory.configuration/1.0.14/jar
+ org.apache.sling/org.apache.sling.installer.provider.jcr/3.1.8/jar
+
+[artifacts startLevel=5]
+ org.apache.sling/org.apache.sling.extensions.webconsolebranding/1.0.0/jar
+ org.apache.sling/org.apache.sling.extensions.webconsolesecurityprovider/1.0.0/jar
+ org.apache.felix/org.apache.felix.inventory/1.0.4/jar
+ org.apache.felix/org.apache.felix.prefs/1.0.6/jar
+ org.apache.felix/org.apache.felix.webconsole/4.2.2/jar
+ org.apache.geronimo.bundles/json/20090211_1/jar
+ org.apache.felix/org.apache.felix.webconsole.plugins.ds/1.0.0/jar
+ org.apache.felix/org.apache.felix.webconsole.plugins.packageadmin/1.0.0/jar
+ org.apache.felix/org.apache.felix.webconsole.plugins.event/1.0.2/jar
+ org.apache.felix/org.apache.felix.webconsole.plugins.memoryusage/1.0.4/jar
+ org.apache.sling/org.apache.sling.commons.json/2.0.8/jar
+ org.apache.felix/org.apache.felix.bundlerepository/1.6.4/jar
+ org.apache.sling/org.apache.sling.extensions.threaddump/0.2.2/jar
+ org.apache.sling/org.apache.sling.jcr.webconsole/1.0.1-SNAPSHOT/jar
+ org.apache.sling/org.apache.sling.extensions.explorer/1.0.4/jar
+ org.apache.aries.jmx/org.apache.aries.jmx.api/1.1.0/jar
+ org.apache.aries/org.apache.aries.util/1.1.0/jar
+ org.apache.aries.jmx/org.apache.aries.jmx.core/1.1.1/jar
+ org.apache.aries.jmx/org.apache.aries.jmx.whiteboard/1.0.0/jar
+
+[artifacts startLevel=10]
+ org.apache.felix/org.apache.felix.scr/1.8.2/jar
+ org.apache.felix/org.apache.felix.metatype/1.0.10/jar
+ org.apache.tika/tika-core/1.2/jar
+ org.apache.tika/tika-bundle/1.2/jar
+
+[artifacts startLevel=15]
+ org.apache.sling/org.apache.sling.jcr.jcr-wrapper/2.0.0/jar
+ org.apache.sling/org.apache.sling.jcr.api/2.2.0/jar
+ org.apache.sling/org.apache.sling.jcr.base/2.2.2/jar
+ org.apache.sling/org.apache.sling.jcr.registration/1.0.1-SNAPSHOT/jar
+ org.apache.jackrabbit/jackrabbit-api/2.7.5/jar
+ org.apache.jackrabbit/jackrabbit-jcr-commons/2.7.5/jar
+ org.apache.jackrabbit/jackrabbit-spi/2.7.1/jar
+ org.apache.jackrabbit/jackrabbit-spi-commons/2.7.1/jar
+ org.apache.jackrabbit/jackrabbit-webdav/2.7.1/jar
+ org.apache.jackrabbit/jackrabbit-jcr-rmi/2.7.1/jar
+ org.apache.sling/org.apache.sling.jcr.webdav/2.2.2/jar
+ org.apache.sling/org.apache.sling.jcr.davex/1.2.1-SNAPSHOT/jar
+ org.apache.sling/org.apache.sling.jcr.jackrabbit.usermanager/2.2.1-SNAPSHOT/jar
+ org.apache.sling/org.apache.sling.jcr.jackrabbit.accessmanager/2.1.1-SNAPSHOT/jar
+
+[artifacts startLevel=15 runModes=jackrabbit]
+ org.apache.derby/derby/10.5.3.0_1/jar
+ org.apache.sling/org.apache.sling.jcr.jackrabbit.server/2.1.3-SNAPSHOT/jar
+
+
diff --git a/src/test/resources/oak.txt b/src/test/resources/oak.txt
new file mode 100644
index 0000000..936c2ac
--- /dev/null
+++ b/src/test/resources/oak.txt
@@ -0,0 +1,19 @@
+# This is the OAK feature.
+[feature name=oak]
+# All bundles are defined to be started at start level 15
+# The segment node store is used via a configuration
+[artifacts startLevel=15 runModes=oak]
+ org.apache.sling/org.apache.sling.jcr.oak.server/0.0.2-SNAPSHOT/jar
+ com.google.guava/guava/15.0/jar
+ org.apache.jackrabbit/oak-core/1.0.0/jar
+ org.apache.jackrabbit/oak-commons/1.0.0/jar
+ org.apache.jackrabbit/oak-mk/1.0.0/jar
+ org.apache.jackrabbit/oak-mk-api/1.0.0/jar
+ org.apache.jackrabbit/oak-mk-remote/1.0.0/jar
+ org.apache.jackrabbit/oak-lucene/1.0.0/jar
+ org.apache.jackrabbit/oak-blob/1.0.0/jar
+
+[configurations runModes=oak]
+ org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStoreService
+ name="Default\ NodeStore"
+ repository.home="sling/oak/repository"
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.