blob: 12bda08f4768fd7b9c1b91090144b51250e384ed [file] [log] [blame]
/*******************************************************************************
* 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.
*
* <p>
* This class manages a prototype service factory.
*
* @ThreadSafe
*/
public class PrototypeServiceFactoryUse<S> extends ServiceFactoryUse<S> {
/** Service objects returned by PrototypeServiceFactory.getService() and their use count. */
/* @GuardedBy("this") */
private final Map<S, AtomicInteger> 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<S> registration) {
super(context, registration);
this.serviceObjects = new IdentityHashMap<>();
}
/**
* Create a new service object for the service.
*
* <p>
*
* @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.
*
* <ol>
* <li>The bundle's use count for this service is set to zero.
* <li>The {@link PrototypeServiceFactory#ungetService(Bundle, ServiceRegistration, Object)} method
* is called to release the service object for the bundle.
* </ol>
*/
/* @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();
}
}