You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by da...@apache.org on 2019/12/18 16:50:38 UTC

[sling-whiteboard] branch master updated: Initial Extension Handling, WIP

This is an automated email from the ASF dual-hosted git repository.

davidb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git


The following commit(s) were added to refs/heads/master by this push:
     new 19aa12a  Initial Extension Handling, WIP
19aa12a is described below

commit 19aa12ae184ed646877b560355fa07ad48dacdd5
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Wed Dec 18 16:49:34 2019 +0000

    Initial Extension Handling, WIP
---
 .../src/main/java/org/osgi/feature/Extension.java  |  3 ++
 .../src/main/java/org/osgi/feature/Feature.java    |  2 +
 .../org/osgi/feature/builder/ExtensionBuilder.java | 15 ++++--
 .../org/osgi/feature/builder/FeatureBuilder.java   | 21 +++++++-
 .../org/osgi/feature/impl/FeatureServiceImpl.java  | 62 +++++++++++++++++++++-
 .../osgi/feature/impl/FeatureServiceImplTest.java  | 27 ++++++++++
 .../src/test/resources/features/test-exfeat1.json  | 18 +++++++
 .../src/test/resources/features/test-exfeat2.json  | 10 ++++
 8 files changed, 151 insertions(+), 7 deletions(-)

diff --git a/osgi-featuremodel/src/main/java/org/osgi/feature/Extension.java b/osgi-featuremodel/src/main/java/org/osgi/feature/Extension.java
index 9309c46..ab2ca1d 100644
--- a/osgi-featuremodel/src/main/java/org/osgi/feature/Extension.java
+++ b/osgi-featuremodel/src/main/java/org/osgi/feature/Extension.java
@@ -19,12 +19,15 @@ package org.osgi.feature;
 import java.util.List;
 
 public interface Extension {
+    enum Kind { MANDATORY, OPTIONAL, TRANSIENT };
     enum Type { JSON, TEXT, ARTIFACTS };
 
     String getName();
 
     Type getType();
 
+    Kind getKind();
+
     String getJSON();
 
     String getText();
diff --git a/osgi-featuremodel/src/main/java/org/osgi/feature/Feature.java b/osgi-featuremodel/src/main/java/org/osgi/feature/Feature.java
index f041817..8c8a1ad 100644
--- a/osgi-featuremodel/src/main/java/org/osgi/feature/Feature.java
+++ b/osgi-featuremodel/src/main/java/org/osgi/feature/Feature.java
@@ -38,6 +38,8 @@ public interface Feature extends Artifact {
 
     Map<String, Configuration> getConfigurations();
 
+    Map<String, Extension> getExtensions();
+
     Map<String, String> getVariables();
 
     // add prototype
diff --git a/osgi-featuremodel/src/main/java/org/osgi/feature/builder/ExtensionBuilder.java b/osgi-featuremodel/src/main/java/org/osgi/feature/builder/ExtensionBuilder.java
index a2ef848..e93fb3e 100644
--- a/osgi-featuremodel/src/main/java/org/osgi/feature/builder/ExtensionBuilder.java
+++ b/osgi-featuremodel/src/main/java/org/osgi/feature/builder/ExtensionBuilder.java
@@ -18,6 +18,7 @@ package org.osgi.feature.builder;
 
 import org.osgi.feature.ArtifactID;
 import org.osgi.feature.Extension;
+import org.osgi.feature.Extension.Kind;
 import org.osgi.feature.Extension.Type;
 
 import java.io.BufferedReader;
@@ -30,12 +31,14 @@ import java.util.Objects;
 public class ExtensionBuilder {
     private final String name;
     private final Type type;
+    private final Kind kind;
 
     private final StringBuilder content = new StringBuilder();
 
-    public ExtensionBuilder(String name, Type type) {
+    public ExtensionBuilder(String name, Type type, Kind kind) {
         this.name = name;
         this.type = type;
+        this.kind = kind;
     }
 
     public ExtensionBuilder addText(String text) {
@@ -90,17 +93,19 @@ public class ExtensionBuilder {
     }
 
     public Extension build() {
-        return new ExtensionImpl(name, type, content.toString());
+        return new ExtensionImpl(name, type, kind, content.toString());
     }
 
     private static class ExtensionImpl implements Extension {
         private final String name;
         private final Type type;
+        private final Kind kind;
         private final String content;
 
-        private ExtensionImpl(String name, Type type, String content) {
+        private ExtensionImpl(String name, Type type, Kind kind, String content) {
             this.name = name;
             this.type = type;
+            this.kind = kind;
             this.content = content;
         }
 
@@ -112,6 +117,10 @@ public class ExtensionBuilder {
             return type;
         }
 
+        public Kind getKind() {
+            return kind;
+        }
+
         public String getJSON() {
             if (type != Type.JSON)
                 throw new IllegalStateException("Extension is not of type JSON " + type);
diff --git a/osgi-featuremodel/src/main/java/org/osgi/feature/builder/FeatureBuilder.java b/osgi-featuremodel/src/main/java/org/osgi/feature/builder/FeatureBuilder.java
index f2b0e77..56f3b4c 100644
--- a/osgi-featuremodel/src/main/java/org/osgi/feature/builder/FeatureBuilder.java
+++ b/osgi-featuremodel/src/main/java/org/osgi/feature/builder/FeatureBuilder.java
@@ -19,6 +19,7 @@ package org.osgi.feature.builder;
 import org.osgi.feature.ArtifactID;
 import org.osgi.feature.Bundle;
 import org.osgi.feature.Configuration;
+import org.osgi.feature.Extension;
 import org.osgi.feature.Feature;
 
 import java.util.ArrayList;
@@ -42,6 +43,7 @@ public class FeatureBuilder {
 
     private final List<Bundle> bundles = new ArrayList<>();
     private final Map<String,Configuration> configurations = new HashMap<>();
+    private final Map<String,Extension> extensions = new HashMap<>();
     private final Map<String,String> variables = new HashMap<>();
 
     public FeatureBuilder(ArtifactID id) {
@@ -95,6 +97,13 @@ public class FeatureBuilder {
         return this;
     }
 
+    public FeatureBuilder addExtensions(Extension ... extensions) {
+        for (Extension ex : extensions) {
+            this.extensions.put(ex.getName(), ex);
+        }
+        return this;
+    }
+
     public FeatureBuilder addVariable(String key, String value) {
         this.variables.put(key, value);
         return this;
@@ -108,7 +117,7 @@ public class FeatureBuilder {
     public Feature build() {
         return new FeatureImpl(id, title,
                 description, vendor, license, location, complete, isFinal,
-                bundles, configurations, variables);
+                bundles, configurations, extensions, variables);
     }
 
     private static class FeatureImpl extends ArtifactImpl implements Feature {
@@ -122,10 +131,12 @@ public class FeatureBuilder {
 
         private final List<Bundle> bundles;
         private final Map<String,Configuration> configurations;
+        private final Map<String,Extension> extensions;
         private final Map<String,String> variables;
 
         private FeatureImpl(ArtifactID id, String aTitle, String desc, String vnd, String lic, String loc,
-                boolean comp, boolean fin, List<Bundle> bs, Map<String,Configuration> cs, Map<String,String> vars) {
+                boolean comp, boolean fin, List<Bundle> bs, Map<String,Configuration> cs,
+                Map<String,Extension> es, Map<String,String> vars) {
             super(id);
 
             title = aTitle;
@@ -138,6 +149,7 @@ public class FeatureBuilder {
 
             bundles = Collections.unmodifiableList(bs);
             configurations = Collections.unmodifiableMap(cs);
+            extensions = Collections.unmodifiableMap(es);
             variables = Collections.unmodifiableMap(vars);
         }
 
@@ -187,6 +199,11 @@ public class FeatureBuilder {
         }
 
         @Override
+        public Map<String,Extension> getExtensions() {
+            return extensions;
+        }
+
+        @Override
         public Map<String,String> getVariables() {
             return variables;
         }
diff --git a/osgi-featuremodel/src/main/java/org/osgi/feature/impl/FeatureServiceImpl.java b/osgi-featuremodel/src/main/java/org/osgi/feature/impl/FeatureServiceImpl.java
index cbd4645..b2d23d2 100644
--- a/osgi-featuremodel/src/main/java/org/osgi/feature/impl/FeatureServiceImpl.java
+++ b/osgi-featuremodel/src/main/java/org/osgi/feature/impl/FeatureServiceImpl.java
@@ -19,11 +19,13 @@ package org.osgi.feature.impl;
 import org.osgi.feature.ArtifactID;
 import org.osgi.feature.Bundle;
 import org.osgi.feature.Configuration;
+import org.osgi.feature.Extension;
 import org.osgi.feature.Feature;
 import org.osgi.feature.FeatureService;
 import org.osgi.feature.MergeContext;
 import org.osgi.feature.builder.BundleBuilder;
 import org.osgi.feature.builder.ConfigurationBuilder;
+import org.osgi.feature.builder.ExtensionBuilder;
 import org.osgi.feature.builder.FeatureBuilder;
 
 import java.io.IOException;
@@ -62,14 +64,18 @@ public class FeatureServiceImpl implements FeatureService {
 
         builder.addBundles(getBundles(json));
         builder.addConfigurations(getConfigurations(json));
+        builder.addExtensions(getExtensions(json));
 
         return builder.build();
     }
 
     private Bundle[] getBundles(JsonObject json) {
+        JsonArray ja = json.getJsonArray("bundles");
+        if (ja == null)
+            return new Bundle[] {};
+
         List<Bundle> bundles = new ArrayList<>();
 
-        JsonArray ja = json.getJsonArray("bundles");
         for (JsonValue val : ja) {
             if (val.getValueType() == JsonValue.ValueType.OBJECT) {
                 JsonObject jo = val.asJsonObject();
@@ -103,9 +109,12 @@ public class FeatureServiceImpl implements FeatureService {
     }
 
     private Configuration[] getConfigurations(JsonObject json) {
+        JsonObject jo = json.getJsonObject("configurations");
+        if (jo == null)
+            return new Configuration[] {};
+
         List<Configuration> configs = new ArrayList<>();
 
-        JsonObject jo = json.getJsonObject("configurations");
         for (Map.Entry<String, JsonValue> entry : jo.entrySet()) {
 
             String p = entry.getKey();
@@ -154,6 +163,55 @@ public class FeatureServiceImpl implements FeatureService {
         return configs.toArray(new Configuration[] {});
     }
 
+    private Extension[] getExtensions(JsonObject json) {
+        JsonArray ja = json.getJsonArray("extensions");
+        if (ja == null)
+            return new Extension[] {};
+
+        List<Extension> extensions = new ArrayList<>();
+
+        for (JsonValue ex : ja) {
+            for (Map.Entry<String,JsonValue> entry : ex.asJsonObject().entrySet()) {
+                JsonObject exData = entry.getValue().asJsonObject();
+                Extension.Type type;
+                if (exData.containsKey("text")) {
+                    type = Extension.Type.TEXT;
+                } else if (exData.containsKey("artifacts")) {
+                    type = Extension.Type.ARTIFACTS;
+                } else if (exData.containsKey("json")) {
+                    type = Extension.Type.JSON;
+                } else {
+                    throw new IllegalStateException("Invalid extension: " + entry);
+                }
+                String k = exData.getString("kind", "optional");
+                Extension.Kind kind = Extension.Kind.valueOf(k.toUpperCase());
+
+                ExtensionBuilder builder = new ExtensionBuilder(entry.getKey(), type, kind);
+
+                switch (type) {
+                case TEXT:
+                    builder.addText(exData.getString("text"));
+                    break;
+                case ARTIFACTS:
+                    JsonArray ja2 = exData.getJsonArray("artifacts");
+                    for (JsonValue jv : ja2) {
+                        if (jv.getValueType() == JsonValue.ValueType.STRING) {
+                            String id = ((JsonString) jv).getString();
+                            builder.addArtifact(ArtifactID.fromMavenID(id));
+                        }
+                    }
+                    break;
+                case JSON:
+                    exData.getJsonObject("json").toString();
+                    break;
+                }
+                extensions.add(builder.build());
+            }
+        }
+
+        return extensions.toArray(new Extension[] {});
+    }
+
     @Override
     public void writeFeature(Feature feature, Writer jsonWriter) throws IOException {
         // TODO Auto-generated method stub
diff --git a/osgi-featuremodel/src/test/java/org/osgi/feature/impl/FeatureServiceImplTest.java b/osgi-featuremodel/src/test/java/org/osgi/feature/impl/FeatureServiceImplTest.java
index 79c922d..bce29e3 100644
--- a/osgi-featuremodel/src/test/java/org/osgi/feature/impl/FeatureServiceImplTest.java
+++ b/osgi-featuremodel/src/test/java/org/osgi/feature/impl/FeatureServiceImplTest.java
@@ -20,6 +20,7 @@ import org.junit.Test;
 import org.osgi.feature.ArtifactID;
 import org.osgi.feature.Bundle;
 import org.osgi.feature.Configuration;
+import org.osgi.feature.Extension;
 import org.osgi.feature.Feature;
 import org.osgi.feature.FeatureService;
 import org.osgi.feature.MergeContext;
@@ -121,4 +122,30 @@ public class FeatureServiceImplTest {
         expected.put("number:Integer", 7L); // this is wrong TODO
         assertEquals(expected, cfg2.getValues());
     }
+
+    @Test
+    public void testMergeExtensions() throws IOException {
+        FeatureService fs = new FeatureServiceImpl();
+
+        URL res1 = getClass().getResource("/features/test-exfeat1.json");
+        Feature f1;
+        try (Reader r = new InputStreamReader(res1.openStream())) {
+            f1 = fs.readFeature(r);
+        }
+
+        URL res2 = getClass().getResource("/features/test-exfeat2.json");
+        Feature f2;
+        try (Reader r = new InputStreamReader(res2.openStream())) {
+            f2 = fs.readFeature(r);
+        }
+
+        MergeContext ctx = new MergeContextBuilder().build();
+
+        ArtifactID tid = new ArtifactID("g", "a", "1.2.3");
+        Feature f3 = fs.mergeFeatures(tid, f1, f2, ctx);
+
+        Map<String, Extension> extensions = f3.getExtensions();
+        assertEquals(3, extensions.size());
+        assertEquals("ABCDEF", extensions.get("my-text-ex").getText());
+    }
 }
diff --git a/osgi-featuremodel/src/test/resources/features/test-exfeat1.json b/osgi-featuremodel/src/test/resources/features/test-exfeat1.json
new file mode 100644
index 0000000..4d22abd
--- /dev/null
+++ b/osgi-featuremodel/src/test/resources/features/test-exfeat1.json
@@ -0,0 +1,18 @@
+{
+    "id" : "org.apache.sling:test-extension-feature:1.0.0",
+    "extensions" : [
+        { "my-text-ex": {
+          "kind": "optional",
+          "text": "ABC" }
+        },
+        { "my-art-ex": {
+          "artifacts": ["g:a:1", "g:a:2"],
+          "kind": "mandatory" 
+          } 
+        },
+        { "my-json-ex": {
+          "kind": "transient", 
+          "json": {"foo": [1, 2, 3] }}
+        }
+    ]
+}
\ No newline at end of file
diff --git a/osgi-featuremodel/src/test/resources/features/test-exfeat2.json b/osgi-featuremodel/src/test/resources/features/test-exfeat2.json
new file mode 100644
index 0000000..7db40bb
--- /dev/null
+++ b/osgi-featuremodel/src/test/resources/features/test-exfeat2.json
@@ -0,0 +1,10 @@
+{
+    "id" : "org.apache.sling:test-extension-feature2:1.0.0",
+    "extensions" : [
+        { "my-text-ex": 
+          {
+            "text": "DEF"
+          }
+        }
+    ]
+}
\ No newline at end of file