Skip to content

Instantly share code, notes, and snippets.

@cescoffier
Created August 23, 2016 06:51
Show Gist options
  • Save cescoffier/ae0f17a217691097849eb9615bb08d98 to your computer and use it in GitHub Desktop.
Save cescoffier/ae0f17a217691097849eb9615bb08d98 to your computer and use it in GitHub Desktop.
Utilities to load Vert.x in OSGi
package io.vertx.example.osgi;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.concurrent.Callable;
/**
* The famous TCCL trick for OSGi.
*/
public class TcclSwitch {
public static <T> T executeWithTCCLSwitch(Callable<T> action) throws Exception {
final ClassLoader original = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(TcclSwitch.class.getClassLoader());
return action.call();
} finally {
Thread.currentThread().setContextClassLoader(original);
}
}
public static <T> T executeWithTCCLSwitch(Callable<T> action, BundleContext context, Class... classes) throws Exception {
final ClassLoader original = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(new AllBundleClassLoader(context, classes));
return action.call();
} finally {
Thread.currentThread().setContextClassLoader(original);
}
}
public static void executeWithTCCLSwitch(Runnable action) {
final ClassLoader original = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(TcclSwitch.class.getClassLoader());
action.run();
} finally {
Thread.currentThread().setContextClassLoader(original);
}
}
private static class AllBundleClassLoader extends ClassLoader {
private final BundleContext context;
private Set<ClassLoader> classloaders = new LinkedHashSet<>();
public AllBundleClassLoader(BundleContext context, Class... classes) {
this.context = context;
classloaders.add(this.getClass().getClassLoader());
Arrays.stream(classes).forEach(c -> classloaders.add(c.getClassLoader()));
Arrays.stream(context.getBundles()).forEach(bundle -> classloaders.add(new ClassLoaderFromBundle(bundle)));
}
private Class<?> loadOrNull(String name, ClassLoader cl) {
try {
return cl.loadClass(name);
} catch (ClassNotFoundException e) {
return null;
}
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
for (ClassLoader cl : classloaders) {
Class<?> c = loadOrNull(name, cl);
if (c != null) {
return c;
}
}
throw new ClassNotFoundException("Unable to load " + name);
}
@Override
public URL getResource(String name) {
for (ClassLoader cl : classloaders) {
URL c = cl.getResource(name);
if (c != null) {
return c;
}
}
return null;
}
@Override
public Enumeration<URL> getResources(String name) throws IOException {
Vector<URL> list = new Vector<>();
for (ClassLoader cl : classloaders) {
Enumeration<URL> c = cl.getResources(name);
if (c != null) {
while (c.hasMoreElements()) {
URL url = c.nextElement();
list.add(url);
}
}
}
return list.elements();
}
}
private static class ClassLoaderFromBundle extends ClassLoader {
private final Bundle bundle;
public ClassLoaderFromBundle(Bundle bundle) {
this.bundle = bundle;
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
return bundle.loadClass(name);
}
@Override
public URL getResource(String name) {
return bundle.getResource(name);
}
@Override
public Enumeration<URL> getResources(String name) throws IOException {
return bundle.getResources(name);
}
public String toString() {
return "[classloader of " + bundle.getSymbolicName() + "]";
}
}
}
package io.vertx.example.osgi;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.eventbus.EventBus;
import io.vertx.ext.dropwizard.DropwizardMetricsOptions;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import java.util.logging.Logger;
import static io.vertx.example.osgi.TcclSwitch.executeWithTCCLSwitch;
/**
* A bundle activator registering the Vert.x instance and the event bus as OSGi service.
*/
public class VertxActivator implements BundleActivator {
private final static Logger LOGGER = Logger.getLogger("VertxPublisher");
private ServiceRegistration<Vertx> vertxRegistration;
private ServiceRegistration<EventBus> ebRegistration;
@Override
public void start(BundleContext context) throws Exception {
LOGGER.info("Creating Vert.x instance");
VertxOptions options = new VertxOptions().setMetricsOptions(new DropwizardMetricsOptions()
.setJmxEnabled(true)
.setJmxDomain("vertx")
.setRegistryName("my-registry")
);
Vertx vertx = executeWithTCCLSwitch(() -> Vertx.vertx(options), context, Vertx.class, DropwizardMetricsOptions.class);
vertxRegistration = context.registerService(Vertx.class, vertx, null);
LOGGER.info("Vert.x service registered");
ebRegistration = context.registerService(EventBus.class, vertx.eventBus(), null);
LOGGER.info("Vert.x Event Bus service registered");
}
@Override
public void stop(BundleContext context) throws Exception {
if (vertxRegistration != null) {
vertxRegistration.unregister();
vertxRegistration = null;
}
if (ebRegistration != null) {
ebRegistration.unregister();
ebRegistration = null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment