You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2013/01/31 17:56:17 UTC

svn commit: r1441061 - /sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java

Author: cziegeler
Date: Thu Jan 31 16:56:17 2013
New Revision: 1441061

URL: http://svn.apache.org/viewvc?rev=1441061&view=rev
Log:
SLING-2719 : Deadlock in ResourceResolverFactoryActivator.checkFactoryPreconditions

Modified:
    sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java

Modified: sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java?rev=1441061&r1=1441060&r2=1441061&view=diff
==============================================================================
--- sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java (original)
+++ sling/trunk/bundles/resourceresolver/src/main/java/org/apache/sling/resourceresolver/impl/ResourceResolverFactoryActivator.java Thu Jan 31 16:56:17 2013
@@ -75,6 +75,15 @@ import org.osgi.service.event.EventAdmin
     @Reference(name = "ResourceDecorator", referenceInterface = ResourceDecorator.class, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE, policy = ReferencePolicy.DYNAMIC) })
 public class ResourceResolverFactoryActivator {
 
+    private static final class FactoryRegistration {
+
+        /** Registered resource resolver factory. */
+        public volatile ResourceResolverFactoryImpl factory;
+
+        /** Registration .*/
+        public volatile ServiceRegistration factoryRegistration;
+    }
+
     @Property(value = { "/apps", "/libs" })
     public static final String PROP_PATH = "resource.resolver.searchpath";
 
@@ -86,7 +95,7 @@ public class ResourceResolverFactoryActi
      * Mangling means that any namespace prefix contained in the path is replaced as per the generic
      * substitution pattern <code>/([^:]+):/_$1_/</code> when calling the <code>map</code> method of
      * the resource resolver. Likewise the <code>resolve</code> methods will unmangle such namespace
-     * prefixes according to the substituation pattern <code>/_([^_]+)_/$1:/</code>.
+     * prefixes according to the substitution pattern <code>/_([^_]+)_/$1:/</code>.
      * <p>
      * This feature is provided since there may be systems out there in the wild which cannot cope
      * with URLs containing colons, even though they are perfectly valid characters in the path part
@@ -105,7 +114,7 @@ public class ResourceResolverFactoryActi
     private static final String PROP_REQUIRED_PROVIDERS = "resource.resolver.required.providers";
 
     /**
-     * The resolver.virtual property has no default configuration. But the sling
+     * The resolver.virtual property has no default configuration. But the Sling
      * maven plugin and the sling management console cannot handle empty
      * multivalue properties at the moment. So we just add a dummy direct
      * mapping.
@@ -128,7 +137,7 @@ public class ResourceResolverFactoryActi
     /** all mappings */
     private Mapping[] mappings;
 
-    /** The fake urls */
+    /** The fake URLs */
     private BidiMap virtualURLMap;
 
     /** <code>true</code>, if direct mappings from URI to handle are allowed */
@@ -150,19 +159,16 @@ public class ResourceResolverFactoryActi
     @Reference
     private EventAdmin eventAdmin;
 
-    /** Registered resource resolver factory. */
-    private ResourceResolverFactoryImpl factory;
-
-    /** Registration .*/
-    private ServiceRegistration factoryRegistration;
-
     /** ComponentContext */
-    private ComponentContext componentContext;
+    private volatile ComponentContext componentContext;
 
     private int defaultVanityPathRedirectStatus;
 
     private final FactoryPreconditions preconds = new FactoryPreconditions();
 
+    /** Factory registration. */
+    private volatile FactoryRegistration factoryRegistration;
+
     /**
      * Get the resource decorator tracker.
      */
@@ -272,7 +278,8 @@ public class ResourceResolverFactoryActi
         // the root of the resolver mappings
         mapRoot = PropertiesUtil.toString(properties.get(PROP_MAP_LOCATION), MapEntries.DEFAULT_MAP_ROOT);
 
-        defaultVanityPathRedirectStatus = PropertiesUtil.toInteger(properties.get(PROP_DEFAULT_VANITY_PATH_REDIRECT_STATUS), MapEntries.DEFAULT_DEFAULT_VANITY_PATH_REDIRECT_STATUS);
+        defaultVanityPathRedirectStatus = PropertiesUtil.toInteger(properties.get(PROP_DEFAULT_VANITY_PATH_REDIRECT_STATUS),
+                                                                   MapEntries.DEFAULT_DEFAULT_VANITY_PATH_REDIRECT_STATUS);
 
         final BundleContext bc = componentContext.getBundleContext();
 
@@ -283,7 +290,7 @@ public class ResourceResolverFactoryActi
     }
 
     /**
-     * Deativates this component (called by SCR to take out of service)
+     * Deactivates this component (called by SCR to take out of service)
      */
     @Deactivate
     protected void deactivate() {
@@ -292,47 +299,82 @@ public class ResourceResolverFactoryActi
         this.rootProviderEntry.setEventAdmin(null);
         this.resourceDecoratorTracker.close();
 
+        this.unregisterFactory();
+    }
+
+    /**
+     * Unregister the factory (if registered)
+     */
+    private void unregisterFactory() {
+        FactoryRegistration local = null;
         synchronized ( this ) {
-            this.unregisterFactory();
+            if ( this.factoryRegistration != null ) {
+                local = this.factoryRegistration;
+                this.factoryRegistration = null;
+            }
         }
+        this.unregisterFactory(local);
     }
 
-    private void unregisterFactory() {
-        if ( this.factoryRegistration != null ) {
-            final ServiceRegistration local = this.factoryRegistration;
-            this.factoryRegistration = null;
-            local.unregister();
+    /**
+     * Unregister the provided factory
+     */
+    private void unregisterFactory(final FactoryRegistration local) {
+        if ( local != null ) {
+            if ( local.factoryRegistration != null ) {
+                local.factoryRegistration.unregister();
+            }
+            if ( local.factory != null ) {
+                local.factory.deactivate();
+            }
+        }
+    }
+
+    /**
+     * Try to register the factory.
+     */
+    private void registerFactory(final ComponentContext localContext) {
+        FactoryRegistration local = null;
+        synchronized ( this ) {
+            if ( this.factoryRegistration == null ) {
+                this.factoryRegistration = new FactoryRegistration();
+                local = this.factoryRegistration;
+            }
         }
-        if ( this.factory != null ) {
-            final ResourceResolverFactoryImpl local = this.factory;
-            this.factory = null;
-            local.deactivate();
+        if ( local != null ) {
+            // activate and register factory
+            local.factory = new ResourceResolverFactoryImpl(this);
+            local.factory.activate(localContext.getBundleContext());
+            final Dictionary<String, Object> serviceProps = new Hashtable<String, Object>();
+            serviceProps.put(Constants.SERVICE_VENDOR, localContext.getProperties().get(Constants.SERVICE_VENDOR));
+            serviceProps.put(Constants.SERVICE_DESCRIPTION, localContext.getProperties().get(Constants.SERVICE_DESCRIPTION));
+
+            local.factoryRegistration = localContext.getBundleContext().registerService(ResourceResolverFactory.class.getName(),
+                    local.factory, serviceProps);
+            // check if an unregister happened in between
+            boolean doUnregister = false;
+            synchronized ( this ) {
+                if ( this.factoryRegistration != local ) {
+                    doUnregister = true;
+                }
+            }
+            if ( doUnregister ) {
+                this.unregisterFactory(local);
+            }
         }
     }
 
+    /**
+     * Check the preconditions and if it changed, either register factory or unregister
+     */
     private void checkFactoryPreconditions() {
-        if ( this.componentContext != null ) {
+        final ComponentContext localContext = this.componentContext;
+        if ( localContext != null ) {
             final boolean result = this.preconds.checkPreconditions();
             if ( result ) {
-                synchronized ( this ) {
-                    if ( factory == null ) {
-                        // register factory
-                        this.factory = new ResourceResolverFactoryImpl(this);
-                        this.factory.activate(this.componentContext.getBundleContext());
-                        final Dictionary<String, Object> serviceProps = new Hashtable<String, Object>();
-                        serviceProps.put(Constants.SERVICE_VENDOR, this.componentContext.getProperties().get(Constants.SERVICE_VENDOR));
-                        serviceProps.put(Constants.SERVICE_DESCRIPTION, this.componentContext.getProperties().get(Constants.SERVICE_DESCRIPTION));
-
-                        this.factoryRegistration = this.componentContext.getBundleContext().registerService(ResourceResolverFactory.class.getName(),
-                                        factory, serviceProps);
-                    }
-                }
+                this.registerFactory(localContext);
             } else {
-                synchronized ( this ) {
-                    if ( factory != null ) {
-                        this.unregisterFactory();
-                    }
-                }
+                this.unregisterFactory();
             }
         }
     }