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