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();
}
}
}