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

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


The following commit(s) were added to refs/heads/master by this push:
     new f2f1bc2  SLING-6943 : Don't call into service registry from within a 
synchronized block
f2f1bc2 is described below

commit f2f1bc26fd40c4eadf0c77ad46c653f3dab0eb57
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Fri Nov 24 08:14:43 2017 +0100

    SLING-6943 : Don't call into service registry from within a synchronized 
block
---
 .../impl/providers/ResourceProviderTracker.java    | 184 ++++++++++++---------
 1 file changed, 107 insertions(+), 77 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderTracker.java
 
b/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderTracker.java
index 849b140..f524cbf 100644
--- 
a/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderTracker.java
+++ 
b/src/main/java/org/apache/sling/resourceresolver/impl/providers/ResourceProviderTracker.java
@@ -74,15 +74,17 @@ public class ResourceProviderTracker implements 
ResourceProviderStorageProvider
 
     private final Logger logger = LoggerFactory.getLogger(this.getClass());
 
-    private final Map<ServiceReference, ResourceProviderInfo> infos = new 
ConcurrentHashMap<ServiceReference, ResourceProviderInfo>();
+    @SuppressWarnings("rawtypes")
+    private final Map<ServiceReference<ResourceProvider>, 
ResourceProviderInfo> infos = new ConcurrentHashMap<>();
 
     private volatile BundleContext bundleContext;
 
-    private volatile ServiceTracker tracker;
+    @SuppressWarnings("rawtypes")
+    private volatile ServiceTracker<ResourceProvider, 
ServiceReference<ResourceProvider>> tracker;
 
-    private final Map<String, List<ResourceProviderHandler>> handlers = new 
HashMap<String, List<ResourceProviderHandler>>();
+    private final Map<String, List<ResourceProviderHandler>> handlers = new 
HashMap<>();
 
-    private final Map<ResourceProviderInfo, FailureReason> invalidProviders = 
new ConcurrentHashMap<ResourceProviderInfo, FailureReason>();
+    private final Map<ResourceProviderInfo, FailureReason> invalidProviders = 
new ConcurrentHashMap<>();
 
     private volatile EventAdmin eventAdmin;
 
@@ -94,17 +96,17 @@ public class ResourceProviderTracker implements 
ResourceProviderStorageProvider
 
     private volatile ChangeListener listener;
 
+    @SuppressWarnings("rawtypes")
     public void activate(final BundleContext bundleContext, final EventAdmin 
eventAdmin, final ChangeListener listener) {
         this.bundleContext = bundleContext;
         this.eventAdmin = eventAdmin;
         this.listener = listener;
-        this.tracker = new ServiceTracker(bundleContext,
-                ResourceProvider.class.getName(),
-                new ServiceTrackerCustomizer() {
+        this.tracker = new ServiceTracker<>(bundleContext,
+                ResourceProvider.class,
+                new ServiceTrackerCustomizer<ResourceProvider, 
ServiceReference<ResourceProvider>>() {
 
             @Override
-            public void removedService(final ServiceReference reference, final 
Object service) {
-                final ServiceReference ref = (ServiceReference)service;
+            public void removedService(final 
ServiceReference<ResourceProvider> reference, final 
ServiceReference<ResourceProvider> ref) {
                 final ResourceProviderInfo info = infos.remove(ref);
                 if ( info != null ) {
                     Object pid = ref.getProperty(Constants.SERVICE_PID);
@@ -116,13 +118,13 @@ public class ResourceProviderTracker implements 
ResourceProviderStorageProvider
             }
 
             @Override
-            public void modifiedService(final ServiceReference reference, 
final Object service) {
+            public void modifiedService(final 
ServiceReference<ResourceProvider> reference, final 
ServiceReference<ResourceProvider> service) {
                 removedService(reference, service);
                 addingService(reference);
             }
 
             @Override
-            public Object addingService(final ServiceReference reference) {
+            public ServiceReference<ResourceProvider> addingService(final 
ServiceReference<ResourceProvider> reference) {
                 final ResourceProviderInfo info = new 
ResourceProviderInfo(reference);
                 infos.put(reference, info);
                 register(info);
@@ -166,35 +168,45 @@ public class ResourceProviderTracker implements 
ResourceProviderStorageProvider
     private void register(final ResourceProviderInfo info) {
         if ( info.isValid() ) {
            logger.debug("Registering new resource provider {}", info);
-           final List<ProviderEvent> events = new 
ArrayList<ResourceProviderTracker.ProviderEvent>();
+           final List<ProviderEvent> events = new ArrayList<>();
            boolean providerAdded = false;
            ResourceProviderHandler deactivateHandler = null;
 
+           ResourceProviderHandler activate = null;
            synchronized ( this.handlers ) {
                List<ResourceProviderHandler> matchingHandlers = 
this.handlers.get(info.getPath());
                if ( matchingHandlers == null ) {
-                   matchingHandlers = new ArrayList<ResourceProviderHandler>();
+                   matchingHandlers = new ArrayList<>();
                    this.handlers.put(info.getPath(), matchingHandlers);
                }
                final ResourceProviderHandler handler = new 
ResourceProviderHandler(bundleContext, info);
                matchingHandlers.add(handler);
                Collections.sort(matchingHandlers);
                if ( matchingHandlers.get(0) == handler ) {
-                   if ( !this.activate(handler) ) {
-                       matchingHandlers.remove(handler);
-                       if ( matchingHandlers.isEmpty() ) {
-                           this.handlers.remove(info.getPath());
-                       }
-                   } else {
-                       providerAdded = true;
-                       events.add(new ProviderEvent(true, info));
-                       if ( matchingHandlers.size() > 1 ) {
+                   activate = handler;
+               }
+           }
+           if ( activate != null ) {
+               if ( this.activate(activate) ) {
+                   providerAdded = true;
+                   events.add(new ProviderEvent(true, info));
+                   synchronized ( this.handlers ) {
+                       storage = null;
+                       final List<ResourceProviderHandler> matchingHandlers = 
this.handlers.get(info.getPath());
+                       if ( matchingHandlers != null && 
matchingHandlers.size() > 1  ) {
                            deactivateHandler = matchingHandlers.get(1);
                        }
-                       storage = null;
+                   }
+               } else {
+                   synchronized ( this.handlers ) {
+                       final List<ResourceProviderHandler> matchingHandlers = 
this.handlers.get(info.getPath());
+                       if ( matchingHandlers != null && 
!matchingHandlers.isEmpty() && matchingHandlers.remove(activate) ) {
+                           storage = null;
+                       }
                    }
                }
            }
+
            final ChangeListener cl = this.listener;
            if ( providerAdded && cl != null ) {
                cl.providerAdded();
@@ -211,11 +223,11 @@ public class ResourceProviderTracker implements 
ResourceProviderStorageProvider
                                handlerInfo.getAuthType() != AuthType.no,
                                        deactivateHandler.isUsed());
                }
+               this.deactivate(deactivateHandler);
                synchronized ( this.handlers ) {
-                   this.deactivate(deactivateHandler);
-                   events.add(new ProviderEvent(false, handlerInfo));
                    storage = null;
                }
+               events.add(new ProviderEvent(false, handlerInfo));
            }
            this.postEvents(events);
         } else {
@@ -236,87 +248,103 @@ public class ResourceProviderTracker implements 
ResourceProviderStorageProvider
 
         if ( !isInvalid ) {
             logger.debug("Unregistering resource provider {}", info);
-            final List<ProviderEvent> events = new 
ArrayList<ResourceProviderTracker.ProviderEvent>();
+
+            // remove provider from handlers and if the provider is active 
(first handler)
+            // keep the reference for deactivation
             ResourceProviderHandler deactivateHandler = null;
             synchronized (this.handlers) {
                 final List<ResourceProviderHandler> matchingHandlers = 
this.handlers.get(info.getPath());
                 if ( matchingHandlers != null ) {
-                    final ResourceProviderHandler firstHandler = 
matchingHandlers.get(0);
-                    if ( firstHandler.getInfo() == info ) {
-                        deactivateHandler = firstHandler;
+                    final Iterator<ResourceProviderHandler> it = 
matchingHandlers.iterator();
+                    boolean first = true;
+                    while (it.hasNext()) {
+                        final ResourceProviderHandler h = it.next();
+                        if (h.getInfo() == info) {
+                            it.remove();
+                            if ( first ) {
+                                deactivateHandler = h;
+                            } else {
+                                h.dispose();
+                            }
+                            if (matchingHandlers.isEmpty()) {
+                                this.handlers.remove(info.getPath());
+                            }
+                            storage = null;
 
+                            break;
+                        }
+                        first = false;
                     }
                 }
             }
+
             if ( deactivateHandler != null ) {
+                final List<ProviderEvent> events = new ArrayList<>();
                 final ChangeListener cl = this.listener;
                 if ( cl != null ) {
                     cl.providerRemoved(info.getName(), pid,
                             info.getAuthType() != AuthType.no,
                                     deactivateHandler.isUsed());
                 }
-                boolean providerAdded = false;
-                synchronized ( this.handlers ) {
-                    this.deactivate(deactivateHandler);
-                    storage = null;
+                this.deactivate(deactivateHandler);
+                deactivateHandler.dispose();
 
+                // check if we can activate another handler
+                ResourceProviderHandler addingProvider = null;
+                synchronized ( this.handlers ) {
                     final List<ResourceProviderHandler> matchingHandlers = 
this.handlers.get(info.getPath());
-                    if ( matchingHandlers != null && 
!matchingHandlers.isEmpty() ) {
-                        final ResourceProviderHandler firstHandler = 
matchingHandlers.get(0);
-                        boolean doActivateNext = firstHandler.getInfo() == 
info;
-
-                        if (removeHandlerByInfo(info, matchingHandlers)) {
-                            while (doActivateNext && 
!matchingHandlers.isEmpty()) {
-                                if (this.activate(matchingHandlers.get(0))) {
-                                    doActivateNext = false;
-                                    events.add(new ProviderEvent(true, 
matchingHandlers.get(0).getInfo()));
-                                    providerAdded = true;
-                                } else {
+                    if ( matchingHandlers != null ) {
+                        if ( matchingHandlers.isEmpty() ) {
+                            this.handlers.remove(info.getPath());
+                        } else {
+                            addingProvider = matchingHandlers.get(0);
+                        }
+                    }
+                }
+                boolean providerAdded = false;
+                while ( addingProvider != null ) {
+                    if (this.activate(addingProvider)) {
+                        events.add(new ProviderEvent(true, 
addingProvider.getInfo()));
+                        providerAdded = true;
+                        addingProvider = null;
+                        synchronized ( this.handlers ) {
+                            this.storage = null;
+                        }
+                    } else {
+                        synchronized ( this.handlers ) {
+                            final List<ResourceProviderHandler> 
matchingHandlers = this.handlers.get(info.getPath());
+                            if ( matchingHandlers != null && 
!matchingHandlers.isEmpty() ) {
+                                if ( matchingHandlers.get(0) == addingProvider 
) {
+                                    this.storage = null;
                                     matchingHandlers.remove(0);
+                                    addingProvider.dispose();
+                                    if ( matchingHandlers.isEmpty() ) {
+                                        this.handlers.remove(info.getPath());
+                                        addingProvider = null;
+                                    } else {
+                                        addingProvider = 
matchingHandlers.get(0);
+                                    }
                                 }
                             }
                         }
-                        if (matchingHandlers.isEmpty()) {
-                            this.handlers.remove(info.getPath());
-                        }
                     }
                 }
+
                 if ( providerAdded && cl != null ) {
                     if ( cl != null ) {
                         cl.providerAdded();
                     }
                 }
                 events.add(new ProviderEvent(false,info));
+                this.postEvents(events);
 
             }
-            this.postEvents(events);
         } else {
             logger.debug("Unregistering invalid resource provider {}", info);
         }
     }
 
     /**
-     * Search the info in the list of handlers.
-     * @param info The provider info
-     * @param infos The list of handlers
-     * @return {@code true} if the info got removed.
-     */
-    private boolean removeHandlerByInfo(final ResourceProviderInfo info, final 
List<ResourceProviderHandler> infos) {
-        Iterator<ResourceProviderHandler> it = infos.iterator();
-        boolean removed = false;
-        while (it.hasNext()) {
-            final ResourceProviderHandler h = it.next();
-            if (h.getInfo() == info) {
-                it.remove();
-                h.dispose();
-                removed = true;
-                break;
-            }
-        }
-        return removed;
-    }
-
-    /**
      * Activate a resource provider
      * @param handler The provider handler
      */
@@ -348,7 +376,7 @@ public class ResourceProviderTracker implements 
ResourceProviderStorageProvider
     private void postOSGiEvent(final ProviderEvent event) {
         final EventAdmin ea = this.eventAdmin;
         if ( ea != null ) {
-            final Dictionary<String, Object> eventProps = new 
Hashtable<String, Object>();
+            final Dictionary<String, Object> eventProps = new Hashtable<>();
             eventProps.put(SlingConstants.PROPERTY_PATH, event.path);
             if (event.pid != null) {
                 eventProps.put(Constants.SERVICE_PID, event.pid);
@@ -373,8 +401,8 @@ public class ResourceProviderTracker implements 
ResourceProviderStorageProvider
     }
 
     public void fill(final RuntimeDTO dto) {
-        final List<ResourceProviderDTO> dtos = new 
ArrayList<ResourceProviderDTO>();
-        final List<ResourceProviderFailureDTO> failures = new 
ArrayList<ResourceProviderFailureDTO>();
+        final List<ResourceProviderDTO> dtos = new ArrayList<>();
+        final List<ResourceProviderFailureDTO> failures = new ArrayList<>();
 
         synchronized ( this.handlers ) {
             for(final List<ResourceProviderHandler> handlers : 
this.handlers.values()) {
@@ -412,11 +440,13 @@ public class ResourceProviderTracker implements 
ResourceProviderStorageProvider
         if (result == null) {
             synchronized (this.handlers) {
                 if (storage == null) {
-                    final List<ResourceProviderHandler> handlerList = new 
ArrayList<ResourceProviderHandler>();
+                    final List<ResourceProviderHandler> handlerList = new 
ArrayList<>();
                     for (List<ResourceProviderHandler> list : 
handlers.values()) {
-                        ResourceProviderHandler h  = list.get(0);
-                        if (h != null) {
-                            handlerList.add(h);
+                        if ( !list.isEmpty() ) {
+                            final ResourceProviderHandler h = list.get(0);
+                            if (h != null && h.getResourceProvider() != null ) 
{
+                                handlerList.add(h);
+                            }
                         }
                     }
                     storage = new ResourceProviderStorage(handlerList);
@@ -449,7 +479,7 @@ public class ResourceProviderTracker implements 
ResourceProviderStorageProvider
     }
 
     private void updateProviderContext(final ResourceProviderHandler handler) {
-        final Set<String> excludedPaths = new HashSet<String>();
+        final Set<String> excludedPaths = new HashSet<>();
         final Path handlerPath = new Path(handler.getPath());
         for(final String otherPath : handlers.keySet()) {
             if ( !handler.getPath().equals(otherPath) && 
handlerPath.matches(otherPath) ) {

-- 
To stop receiving notification emails like this one, please contact
['"[email protected]" <[email protected]>'].

Reply via email to