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.22.1
Show newest version
/*******************************************************************************
 * 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: *

    *
  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("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: *

    *
  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("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. * *
    *
  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("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); } } }