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 10:13:55 UTC

[sling-org-apache-sling-serviceusermapper] 05/08: SLING-4312: Register an osgi service for each available service user

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

rombert pushed a commit to annotated tag org.apache.sling.serviceusermapper-1.1.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-serviceusermapper.git

commit eb2a1ce0a0683d4e119a4356bce49a6ff18a0a62
Author: Marius Petria <mp...@apache.org>
AuthorDate: Fri Feb 20 10:08:49 2015 +0000

    SLING-4312: Register an osgi service for each available service user
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/serviceusermapper@1661081 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml                                            |   4 +-
 .../serviceusermapping/ServiceUserMapping.java     |  41 ++++++++
 .../sling/serviceusermapping/impl/Mapping.java     |  45 +++++++-
 .../impl/ServiceUserMapperImpl.java                |  55 +++++++++-
 .../impl/ServiceUserMappingBundleFilter.java       |  94 +++++++++++++++++
 .../impl/ServiceUserMapperImplTest.java            | 114 ++++++++++++++++++++-
 6 files changed, 346 insertions(+), 7 deletions(-)

diff --git a/pom.xml b/pom.xml
index f6dd450..7327f9d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -97,6 +97,8 @@
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.core</artifactId>
+            <version>4.3.0</version>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
@@ -126,7 +128,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.commons.testing</artifactId>
-            <version>2.0.6</version>
+            <version>2.0.16</version>
             <scope>test</scope>
             <exclusions>
                 <!-- slf4j simple implementation logs INFO + higher to stdout (we don't want that behaviour) -->
diff --git a/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapping.java b/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapping.java
new file mode 100644
index 0000000..f841ddd
--- /dev/null
+++ b/src/main/java/org/apache/sling/serviceusermapping/ServiceUserMapping.java
@@ -0,0 +1,41 @@
+package org.apache.sling.serviceusermapping;
+
+import aQute.bnd.annotation.ProviderType;
+
+/**
+ * The <code>ServiceUserMapping</code> service can be used to retrieve an already registered service user mapping.
+ * A service reference targeting a service user mapping will be satisfied only when <code>ServiceUserMapper.getServiceUserID</code>
+ * will return the registered user ID in that bundle.
+ * For example setting the reference target to "(subServiceName=mySubService)"
+ * ensures that your component only starts when the subService is available. Trying to reference a sub service from a bundle
+ * for which it was not registered for will not work.
+ */
+@ProviderType
+public interface ServiceUserMapping {
+
+    /**
+     * The name of the osgi property holding the service name.
+     */
+    static String SERVICENAME = "serviceName";
+
+
+    /**
+     * The name of the osgi property holding the sub service name.
+     */
+    static String SUBSERVICENAME = "subServiceName";
+
+
+    /**
+     * Returns the service name for this mapping.
+     *
+     * @return The service name for this mapping.
+     */
+    String getServiceName();
+
+    /**
+     * Returns the sub service name for this mapping.
+     *
+     * @return The sub service name for this mapping. This can be {@code null} if no sub service name is configured for this mapping.
+     */
+    String getSubServiceName();
+}
diff --git a/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java b/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java
index 07ca263..4ff0fc1 100644
--- a/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java
+++ b/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java
@@ -18,11 +18,14 @@
  */
 package org.apache.sling.serviceusermapping.impl;
 
+import org.apache.sling.serviceusermapping.ServiceUserMapping;
+
 /**
  * The <code>Mapping</code> class defines the mapping of a service's name and
  * optional service information to a user name.
  */
-class Mapping {
+class Mapping implements ServiceUserMapping, Comparable<Mapping> {
+
 
     private final String serviceName;
 
@@ -93,4 +96,44 @@ class Mapping {
         return "Mapping [serviceName=" + serviceName + ", subServiceName="
                 + subServiceName + ", userName=" + userName + "]";
     }
+
+    public String getServiceName() {
+        return serviceName;
+    }
+
+    public String getSubServiceName() {
+        return subServiceName;
+    }
+
+
+    public int compareTo(Mapping o) {
+        if (o == null) {
+            return -1;
+        }
+
+        int result = compare(this.serviceName, o.serviceName);
+        if (result == 0) {
+            result = compare(this.subServiceName, o.subServiceName);
+            if (result == 0) {
+                result = compare(this.userName, o.userName);
+            }
+        }
+        return result;
+    }
+
+    private int compare(String str1, String str2) {
+        if (str1 == str2) {
+            return 0;
+        }
+
+        if (str1 == null) {
+            return -1;
+        }
+
+        if (str2 == null) {
+            return 1;
+        }
+
+        return str1.hashCode() - str2.hashCode();
+    }
 }
diff --git a/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java b/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java
index 914a642..86acf39 100644
--- a/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java
+++ b/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java
@@ -19,11 +19,19 @@
 package org.apache.sling.serviceusermapping.impl;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.Dictionary;
 import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Vector;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
 
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
@@ -38,8 +46,12 @@ import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.commons.osgi.PropertiesUtil;
 import org.apache.sling.serviceusermapping.ServiceUserMapper;
 import org.apache.sling.serviceusermapping.ServiceUserValidator;
+import org.apache.sling.serviceusermapping.ServiceUserMapping;
 import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.framework.hooks.service.ListenerHook;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -95,9 +107,14 @@ public class ServiceUserMapperImpl implements ServiceUserMapper {
 
     private Vector <ServiceUserValidator> validators = new Vector<ServiceUserValidator>();
 
+    private SortedMap<Mapping, ServiceRegistration> activeMappingRegistrations = new TreeMap<Mapping, ServiceRegistration>();
+
+    private BundleContext bundleContext;
+
     @Activate
     @Modified
-    void configure(final Map<String, Object> config) {
+    void configure(BundleContext bundleContext, final Map<String, Object> config) {
+        this.bundleContext = bundleContext;
         final String[] props = PropertiesUtil.toStringArray(config.get(PROP_SERVICE2USER_MAPPING),
             PROP_SERVICE2USER_MAPPING_DEFAULT);
 
@@ -185,7 +202,43 @@ public class ServiceUserMapperImpl implements ServiceUserMapper {
                 mappings.add(m);
             }
         }
+
+
         activeMappings = mappings.toArray(new Mapping[mappings.size()]);
+
+        registerServiceMappings(mappings);
+
+    }
+
+
+    void registerServiceMappings(List<Mapping> newMappings) {
+
+        SortedSet<Mapping> orderedActiveMappings = new TreeSet<Mapping>(newMappings);
+
+
+        Iterator<Map.Entry<Mapping, ServiceRegistration>> it = activeMappingRegistrations.entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<Mapping, ServiceRegistration> registrationEntry = it.next();
+
+            if (!orderedActiveMappings.contains(registrationEntry.getKey())) {
+                registrationEntry.getValue().unregister();
+                it.remove();
+            }
+        }
+
+        if (bundleContext == null) {
+            return;
+        }
+
+        for (Mapping mapping: orderedActiveMappings) {
+            if (!activeMappingRegistrations.containsKey(mapping)) {
+                Dictionary<String, Object> properties = new Hashtable<String, Object>();
+                properties.put(ServiceUserMapping.SUBSERVICENAME, mapping.getSubServiceName() == null ? "" : mapping.getSubServiceName());
+                properties.put(ServiceUserMapping.SERVICENAME, mapping.getServiceName());
+                ServiceRegistration registration = bundleContext.registerService(ServiceUserMapping.class.getName(), mapping, properties);
+                activeMappingRegistrations.put(mapping, registration);
+            }
+        }
     }
 
     private String internalGetUserId(String serviceName, String subServiceName) {
diff --git a/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMappingBundleFilter.java b/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMappingBundleFilter.java
new file mode 100644
index 0000000..4300ee7
--- /dev/null
+++ b/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMappingBundleFilter.java
@@ -0,0 +1,94 @@
+/*
+ * 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.serviceusermapping.impl;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.serviceusermapping.ServiceUserMapping;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.hooks.service.EventListenerHook;
+import org.osgi.framework.hooks.service.FindHook;
+import org.osgi.framework.hooks.service.ListenerHook;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+@Component
+@Service(value = {EventListenerHook.class, FindHook.class} )
+/**
+ * The <code>ServiceUserMappingBundleFilter</code> only allows the bundle for which the service mapping is available to see it.
+ */
+public class ServiceUserMappingBundleFilter implements EventListenerHook, FindHook {
+
+    public void event(ServiceEvent serviceEvent, Map map) {
+
+        ServiceReference serviceReference = serviceEvent.getServiceReference();
+        if (isServiceMappingReference(serviceReference)) {
+            Object serviceName = serviceReference.getProperty(ServiceUserMapping.SERVICENAME);
+
+            if (serviceName != null && serviceName instanceof String) {
+                Iterator<Map.Entry<BundleContext, Collection<ListenerHook.ListenerInfo>>> it = map.entrySet().iterator();
+                while (it.hasNext()) {
+                    BundleContext ctx = it.next().getKey();
+
+                    String bundleName = ctx.getBundle().getSymbolicName();
+                    if (!serviceName.equals(bundleName)) {
+                        it.remove();
+                    }
+                }
+            }
+        }
+    }
+
+    public void find(BundleContext bundleContext, String name, String filter, boolean allServices,
+                     Collection references) {
+        String bundleName = bundleContext.getBundle().getSymbolicName();
+
+        Iterator<ServiceReference> it = references.iterator();
+        while (it.hasNext()) {
+            ServiceReference serviceReference = it.next();
+            if (isServiceMappingReference(serviceReference)) {
+                Object serviceName = serviceReference.getProperty(ServiceUserMapping.SERVICENAME);
+
+                if (serviceName != null && !serviceName.equals(bundleName)) {
+                    it.remove();
+                }
+            }
+        }
+    }
+
+    private static boolean isServiceMappingReference(ServiceReference serviceReference) {
+        Object objectClass = serviceReference.getProperty(Constants.OBJECTCLASS);
+        for (Object o :  (Object[]) objectClass) {
+            if (ServiceUserMapping.class.getName().equals(o)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+
+}
diff --git a/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java b/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java
index ca5ba7f..0b2243f 100644
--- a/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java
+++ b/src/test/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImplTest.java
@@ -18,6 +18,7 @@
  */
 package org.apache.sling.serviceusermapping.impl;
 
+import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
@@ -25,10 +26,15 @@ import java.util.Map;
 import junit.framework.TestCase;
 
 import org.apache.sling.commons.testing.osgi.MockBundle;
+import org.apache.sling.serviceusermapping.ServiceUserMapping;
 import org.apache.sling.serviceusermapping.ServiceUserValidator;
+import org.apache.sling.commons.testing.osgi.MockBundleContext;
 import org.junit.Test;
 import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
 import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
 
 public class ServiceUserMapperImplTest {
     private static final String BUNDLE_SYMBOLIC1 = "bundle1";
@@ -64,6 +70,7 @@ public class ServiceUserMapperImplTest {
         };
     };
 
+
     private static final Bundle BUNDLE2 = new MockBundle(10) {
         @Override
         public String getSymbolicName() {
@@ -76,6 +83,7 @@ public class ServiceUserMapperImplTest {
         };
     };
 
+
     @Test
     public void test_getServiceUserID() {
         @SuppressWarnings("serial")
@@ -92,7 +100,7 @@ public class ServiceUserMapperImplTest {
         };
 
         final ServiceUserMapperImpl sum = new ServiceUserMapperImpl();
-        sum.configure(config);
+        sum.configure(null, config);
 
         TestCase.assertEquals(SAMPLE, sum.getServiceUserID(BUNDLE1, null));
         TestCase.assertEquals(ANOTHER, sum.getServiceUserID(BUNDLE2, null));
@@ -118,7 +126,7 @@ public class ServiceUserMapperImplTest {
         };
 
         final ServiceUserMapperImpl sum = new ServiceUserMapperImpl();
-        sum.configure(config);
+        sum.configure(null, config);
         ServiceUserValidator serviceUserValidator = new ServiceUserValidator() {
             
             public boolean isValid(String serviceUserId, String serviceName,
@@ -153,7 +161,7 @@ public class ServiceUserMapperImplTest {
         };
 
         final ServiceUserMapperImpl sum = new ServiceUserMapperImpl();
-        sum.configure(config);
+        sum.configure(null, config);
         final MappingConfigAmendment mca1 = new MappingConfigAmendment();
         @SuppressWarnings("serial")
         final Map<String, Object> mca1Config = new HashMap<String, Object>() {
@@ -195,7 +203,7 @@ public class ServiceUserMapperImplTest {
         };
 
         final ServiceUserMapperImpl sum = new ServiceUserMapperImpl();
-        sum.configure(config);
+        sum.configure(null, config);
 
         final MappingConfigAmendment mca1 = new MappingConfigAmendment();
         @SuppressWarnings("serial")
@@ -221,4 +229,102 @@ public class ServiceUserMapperImplTest {
 
         TestCase.assertEquals(ANOTHER_SUB, sum.getServiceUserID(BUNDLE2, ""));
     }
+
+
+
+    @Test
+    public void test_amendmentServiceUserMapping() {
+        @SuppressWarnings("serial")
+        Map<String, Object> config = new HashMap<String, Object>() {
+            {
+                put("user.mapping", new String[] {
+                        BUNDLE_SYMBOLIC1 + "=" + SAMPLE, //
+                        BUNDLE_SYMBOLIC1 + ":" + SUB + "=" + SAMPLE_SUB, //
+                });
+                put("user.default", NONE);
+            }
+        };
+
+        final ServiceUserMapperImpl sum = new ServiceUserMapperImpl();
+        final ServiceRegistrationContext bundleContext = new ServiceRegistrationContext();
+        sum.configure(bundleContext, config);
+
+        TestCase.assertEquals(2, bundleContext.getRegistrations(ServiceUserMapping.class.getName()).size());
+
+        final MappingConfigAmendment mca1 = new MappingConfigAmendment();
+        @SuppressWarnings("serial")
+        final Map<String, Object> mca1Config = new HashMap<String, Object>() {
+            {
+                put("user.mapping", new String [] {BUNDLE_SYMBOLIC2 + "=" + ANOTHER});
+                put(Constants.SERVICE_ID, 1L);
+                put(Constants.SERVICE_RANKING, 100);
+            }
+        };
+        mca1.configure(mca1Config);
+        sum.bindAmendment(mca1, mca1Config);
+
+        TestCase.assertEquals(3, bundleContext.getRegistrations(ServiceUserMapping.class.getName()).size());
+
+        final MappingConfigAmendment mca2 = new MappingConfigAmendment();
+        @SuppressWarnings("serial")
+        final Map<String, Object> mca2Config = new HashMap<String, Object>() {
+            {
+                put("user.mapping", new String [] {BUNDLE_SYMBOLIC2 + ":" + SUB + "=" + ANOTHER_SUB});
+                put(Constants.SERVICE_ID, 2L);
+                put(Constants.SERVICE_RANKING, 200);
+            }
+        };
+        mca2.configure(mca2Config);
+        sum.bindAmendment(mca2, mca2Config);
+
+        TestCase.assertEquals(4, bundleContext.getRegistrations(ServiceUserMapping.class.getName()).size());
+
+        sum.unbindAmendment(mca1, mca1Config);
+
+        TestCase.assertEquals(3, bundleContext.getRegistrations(ServiceUserMapping.class.getName()).size());
+    }
+
+
+    private class ServiceRegistrationContext extends MockBundleContext {
+
+
+
+        final Map<String, Map<Object, Dictionary>> registrations = new HashMap<String, Map<Object, Dictionary>>();
+
+        public ServiceRegistrationContext() {
+            super(null);
+        }
+
+        @Override
+        public ServiceRegistration registerService(String string, Object o, Dictionary dictionary) {
+            if (!registrations.containsKey(string)) {
+                registrations.put(string, new HashMap<Object, Dictionary>());
+            }
+            final Map<Object, Dictionary> serviceRegistrations = registrations.get(string);
+            serviceRegistrations.put(o, dictionary);
+
+            final Object registeredObject = o;
+
+
+            return new ServiceRegistration() {
+                public ServiceReference getReference() {
+                    return null;
+                }
+
+                public void setProperties(Dictionary dictionary) {
+
+                }
+
+                public void unregister() {
+                    serviceRegistrations.remove(registeredObject);
+                }
+            };
+        }
+
+        public Map<Object, Dictionary> getRegistrations(String name) {
+            return registrations.get(name);
+        }
+
+    }
+
 }

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.