SLING-1694 : Instantiate adapter factories lazy

git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@989023 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/sling/adapter/internal/AdapterFactoryDescriptor.java b/src/main/java/org/apache/sling/adapter/internal/AdapterFactoryDescriptor.java
index 99fd459..fe64e9c 100644
--- a/src/main/java/org/apache/sling/adapter/internal/AdapterFactoryDescriptor.java
+++ b/src/main/java/org/apache/sling/adapter/internal/AdapterFactoryDescriptor.java
@@ -19,6 +19,8 @@
 package org.apache.sling.adapter.internal;
 
 import org.apache.sling.api.adapter.AdapterFactory;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.component.ComponentContext;
 
 /**
  * The <code>AdapterFactoryDescriptor</code> is an entry in the
@@ -26,22 +28,37 @@
  * types and the respective {@link AdapterFactory}.
  */
 public class AdapterFactoryDescriptor {
-    
+
     private AdapterFactory factory;
 
-    private String[] adapters;
+    private final String[] adapters;
 
-    public AdapterFactoryDescriptor(AdapterFactory factory, String[] adapters) {
-        this.factory = factory;
+    private final ServiceReference reference;
+
+    private final ComponentContext context;
+
+    public AdapterFactoryDescriptor(
+            final ComponentContext context,
+            final ServiceReference reference,
+            final String[] adapters) {
+        this.reference = reference;
+        this.context = context;
         this.adapters = adapters;
     }
 
     public AdapterFactory getFactory() {
+        if ( factory == null ) {
+            synchronized ( this ) {
+                if ( factory == null ) {
+                    factory = (AdapterFactory) context.locateService(
+                            "AdapterFactory", reference);
+                }
+            }
+        }
         return factory;
     }
 
     public String[] getAdapters() {
         return adapters;
     }
-
 }
diff --git a/src/main/java/org/apache/sling/adapter/internal/AdapterFactoryDescriptorMap.java b/src/main/java/org/apache/sling/adapter/internal/AdapterFactoryDescriptorMap.java
index cfa6e0c..2cc27d1 100644
--- a/src/main/java/org/apache/sling/adapter/internal/AdapterFactoryDescriptorMap.java
+++ b/src/main/java/org/apache/sling/adapter/internal/AdapterFactoryDescriptorMap.java
@@ -36,4 +36,6 @@
 public class AdapterFactoryDescriptorMap extends
         TreeMap<AdapterFactoryDescriptorKey, AdapterFactoryDescriptor> {
 
+    private static final long serialVersionUID = 1L;
+
 }
diff --git a/src/main/java/org/apache/sling/adapter/internal/AdapterManagerImpl.java b/src/main/java/org/apache/sling/adapter/internal/AdapterManagerImpl.java
index 6ebba7f..d2f57ad 100644
--- a/src/main/java/org/apache/sling/adapter/internal/AdapterManagerImpl.java
+++ b/src/main/java/org/apache/sling/adapter/internal/AdapterManagerImpl.java
@@ -21,6 +21,7 @@
 import static org.apache.sling.api.adapter.AdapterFactory.ADAPTABLE_CLASSES;
 import static org.apache.sling.api.adapter.AdapterFactory.ADAPTER_CLASSES;
 
+import java.util.ArrayList;
 import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.Hashtable;
@@ -38,7 +39,6 @@
 import org.osgi.service.event.Event;
 import org.osgi.service.event.EventAdmin;
 import org.osgi.service.log.LogService;
-import org.osgi.util.tracker.ServiceTracker;
 
 /**
  * The <code>AdapterManagerImpl</code> class implements the
@@ -85,7 +85,7 @@
      * The OSGi <code>ComponentContext</code> to retrieve
      * {@link AdapterFactory} service instances.
      */
-    private ComponentContext context;
+    private volatile ComponentContext context;
 
     /**
      * A list of {@link AdapterFactory} services bound to this manager before
@@ -115,9 +115,11 @@
      */
     private Map<String, Map<String, AdapterFactory>> factoryCache;
 
-    /** The service tracker for the event admin
+    /**
+     * The service tracker for the event admin
+     * @scr.reference cardinality="0..1" policy="dynamic"
      */
-    private ServiceTracker eventAdminTracker;
+    private EventAdmin eventAdmin;
 
     // ---------- AdapterManager interface -------------------------------------
 
@@ -155,18 +157,18 @@
 
     // ----------- SCR integration ---------------------------------------------
 
-    protected synchronized void activate(ComponentContext context) {
-        // setup tracker first as this is used in the bind/unbind methods
-        this.eventAdminTracker = new ServiceTracker(context.getBundleContext(),
-                EventAdmin.class.getName(), null);
-        this.eventAdminTracker.open();
+    protected void activate(ComponentContext context) {
         this.context = context;
 
         // register all adapter factories bound before activation
-        for (ServiceReference reference : boundAdapterFactories) {
+        final List<ServiceReference> refs;
+        synchronized ( this.boundAdapterFactories ) {
+            refs = new ArrayList<ServiceReference>(this.boundAdapterFactories);
+            boundAdapterFactories.clear();
+        }
+        for (ServiceReference reference : refs) {
             registerAdapterFactory(context, reference);
         }
-        boundAdapterFactories.clear();
 
         // final "enable" this manager by setting the instance
         // do not overwrite the field if already set (this is unexpected
@@ -184,7 +186,7 @@
     /**
      * @param context Not used
      */
-    protected synchronized void deactivate(ComponentContext context) {
+    protected void deactivate(ComponentContext context) {
         SyntheticResource.unsetAdapterManager(this);
         // "disable" the manager by clearing the instance
         // do not clear the field if not set to this instance
@@ -195,22 +197,25 @@
                 "Not clearing instance field: Set to another manager "
                     + AdapterManagerImpl.INSTANCE, null);
         }
-        if ( this.eventAdminTracker != null ) {
-            this.eventAdminTracker.close();
-            this.eventAdminTracker = null;
-        }
         this.context = null;
     }
 
-    protected synchronized void bindAdapterFactory(ServiceReference reference) {
+    protected void bindAdapterFactory(ServiceReference reference) {
+        boolean create = true;
         if (context == null) {
-            boundAdapterFactories.add(reference);
-        } else {
+            synchronized ( this.boundAdapterFactories ) {
+                if (context == null) {
+                    boundAdapterFactories.add(reference);
+                    create = false;
+                }
+            }
+        }
+        if ( create ) {
             registerAdapterFactory(context, reference);
         }
     }
 
-    protected synchronized void unbindAdapterFactory(ServiceReference reference) {
+    protected void unbindAdapterFactory(ServiceReference reference) {
         unregisterAdapterFactory(reference);
     }
 
@@ -251,14 +256,6 @@
     }
 
     /**
-     * Get the event admin.
-     * @return The event admin or <code>null</code>
-     */
-    private EventAdmin getEventAdmin() {
-        return (EventAdmin) (this.eventAdminTracker != null ? this.eventAdminTracker.getService() : null);
-    }
-
-    /**
      * Unregisters the {@link AdapterFactory} referred to by the service
      * <code>reference</code> from the registry.
      */
@@ -272,18 +269,13 @@
             return;
         }
 
-        AdapterFactory factory = (AdapterFactory) context.locateService(
-            "AdapterFactory", reference);
-        if ( factory == null ) {
-            return;
-        }
-        AdapterFactoryDescriptorKey factoryKey = new AdapterFactoryDescriptorKey(
+        final AdapterFactoryDescriptorKey factoryKey = new AdapterFactoryDescriptorKey(
             reference);
-        AdapterFactoryDescriptor factoryDesc = new AdapterFactoryDescriptor(
-            factory, adapters);
+        final AdapterFactoryDescriptor factoryDesc = new AdapterFactoryDescriptor(context,
+            reference, adapters);
 
         synchronized (factories) {
-            for (String adaptable : adaptables) {
+            for (final String adaptable : adaptables) {
                 AdapterFactoryDescriptorMap adfMap = factories.get(adaptable);
                 if (adfMap == null) {
                     adfMap = new AdapterFactoryDescriptorMap();
@@ -297,7 +289,7 @@
         factoryCache = null;
 
         // send event
-        final EventAdmin localEA = this.getEventAdmin();
+        final EventAdmin localEA = this.eventAdmin;
         if ( localEA != null ) {
             final Dictionary<String, Object> props = new Hashtable<String, Object>();
             props.put(SlingConstants.PROPERTY_ADAPTABLE_CLASSES, adaptables);
@@ -312,8 +304,9 @@
      * <code>reference</code> from the registry.
      */
     private void unregisterAdapterFactory(ServiceReference reference) {
-        boundAdapterFactories.remove(reference);
-
+        synchronized ( this.boundAdapterFactories ) {
+            boundAdapterFactories.remove(reference);
+        }
         final String[] adaptables = OsgiUtil.toStringArray(reference.getProperty(ADAPTABLE_CLASSES));
         final String[] adapters = OsgiUtil.toStringArray(reference.getProperty(ADAPTER_CLASSES));
 
@@ -345,7 +338,7 @@
         }
 
         // send event
-        final EventAdmin localEA = this.getEventAdmin();
+        final EventAdmin localEA = this.eventAdmin;
         if ( localEA != null ) {
             final Dictionary<String, Object> props = new Hashtable<String, Object>();
             props.put(SlingConstants.PROPERTY_ADAPTABLE_CLASSES, adaptables);
@@ -431,7 +424,10 @@
                 String[] adapters = afd.getAdapters();
                 for (String adapter : adapters) {
                     if (!afm.containsKey(adapter)) {
-                        afm.put(adapter, afd.getFactory());
+                        final AdapterFactory factory = afd.getFactory();
+                        if ( factory != null ) {
+                            afm.put(adapter, factory);
+                        }
                     }
                 }
             }