Author: mpetria
Date: Thu Aug 13 13:16:49 2015
New Revision: 1695707

URL: http://svn.apache.org/r1695707
Log:
SLING-4895: Service registry should not be called from within synchronized block

Modified:
    
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java
    
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java

Modified: 
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java?rev=1695707&r1=1695706&r2=1695707&view=diff
==============================================================================
--- 
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java
 (original)
+++ 
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/Mapping.java
 Thu Aug 13 13:16:49 2015
@@ -117,9 +117,6 @@ class Mapping implements Comparable<Mapp
         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;
     }

Modified: 
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java?rev=1695707&r1=1695706&r2=1695707&view=diff
==============================================================================
--- 
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java
 (original)
+++ 
sling/trunk/bundles/extensions/serviceusermapper/src/main/java/org/apache/sling/serviceusermapping/impl/ServiceUserMapperImpl.java
 Thu Aug 13 13:16:49 2015
@@ -24,7 +24,6 @@ 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.SortedMap;
@@ -107,7 +106,7 @@ public class ServiceUserMapperImpl imple
 
     private final List<ServiceUserValidator> validators = new 
CopyOnWriteArrayList<ServiceUserValidator>();
 
-    private SortedMap<Mapping, ServiceRegistration> activeMappingRegistrations 
= new TreeMap<Mapping, ServiceRegistration>();
+    private SortedMap<Mapping, Registration> activeRegistrations = new 
TreeMap<Mapping, Registration>();
 
     private BundleContext bundleContext;
 
@@ -131,18 +130,26 @@ public class ServiceUserMapperImpl imple
 
         this.globalServiceUserMappings = mappings.toArray(new 
Mapping[mappings.size()]);
         this.defaultUser = 
PropertiesUtil.toString(config.get(PROP_DEFAULT_USER), 
PROP_DEFAULT_USER_DEFAULT);
+
+        RegistrationSet registrationSet = null;
         synchronized ( this.amendments ) {
             this.bundleContext = bundleContext;
-            this.updateMappings();
+            registrationSet = this.updateMappings();
         }
+
+        this.executeServiceRegistrations(registrationSet);
     }
 
     @Deactivate
     void deactivate() {
-        synchronized ( this.amendments) {
-            updateServiceMappings(new ArrayList<Mapping>());
+        RegistrationSet registrationSet = null;
+
+        synchronized ( this.amendments ) {
+            updateServiceRegistrations(new Mapping[0]);
             bundleContext = null;
         }
+
+        this.executeServiceRegistrations(registrationSet);
     }
 
     /**
@@ -173,27 +180,32 @@ public class ServiceUserMapperImpl imple
 
     protected void bindAmendment(final MappingConfigAmendment amendment, final 
Map<String, Object> props) {
         final Long key = (Long) props.get(Constants.SERVICE_ID);
+        RegistrationSet registrationSet = null;
         synchronized ( this.amendments ) {
             amendments.put(key, amendment);
-            this.updateMappings();
+            registrationSet = this.updateMappings();
         }
+
+        executeServiceRegistrations(registrationSet);
     }
 
     protected void unbindAmendment(final MappingConfigAmendment amendment, 
final Map<String, Object> props) {
         final Long key = (Long) props.get(Constants.SERVICE_ID);
+        RegistrationSet registrationSet = null;
         synchronized ( this.amendments ) {
             if ( amendments.remove(key) != null ) {
-                this.updateMappings();
+                registrationSet = this.updateMappings();
             }
         }
 
+        executeServiceRegistrations(registrationSet);
     }
 
     protected void updateAmendment(final MappingConfigAmendment amendment, 
final Map<String, Object> props) {
         this.bindAmendment(amendment, props);
     }
 
-    protected void updateMappings() {
+    protected RegistrationSet updateMappings() {
         final List<MappingConfigAmendment> sortedMappings = new 
ArrayList<MappingConfigAmendment>();
         for(final MappingConfigAmendment amendment : this.amendments.values() 
) {
             sortedMappings.add(amendment);
@@ -212,43 +224,94 @@ public class ServiceUserMapperImpl imple
 
         activeMappings = mappings.toArray(new Mapping[mappings.size()]);
 
-        updateServiceMappings(mappings);
+        RegistrationSet registrationSet = 
updateServiceRegistrations(activeMappings);
+
+        return registrationSet;
+
     }
 
 
-    void updateServiceMappings(final List<Mapping> newMappings) {
+    RegistrationSet updateServiceRegistrations(final Mapping[] newMappings) {
 
+        RegistrationSet result = new RegistrationSet();
         // do not do anything if not activated
         if (bundleContext == null) {
-            return;
+            return result;
         }
 
-        final SortedSet<Mapping> orderedActiveMappings = new 
TreeSet<Mapping>(newMappings);
+        final SortedSet<Mapping> orderedNewMappings = new 
TreeSet<Mapping>(Arrays.asList(newMappings));
+        final SortedMap<Mapping, Registration> newRegistrations = new 
TreeMap<Mapping, Registration>();
+
+        // keep those that are still mapped
+        for (Map.Entry<Mapping, Registration> registrationEntry: 
activeRegistrations.entrySet()) {
+            boolean keepEntry = true;
 
-        final Iterator<Map.Entry<Mapping, ServiceRegistration>> it = 
activeMappingRegistrations.entrySet().iterator();
-        while (it.hasNext()) {
-            final Map.Entry<Mapping, ServiceRegistration> registrationEntry = 
it.next();
+            if (!orderedNewMappings.contains(registrationEntry.getKey())) {
+                Registration registration = registrationEntry.getValue();
 
-            if (!orderedActiveMappings.contains(registrationEntry.getKey())) {
-                registrationEntry.getValue().unregister();
-                it.remove();
+                // remove it only if it is a completed registration
+                if (registration.serviceRegistration != null) {
+                    result.removed.add(registration);
+                    keepEntry = false;
+                }
+            }
+
+            if (keepEntry) {
+                newRegistrations.put(registrationEntry.getKey(), 
registrationEntry.getValue());
             }
         }
 
+        // add those that are new
+        for (final Mapping mapping: orderedNewMappings) {
+            if (!newRegistrations.containsKey(mapping)) {
+                Registration registration = new Registration(mapping, null);
+                newRegistrations.put(mapping, registration);
+                result.added.add(registration);
+            }
+        }
+
+        activeRegistrations = newRegistrations;
+
+        return result;
+    }
+
+    private void executeServiceRegistrations(RegistrationSet registrationSet) {
 
-        for (final Mapping mapping: orderedActiveMappings) {
-            if (!activeMappingRegistrations.containsKey(mapping)) {
-                final Dictionary<String, Object> properties = new 
Hashtable<String, Object>();
-                if (mapping.getSubServiceName() != null) {
-                    properties.put(ServiceUserMapped.SUBSERVICENAME, 
mapping.getSubServiceName());
+        if (registrationSet == null) {
+            return;
+        }
+
+        for (Registration registration : registrationSet.removed) {
+            if (registration.serviceRegistration != null) {
+                try {
+                    registration.serviceRegistration.unregister();
+                } catch (IllegalStateException e) {
+                    log.error("cannot unregister ServiceUserMapped {}", 
registration.mapping,  e);
                 }
+                registration.serviceRegistration = null;
+            }
+        }
+
+        BundleContext savedBundleContext = bundleContext;
+
+        if (savedBundleContext == null) {
+            return;
+        }
 
-                properties.put(Mapping.SERVICENAME, mapping.getServiceName());
-                final ServiceRegistration registration = 
bundleContext.registerService(ServiceUserMappedImpl.SERVICEUSERMAPPED,
-                        new ServiceUserMappedImpl(), properties);
-                activeMappingRegistrations.put(mapping, registration);
+        for (Registration registration : registrationSet.added) {
+            Mapping mapping = registration.mapping;
+            final Dictionary<String, Object> properties = new 
Hashtable<String, Object>();
+            if (mapping.getSubServiceName() != null) {
+                properties.put(ServiceUserMapped.SUBSERVICENAME, 
mapping.getSubServiceName());
             }
+
+            properties.put(Mapping.SERVICENAME, mapping.getServiceName());
+            final ServiceRegistration serviceRegistration = 
savedBundleContext.registerService(ServiceUserMappedImpl.SERVICEUSERMAPPED,
+                    new ServiceUserMappedImpl(), properties);
+
+            registration.serviceRegistration = serviceRegistration;
         }
+
     }
 
     private String internalGetUserId(final String serviceName, final String 
subServiceName) {
@@ -294,5 +357,20 @@ public class ServiceUserMapperImpl imple
     List<Mapping> getActiveMappings() {
         return Collections.unmodifiableList(Arrays.asList(activeMappings));
     }
+
+    class Registration {
+        private Mapping mapping;
+        private ServiceRegistration serviceRegistration;
+
+        Registration(Mapping mapping, ServiceRegistration serviceRegistration) 
{
+            this.mapping = mapping;
+            this.serviceRegistration = serviceRegistration;
+        }
+    }
+
+    class RegistrationSet {
+        List<Registration> added = new ArrayList<Registration>();
+        List<Registration> removed = new ArrayList<Registration>();
+    }
 }
 


Reply via email to