Author: tjwatson
Date: Tue Feb  5 16:23:06 2019
New Revision: 1853021

URL: http://svn.apache.org/viewvc?rev=1853021&view=rev
Log:
FELIX-6044 - Fixes for maintaining correct reference usage

 - unget non-prototype service refs
 - avoid creating multiple prototype instances for same component

Modified:
    
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentServiceObjectsHelper.java
    
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
    
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/MultiplePrototypeRefPair.java
    felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/RefPair.java
    
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java
    
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SinglePrototypeRefPair.java
    
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleRefPair.java

Modified: 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentServiceObjectsHelper.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentServiceObjectsHelper.java?rev=1853021&r1=1853020&r2=1853021&view=diff
==============================================================================
--- 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentServiceObjectsHelper.java
 (original)
+++ 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentServiceObjectsHelper.java
 Tue Feb  5 16:23:06 2019
@@ -41,6 +41,8 @@ public class ComponentServiceObjectsHelp
 
     private final List<ComponentServiceObjectsImpl> closedServices = new 
ArrayList<ComponentServiceObjectsImpl>();
 
+    private final ConcurrentMap<ServiceReference<?>, Object> 
prototypeInstances = new ConcurrentHashMap<ServiceReference<?>, Object>();
+
     public ComponentServiceObjectsHelper(final BundleContext bundleContext)
     {
         this.bundleContext = bundleContext;
@@ -63,6 +65,7 @@ public class ComponentServiceObjectsHelp
         {
                cso.deactivate();
         }
+        prototypeInstances.clear();
     }
 
     public ComponentServiceObjects getServiceObjects(final ServiceReference<?> 
ref)
@@ -98,7 +101,19 @@ public class ComponentServiceObjectsHelp
 
     public <T> T getPrototypeRefInstance(final ServiceReference<T> ref)
     {
-       return (T) getServiceObjects(ref).getService();
+       T service = (T) prototypeInstances.get(ref);
+       if ( service == null )
+       {
+               service = (T) getServiceObjects(ref).getService();
+               T oldService = (T)prototypeInstances.putIfAbsent(ref, service);
+               if ( oldService != null )
+               {
+                       // another thread created the instance already
+                       getServiceObjects(ref).ungetService(service);
+                       service = oldService;
+               }
+       }
+       return service;
     }
 
     private static final class ComponentServiceObjectsImpl implements 
ComponentServiceObjects

Modified: 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java?rev=1853021&r1=1853020&r2=1853021&view=diff
==============================================================================
--- 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
 (original)
+++ 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/DependencyManager.java
 Tue Feb  5 16:23:06 2019
@@ -223,15 +223,7 @@ public class DependencyManager<S, T> imp
 
         protected void ungetService(RefPair<S, T> ref)
         {
-            Object service = ref.unsetServiceObject(null);
-            if (service != null)
-            {
-                BundleContext bundleContext = 
m_componentManager.getBundleContext();
-                if (bundleContext != null)
-                {
-                    bundleContext.ungetService(ref.getRef());
-                }
-            }
+            ref.ungetServiceObjects(m_componentManager.getBundleContext());
         }
 
         protected void tracked(int trackingCount)
@@ -1690,7 +1682,7 @@ public class DependencyManager<S, T> imp
                 invokeUnbindMethod(componentContext, boundRef, 
trackingCount.get(), edgeInfo);
             }
             
-            boundRef.unsetServiceObject(componentContext);
+            boundRef.ungetServiceObject(componentContext);
             
         }
         latch.countDown();

Modified: 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/MultiplePrototypeRefPair.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/MultiplePrototypeRefPair.java?rev=1853021&r1=1853020&r2=1853021&view=diff
==============================================================================
--- 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/MultiplePrototypeRefPair.java
 (original)
+++ 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/MultiplePrototypeRefPair.java
 Tue Feb  5 16:23:06 2019
@@ -54,7 +54,7 @@ public class MultiplePrototypeRefPair<S,
     }
 
     @Override
-    public T unsetServiceObject(ComponentContextImpl<S> key)
+    public T ungetServiceObject(ComponentContextImpl<S> key)
     {
        if ( key == null )
        {
@@ -75,6 +75,11 @@ public class MultiplePrototypeRefPair<S,
     }
 
     @Override
+    public void ungetServiceObjects(BundleContext bundleContext) {
+        ungetServiceObject(null);
+    }
+
+    @Override
     public String toString()
     {
         return "[MultiplePrototypeRefPair: ref: [" + getRef() + "] has 
service: [" + !instances.isEmpty() + "]]";
@@ -83,7 +88,7 @@ public class MultiplePrototypeRefPair<S,
     @Override
     public boolean getServiceObject(ComponentContextImpl<S> key, BundleContext 
context)
     {
-       final T service = 
key.getComponentServiceObjectsHelper().getPrototypeRefInstance(this.getRef());
+        final T service = 
key.getComponentServiceObjectsHelper().getPrototypeRefInstance(this.getRef());
         if ( service == null )
         {
             setFailed();

Modified: 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/RefPair.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/RefPair.java?rev=1853021&r1=1853020&r2=1853021&view=diff
==============================================================================
--- 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/RefPair.java 
(original)
+++ 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/RefPair.java 
Tue Feb  5 16:23:06 2019
@@ -50,7 +50,8 @@ public abstract class RefPair<S, T>
 
     public abstract boolean setServiceObject( ComponentContextImpl<S> key, T 
serviceObject );
 
-    public abstract T unsetServiceObject(ComponentContextImpl<S> key);
+    public abstract void ungetServiceObjects(BundleContext context);
+    public abstract T ungetServiceObject(ComponentContextImpl<S> key);
 
     public void setFailed( )
     {

Modified: 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java?rev=1853021&r1=1853020&r2=1853021&view=diff
==============================================================================
--- 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java
 (original)
+++ 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleComponentManager.java
 Tue Feb  5 16:23:06 2019
@@ -161,7 +161,6 @@ public class SingleComponentManager<S> e
         {
             m_useCount.set( 0 );
             disposeImplementationObject( m_componentContext, reason );
-            m_componentContext.cleanup();
             m_componentContext = null;
             getLogger().log( LogService.LOG_DEBUG, "Unset and deconfigured 
implementation object for component in deleteComponent for reason {0}", null, 
REASONS[ reason ] );
             clearServiceProperties();
@@ -417,7 +416,7 @@ public class SingleComponentManager<S> e
                 md.close( componentContext, componentContext.getEdgeInfo( md ) 
);
             }
         }
-
+        componentContext.cleanup();
     }
 
     @Override

Modified: 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SinglePrototypeRefPair.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SinglePrototypeRefPair.java?rev=1853021&r1=1853020&r2=1853021&view=diff
==============================================================================
--- 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SinglePrototypeRefPair.java
 (original)
+++ 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SinglePrototypeRefPair.java
 Tue Feb  5 16:23:06 2019
@@ -20,6 +20,8 @@
 
 package org.apache.felix.scr.impl.manager;
 
+import java.util.concurrent.atomic.AtomicReference;
+
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.log.LogService;
@@ -27,14 +29,56 @@ import org.osgi.service.log.LogService;
 /**
  * @version $Rev$ $Date$
  */
-public class SinglePrototypeRefPair<S, T> extends SingleRefPair<S, T>
+public class SinglePrototypeRefPair<S, T> extends RefPair<S, T>
 {
+    class SingleKeyService {
+        final ComponentContextImpl<S> key;
+        final T serviceObject;
+        SingleKeyService(ComponentContextImpl<S> key, T serviceObject) {
+            this.key = key;
+            this.serviceObject = serviceObject;
+        }
+    }
+    protected AtomicReference<SingleKeyService> serviceObjectRef = new 
AtomicReference<>();
+
     public SinglePrototypeRefPair( ServiceReference<T> ref )
     {
         super(ref);
     }
 
     @Override
+    public T getServiceObject(ComponentContextImpl<S> key)
+    {
+        SingleKeyService service = serviceObjectRef.get();
+        return service == null ? null : service.serviceObject;
+    }
+
+    @Override
+    public boolean setServiceObject(ComponentContextImpl<S> key, T 
serviceObject)
+    {
+        return serviceObjectRef.compareAndSet(null, new SingleKeyService(key, 
serviceObject ));
+    }
+
+    @Override
+    public T ungetServiceObject(ComponentContextImpl<S> key)
+    {
+        SingleKeyService service = serviceObjectRef.getAndSet(null);
+        if (service != null) {
+            if (key == null) {
+                key = service.key;
+            }
+            doUngetService(key, service.serviceObject);
+            return service.serviceObject;
+        }
+               return null;
+    }
+
+    @Override
+    public void ungetServiceObjects(BundleContext bundleContext) {
+        ungetServiceObject(null);
+    }
+
+    @Override
     public String toString()
     {
         return "[SinglePrototypeRefPair: ref: [" + getRef() + "] service: [" + 
getServiceObject(null) + "]]";
@@ -49,37 +93,25 @@ public class SinglePrototypeRefPair<S, T
             setFailed();
             key.getLogger().log(
                  LogService.LOG_WARNING,
-                 "Could not get service from serviceobjects for ref {0}",null, 
getRef() );
+                 "Could not get service from serviceobjects for ref {0}", 
null, getRef() );
             return false;
         }
         if (!setServiceObject(key, service))
         {
             // Another thread got the service before, so unget our
-               doUngetService(key, service);
+               doUngetService( key, service );
         }
         return true;
     }
 
-    @Override
-    public T unsetServiceObject(ComponentContextImpl<S> key)
-    {
-       final T service = super.unsetServiceObject(key);
-       if ( service != null )
-       {
-                       doUngetService(key, service);
-       }
-       return null ;
-    }
-
        private void doUngetService(ComponentContextImpl<S> key, final T 
service) {
                try 
                {
-                       
key.getComponentServiceObjectsHelper().getServiceObjects(getRef()).ungetService(service);
+                       
key.getComponentServiceObjectsHelper().getServiceObjects(getRef()).ungetService(
 service );
                }
-               catch (final IllegalStateException ise)
+               catch ( final IllegalStateException ise )
                {
                        // ignore
                }
        }
-    
 }

Modified: 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleRefPair.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleRefPair.java?rev=1853021&r1=1853020&r2=1853021&view=diff
==============================================================================
--- 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleRefPair.java
 (original)
+++ 
felix/trunk/scr/src/main/java/org/apache/felix/scr/impl/manager/SingleRefPair.java
 Tue Feb  5 16:23:06 2019
@@ -31,7 +31,7 @@ import org.osgi.service.log.LogService;
  */
 public class SingleRefPair<S, T> extends RefPair<S, T>
 {
-    private AtomicReference<T> serviceObjectRef = new AtomicReference<>();
+    protected AtomicReference<T> serviceObjectRef = new AtomicReference<>();
 
     public SingleRefPair( ServiceReference<T> ref )
     {
@@ -56,9 +56,22 @@ public class SingleRefPair<S, T> extends
     }
 
     @Override
-    public T unsetServiceObject(ComponentContextImpl<S> key)
+    public T ungetServiceObject(ComponentContextImpl<S> key) {
+        // null operation for singleRefPair
+        return null;
+    }
+
+    @Override
+    public void ungetServiceObjects(BundleContext bundleContext)
     {
-        return serviceObjectRef.getAndSet( null );
+        T service = serviceObjectRef.getAndSet( null );
+        if (service != null)
+        {
+            if (bundleContext != null)
+            {
+                bundleContext.ungetService(getRef());
+            }
+        }
     }
 
     @Override


Reply via email to