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 2018/07/10 10:59:22 UTC

[sling-whiteboard] branch master updated: Update Features service API and extend the whitelist unit tests

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 03e429e  Update Features service API and extend the whitelist unit tests
03e429e is described below

commit 03e429e3035e9e9db5a5f5332217c9d0d90ea14c
Author: David Bosschaert <da...@gmail.com>
AuthorDate: Tue Jul 10 11:58:57 2018 +0100

    Update Features service API and extend the whitelist unit tests
---
 .../org/apache/sling/feature/service/Features.java |  4 +-
 .../feature/service/impl/FeatureServiceImpl.java   | 16 +++---
 .../service/impl/FeaturesServiceManager.java       | 44 +++++++++-------
 .../service/impl/FeatureServiceImplTest.java       | 19 ++++---
 .../feature/whitelist/impl/ResolverHookImpl.java   | 18 +++++--
 .../whitelist/impl/ResolverHookImplTest.java       | 60 ++++++++++++++--------
 6 files changed, 101 insertions(+), 60 deletions(-)

diff --git a/featuremodel/feature-service/src/main/java/org/apache/sling/feature/service/Features.java b/featuremodel/feature-service/src/main/java/org/apache/sling/feature/service/Features.java
index d1e91a6..46dd595 100644
--- a/featuremodel/feature-service/src/main/java/org/apache/sling/feature/service/Features.java
+++ b/featuremodel/feature-service/src/main/java/org/apache/sling/feature/service/Features.java
@@ -18,9 +18,11 @@
  */
 package org.apache.sling.feature.service;
 
+import org.osgi.framework.Version;
+
 import java.util.Collection;
 
 public interface Features {
     Collection<String> listFeatures();
-    String getFeatureForBundle(long bundleId);
+    String getFeatureForBundle(String bsn, Version ver);
 }
diff --git a/featuremodel/feature-service/src/main/java/org/apache/sling/feature/service/impl/FeatureServiceImpl.java b/featuremodel/feature-service/src/main/java/org/apache/sling/feature/service/impl/FeatureServiceImpl.java
index f0fa389..03d2064 100644
--- a/featuremodel/feature-service/src/main/java/org/apache/sling/feature/service/impl/FeatureServiceImpl.java
+++ b/featuremodel/feature-service/src/main/java/org/apache/sling/feature/service/impl/FeatureServiceImpl.java
@@ -19,21 +19,21 @@
 package org.apache.sling.feature.service.impl;
 
 import org.apache.sling.feature.service.Features;
+import org.osgi.framework.Version;
 
+import java.util.AbstractMap;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
-public class FeatureServiceImpl implements Features {
+class FeatureServiceImpl implements Features {
     private final Set<String> features;
-    private final Map<Long, String> bundleFeatureMap;
+    private final Map<Map.Entry<String, Version>, String> bundleFeatureMap;
 
-    public FeatureServiceImpl(Map<Long, String> bundleIDFeatures) {
-        Map<Long, String> bfm = new HashMap<>(bundleIDFeatures);
-        bundleFeatureMap = Collections.unmodifiableMap(bfm);
+    FeatureServiceImpl(Map<Map.Entry<String, Version>, String> bundleIDFeatures) {
+        bundleFeatureMap = Collections.unmodifiableMap(bundleIDFeatures);
 
         Set<String> fs = new HashSet<>(bundleIDFeatures.values());
         features = Collections.unmodifiableSet(fs);
@@ -45,7 +45,7 @@ public class FeatureServiceImpl implements Features {
     }
 
     @Override
-    public String getFeatureForBundle(long bundleId) {
-        return bundleFeatureMap.get(bundleId);
+    public String getFeatureForBundle(String bsn, Version version) {
+        return bundleFeatureMap.get(new AbstractMap.SimpleEntry<String, Version>(bsn, version));
     }
 }
diff --git a/featuremodel/feature-service/src/main/java/org/apache/sling/feature/service/impl/FeaturesServiceManager.java b/featuremodel/feature-service/src/main/java/org/apache/sling/feature/service/impl/FeaturesServiceManager.java
index 4925bbb..e4492c9 100644
--- a/featuremodel/feature-service/src/main/java/org/apache/sling/feature/service/impl/FeaturesServiceManager.java
+++ b/featuremodel/feature-service/src/main/java/org/apache/sling/feature/service/impl/FeaturesServiceManager.java
@@ -19,16 +19,19 @@
 package org.apache.sling.feature.service.impl;
 
 import org.apache.sling.feature.service.Features;
-import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.Version;
 import org.osgi.service.cm.ConfigurationException;
 import org.osgi.service.cm.ManagedService;
 
+import java.util.AbstractMap;
 import java.util.Collection;
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.HashMap;
+import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.Map;
 
@@ -42,36 +45,40 @@ class FeaturesServiceManager implements ManagedService {
 
     @Override
     public synchronized void updated(Dictionary<String, ?> properties) throws ConfigurationException {
-        System.out.println("######******* Updated " + properties);
         if (reg != null)
             reg.unregister();
 
         if (properties == null)
             return;
 
-        Map<String, Long> bsnVerToID = getBundleToID();
-
-        Map<Long, String> bundleIDFeatures = new HashMap<>();
+        Map<Map.Entry<String, Version>, String> bundleIDFeatures = new HashMap<>();
+        Dictionary<String, String> props = new Hashtable<>();
         for(Enumeration<String> e = properties.keys(); e.hasMoreElements(); ) {
             String key = e.nextElement();
-            Long bid = bsnVerToID.get(key);
-            if (bid != null) {
-                bundleIDFeatures.put(bid, getStringPlus(properties.get(key)));
-            }
-        }
+            if (key.startsWith("."))
+                continue;
 
-        FeatureServiceImpl fs = new FeatureServiceImpl(bundleIDFeatures);
-        reg = bundleContext.registerService(Features.class, fs, null);
-    }
+            if (Constants.SERVICE_PID.equals(key))
+                continue;
 
-    private Map<String, Long> getBundleToID() {
-        Map<String, Long> m = new HashMap<>();
+            String[] bsnver = key.split(":");
+            if (bsnver.length != 2)
+                continue;
 
-        for (Bundle b : bundleContext.getBundles()) {
-            m.put(b.getSymbolicName() + ":" + b.getVersion(), b.getBundleId());
+            try {
+                Version ver = Version.valueOf(bsnver[1]);
+
+                String value = getStringPlus(properties.get(key));
+                AbstractMap.SimpleEntry<String, Version> newKey = new AbstractMap.SimpleEntry<>(bsnver[0], ver);
+                bundleIDFeatures.put(newKey, value);
+                props.put(key, value);
+            } catch (IllegalArgumentException iae) {
+                // TODO log
+            }
         }
 
-        return m;
+        FeatureServiceImpl fs = new FeatureServiceImpl(bundleIDFeatures);
+        reg = bundleContext.registerService(Features.class, fs, props);
     }
 
     private String getStringPlus(Object obj) {
@@ -85,4 +92,5 @@ class FeaturesServiceManager implements ManagedService {
         }
         return null;
     }
+
 }
diff --git a/featuremodel/feature-service/src/test/java/org/apache/sling/feature/service/impl/FeatureServiceImplTest.java b/featuremodel/feature-service/src/test/java/org/apache/sling/feature/service/impl/FeatureServiceImplTest.java
index 0a3ef0c..5b9a74a 100644
--- a/featuremodel/feature-service/src/test/java/org/apache/sling/feature/service/impl/FeatureServiceImplTest.java
+++ b/featuremodel/feature-service/src/test/java/org/apache/sling/feature/service/impl/FeatureServiceImplTest.java
@@ -20,9 +20,12 @@ package org.apache.sling.feature.service.impl;
 
 import org.apache.sling.feature.service.Features;
 import org.junit.Test;
+import org.osgi.framework.Version;
 
+import java.util.AbstractMap;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Map.Entry;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
@@ -30,21 +33,21 @@ import static org.junit.Assert.assertNull;
 public class FeatureServiceImplTest {
     @Test
     public void testFeatureService() {
-        Map<Long, String> bif = new HashMap<>();
+        Map<Entry<String, Version>, String> bif = new HashMap<>();
 
         String f1 = "gid:aid:1.0.0:myfeature:slingfeature";
-        bif.put(123L, f1);
-        bif.put(456L, f1);
+        bif.put(new AbstractMap.SimpleEntry<String,Version>("mybsn", new Version(1,2,3)), f1);
+        bif.put(new AbstractMap.SimpleEntry<String,Version>("mybsn2", new Version(4,5,6)), f1);
 
         String f2 = "gid:aid2:1.0.0";
-        bif.put(789L, f2);
+        bif.put(new AbstractMap.SimpleEntry<String,Version>("mybsn", new Version(7,8,9)), f2);
 
         Features fs = new FeatureServiceImpl(bif);
         assertEquals(2, fs.listFeatures().size());
 
-        assertEquals(f1, fs.getFeatureForBundle(123));
-        assertEquals(f1, fs.getFeatureForBundle(456));
-        assertEquals(f2, fs.getFeatureForBundle(789));
-        assertNull(fs.getFeatureForBundle(999));
+        assertEquals(f1, fs.getFeatureForBundle("mybsn", new Version(1,2,3)));
+        assertEquals(f1, fs.getFeatureForBundle("mybsn2", new Version(4,5,6)));
+        assertEquals(f2, fs.getFeatureForBundle("mybsn", new Version(7,8,9)));
+        assertNull(fs.getFeatureForBundle("mybsn2", new Version(1,2,3)));
     }
 }
diff --git a/featuremodel/feature-whitelist/src/main/java/org/apache/sling/feature/whitelist/impl/ResolverHookImpl.java b/featuremodel/feature-whitelist/src/main/java/org/apache/sling/feature/whitelist/impl/ResolverHookImpl.java
index 21a737a..eff6353 100644
--- a/featuremodel/feature-whitelist/src/main/java/org/apache/sling/feature/whitelist/impl/ResolverHookImpl.java
+++ b/featuremodel/feature-whitelist/src/main/java/org/apache/sling/feature/whitelist/impl/ResolverHookImpl.java
@@ -20,6 +20,8 @@ package org.apache.sling.feature.whitelist.impl;
 
 import org.apache.sling.feature.service.Features;
 import org.apache.sling.feature.whitelist.WhitelistService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
 import org.osgi.framework.hooks.resolver.ResolverHook;
 import org.osgi.framework.namespace.PackageNamespace;
 import org.osgi.framework.wiring.BundleCapability;
@@ -59,7 +61,10 @@ class ResolverHookImpl implements ResolverHook {
         if (!PackageNamespace.PACKAGE_NAMESPACE.equals(requirement.getNamespace()))
             return;
 
-        long reqBundleID = requirement.getRevision().getBundle().getBundleId();
+        Bundle reqBundle = requirement.getRevision().getBundle();
+        long reqBundleID = reqBundle.getBundleId();
+        String reqBundleName = reqBundle.getSymbolicName();
+        Version reqBundleVersion = reqBundle.getVersion();
 
         try {
             Features fs = featureServiceTracker.waitForService(SERVICE_WAIT_TIMEOUT);
@@ -70,7 +75,7 @@ class ResolverHookImpl implements ResolverHook {
                 return;
             }
 
-            String reqFeat = fs.getFeatureForBundle(reqBundleID);
+            String reqFeat = fs.getFeatureForBundle(reqBundleName, reqBundleVersion);
             Set<String> regions = whitelistService.listRegions(reqFeat);
 
             nextCapability:
@@ -80,17 +85,20 @@ class ResolverHookImpl implements ResolverHook {
                 BundleRevision rev = bc.getRevision();
 
                 // A bundle is allowed to wire to itself
-                long capBundleID = rev.getBundle().getBundleId();
+                Bundle capBundle = rev.getBundle();
+                long capBundleID = capBundle.getBundleId();
                 if (capBundleID == reqBundleID)
                     continue nextCapability;
 
-                String capFeat = fs.getFeatureForBundle(capBundleID);
+                String capBundleName = capBundle.getSymbolicName();
+                Version capBundleVersion = capBundle.getVersion();
+
+                String capFeat = fs.getFeatureForBundle(capBundleName, capBundleVersion);
 
                 // Within a single feature everything can wire to everything else
                 if (reqFeat.equals(capFeat))
                     continue nextCapability;
 
-
                 Object pkg = bc.getAttributes().get(PackageNamespace.PACKAGE_NAMESPACE);
                 if (pkg instanceof String) {
                     String packageName = (String) pkg;
diff --git a/featuremodel/feature-whitelist/src/test/java/org/apache/sling/feature/whitelist/impl/ResolverHookImplTest.java b/featuremodel/feature-whitelist/src/test/java/org/apache/sling/feature/whitelist/impl/ResolverHookImplTest.java
index eb36749..18ab601 100644
--- a/featuremodel/feature-whitelist/src/test/java/org/apache/sling/feature/whitelist/impl/ResolverHookImplTest.java
+++ b/featuremodel/feature-whitelist/src/test/java/org/apache/sling/feature/whitelist/impl/ResolverHookImplTest.java
@@ -23,6 +23,7 @@ import org.apache.sling.feature.whitelist.WhitelistService;
 import org.junit.Test;
 import org.mockito.Mockito;
 import org.osgi.framework.Bundle;
+import org.osgi.framework.Version;
 import org.osgi.framework.namespace.PackageNamespace;
 import org.osgi.framework.wiring.BundleCapability;
 import org.osgi.framework.wiring.BundleRequirement;
@@ -48,11 +49,16 @@ public class ResolverHookImplTest {
     public void testFilterMatches() throws Exception {
         String f = "gid:aid:0.0.9";
         String f2 = "gid2:aid2:1.0.0-SNAPSHOT";
+        String f3 = "gid3:aid3:1.2.3";
+        String f4 = "gid4:aid4:1.2.3";
 
         Features fs = Mockito.mock(Features.class);
-        Mockito.when(fs.getFeatureForBundle(7)).thenReturn(f);
-        Mockito.when(fs.getFeatureForBundle(9)).thenReturn(f2);
-        Mockito.when(fs.getFeatureForBundle(10)).thenReturn(f2);
+        Mockito.when(fs.getFeatureForBundle("a.b.c", new Version(0,0,0))).thenReturn(f); // b7
+        Mockito.when(fs.getFeatureForBundle("some.other.bundle", new Version(9,9,9,"suffix"))).thenReturn(f2); // b9
+        Mockito.when(fs.getFeatureForBundle("a-bundle", new Version(1,0,0,"SNAPSHOT"))).thenReturn(f2); // b10
+        Mockito.when(fs.getFeatureForBundle("a.b.c", new Version(1,2,3))).thenReturn(f3); // b17
+        Mockito.when(fs.getFeatureForBundle("x.y.z", new Version(9,9,9))).thenReturn(f3); // b19
+        Mockito.when(fs.getFeatureForBundle("zzz", new Version(1,0,0))).thenReturn(f4); // b20
 
         ServiceTracker st = Mockito.mock(ServiceTracker.class);
         Mockito.when(st.waitForService(Mockito.anyLong())).thenReturn(fs);
@@ -61,57 +67,60 @@ public class ResolverHookImplTest {
         rpm.put("r0", Collections.singleton("org.bar"));
         rpm.put("r1", new HashSet<>(Arrays.asList("org.blah", "org.foo")));
         rpm.put(WhitelistService.GLOBAL_REGION, Collections.singleton("org.bar.tar"));
+        rpm.put("r3", Collections.singleton("xyz"));
 
         Map<String, Set<String>> frm = new HashMap<>();
         frm.put("gid:aid:0.0.9",
                 new HashSet<>(Arrays.asList("r1", "r2", WhitelistService.GLOBAL_REGION)));
         frm.put("gid2:aid2:1.0.0-SNAPSHOT", Collections.singleton("r2"));
+        frm.put("gid3:aid3:1.2.3", Collections.singleton("r3"));
+        frm.put("gid4:aid4:1.2.3", Collections.singleton("r3"));
 
         WhitelistService wls = new WhitelistServiceImpl(rpm, frm);
         ResolverHookImpl rh = new ResolverHookImpl(st, wls);
 
         // Check that we can get the capability from another bundle in the same region
         // Bundle 7 is in feature f with regions r1, r2
-        BundleRequirement req = mockRequirement(7);
-        BundleCapability bc1 = mockCapability("org.foo", 19);
+        BundleRequirement req = mockRequirement(17, "a.b.c", new Version(1,2,3));
+        BundleCapability bc1 = mockCapability("org.foo", 19, "x.y.z", new Version(9,9,9));
         List<BundleCapability> candidates = new ArrayList<>(Arrays.asList(bc1));
         rh.filterMatches(req, candidates);
         assertEquals(Collections.singletonList(bc1), candidates);
 
         // Check that we cannot get the capability from another bundle in a different region
         // Bundle 9 is in feature f2 with region r2
-        BundleRequirement req2 = mockRequirement(9);
-        BundleCapability bc2 = mockCapability("org.bar", 17);
+        BundleRequirement req2 = mockRequirement(9, "some.other.bundle", new Version(9,9,9,"suffix"));
+        BundleCapability bc2 = mockCapability("org.bar", 17, "a.b.c", new Version(1,2,3));
         Collection<BundleCapability> c2 = new ArrayList<>(Arrays.asList(bc2));
         rh.filterMatches(req2, c2);
         assertEquals(0, c2.size());
 
         // Check that we can get the capability from the same bundle
-        BundleRequirement req3 = mockRequirement(9);
-        BundleCapability bc3 = mockCapability("org.bar", 9);
+        BundleRequirement req3 = mockRequirement(9, "some.other.bundle", new Version(9,9,9,"suffix"));
+        BundleCapability bc3 = mockCapability("org.bar", 9, "some.other.bundle", new Version(9,9,9,"suffix"));
         Collection<BundleCapability> c3 = new ArrayList<>(Arrays.asList(bc3));
         rh.filterMatches(req3, c3);
         assertEquals(Collections.singletonList(bc3), c3);
 
         // Check that we can get the capability from the another bundle in the same feature
-        BundleRequirement req4 = mockRequirement(9);
-        BundleCapability bc4 = mockCapability("org.bar", 10);
+        BundleRequirement req4 = mockRequirement(9, "some.other.bundle", new Version(9,9,9,"suffix"));
+        BundleCapability bc4 = mockCapability("org.bar", 10, "a-bundle", new Version(1,0,0,"SNAPSHOT"));
         Collection<BundleCapability> c4 = new ArrayList<>(Arrays.asList(bc4));
         rh.filterMatches(req4, c4);
         assertEquals(Collections.singletonList(bc4), c4);
 
-        // Check that we cannot get the capability from another bundle where the capability
+        // Check that we can get the capability from another bundle where the capability
         // is globally visible (from bundle 9, f2)
-        BundleRequirement req5 = mockRequirement(9);
-        BundleCapability bc5 = mockCapability("org.bar.tar", 17);
+        BundleRequirement req5 = mockRequirement(17, "a.b.c", new Version(1,2,3));
+        BundleCapability bc5 = mockCapability("org.bar.tar", 9, "some.other.bundle", new Version(9,9,9,"suffix"));
         Collection<BundleCapability> c5 = new ArrayList<>(Arrays.asList(bc5));
         rh.filterMatches(req5, c5);
         assertEquals(Collections.singletonList(bc5), c5);
 
-        // Check that we cannot get the capability from another bundle where the capability
+        // Check that we can get the capability from another bundle where the capability
         // is globally visible (from bundle 7, f)
-        BundleRequirement req6 = mockRequirement(7);
-        BundleCapability bc6 = mockCapability("org.bar.tar", 17);
+        BundleRequirement req6 = mockRequirement(7, "a.b.c", new Version(0,0,0));
+        BundleCapability bc6 = mockCapability("org.bar.tar", 17, "a.b.c", new Version(1,2,3));
         Collection<BundleCapability> c6 = new ArrayList<>(Arrays.asList(bc6));
         rh.filterMatches(req6, c6);
         assertEquals(Collections.singletonList(bc6), c6);
@@ -119,18 +128,27 @@ public class ResolverHookImplTest {
         // Check that capabilities in non-package namespaces are ignored
         BundleRequirement req7 = Mockito.mock(BundleRequirement.class);
         Mockito.when(req7.getNamespace()).thenReturn("some.other.namespace");
-        BundleCapability bc7 = mockCapability("org.bar", 17);
+        BundleCapability bc7 = mockCapability("org.bar", 17, "a.b.c", new Version(1,2,3));
         Collection<BundleCapability> c7 = new ArrayList<>(Arrays.asList(bc7));
         rh.filterMatches(req7, c7);
         assertEquals(Collections.singletonList(bc7), c7);
+
+        // Check that we can get the capability from another provider in the same region
+        BundleRequirement req8 = mockRequirement(20, "zzz", new Version(1,0,0));
+        BundleCapability bc8 = mockCapability("xyz", 19, "x.y.z", new Version(9,9,9));
+        Collection<BundleCapability> c8 = new ArrayList<>(Arrays.asList(bc8));
+        rh.filterMatches(req8, c8);
+        assertEquals(Collections.singletonList(bc8), c8);
     }
 
-    private BundleCapability mockCapability(String pkg, long bundleID) {
+    private BundleCapability mockCapability(String pkg, long bundleID, String bsn, Version version) {
         Map<String, Object> attrs =
                 Collections.singletonMap(PackageNamespace.PACKAGE_NAMESPACE, pkg);
 
         Bundle bundle = Mockito.mock(Bundle.class);
         Mockito.when(bundle.getBundleId()).thenReturn(bundleID);
+        Mockito.when(bundle.getSymbolicName()).thenReturn(bsn);
+        Mockito.when(bundle.getVersion()).thenReturn(version);
 
         BundleRevision br = Mockito.mock(BundleRevision.class);
         Mockito.when(br.getBundle()).thenReturn(bundle);
@@ -142,9 +160,11 @@ public class ResolverHookImplTest {
         return cap;
     }
 
-    private BundleRequirement mockRequirement(long bundleID) {
+    private BundleRequirement mockRequirement(long bundleID, String bsn, Version version) {
         Bundle bundle = Mockito.mock(Bundle.class);
         Mockito.when(bundle.getBundleId()).thenReturn(bundleID);
+        Mockito.when(bundle.getSymbolicName()).thenReturn(bsn);
+        Mockito.when(bundle.getVersion()).thenReturn(version);
 
         BundleRevision br = Mockito.mock(BundleRevision.class);
         Mockito.when(br.getBundle()).thenReturn(bundle);