/******************************************************************************* * Copyright (c) 2013, 2016 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.osgi.internal.serviceregistry; 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; import org.osgi.framework.*; /** * This class represents the use of a service by a bundle. One is created for each * service acquired by a bundle. * *

* This class manages a prototype service factory. * * @ThreadSafe */ public class PrototypeServiceFactoryUse extends ServiceFactoryUse { /** Service objects returned by PrototypeServiceFactory.getService() and their use count. */ /* @GuardedBy("this") */ private final Map serviceObjects; /** * Constructs a service use encapsulating the service object. * * @param context bundle getting the service * @param registration ServiceRegistration of the service */ PrototypeServiceFactoryUse(BundleContextImpl context, ServiceRegistrationImpl registration) { super(context, registration); this.serviceObjects = new IdentityHashMap<>(); } /** * Create a new service object for the service. * *

* * @return The service object. */ /* @GuardedBy("this") */ @Override S newServiceObject() { assert Thread.holdsLock(this); if (debug.DEBUG_SERVICES) { Debug.println("getServiceObject[factory=" + registration.getBundle() + "](" + context.getBundleImpl() + "," + registration + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } final S service = factoryGetService(); if (service == null) { return null; } 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; } /** * Release a service object for the service. * * @param service The service object to release. * @return true if the service was released; otherwise false. * @throws IllegalArgumentException If the specified service was not * provided by this object. */ /* @GuardedBy("this") */ @Override boolean releaseServiceObject(final S service) { assert Thread.holdsLock(this); 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$ } AtomicInteger useCount = serviceObjects.get(service); if (useCount.decrementAndGet() < 1) { serviceObjects.remove(service); factoryUngetService(service); } return true; } /** * Release all uses of the service and reset the use count to zero. * *

    *
  1. The bundle's use count for this service is set to zero. *
  2. The {@link PrototypeServiceFactory#ungetService(Bundle, ServiceRegistration, Object)} method * is called to release the service object for the bundle. *
*/ /* @GuardedBy("this") */ @Override void release() { super.release(); 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$ } factoryUngetService(service); } serviceObjects.clear(); } /** * Is this service use using any services? * * @return true if no services are being used and this service use can be discarded. */ /* @GuardedBy("this") */ @Override boolean isEmpty() { return super.isEmpty() && serviceObjects.isEmpty(); } }