org.eclipse.osgi.internal.serviceregistry.ServiceFactoryUse Maven / Gradle / Ivy
Show all versions of aspectjtools Show documentation
/*******************************************************************************
* Copyright (c) 2003, 2013 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.security.AccessController;
import java.security.PrivilegedAction;
import org.eclipse.osgi.internal.debug.Debug;
import org.eclipse.osgi.internal.framework.BundleContextImpl;
import org.eclipse.osgi.internal.messages.Msg;
import org.eclipse.osgi.util.NLS;
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 service factory.
*
* @ThreadSafe
*/
public class ServiceFactoryUse extends ServiceUse {
/** BundleContext associated with this service use */
final BundleContextImpl context;
/** ServiceFactory object */
final ServiceFactory factory;
final Debug debug;
/** Service object returned by ServiceFactory.getService() */
/* @GuardedBy("this") */
private S cachedService;
/** true if we are calling the factory getService method. Used to detect recursion. */
/* @GuardedBy("this") */
private boolean factoryInUse;
/**
* Constructs a service use encapsulating the service factory.
*
* @param context bundle getting the service
* @param registration ServiceRegistration of the service
*/
ServiceFactoryUse(BundleContextImpl context, ServiceRegistrationImpl registration) {
super(context, registration);
this.debug = context.getContainer().getConfiguration().getDebug();
this.context = context;
this.factoryInUse = false;
this.cachedService = null;
@SuppressWarnings("unchecked")
ServiceFactory f = (ServiceFactory) registration.getServiceObject();
this.factory = f;
}
/**
* Get a service's service object and increment the use count.
*
*
The following steps are followed to get the service object:
*
* - The use count is incremented by one.
*
- If the use count is now one,
* the {@link ServiceFactory#getService(Bundle, ServiceRegistration)} method
* is called to create a service object for the context bundle.
* This service object is cached.
* While the use count is greater than zero,
* subsequent calls to get the service object
* will return the cached service object.
*
If the service object returned by the {@link ServiceFactory}
* is not an instanceof
* all the classes named when the service was registered or
* the {@link ServiceFactory} throws an exception,
* null
is returned and a
* {@link FrameworkEvent} of type {@link FrameworkEvent#ERROR} is broadcast.
* - The service object is returned.
*
*
* @return The service object.
*/
/* @GuardedBy("this") */
@Override
S getService() {
assert Thread.holdsLock(this);
if (inUse()) {
incrementUse();
return cachedService;
}
if (debug.DEBUG_SERVICES) {
Debug.println("getService[factory=" + registration.getBundle() + "](" + context.getBundleImpl() + "," + registration + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
// check for recursive call on this thread
if (factoryInUse) {
if (debug.DEBUG_SERVICES) {
Debug.println(factory + ".getService() recursively called."); //$NON-NLS-1$
}
ServiceException se = new ServiceException(NLS.bind(Msg.SERVICE_FACTORY_RECURSION, factory.getClass().getName(), "getService"), ServiceException.FACTORY_RECURSION); //$NON-NLS-1$
context.getContainer().getEventPublisher().publishFrameworkEvent(FrameworkEvent.WARNING, registration.getBundle(), se);
return null;
}
factoryInUse = true;
final S service;
try {
service = factoryGetService();
if (service == null) {
return null;
}
} finally {
factoryInUse = false;
}
this.cachedService = service;
incrementUse();
return service;
}
/**
* Unget a service's service object.
*
*
* Decrements the use count if the service was being used.
*
*
The following steps are followed to unget the service object:
*
* - If the use count is zero, return.
*
- The use count is decremented by one.
*
- If the use count is non zero, return.
*
- The {@link ServiceFactory#ungetService(Bundle, ServiceRegistration, Object)} method
* is called to release the service object for the context bundle.
*
* @return true if the service was ungotten; otherwise false.
*/
/* @GuardedBy("this") */
@Override
boolean ungetService() {
assert Thread.holdsLock(this);
if (!inUse()) {
return false;
}
decrementUse();
if (inUse()) {
return true;
}
final S service = cachedService;
cachedService = null;
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);
return true;
}
/**
* Release all uses of the service and reset the use count to zero.
*
*
* - The bundle's use count for this service is set to zero.
*
- The {@link ServiceFactory#ungetService(Bundle, ServiceRegistration, Object)} method
* is called to release the service object for the bundle.
*
*/
/* @GuardedBy("this") */
@Override
void release() {
super.release();
final S service = cachedService;
if (service == null) {
return;
}
cachedService = null;
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);
}
/**
* Return the service object for this service use.
*
* @return The service object.
*/
/* @GuardedBy("this") */
@Override
S getCachedService() {
return cachedService;
}
/**
* Call the service factory to get the service.
*
* @return The service returned by the factory or null if there was an error.
*/
/* @GuardedBy("this") */
S factoryGetService() {
final S service;
try {
service = AccessController.doPrivileged(new PrivilegedAction() {
@Override
public S run() {
return factory.getService(context.getBundleImpl(), registration);
}
});
} catch (Throwable t) {
if (debug.DEBUG_SERVICES) {
Debug.println(factory + ".getService() exception: " + t.getMessage()); //$NON-NLS-1$
Debug.printStackTrace(t);
}
// allow the adaptor to handle this unexpected error
context.getContainer().handleRuntimeError(t);
ServiceException se = new ServiceException(NLS.bind(Msg.SERVICE_FACTORY_EXCEPTION, factory.getClass().getName(), "getService"), ServiceException.FACTORY_EXCEPTION, t); //$NON-NLS-1$
context.getContainer().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, registration.getBundle(), se);
return null;
}
if (service == null) {
if (debug.DEBUG_SERVICES) {
Debug.println(factory + ".getService() returned null."); //$NON-NLS-1$
}
ServiceException se = new ServiceException(NLS.bind(Msg.SERVICE_OBJECT_NULL_EXCEPTION, factory.getClass().getName()), ServiceException.FACTORY_ERROR);
context.getContainer().getEventPublisher().publishFrameworkEvent(FrameworkEvent.WARNING, registration.getBundle(), se);
return null;
}
String[] clazzes = registration.getClasses();
String invalidService = ServiceRegistry.checkServiceClass(clazzes, service);
if (invalidService != null) {
if (debug.DEBUG_SERVICES) {
Debug.println("Service object is not an instanceof " + invalidService); //$NON-NLS-1$
}
ServiceException se = new ServiceException(NLS.bind(Msg.SERVICE_FACTORY_NOT_INSTANCEOF_CLASS_EXCEPTION, factory.getClass().getName(), invalidService), ServiceException.FACTORY_ERROR);
context.getContainer().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, registration.getBundle(), se);
return null;
}
return service;
}
/**
* Call the service factory to unget the service.
*
* @param service The service object to pass to the factory.
*/
/* @GuardedBy("this") */
void factoryUngetService(final S service) {
try {
AccessController.doPrivileged(new PrivilegedAction() {
@Override
public Void run() {
factory.ungetService(context.getBundleImpl(), registration, service);
return null;
}
});
} catch (Throwable t) {
if (debug.DEBUG_SERVICES) {
Debug.println(factory + ".ungetService() exception"); //$NON-NLS-1$
Debug.printStackTrace(t);
}
ServiceException se = new ServiceException(NLS.bind(Msg.SERVICE_FACTORY_EXCEPTION, factory.getClass().getName(), "ungetService"), ServiceException.FACTORY_EXCEPTION, t); //$NON-NLS-1$
context.getContainer().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, registration.getBundle(), se);
}
}
}