From a5083a05d9fbc19d8281009b4a3006f9625e0246 Mon Sep 17 00:00:00 2001 From: BJ Hargrave Date: Mon, 1 Feb 2016 16:33:03 -0500 Subject: Bug 486947: Use count objects returned by PrototypeServiceFactory For OSGi R6 the framework does not use count the 'same' objects that get returned by a PrototypeServiceFactory. When a bundle calls ServiceObjects.getService() multiple times a PrototypeServiceFactory may return the 'same' object multiple times. The bundle then may call ServiceObjects.ungetService(S) with the 'same' service object multiple times. Currently the framework implementation will throw an IllegalArgumentException on the second call to ungetService(S) if the 'same' service object is passed in more than once. This is because we do not use count the service object for ServiceObjects.getService() The core expert group has decided the framework must use count the service objects returned by ServiceObjects.getService() and decrement the use count on calls to ServiceObjects.ungetService(S). --- .../PrototypeServiceFactoryUse.java | 32 ++++++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) (limited to 'bundles/org.eclipse.osgi') diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/PrototypeServiceFactoryUse.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/PrototypeServiceFactoryUse.java index 661021b5a..52d935d01 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/PrototypeServiceFactoryUse.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/serviceregistry/PrototypeServiceFactoryUse.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2013 IBM Corporation and others. + * Copyright (c) 2013, 2016 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -11,7 +11,9 @@ package org.eclipse.osgi.internal.serviceregistry; -import java.util.*; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import org.eclipse.osgi.internal.debug.Debug; import org.eclipse.osgi.internal.framework.BundleContextImpl; import org.eclipse.osgi.internal.messages.Msg; @@ -27,9 +29,9 @@ import org.osgi.framework.*; * @ThreadSafe */ public class PrototypeServiceFactoryUse extends ServiceFactoryUse { - /** Service objects returned by PrototypeServiceFactory.getService() */ + /** Service objects returned by PrototypeServiceFactory.getService() and their use count. */ /* @GuardedBy("this") */ - private final Set serviceObjects; + private final Map serviceObjects; /** * Constructs a service use encapsulating the service object. @@ -39,7 +41,7 @@ public class PrototypeServiceFactoryUse extends ServiceFactoryUse { */ PrototypeServiceFactoryUse(BundleContextImpl context, ServiceRegistrationImpl registration) { super(context, registration); - this.serviceObjects = Collections.newSetFromMap(new IdentityHashMap()); + this.serviceObjects = new IdentityHashMap(); } /** @@ -60,7 +62,15 @@ public class PrototypeServiceFactoryUse extends ServiceFactoryUse { if (service == null) { return null; } - serviceObjects.add(service); + AtomicInteger useCount = serviceObjects.get(service); + if (useCount == null) { + serviceObjects.put(service, new AtomicInteger(1)); + } else { + if (useCount.getAndIncrement() == Integer.MAX_VALUE) { + useCount.getAndDecrement(); + throw new ServiceException(Msg.SERVICE_USE_OVERFLOW); + } + } return service; } @@ -76,13 +86,17 @@ public class PrototypeServiceFactoryUse extends ServiceFactoryUse { @Override boolean releaseServiceObject(final S service) { assert Thread.holdsLock(this); - if ((service == null) || !serviceObjects.remove(service)) { + if ((service == null) || !serviceObjects.containsKey(service)) { throw new IllegalArgumentException(Msg.SERVICE_OBJECTS_UNGET_ARGUMENT_EXCEPTION); } if (debug.DEBUG_SERVICES) { Debug.println("ungetService[factory=" + registration.getBundle() + "](" + context.getBundleImpl() + "," + registration + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } - factoryUngetService(service); + AtomicInteger useCount = serviceObjects.get(service); + if (useCount.decrementAndGet() < 1) { + serviceObjects.remove(service); + factoryUngetService(service); + } return true; } @@ -99,7 +113,7 @@ public class PrototypeServiceFactoryUse extends ServiceFactoryUse { @Override void release() { super.release(); - for (S service : serviceObjects) { + for (S service : serviceObjects.keySet()) { if (debug.DEBUG_SERVICES) { Debug.println("releaseService[factory=" + registration.getBundle() + "](" + context.getBundleImpl() + "," + registration + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } -- cgit v1.2.3