Author: cziegeler
Date: Tue May 30 13:26:08 2017
New Revision: 1796861
URL: http://svn.apache.org/viewvc?rev=1796861&view=rev
Log:
Start implementing extensions
Modified:
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/ArtifactId.java
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Bundles.java
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Extension.java
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Include.java
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONReader.java
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONWriter.java
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/JSONConstants.java
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/ApplicationBuilder.java
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureBuilder.java
Modified:
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/ArtifactId.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/ArtifactId.java?rev=1796861&r1=1796860&r2=1796861&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/ArtifactId.java
(original)
+++
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/ArtifactId.java
Tue May 30 13:26:08 2017
@@ -75,7 +75,7 @@ public class ArtifactId implements Compa
/**
* Create a new artifact from a maven url,
- * 'mvn:' [ repository-url '!' ] group-id '/' artifact-id [ '/' [version]
[ '/' [type] [ '/' classifier ] ] ] ]
+ * 'mvn:' group-id '/' artifact-id [ '/' [version] [ '/' [type] [ '/'
classifier ] ] ] ]
* @param url The url
* @return A new artifact
* @throws IllegalArgumentException If the url is not valid
@@ -88,19 +88,17 @@ public class ArtifactId implements Compa
}
/**
- * Create a new artifact from a maven url,
- * [ repository-url '!' ] group-id '/' artifact-id [ '/' [version] [ '/'
[type] [ '/' classifier ] ] ] ]
+ * Create a new artifact from a maven id,
+ * group-id '/' artifact-id [ '/' [version] [ '/' [type] [ '/' classifier
] ] ] ]
* @param content The id
* @return A new artifact
* @throws IllegalArgumentException If the id is not valid
*/
- public static ArtifactId fromMvnId(final String content) {
- // ignore repository url
- int pos = content.indexOf('!');
- if ( pos != -1 ) {
+ public static ArtifactId fromMvnId(final String coordinates) {
+ // throw if repository url is included
+ if ( coordinates.indexOf('!') != -1 ) {
throw new IllegalArgumentException("Repository url is not
supported for Maven artifacts at the moment.");
}
- final String coordinates = (pos == -1 ? content :
content.substring(pos + 1));
String gId = null;
String aId = null;
String version = null;
@@ -109,7 +107,7 @@ public class ArtifactId implements Compa
int part = 0;
String value = coordinates;
while ( value != null ) {
- pos = value.indexOf('/');
+ final int pos = value.indexOf('/');
final String current;
if ( pos == -1 ) {
current = value;
@@ -149,10 +147,20 @@ public class ArtifactId implements Compa
return toId(new StringBuilder("mvn:"));
}
+ /**
+ * Return a mvn id
+ * @return The mvn id
+ * #see {@link #fromMvnId(String)}
+ */
public String toMvnId() {
return toId(new StringBuilder());
}
+ /**
+ * Internal method to create the mvn url/id
+ * @param sb A string builder
+ * @return The resulting id
+ */
private String toId(final StringBuilder sb) {
sb.append(this.groupId);
sb.append('/');
@@ -187,6 +195,22 @@ public class ArtifactId implements Compa
}
/**
+ * Return the optional classifier.
+ * @return The classifier or null.
+ */
+ public String getClassifier() {
+ return classifier;
+ }
+
+ /**
+ * Return the type.
+ * @return The type.
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
* Return the version.
* @return The version.
*/
@@ -194,6 +218,31 @@ public class ArtifactId implements Compa
return version;
}
+ /**
+ * Test whether the artifact id is pointing to the same artifact but
potentially a different version
+ * @param id The artifact id
+ * @return {@code true} if group id, artifact id, type and classifier equal
+ */
+
+ public boolean isSame(final ArtifactId id) {
+ if ( this.groupId.equals(id.groupId)
+ && this.artifactId.equals(id.artifactId)
+ && this.type.equals(id.type) ) {
+ if (this.classifier == null && id.classifier == null ) {
+ return true;
+ }
+ if ( this.classifier != null ) {
+ return this.classifier.equals(id.classifier);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Return the OSGi version
+ * @return The OSGi version
+ * @throws IllegalArgumentException If the version is no valid OSGi version
+ */
public Version getOSGiVersion() {
final int qualifier = this.version.indexOf('-');
if ( qualifier == -1 ) {
@@ -216,24 +265,8 @@ public class ArtifactId implements Compa
}
/**
- * Return the optional classifier.
- * @return The classifier or null.
- */
- public String getClassifier() {
- return classifier;
- }
-
- /**
- * Return the type.
- * @return The type.
- */
- public String getType() {
- return type;
- }
-
- /**
* Create a Maven like relative repository path.
- * @return A relative repository path.
+ * @return A relative repository path. The path does not start with a
slash.
*/
public String toMvnPath() {
final StringBuilder sb = new StringBuilder();
Modified:
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Bundles.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Bundles.java?rev=1796861&r1=1796860&r2=1796861&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Bundles.java
(original)
+++
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Bundles.java
Tue May 30 13:26:08 2017
@@ -53,7 +53,7 @@ public class Bundles {
list.add(bundle);
}
- public boolean remove(final ArtifactId id) {
+ public boolean removeExact(final ArtifactId id) {
for(final Map.Entry<Integer, List<Artifact>> entry :
this.startLevelMap.entrySet()) {
for(final Artifact artifact : entry.getValue()) {
if ( artifact.getId().equals(id)) {
@@ -68,10 +68,52 @@ public class Bundles {
return false;
}
+ public boolean removeSame(final ArtifactId id) {
+ for(final Map.Entry<Integer, List<Artifact>> entry :
this.startLevelMap.entrySet()) {
+ for(final Artifact artifact : entry.getValue()) {
+ if ( artifact.getId().isSame(id)) {
+ entry.getValue().remove(artifact);
+ if ( entry.getValue().isEmpty() ) {
+ this.startLevelMap.remove(entry.getKey());
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
public void clear() {
this.startLevelMap.clear();
}
+ public Map.Entry<Integer, Artifact> getSame(final ArtifactId id) {
+ for(final Map.Entry<Integer, List<Artifact>> entry :
this.startLevelMap.entrySet()) {
+ for(final Artifact artifact : entry.getValue()) {
+ if ( artifact.getId().isSame(id)) {
+ return new Map.Entry<Integer, Artifact>() {
+
+ @Override
+ public Integer getKey() {
+ return entry.getKey();
+ }
+
+ @Override
+ public Artifact getValue() {
+ return artifact;
+ }
+
+ @Override
+ public Artifact setValue(final Artifact value) {
+ throw new IllegalStateException();
+ }
+ };
+ }
+ }
+ }
+ return null;
+ }
+
public boolean contains(final ArtifactId id) {
for(final Map.Entry<Integer, List<Artifact>> entry :
this.startLevelMap.entrySet()) {
for(final Artifact artifact : entry.getValue()) {
Modified:
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Extension.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Extension.java?rev=1796861&r1=1796860&r2=1796861&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Extension.java
(original)
+++
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Extension.java
Tue May 30 13:26:08 2017
@@ -95,4 +95,25 @@ public class Extension {
public boolean isOptional() {
return !this.isRequired();
}
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ return name.equals(((Extension)obj).name);
+ }
+
+ @Override
+ public String toString() {
+ return "Extension [type=" + type + ", name=" + name + "]";
+ }
}
Modified:
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Include.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Include.java?rev=1796861&r1=1796860&r2=1796861&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Include.java
(original)
+++
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/Include.java
Tue May 30 13:26:08 2017
@@ -34,9 +34,9 @@ public class Include implements Comparab
private final List<String> frameworkPropertiesRemovals = new ArrayList<>();
- private final List<String> textExtensionRemovals = new ArrayList<>();
+ private final List<String> extensionRemovals = new ArrayList<>();
- private final Map<String, List<Artifact>> artifactExtensionRemovals = new
HashMap<>();
+ private final Map<String, List<ArtifactId>> artifactExtensionRemovals =
new HashMap<>();
/**
* Construct a new Include.
@@ -70,11 +70,11 @@ public class Include implements Comparab
return frameworkPropertiesRemovals;
}
- public List<String> getTextExtensionRemovals() {
- return textExtensionRemovals;
+ public List<String> getExtensionRemovals() {
+ return extensionRemovals;
}
- public Map<String, List<Artifact>> getArtifactExtensionRemovals() {
+ public Map<String, List<ArtifactId>> getArtifactExtensionRemovals() {
return artifactExtensionRemovals;
}
Modified:
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONReader.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONReader.java?rev=1796861&r1=1796860&r2=1796861&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONReader.java
(original)
+++
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONReader.java
Tue May 30 13:26:08 2017
@@ -29,7 +29,11 @@ import java.util.Map;
import java.util.Set;
import javax.json.Json;
+import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonStructure;
+import javax.json.JsonWriter;
import org.apache.felix.configurator.impl.conversion.TypeConverter;
import org.apache.felix.configurator.impl.json.JSMin;
@@ -131,7 +135,6 @@ public class FeatureJSONReader {
this.readExtensions(map);
- // check duplicates in configurations, includes
return feature;
}
@@ -175,16 +178,81 @@ public class FeatureJSONReader {
final boolean opt = Boolean.valueOf(optional).booleanValue();
final Extension ext = new Extension(extType, name, opt);
+ final Object value = map.get(key);
switch ( extType ) {
- case ARTIFACTS : // TODO
- case JSON : // TODO
- case TEXT : // TODO
+ case ARTIFACTS : final List<Artifact> list = new ArrayList<>();
+ readArtifacts("Extension " + name,
"artifact", list, value);
+ for(final Artifact a : list) {
+ if ( ext.getArtifacts().contains(a) ) {
+ throw new IOException(exceptionPrefix
+ "Duplicate artifact in extension " + name + " : " + a.getId().toMvnId());
+ }
+ ext.getArtifacts().add(a);
+ }
+ break;
+ case JSON : checkType("JSON Extension " + name, value,
Map.class, List.class);
+ final JsonStructure struct = build(value);
+ try ( final StringWriter w = new StringWriter()) {
+ final JsonWriter jw = Json.createWriter(w);
+ jw.write(struct);
+ w.flush();
+ ext.setJSON(w.toString());
+ }
+ break;
+ case TEXT : checkType("Text Extension " + name, value,
String.class);
+ ext.setText(value.toString());
+ break;
}
this.feature.getExtensions().add(ext);
}
}
+ private JsonStructure build(final Object value) {
+ if ( value instanceof List ) {
+ @SuppressWarnings("unchecked")
+ final List<Object> list = (List<Object>)value;
+ final JsonArrayBuilder builder = Json.createArrayBuilder();
+ for(final Object obj : list) {
+ if ( obj instanceof String ) {
+ builder.add(obj.toString());
+ } else if ( obj instanceof Long ) {
+ builder.add((Long)obj);
+ } else if ( obj instanceof Double ) {
+ builder.add((Double)obj);
+ } else if (obj instanceof Boolean ) {
+ builder.add((Boolean)obj);
+ } else if ( obj instanceof Map ) {
+ builder.add(build(obj));
+ } else if ( obj instanceof List ) {
+ builder.add(build(obj));
+ }
+
+ }
+ return builder.build();
+ } else if ( value instanceof Map ) {
+ @SuppressWarnings("unchecked")
+ final Map<String, Object> map = (Map<String, Object>)value;
+ final JsonObjectBuilder builder = Json.createObjectBuilder();
+ for(final Map.Entry<String, Object> entry : map.entrySet()) {
+ if ( entry.getValue() instanceof String ) {
+ builder.add(entry.getKey(), entry.getValue().toString());
+ } else if ( entry.getValue() instanceof Long ) {
+ builder.add(entry.getKey(), (Long)entry.getValue());
+ } else if ( entry.getValue() instanceof Double ) {
+ builder.add(entry.getKey(), (Double)entry.getValue());
+ } else if ( entry.getValue() instanceof Boolean ) {
+ builder.add(entry.getKey(), (Boolean)entry.getValue());
+ } else if ( entry.getValue() instanceof Map ) {
+ builder.add(entry.getKey(), build(entry.getValue()));
+ } else if ( entry.getValue() instanceof List ) {
+ builder.add(entry.getKey(), build(entry.getValue()));
+ }
+ }
+ return builder.build();
+ }
+ return null;
+ }
+
private void readIncludes(final Map<String, Object> map) throws
IOException {
if ( map.containsKey(JSONConstants.FEATURE_INCLUDES)) {
final Object includesObj = map.get(JSONConstants.FEATURE_INCLUDES);
@@ -194,9 +262,10 @@ public class FeatureJSONReader {
final List<Object> includes = (List<Object>)includesObj;
for(final Object inc : includes) {
checkType("Include", inc, Map.class, String.class);
+ final Include include;
if ( inc instanceof String ) {
final ArtifactId id = ArtifactId.fromMvnId(inc.toString());
- this.feature.getIncludes().add(new Include(id));
+ include = new Include(id);
} else {
@SuppressWarnings("unchecked")
final Map<String, Object> obj = (Map<String, Object>) inc;
@@ -205,8 +274,7 @@ public class FeatureJSONReader {
}
checkType("Include " + JSONConstants.ARTIFACT_ID,
obj.get(JSONConstants.ARTIFACT_ID), String.class);
final ArtifactId id =
ArtifactId.fromMvnId(obj.get(JSONConstants.ARTIFACT_ID).toString());
- final Include include = new Include(id);
- feature.getIncludes().add(include);
+ include = new Include(id);
if ( obj.containsKey(JSONConstants.INCLUDE_REMOVALS) ) {
checkType("Include removals",
obj.get(JSONConstants.INCLUDE_REMOVALS), Map.class);
@@ -238,11 +306,45 @@ public class FeatureJSONReader {
checkType("Include removal bundles", val,
String.class);
include.getFrameworkPropertiesRemovals().add(val.toString());
}
-
}
- // TODO removal of extensions
+ if (
removalObj.containsKey(JSONConstants.INCLUDE_EXTENSION_REMOVALS) ) {
+ checkType("Include removal extensions",
removalObj.get(JSONConstants.INCLUDE_EXTENSION_REMOVALS), List.class);
+ @SuppressWarnings("unchecked")
+ final List<Object> list =
(List<Object>)removalObj.get(JSONConstants.INCLUDE_EXTENSION_REMOVALS);
+ for(final Object val : list) {
+ checkType("Include removal extension", val,
String.class, Map.class);
+ if ( val instanceof String ) {
+
include.getExtensionRemovals().add(val.toString());
+ } else {
+ @SuppressWarnings("unchecked")
+ final Map<String, Object> removalMap =
(Map<String, Object>)val;
+ final Object nameObj =
removalMap.get("name");
+ checkType("Include removal extension",
nameObj, String.class);
+ if ( removalMap.containsKey("artifacts") )
{
+ checkType("Include removal extension
artifacts", removalMap.get("artifacts"), List.class);
+ @SuppressWarnings("unchecked")
+ final List<Object> artifactList =
(List<Object>)removalMap.get("artifacts");
+ final List<ArtifactId> ids = new
ArrayList<>();
+ for(final Object aid : artifactList) {
+ checkType("Include removal
extension artifact", aid, String.class);
+
ids.add(ArtifactId.fromMvnId(aid.toString()));
+ }
+
include.getArtifactExtensionRemovals().put(nameObj.toString(), ids);
+ } else {
+
include.getExtensionRemovals().add(nameObj.toString());
+ }
+ }
+ }
+ }
+
}
}
+ for(final Include i : feature.getIncludes()) {
+ if ( i.getId().equals(include.getId()) ) {
+ throw new IOException(exceptionPrefix + "Duplicate
include of " + include.getId());
+ }
+ }
+ feature.getIncludes().add(include);
}
}
}
@@ -393,79 +495,62 @@ public class FeatureJSONReader {
}
if (
bundleObj.containsKey(JSONConstants.FEATURE_CONFIGURATIONS) ) {
checkType(artifactType + " configurations",
bundleObj.get(JSONConstants.FEATURE_CONFIGURATIONS), Map.class);
- final JSONUtil.Report report = new JSONUtil.Report();
- @SuppressWarnings("unchecked")
- final List<Config> configs =
JSONUtil.readConfigurationsJSON(new TypeConverter(null),
- 0, "", (Map<String,
?>)bundleObj.get(JSONConstants.FEATURE_CONFIGURATIONS), report);
- if ( !report.errors.isEmpty() ||
!report.warnings.isEmpty() ) {
- final StringBuilder builder = new
StringBuilder(this.exceptionPrefix);
- builder.append("Errors in configurations:");
- for(final String w : report.warnings) {
- builder.append("\n");
- builder.append(w);
- }
- for(final String e : report.errors) {
- builder.append("\n");
- builder.append(e);
- }
- throw new IOException(builder.toString());
- }
- for(final Config c : configs) {
- if ( c.getEnvironments() != null ) {
- throw new IOException(this.exceptionPrefix +
"Environments for configurations are not supported");
- }
- final int pos = c.getPid().indexOf('~');
- final Configuration config;
- if ( pos != -1 ) {
- config = new Configuration(c.getPid().substring(0,
pos), c.getPid().substring(pos + 1));
- } else {
- config = new Configuration(c.getPid());
- }
-
config.getProperties().put(Configuration.PROP_ARTIFACT,
artifact.getId().toMvnId());
- feature.getConfigurations().add(config);
- }
+ addConfigurations(bundleObj, artifact);
}
}
artifacts.add(artifact);
}
}
+ private void addConfigurations(final Map<String, Object> map,
+ final Artifact artifact) throws IOException {
+ final JSONUtil.Report report = new JSONUtil.Report();
+ @SuppressWarnings("unchecked")
+ final List<Config> configs = JSONUtil.readConfigurationsJSON(new
TypeConverter(null),
+ 0, "", (Map<String,
?>)map.get(JSONConstants.FEATURE_CONFIGURATIONS), report);
+ if ( !report.errors.isEmpty() || !report.warnings.isEmpty() ) {
+ final StringBuilder builder = new
StringBuilder(this.exceptionPrefix);
+ builder.append("Errors in configurations:");
+ for(final String w : report.warnings) {
+ builder.append("\n");
+ builder.append(w);
+ }
+ for(final String e : report.errors) {
+ builder.append("\n");
+ builder.append(e);
+ }
+ throw new IOException(builder.toString());
+ }
+ for(final Config c : configs) {
+ if ( c.getEnvironments() != null ) {
+ throw new IOException(this.exceptionPrefix + "Environments for
configurations are not supported");
+ }
+ final int pos = c.getPid().indexOf('~');
+ final Configuration config;
+ if ( pos != -1 ) {
+ config = new Configuration(c.getPid().substring(0, pos),
c.getPid().substring(pos + 1));
+ } else {
+ config = new Configuration(c.getPid());
+ }
+ if ( config.getProperties().get(Configuration.PROP_ARTIFACT) !=
null ) {
+ throw new IOException(this.exceptionPrefix + "Configuration
must not define property " + Configuration.PROP_ARTIFACT);
+ }
+ if ( artifact != null ) {
+ config.getProperties().put(Configuration.PROP_ARTIFACT,
artifact.getId().toMvnId());
+ }
+ for(final Configuration current :
this.feature.getConfigurations()) {
+ if ( current.equals(config) ) {
+ throw new IOException(this.exceptionPrefix + "Duplicate
configuration " + config);
+ }
+ }
+ feature.getConfigurations().add(config);
+ }
+
+ }
private void readConfigurations(final Map<String, Object> map) throws
IOException {
if ( map.containsKey(JSONConstants.FEATURE_CONFIGURATIONS) ) {
checkType(JSONConstants.FEATURE_CONFIGURATIONS,
map.get(JSONConstants.FEATURE_CONFIGURATIONS), Map.class);
- final JSONUtil.Report report = new JSONUtil.Report();
- @SuppressWarnings("unchecked")
- final List<Config> configs = JSONUtil.readConfigurationsJSON(new
TypeConverter(null),
- 0, "", (Map<String,
?>)map.get(JSONConstants.FEATURE_CONFIGURATIONS), report);
- if ( !report.errors.isEmpty() || !report.warnings.isEmpty() ) {
- final StringBuilder builder = new
StringBuilder(this.exceptionPrefix);
- builder.append("Errors in configurations:");
- for(final String w : report.warnings) {
- builder.append("\n");
- builder.append(w);
- }
- for(final String e : report.errors) {
- builder.append("\n");
- builder.append(e);
- }
- throw new IOException(builder.toString());
- }
- for(final Config c : configs) {
- if ( c.getEnvironments() != null ) {
- throw new IOException(this.exceptionPrefix + "Environments
for configurations are not supported");
- }
- final int pos = c.getPid().indexOf('~');
- final Configuration config;
- if ( pos != -1 ) {
- config = new Configuration(c.getPid().substring(0, pos),
c.getPid().substring(pos + 1));
- } else {
- config = new Configuration(c.getPid());
- }
- if ( config.getProperties().get(Configuration.PROP_ARTIFACT)
!= null ) {
- throw new IOException(this.exceptionPrefix +
"Configuration must not define property " + Configuration.PROP_ARTIFACT);
- }
- this.feature.getConfigurations().add(config);
- }
+ addConfigurations(map, null);
}
}
Modified:
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONWriter.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONWriter.java?rev=1796861&r1=1796860&r2=1796861&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONWriter.java
(original)
+++
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/FeatureJSONWriter.java
Tue May 30 13:26:08 2017
@@ -17,6 +17,7 @@
package org.apache.sling.feature.json;
import java.io.IOException;
+import java.io.StringReader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Enumeration;
@@ -24,12 +25,15 @@ import java.util.List;
import java.util.Map;
import javax.json.Json;
+import javax.json.JsonStructure;
import javax.json.stream.JsonGenerator;
import org.apache.sling.feature.Artifact;
import org.apache.sling.feature.ArtifactId;
import org.apache.sling.feature.Capability;
import org.apache.sling.feature.Configuration;
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.ExtensionType;
import org.apache.sling.feature.Feature;
import org.apache.sling.feature.Include;
import org.apache.sling.feature.Requirement;
@@ -70,8 +74,24 @@ public class FeatureJSONWriter {
w.write(JSONConstants.ARTIFACT_ID, inc.getId().toMvnId());
w.write(JSONConstants.INCLUDE_REMOVALS);
w.writeStartObject();
- if ( !inc.getArtifactExtensionRemovals().isEmpty() ) {
- // TODO
+ if ( !inc.getArtifactExtensionRemovals().isEmpty()
+ || inc.getExtensionRemovals().isEmpty() ) {
+ w.write(JSONConstants.INCLUDE_EXTENSION_REMOVALS);
+ w.writeStartArray();
+ for(final String id : inc.getExtensionRemovals()) {
+ w.write(id);
+ }
+ for(final Map.Entry<String, List<ArtifactId>> entry :
inc.getArtifactExtensionRemovals().entrySet()) {
+ w.write(entry.getKey());
+ w.writeStartObject();
+ w.writeStartArray();
+ for(final ArtifactId id : entry.getValue()) {
+ w.write(id.toMvnId());
+ }
+ w.writeEnd();
+ w.writeEnd();
+ }
+ w.writeEnd();
}
if ( !inc.getConfigurationRemovals().isEmpty() ) {
w.write(JSONConstants.FEATURE_CONFIGURATIONS);
@@ -219,7 +239,46 @@ public class FeatureJSONWriter {
w.writeEnd();
}
- // TODO extensions
+ // extensions
+ for(final Extension ext : feature.getExtensions()) {
+ final String key = ext.getName() + ":" + ext.getType().name() +
"|" + ext.isOptional();
+ if ( ext.getType() == ExtensionType.JSON ) {
+ final JsonStructure struct;
+ try ( final StringReader reader = new
StringReader(ext.getJSON()) ) {
+ struct = Json.createReader(reader).read();
+ }
+ w.write(key, struct);
+ } else if ( ext.getType() == ExtensionType.TEXT ) {
+ w.write(key, ext.getText());
+ } else {
+ w.write(key);
+ w.writeStartArray();
+ for(final Artifact artifact : ext.getArtifacts()) {
+ final List<Configuration> artifactCfgs = new ArrayList<>();
+ for(final Configuration cfg : feature.getConfigurations())
{
+ final String artifactProp =
(String)cfg.getProperties().get(Configuration.PROP_ARTIFACT);
+ if ( artifact.getId().toMvnId().equals(artifactProp)
) {
+ artifactCfgs.add(cfg);
+ }
+ }
+ if ( artifact.getMetadata().isEmpty() &&
artifactCfgs.isEmpty() ) {
+ w.write(artifact.getId().toMvnId());
+ } else {
+ w.writeStartObject();
+ w.write(JSONConstants.ARTIFACT_ID,
artifact.getId().toMvnId());
+
+ for(final Map.Entry<String, String> me :
artifact.getMetadata()) {
+ w.write(me.getKey(), me.getValue());
+ }
+
+ writeConfigurations(w, artifactCfgs);
+ w.writeEnd();
+ }
+ }
+ w.writeEnd();
+ }
+ }
+
w.writeEnd();
w.flush();
}
Modified:
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/JSONConstants.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/JSONConstants.java?rev=1796861&r1=1796860&r2=1796861&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/JSONConstants.java
(original)
+++
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/json/JSONConstants.java
Tue May 30 13:26:08 2017
@@ -53,6 +53,8 @@ public abstract class JSONConstants {
public static final String INCLUDE_REMOVALS = "removals";
+ public static final String INCLUDE_EXTENSION_REMOVALS = "extensions";
+
public static final String REQCAP_NAMESPACE = "namespace";
public static final String REQCAP_ATTRIBUTES = "attributes";
public static final String REQCAP_DIRECTIVES = "directives";
Modified:
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/ApplicationBuilder.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/ApplicationBuilder.java?rev=1796861&r1=1796860&r2=1796861&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/ApplicationBuilder.java
(original)
+++
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/ApplicationBuilder.java
Tue May 30 13:26:08 2017
@@ -16,16 +16,25 @@
*/
package org.apache.sling.feature.process;
+import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.json.JsonStructure;
+import javax.json.JsonValue;
+import javax.json.JsonValue.ValueType;
+
import org.apache.sling.feature.Application;
import org.apache.sling.feature.Artifact;
import org.apache.sling.feature.ArtifactId;
import org.apache.sling.feature.Configuration;
+import org.apache.sling.feature.Extension;
import org.apache.sling.feature.Feature;
/**
@@ -94,8 +103,16 @@ public class ApplicationBuilder {
// bundles
for(final Map.Entry<Integer, List<Artifact>> entry :
source.getBundles().getBundlesByStartLevel().entrySet()) {
for(final Artifact a : entry.getValue()) {
- target.getBundles().remove(a.getId());
- target.getBundles().add(entry.getKey(), a);
+ // version handling - highest version wins
+ final Map.Entry<Integer, Artifact> existing =
target.getBundles().getSame(a.getId());
+ boolean replace = true;
+ if ( existing != null &&
existing.getValue().getId().getOSGiVersion().compareTo(a.getId().getOSGiVersion())
> 0 ) {
+ replace = false;
+ }
+ if ( replace ) {
+ target.getBundles().removeSame(a.getId());
+ target.getBundles().add(entry.getKey(), a);
+ }
}
}
@@ -121,6 +138,96 @@ public class ApplicationBuilder {
// framework properties
target.getFrameworkProperties().putAll(source.getFrameworkProperties());
- // TODO - extensions
+ // extensions
+ for(final Extension ext : source.getExtensions()) {
+ boolean found = false;
+ for(final Extension current : target.getExtensions()) {
+ if ( current.getName().equals(ext.getName()) ) {
+ found = true;
+ if ( current.getType() != ext.getType() ) {
+ throw new IllegalStateException("Found different types
for extension " + current.getName()
+ + " : " + current.getType() + " and " + ext.getType());
+ }
+ switch ( current.getType() ) {
+ case TEXT : // simply append
+ current.setText(current.getText() + "\n" +
ext.getText());
+ break;
+ case JSON : final JsonStructure struct1;
+ try ( final StringReader reader = new
StringReader(current.getJSON()) ) {
+ struct1 =
Json.createReader(reader).read();
+ }
+ final JsonStructure struct2;
+ try ( final StringReader reader = new
StringReader(ext.getJSON()) ) {
+ struct2 =
Json.createReader(reader).read();
+ }
+
+ if ( struct1.getValueType() !=
struct2.getValueType() ) {
+ throw new IllegalStateException("Found
different JSON types for extension " + current.getName()
+ + " : " + struct1.getValueType() + "
and " + struct2.getValueType());
+ }
+ if ( struct1.getValueType() ==
ValueType.ARRAY ) {
+ // array is append
+ final JsonArray a1 =
(JsonArray)struct1;
+ final JsonArray a2 =
(JsonArray)struct2;
+ for(final JsonValue val : a2) {
+ a1.add(val);
+ }
+ } else {
+ // object is merge
+ merge((JsonObject)struct1,
(JsonObject)struct2);
+ }
+ break;
+
+ case ARTIFACTS : for(final Artifact a :
ext.getArtifacts()) {
+ // remove same artifact - latest
version wins (not highest)
+ boolean add = true;
+ for(final Artifact targetArtifact
: current.getArtifacts()) {
+ if (
targetArtifact.getId().isSame(a.getId()) ) {
+ if (
targetArtifact.getId().getOSGiVersion().compareTo(a.getId().getOSGiVersion()) >
0 ) {
+ add = false;
+ } else {
+
current.getArtifacts().remove(targetArtifact);
+ }
+ break;
+ }
+ }
+ if ( add ) {
+ current.getArtifacts().add(a);
+ }
+ }
+ break;
+
+ }
+ }
+ }
+ if ( !found ) {
+ target.getExtensions().add(ext);
+ }
+ }
+ }
+
+ private static void merge(final JsonObject obj1, final JsonObject obj2) {
+ for(final Map.Entry<String, JsonValue> entry : obj2.entrySet()) {
+ if ( !obj1.containsKey(entry.getKey()) ) {
+ obj1.put(entry.getKey(), entry.getValue());
+ } else {
+ final JsonValue oldValue = obj1.get(entry.getKey());
+ if ( oldValue.getValueType() !=
entry.getValue().getValueType() ) {
+ // new type wins
+ obj1.put(entry.getKey(), entry.getValue());
+ } else if ( oldValue.getValueType() == ValueType.ARRAY ) {
+ final JsonArray a1 = (JsonArray)oldValue;
+ final JsonArray a2 = (JsonArray)entry.getValue();
+ for(final JsonValue val : a2) {
+ a1.add(val);
+ }
+
+ } else if ( oldValue.getValueType() == ValueType.OBJECT ) {
+ merge((JsonObject)oldValue, (JsonObject)entry.getValue());
+ } else {
+ obj1.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
}
}
Modified:
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureBuilder.java
URL:
http://svn.apache.org/viewvc/sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureBuilder.java?rev=1796861&r1=1796860&r2=1796861&view=diff
==============================================================================
---
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureBuilder.java
(original)
+++
sling/whiteboard/cziegeler/feature/src/main/java/org/apache/sling/feature/process/FeatureBuilder.java
Tue May 30 13:26:08 2017
@@ -16,15 +16,24 @@
*/
package org.apache.sling.feature.process;
+import java.io.StringReader;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.json.JsonStructure;
+import javax.json.JsonValue;
+import javax.json.JsonValue.ValueType;
+
import org.apache.sling.feature.Artifact;
import org.apache.sling.feature.ArtifactId;
import org.apache.sling.feature.Capability;
import org.apache.sling.feature.Configuration;
+import org.apache.sling.feature.Extension;
import org.apache.sling.feature.Feature;
import org.apache.sling.feature.Include;
import org.apache.sling.feature.Requirement;
@@ -58,8 +67,9 @@ public class FeatureBuilder {
final Feature af = assemble(feature, provider);
// process removals
+ // bundles
for(final ArtifactId a : i.getBundleRemovals()) {
- af.getBundles().remove(a);
+ af.getBundles().removeExact(a);
final Iterator<Configuration> iter =
af.getConfigurations().iterator();
while ( iter.hasNext() ) {
final Configuration cfg = iter.next();
@@ -69,6 +79,7 @@ public class FeatureBuilder {
}
}
}
+ // configurations
for(final String c : i.getConfigurationRemovals()) {
final int attrPos = c.indexOf('@');
final String val = (attrPos == -1 ? c : c.substring(0,
attrPos));
@@ -105,11 +116,36 @@ public class FeatureBuilder {
}
}
}
+
+ // framework properties
for(final String p : i.getFrameworkPropertiesRemovals()) {
af.getFrameworkProperties().remove(p);
}
- // TODO process feature removals
+ // extensions
+ for(final String name : i.getExtensionRemovals()) {
+ for(final Extension ext : af.getExtensions()) {
+ if ( ext.getName().equals(name) ) {
+ af.getExtensions().remove(ext);
+ break;
+ }
+ }
+ }
+ for(final Map.Entry<String, List<ArtifactId>> entry :
i.getArtifactExtensionRemovals().entrySet()) {
+ for(final Extension ext : af.getExtensions()) {
+ if ( ext.getName().equals(entry.getKey()) ) {
+ for(final ArtifactId id : entry.getValue() ) {
+ for(final Artifact a : ext.getArtifacts()) {
+ if ( a.getId().equals(id) ) {
+ ext.getArtifacts().remove(a);
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
// and now merge
merge(result, af);
@@ -123,7 +159,8 @@ public class FeatureBuilder {
// bundles
for(final Map.Entry<Integer, List<Artifact>> entry :
source.getBundles().getBundlesByStartLevel().entrySet()) {
for(final Artifact a : entry.getValue()) {
- target.getBundles().remove(a.getId());
+ // latest version wins (not highest!)
+ target.getBundles().removeSame(a.getId());
target.getBundles().add(entry.getKey(), a);
}
}
@@ -134,6 +171,7 @@ public class FeatureBuilder {
for(final Configuration current : target.getConfigurations()) {
if ( current.compareTo(cfg) == 0 ) {
found = true;
+ // merge / override properties
final Enumeration<String> i = cfg.getProperties().keys();
while ( i.hasMoreElements() ) {
final String key = i.nextElement();
@@ -147,19 +185,102 @@ public class FeatureBuilder {
}
}
- // framework properties
+ // framework properties (add/merge)
target.getFrameworkProperties().putAll(source.getFrameworkProperties());
- // requirements
+ // requirements (add)
for(final Requirement req : source.getRequirements()) {
target.getRequirements().add(req);
}
- // capabilities
+ // capabilities (add)
for(final Capability cap : source.getCapabilities()) {
target.getCapabilities().add(cap);
}
- // TODO - extensions
+ // extensions (add/merge)
+ for(final Extension ext : source.getExtensions()) {
+ boolean found = false;
+ for(final Extension current : target.getExtensions()) {
+ if ( current.getName().equals(ext.getName()) ) {
+ found = true;
+ if ( current.getType() != ext.getType() ) {
+ throw new IllegalStateException("Found different types
for extension " + current.getName()
+ + " : " + current.getType() + " and " + ext.getType());
+ }
+ switch ( current.getType() ) {
+ case TEXT : // simply append
+ current.setText(current.getText() + "\n" +
ext.getText());
+ break;
+ case JSON : final JsonStructure struct1;
+ try ( final StringReader reader = new
StringReader(current.getJSON()) ) {
+ struct1 =
Json.createReader(reader).read();
+ }
+ final JsonStructure struct2;
+ try ( final StringReader reader = new
StringReader(ext.getJSON()) ) {
+ struct2 =
Json.createReader(reader).read();
+ }
+
+ if ( struct1.getValueType() !=
struct2.getValueType() ) {
+ throw new IllegalStateException("Found
different JSON types for extension " + current.getName()
+ + " : " + struct1.getValueType() + "
and " + struct2.getValueType());
+ }
+ if ( struct1.getValueType() ==
ValueType.ARRAY ) {
+ // array is append
+ final JsonArray a1 =
(JsonArray)struct1;
+ final JsonArray a2 =
(JsonArray)struct2;
+ for(final JsonValue val : a2) {
+ a1.add(val);
+ }
+ } else {
+ // object is merge
+ merge((JsonObject)struct1,
(JsonObject)struct2);
+ }
+ break;
+
+ case ARTIFACTS : for(final Artifact a :
ext.getArtifacts()) {
+ // remove same artifact - latest
version wins (not highest)
+ for(final Artifact targetArtifact
: current.getArtifacts()) {
+ if (
targetArtifact.getId().isSame(a.getId()) ) {
+
current.getArtifacts().remove(targetArtifact);
+ break;
+ }
+ }
+ current.getArtifacts().add(a);
+ }
+ break;
+
+ }
+ }
+ }
+ if ( !found ) {
+ target.getExtensions().add(ext);
+ }
+ }
+ }
+
+ private static void merge(final JsonObject obj1, final JsonObject obj2) {
+ for(final Map.Entry<String, JsonValue> entry : obj2.entrySet()) {
+ if ( !obj1.containsKey(entry.getKey()) ) {
+ obj1.put(entry.getKey(), entry.getValue());
+ } else {
+ final JsonValue oldValue = obj1.get(entry.getKey());
+ if ( oldValue.getValueType() !=
entry.getValue().getValueType() ) {
+ // new type wins
+ obj1.put(entry.getKey(), entry.getValue());
+ } else if ( oldValue.getValueType() == ValueType.ARRAY ) {
+ final JsonArray a1 = (JsonArray)oldValue;
+ final JsonArray a2 = (JsonArray)entry.getValue();
+ for(final JsonValue val : a2) {
+ a1.add(val);
+ }
+
+ } else if ( oldValue.getValueType() == ValueType.OBJECT ) {
+ merge((JsonObject)oldValue, (JsonObject)entry.getValue());
+ } else {
+ obj1.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
}
}