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/16 16:57:15 UTC

[sling-whiteboard] branch master updated: Merging of Features

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 5d71e62  Merging of Features
5d71e62 is described below

commit 5d71e628db66fe71a12628189f47b94bb2709e6e
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Mon Dec 16 16:56:50 2019 +0000

    Merging of Features
---
 .../src/main/java/org/osgi/feature/Artifact.java   |  2 +-
 .../src/main/java/org/osgi/feature/ArtifactID.java | 10 +++++
 .../src/main/java/org/osgi/feature/Bundle.java     |  7 ++-
 .../main/java/org/osgi/feature/FeatureService.java |  3 +-
 .../feature/{Artifact.java => MergeContext.java}   | 29 ++----------
 .../osgi/feature/builder/MergeContextBuilder.java  | 41 +++++++++++++++++
 .../org/osgi/feature/impl/FeatureServiceImpl.java  | 51 ++++++++++++++++++++--
 .../feature/impl}/FeatureServiceImplTest.java      | 36 ++++++++++++++-
 .../src/test/resources/features/test-feature2.json | 15 +++++++
 9 files changed, 162 insertions(+), 32 deletions(-)

diff --git a/osgi-featuremodel/src/main/java/org/osgi/feature/Artifact.java b/osgi-featuremodel/src/main/java/org/osgi/feature/Artifact.java
index 2841726..3a9085f 100644
--- a/osgi-featuremodel/src/main/java/org/osgi/feature/Artifact.java
+++ b/osgi-featuremodel/src/main/java/org/osgi/feature/Artifact.java
@@ -25,7 +25,7 @@ public class Artifact {
         this.id = id;
     }
 
-    public ArtifactID getId() {
+    public ArtifactID getID() {
         return id;
     }
 
diff --git a/osgi-featuremodel/src/main/java/org/osgi/feature/ArtifactID.java b/osgi-featuremodel/src/main/java/org/osgi/feature/ArtifactID.java
index bad55a5..3a2a8c3 100644
--- a/osgi-featuremodel/src/main/java/org/osgi/feature/ArtifactID.java
+++ b/osgi-featuremodel/src/main/java/org/osgi/feature/ArtifactID.java
@@ -40,6 +40,10 @@ public class ArtifactID {
         return new ArtifactID(gid, aid, ver, t, c);
     }
 
+    public ArtifactID(String groupId, String artifactId, String version) {
+        this(groupId, artifactId, version, null, null);
+    }
+
     public ArtifactID(String groupId, String artifactId, String version, String type, String classifier) {
         this.groupId = groupId;
         this.artifactId = artifactId;
@@ -84,4 +88,10 @@ public class ArtifactID {
                 && Objects.equals(groupId, other.groupId) && Objects.equals(type, other.type)
                 && Objects.equals(version, other.version);
     }
+
+    @Override
+    public String toString() {
+        return "ArtifactID [groupId=" + groupId + ", artifactId=" + artifactId + ", version=" + version + ", type=" + type
+                + ", classifier=" + classifier + "]";
+    }
 }
diff --git a/osgi-featuremodel/src/main/java/org/osgi/feature/Bundle.java b/osgi-featuremodel/src/main/java/org/osgi/feature/Bundle.java
index f80acee..735f27d 100644
--- a/osgi-featuremodel/src/main/java/org/osgi/feature/Bundle.java
+++ b/osgi-featuremodel/src/main/java/org/osgi/feature/Bundle.java
@@ -54,6 +54,11 @@ public class Bundle extends Artifact {
         return Objects.equals(metadata, other.metadata);
     }
 
+    @Override
+    public String toString() {
+        return "Bundle [metadata=" + metadata + ", getID()=" + getID() + "]";
+    }
+
     public static class Builder {
         private final ArtifactID id;
 
@@ -64,7 +69,7 @@ public class Bundle extends Artifact {
         }
 
         public Builder(String groupId, String artifactId, String version) {
-            this(new ArtifactID(groupId, artifactId, version, null, null));
+            this(new ArtifactID(groupId, artifactId, version));
         }
 
         public Builder addMetadata(String key, Object value) {
diff --git a/osgi-featuremodel/src/main/java/org/osgi/feature/FeatureService.java b/osgi-featuremodel/src/main/java/org/osgi/feature/FeatureService.java
index d1102cf..01e9862 100644
--- a/osgi-featuremodel/src/main/java/org/osgi/feature/FeatureService.java
+++ b/osgi-featuremodel/src/main/java/org/osgi/feature/FeatureService.java
@@ -37,5 +37,6 @@ public interface FeatureService {
      */
     void writeFeature(Feature feature, Writer jsonWriter) throws IOException;
 
-    Feature mergeFeatures(Feature f1, Feature f2);
+
+    Feature mergeFeatures(ArtifactID targetID, Feature f1, Feature f2, MergeContext ctx);
 }
diff --git a/osgi-featuremodel/src/main/java/org/osgi/feature/Artifact.java b/osgi-featuremodel/src/main/java/org/osgi/feature/MergeContext.java
similarity index 59%
copy from osgi-featuremodel/src/main/java/org/osgi/feature/Artifact.java
copy to osgi-featuremodel/src/main/java/org/osgi/feature/MergeContext.java
index 2841726..f45fbb5 100644
--- a/osgi-featuremodel/src/main/java/org/osgi/feature/Artifact.java
+++ b/osgi-featuremodel/src/main/java/org/osgi/feature/MergeContext.java
@@ -16,31 +16,10 @@
  */
 package org.osgi.feature;
 
-import java.util.Objects;
+import java.util.List;
 
-public class Artifact {
-    private final ArtifactID id;
+public interface MergeContext {
+    List<Bundle> resolveBundles(Bundle b1, Bundle b2);
 
-    protected Artifact(ArtifactID id) {
-        this.id = id;
-    }
-
-    public ArtifactID getId() {
-        return id;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hash(id);
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (!(obj instanceof Artifact))
-            return false;
-        Artifact other = (Artifact) obj;
-        return Objects.equals(id, other.id);
-    }
+    Configuration resolveConfigurations(Configuration c1, Configuration c2);
 }
diff --git a/osgi-featuremodel/src/main/java/org/osgi/feature/builder/MergeContextBuilder.java b/osgi-featuremodel/src/main/java/org/osgi/feature/builder/MergeContextBuilder.java
new file mode 100644
index 0000000..b0b2472
--- /dev/null
+++ b/osgi-featuremodel/src/main/java/org/osgi/feature/builder/MergeContextBuilder.java
@@ -0,0 +1,41 @@
+package org.osgi.feature.builder;
+
+import org.osgi.feature.Bundle;
+import org.osgi.feature.Configuration;
+import org.osgi.feature.MergeContext;
+
+import java.util.List;
+import java.util.function.BiFunction;
+
+public class MergeContextBuilder {
+    private BiFunction<Bundle, Bundle, List<Bundle>> bundleResolver;
+
+    public MergeContextBuilder setBundleResolver(BiFunction<Bundle, Bundle, List<Bundle>> bf) {
+        bundleResolver = bf;
+        return this;
+    }
+
+    public MergeContext build() {
+        return new MergeContextImpl(bundleResolver);
+    }
+
+    private static class MergeContextImpl implements MergeContext {
+        private BiFunction<Bundle, Bundle, List<Bundle>> bundleResolver;
+
+        private MergeContextImpl(BiFunction<Bundle, Bundle, List<Bundle>> bundleResolver) {
+            this.bundleResolver = bundleResolver;
+        }
+
+        @Override
+        public List<Bundle> resolveBundles(Bundle b1, Bundle b2) {
+            return bundleResolver.apply(b1, b2);
+        }
+
+        @Override
+        public Configuration resolveConfigurations(Configuration c1, Configuration c2) {
+            // TODO Auto-generated method stub
+            return null;
+        }
+
+    }
+}
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 2e5a61f..859fdac 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
@@ -21,11 +21,13 @@ import org.osgi.feature.Bundle;
 import org.osgi.feature.Feature;
 import org.osgi.feature.Feature.Builder;
 import org.osgi.feature.FeatureService;
+import org.osgi.feature.MergeContext;
 
 import java.io.IOException;
 import java.io.Reader;
 import java.io.Writer;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -102,9 +104,52 @@ public class FeatureServiceImpl implements FeatureService {
     }
 
     @Override
-    public Feature mergeFeatures(Feature f1, Feature f2) {
-        // TODO Auto-generated method stub
-        return null;
+    public Feature mergeFeatures(ArtifactID targetID, Feature f1, Feature f2, MergeContext ctx) {
+
+        Builder fb = new Feature.Builder(targetID);
+
+        copyAttrs(f1, fb);
+        copyAttrs(f2, fb);
+
+        List<Bundle> bundles = resolveBundles(f1, f2, ctx);
+        fb.addBundles(bundles.toArray(new Bundle[0]));
+
+        return fb.build();
     }
 
+    private List<Bundle> resolveBundles(Feature f1, Feature f2, MergeContext ctx) {
+        List<Bundle> bundles = new ArrayList<>(f1.getBundles());
+        List<Bundle> addedBundles = new ArrayList<>();
+
+        for (Bundle b : f2.getBundles()) {
+            ArtifactID bID = b.getID();
+            for (Iterator<Bundle> it = bundles.iterator(); it.hasNext(); ) {
+                Bundle orgb = it.next();
+                ArtifactID orgID = orgb.getID();
+
+                if (bID.getGroupId().equals(orgID.getGroupId()) &&
+                        bID.getArtifactId().equals(orgID.getArtifactId())) {
+                    List<Bundle> res = new ArrayList<>(ctx.resolveBundles(b, orgb));
+                    if (res.contains(orgb)) {
+                        res.remove(orgb);
+                    } else {
+                        it.remove();
+                    }
+                    addedBundles.addAll(res);
+                }
+            }
+        }
+        return bundles;
+    }
+
+    private void copyAttrs(Feature f, Builder fb) {
+        fb.setTitle(f.getTitle());
+        fb.setDescription(f.getDescription());
+        fb.setVendor(f.getVendor());
+        fb.setLicense(f.getLicense());
+        fb.setLocation(f.getLocation());
+
+    }
+
+
 }
diff --git a/osgi-featuremodel/src/test/java/org/apache/sling/feature/osgi/FeatureServiceImplTest.java b/osgi-featuremodel/src/test/java/org/osgi/feature/impl/FeatureServiceImplTest.java
similarity index 64%
rename from osgi-featuremodel/src/test/java/org/apache/sling/feature/osgi/FeatureServiceImplTest.java
rename to osgi-featuremodel/src/test/java/org/osgi/feature/impl/FeatureServiceImplTest.java
index b5e4b4f..f416a05 100644
--- a/osgi-featuremodel/src/test/java/org/apache/sling/feature/osgi/FeatureServiceImplTest.java
+++ b/osgi-featuremodel/src/test/java/org/osgi/feature/impl/FeatureServiceImplTest.java
@@ -14,18 +14,22 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package org.apache.sling.feature.osgi;
+package org.osgi.feature.impl;
 
 import org.junit.Test;
+import org.osgi.feature.ArtifactID;
 import org.osgi.feature.Bundle;
 import org.osgi.feature.Feature;
 import org.osgi.feature.FeatureService;
+import org.osgi.feature.MergeContext;
+import org.osgi.feature.builder.MergeContextBuilder;
 import org.osgi.feature.impl.FeatureServiceImpl;
 
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.net.URL;
+import java.util.Arrays;
 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
@@ -60,4 +64,34 @@ public class FeatureServiceImplTest {
             assertTrue(bundles.contains(new Bundle.Builder("org.slf4j", "slf4j-simple", "1.7.29").build()));
         }
     }
+
+    @Test
+    public void testMergeFeatures() throws IOException {
+        FeatureService fs = new FeatureServiceImpl();
+
+        URL res1 = getClass().getResource("/features/test-feature.json");
+        Feature f1;
+        try (Reader r = new InputStreamReader(res1.openStream())) {
+            f1 = fs.readFeature(r);
+        }
+
+        URL res2 = getClass().getResource("/features/test-feature.json");
+        Feature f2;
+        try (Reader r = new InputStreamReader(res2.openStream())) {
+            f2 = fs.readFeature(r);
+        }
+
+        MergeContext ctx = new MergeContextBuilder()
+                .setBundleResolver((b1, b2) -> Arrays.asList(b1, b2))
+                .build();
+        ArtifactID tid = new ArtifactID("foo", "bar", "1.2.3");
+        Feature f3 = fs.mergeFeatures(tid, f1, f2, ctx);
+        assertEquals(tid, f3.getID());
+
+        List<Bundle> bundles = f3.getBundles();
+        assertEquals(4, bundles.size());
+
+        assertTrue(bundles.contains(new Bundle.Builder("org.slf4j", "slf4j-api", "1.7.29").build()));
+        assertTrue(bundles.contains(new Bundle.Builder("org.slf4j", "slf4j-api", "1.7.30").build()));
+    }
 }
diff --git a/osgi-featuremodel/src/test/resources/features/test-feature2.json b/osgi-featuremodel/src/test/resources/features/test-feature2.json
new file mode 100644
index 0000000..3c3400c
--- /dev/null
+++ b/osgi-featuremodel/src/test/resources/features/test-feature2.json
@@ -0,0 +1,15 @@
+{
+    "id" : "org.apache.sling:test-feature2:1.1",
+    "description": "The feature description",
+
+    "bundles" :[
+            {
+              "id" : "org.slf4j:slf4j-api:1.7.30"
+            }
+    ],
+    "configurations" : {
+        "my.pid" : {
+           "bar" : "toast"
+        }
+    }
+}
\ No newline at end of file