All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.osgi.internal.serviceregistry.ServiceFactoryUse Maven / Gradle / Ivy

There is a newer version: 1.9.3.RC1
Show newest version
/*******************************************************************************
 * Copyright (c) 2003, 2022 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 static org.eclipse.osgi.internal.debug.Debug.OPTION_DEBUG_SERVICES;

import java.security.AccessController;
import java.security.PrivilegedAction;
import org.eclipse.osgi.internal.framework.BundleContextImpl;
import org.eclipse.osgi.internal.messages.Msg;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkEvent;
import org.osgi.framework.ServiceException;
import org.osgi.framework.ServiceFactory;
import org.osgi.framework.ServiceRegistration;

/**
 * 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 { /** ServiceFactory object */ final ServiceFactory factory; /** Service object returned by ServiceFactory.getService() */ /* @GuardedBy("getLock()") */ private S cachedService; /** * true if we are calling the factory getService method. Used to detect * recursion. */ /* @GuardedBy("getLock()") */ 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.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: *

    *
  1. The use count is incremented by one. *
  2. 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. *
  3. The service object is returned. *
* * @return The service object. */ /* @GuardedBy("getLock()") */ @Override S getService() { assert isLocked(); if (inUse()) { incrementUse(); return cachedService; } if (debug.DEBUG_SERVICES) { debug.trace(OPTION_DEBUG_SERVICES, "[" + Thread.currentThread().getName() + "] getService[Sfactory=" + registration.getBundle() //$NON-NLS-1$ //$NON-NLS-2$ + "](" + context.getBundleImpl() + "," + registration + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } // check for recursive call on this thread if (factoryInUse) { if (debug.DEBUG_SERVICES) { debug.trace(OPTION_DEBUG_SERVICES, factory + ".getService() recursively called."); //$NON-NLS-1$ } ServiceException se = new ServiceException( NLS.bind(Msg.SERVICE_FACTORY_RECURSION, factory.getClass().getName(), "getService"), //$NON-NLS-1$ ServiceException.FACTORY_RECURSION); 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: *

    *
  1. If the use count is zero, return. *
  2. The use count is decremented by one. *
  3. If the use count is non zero, return. *
  4. 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("getLock()") */ @Override boolean ungetService() { assert isLocked(); if (!inUse()) { return false; } decrementUse(); if (inUse()) { return true; } final S service = cachedService; cachedService = null; if (debug.DEBUG_SERVICES) { debug.trace(OPTION_DEBUG_SERVICES, "[" + Thread.currentThread().getName() + "] ungetService[Sfactory=" + registration.getBundle() //$NON-NLS-1$ //$NON-NLS-2$ + "](" + context.getBundleImpl() + "," + registration + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } 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 ServiceFactory#ungetService(Bundle, ServiceRegistration, Object)} * method is called to release the service object for the bundle. *
*/ /* @GuardedBy("getLock()") */ @Override void release() { super.release(); final S service = cachedService; if (service == null) { return; } cachedService = null; if (debug.DEBUG_SERVICES) { debug.trace(OPTION_DEBUG_SERVICES, "[" + Thread.currentThread().getName() + "] releaseService[Sfactory=" //$NON-NLS-1$ //$NON-NLS-2$ + registration.getBundle() + "](" + context.getBundleImpl() + "," + registration + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } factoryUngetService(service); } /** * Return the service object for this service use. * * @return The service object. */ /* @GuardedBy("getLock()") */ @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("getLock()") */ 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.trace(OPTION_DEBUG_SERVICES, factory + ".getService() exception: " + t.getMessage()); //$NON-NLS-1$ debug.traceThrowable(OPTION_DEBUG_SERVICES, t); } ServiceException se = new ServiceException( NLS.bind(Msg.SERVICE_FACTORY_EXCEPTION, factory.getClass().getName(), "getService"), //$NON-NLS-1$ ServiceException.FACTORY_EXCEPTION, t); context.getContainer().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, registration.getBundle(), se); return null; } if (service == null) { if (debug.DEBUG_SERVICES) { debug.trace(OPTION_DEBUG_SERVICES, 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.trace(OPTION_DEBUG_SERVICES, "Service object is not an instanceof " + invalidService); //$NON-NLS-1$ } ServiceException se = new ServiceException(NLS.bind(Msg.SERVICE_FACTORY_NOT_INSTANCEOF_CLASS_EXCEPTION, new Object[] { factory.getClass().getName(), service.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("getLock()") */ 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.trace(OPTION_DEBUG_SERVICES, factory + ".ungetService() exception"); //$NON-NLS-1$ debug.traceThrowable(OPTION_DEBUG_SERVICES, t); } ServiceException se = new ServiceException( NLS.bind(Msg.SERVICE_FACTORY_EXCEPTION, factory.getClass().getName(), "ungetService"), //$NON-NLS-1$ ServiceException.FACTORY_EXCEPTION, t); context.getContainer().getEventPublisher().publishFrameworkEvent(FrameworkEvent.ERROR, registration.getBundle(), se); } } }