/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.toolkitbridge.api; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import de.rcenvironment.toolkit.core.api.ImmutableServiceRegistry; import de.rcenvironment.toolkit.core.api.Toolkit; /** * Provides static methods for accessing services provided by the RCE {@link Toolkit}. * * @author Robert Mischke */ public final class ToolkitBridge { private static final Object sharedInitializationLock = ToolkitBridge.class; private static Toolkit toolkitInstance; // access synchronized via "sharedInitializationLock" private static ToolkitBridge osgiBridgeInstance; // access synchronized via "sharedInitializationLock" private static List<Runnable> deferredRunnables; // access synchronized via "sharedInitializationLock" private final ImmutableServiceRegistry toolkitServiceRegistry; private final BundleContext bundleContext; private final List<ServiceRegistration<?>> serviceRegistrations = new ArrayList<ServiceRegistration<?>>(); private final Log log = LogFactory.getLog(getClass()); private ToolkitBridge(Toolkit toolkit, BundleContext bundleContext) { this.toolkitServiceRegistry = toolkit.getServiceRegistry(); this.bundleContext = bundleContext; if (bundleContext == null) { throw new IllegalArgumentException("Creating a ToolkitBridge instance without an OSGi BundleContext is not allowed"); } } /** * Initialized this bridge with the given {@link Toolkit} instance. Usually called from a bundle activator. * * @param toolkit the toolkit to delegate services from * @param bundleContext the OSGi {@link BundleContext} */ public static void initialize(Toolkit toolkit, BundleContext bundleContext) { synchronized (sharedInitializationLock) { toolkitInstance = toolkit; StaticToolkitHolder.setInstance(toolkit); osgiBridgeInstance = new ToolkitBridge(toolkit, bundleContext); osgiBridgeInstance.registerOsgiServices(); if (deferredRunnables != null) { LogFactory.getLog(ToolkitBridge.class).debug( "Running " + deferredRunnables.size() + " deferred task(s) after toolkit initialization"); for (Runnable runnable : deferredRunnables) { // note: not catching RTEs for now - if a Runnable does not behave, let it crash the startup runnable.run(); } deferredRunnables = null; } } } /** * Performs cleanup (if necessary) and removes the registered {@link Toolkit} instance. */ public static void dispose() { synchronized (sharedInitializationLock) { try { osgiBridgeInstance.unregisterOsgiServices(); toolkitInstance.shutdown(); toolkitInstance = null; } finally { osgiBridgeInstance = null; StaticToolkitHolder.setInstance(null); } } } /** * This method provides a call mechanism for cases when the timing between caller and the toolkit bridge is not certain. If the toolkit * is already available at the time of this call, the {@link Runnable} is immediately executed within the caller's thread. If it is not * available yet, it will be executed right after the toolkit becomes available. The caller should make no assumptions about the thread * used to execute the provided {@link Runnable}. * * @param runnable the task to execute immediately or when the toolkit has become available */ public static void afterToolkitAvailable(Runnable runnable) { synchronized (sharedInitializationLock) { if (osgiBridgeInstance != null) { runnable.run(); } else { // lazy init if (deferredRunnables == null) { deferredRunnables = new ArrayList<>(); } deferredRunnables.add(runnable); } } } private void registerOsgiServices() { // publish all toolkit APIs as OSGi services synchronized (serviceRegistrations) { for (Class<?> apiClass : toolkitServiceRegistry.listServices()) { serviceRegistrations.add(bundleContext.registerService(apiClass.getName(), toolkitServiceRegistry.getService(apiClass), null)); // note: avoiding StringUtils here, as this would create a bundle dependency cycle log.debug("Registered RCE Tookit service " + apiClass.getName() + " as an OSGi service"); } } } private void unregisterOsgiServices() { synchronized (serviceRegistrations) { for (ServiceRegistration<?> registration : serviceRegistrations) { registration.unregister(); } serviceRegistrations.clear(); } log.info("Unregistered all toolkit OSGi services"); } }