Improve sync handling for service objects. Update to spec
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1691622 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentServiceObjectsHelper.java b/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentServiceObjectsHelper.java
index 31ff915..634d192 100644
--- a/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentServiceObjectsHelper.java
+++ b/scr/src/main/java/org/apache/felix/scr/impl/helper/ComponentServiceObjectsHelper.java
@@ -18,11 +18,9 @@
*/
package org.apache.felix.scr.impl.helper;
-
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Collection;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@@ -31,7 +29,6 @@
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentServiceObjects;
-
/**
* Utility class for handling references using a ComponentServiceObjects
* to get services.
@@ -40,7 +37,9 @@
{
private final BundleContext bundleContext;
- private final Map<ServiceReference<?>, ComponentServiceObjectsImpl> services = new HashMap<ServiceReference<?>, ComponentServiceObjectsImpl>();
+ private final ConcurrentMap<ServiceReference<?>, ComponentServiceObjectsImpl> services = new ConcurrentHashMap<ServiceReference<?>, ComponentServiceObjectsImpl>();
+
+ private final List<ComponentServiceObjectsImpl> closedServices = new ArrayList<ComponentServiceObjectsImpl>();
private final ConcurrentMap<ServiceReference, Object> prototypeInstances = new ConcurrentHashMap<ServiceReference, Object>();
@@ -51,43 +50,51 @@
public void cleanup()
{
- synchronized ( this )
+ Collection<ComponentServiceObjectsImpl> csos = services.values();
+ services.clear();
+ for(final ComponentServiceObjectsImpl cso : csos)
{
- for(final Map.Entry<ServiceReference<?>, ComponentServiceObjectsImpl> entry : services.entrySet())
- {
- entry.getValue().close();
- }
- services.clear();
+ cso.deactivate();
+ }
+ synchronized ( this.closedServices )
+ {
+ csos = new ArrayList<ComponentServiceObjectsImpl>(this.closedServices);
+ this.closedServices.clear();
+ }
+ for(final ComponentServiceObjectsImpl cso : csos)
+ {
+ cso.deactivate();
}
prototypeInstances.clear();
}
public ComponentServiceObjects getServiceObjects(final ServiceReference<?> ref)
{
- synchronized ( this )
+ ComponentServiceObjectsImpl cso = this.services.get(ref);
+ if ( cso == null )
{
- ComponentServiceObjectsImpl cso = this.services.get(ref);
- if ( cso == null )
+ final ServiceObjects serviceObjects = this.bundleContext.getServiceObjects(ref);
+ if ( serviceObjects != null )
{
- final ServiceObjects serviceObjects = this.bundleContext.getServiceObjects(ref);
- if ( serviceObjects != null )
+ cso = new ComponentServiceObjectsImpl(serviceObjects);
+ final ComponentServiceObjectsImpl oldCSO = this.services.putIfAbsent(ref, cso);
+ if ( oldCSO != null )
{
- cso = new ComponentServiceObjectsImpl(serviceObjects);
- this.services.put(ref, cso);
+ cso = oldCSO;
}
}
- return cso;
}
+ return cso;
}
public void closeServiceObjects(final ServiceReference<?> ref) {
- ComponentServiceObjectsImpl cso;
- synchronized ( this )
- {
- cso = this.services.remove(ref);
- }
+ ComponentServiceObjectsImpl cso = this.services.remove(ref);
if ( cso != null )
{
+ synchronized ( closedServices )
+ {
+ closedServices.add(cso);
+ }
cso.close();
}
}
@@ -115,11 +122,19 @@
private volatile ServiceObjects serviceObjects;
+ private volatile boolean deactivated = false;
+
public ComponentServiceObjectsImpl(final ServiceObjects so)
{
this.serviceObjects = so;
}
+ public void deactivate()
+ {
+ this.deactivated = true;
+ close();
+ }
+
/**
* Close this instance and unget all services.
*/
@@ -129,30 +144,36 @@
this.serviceObjects = null;
if ( so != null )
{
+ final List<Object> localInstances = new ArrayList<Object>();
synchronized ( this.instances )
{
- for(final Object obj : instances)
+ localInstances.addAll(this.instances);
+ this.instances.clear();
+ }
+ for(final Object obj : localInstances)
+ {
+ try
{
- try
- {
- so.ungetService(obj);
- }
- catch ( final IllegalStateException ise )
- {
- // ignore (this happens if the bundle is not valid anymore)
- }
- catch ( final IllegalArgumentException iae )
- {
- // ignore (this happens if the service has not been returned by the service objects)
- }
+ so.ungetService(obj);
}
- this.instances.clear();
+ catch ( final IllegalStateException ise )
+ {
+ // ignore (this happens if the bundle is not valid anymore)
+ }
+ catch ( final IllegalArgumentException iae )
+ {
+ // ignore (this happens if the service has not been returned by the service objects)
+ }
}
}
}
public Object getService()
{
+ if ( this.deactivated )
+ {
+ throw new IllegalStateException();
+ }
final ServiceObjects so = this.serviceObjects;
Object service = null;
if ( so != null )
@@ -171,6 +192,10 @@
public void ungetService(final Object service)
{
+ if ( this.deactivated )
+ {
+ throw new IllegalStateException();
+ }
final ServiceObjects so = this.serviceObjects;
if ( so != null )
{
@@ -194,5 +219,12 @@
}
return null;
}
+
+ @Override
+ public String toString() {
+ return "ComponentServiceObjectsImpl [instances=" + instances + ", serviceObjects=" + serviceObjects
+ + ", deactivated=" + deactivated + ", hashCode=" + this.hashCode() + "]";
+ }
+
}
}