final ImmutableList<Type> usedInGenericType(Type[] types) { ImmutableList.Builder<Type> builder = ImmutableList.builder(); for (Type type : types) { builder.add(usedInGenericType(type)); } return builder.build(); }
/** Singleton Wrapper around OSGi module loading and unloading operations. */ public class ModuleManager { /* * Note for developers: please keep list in alpha-numerical order */ static final List<String> SYSTEM_PACKAGES = ImmutableList.<String>builder() .add("com.google_voltpatches.common.base;") .add("com.google_voltpatches.common.collect;") .add("com.google_voltpatches.common.io;") .add("com.google_voltpatches.common.net;") .add("com.google_voltpatches.common.util.concurrent;") .add("jsr166y;") .add("org.apache.log4j;") .add("org.slf4j;") .add("org.voltcore.network;") .add("org.voltcore.logging;") .add("org.voltcore.utils;") .add("org.voltdb;include:=\"VoltType\",") .add("org.voltdb.client;") .add("org.voltdb.common;exclude=\"Permission\",") .add("org.voltdb.importer;") .add("org.voltdb.importer.formatter;") .add("org.voltdb.types;") .build(); private static final VoltLogger LOG = new VoltLogger("HOST"); private static final Joiner COMMA_JOINER = Joiner.on(",").skipNulls(); private static final AtomicReference<File> CACHE_ROOT = new AtomicReference<>(); private static ModuleManager m_self = null; public static void initializeCacheRoot(File cacheRoot) { if (CACHE_ROOT.compareAndSet(null, checkNotNull(cacheRoot))) { if (!cacheRoot.exists() && !cacheRoot.mkdirs()) { throw new SetUpException( "Failed to create required OSGI cache directory: " + cacheRoot.getAbsolutePath()); } if (!cacheRoot.isDirectory() || !cacheRoot.canRead() || !cacheRoot.canWrite() || !cacheRoot.canExecute()) { throw new SetUpException( "Cannot access OSGI cache directory: " + cacheRoot.getAbsolutePath()); } m_self = new ModuleManager(cacheRoot); } } public static void resetCacheRoot() { File cacheRoot = CACHE_ROOT.get(); if (cacheRoot != null && CACHE_ROOT.compareAndSet(cacheRoot, null)) { m_self = null; } } private static final Function<String, String> appendVersion = new Function<String, String>() { @Override public String apply(String input) { return input + "version=1.0.0"; } }; public static ModuleManager instance() { return m_self; } static ModularException loggedModularException(Throwable e, String msg, Object... args) { ModularException.isCauseFor(e) .map( me -> { throw me; }); LOG.error(String.format(msg, args), e); return new ModularException(msg, e, args); } public static URI bundleURI(File fl) { return fl.toPath().toUri(); } private final Framework m_framework; private final BundleRef m_bundles; private ModuleManager(File cacheRoot) { String systemPackagesSpec = FluentIterable.from(SYSTEM_PACKAGES).transform(appendVersion).join(COMMA_JOINER); Map<String, String> frameworkProps = ImmutableMap.<String, String>builder() .put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, systemPackagesSpec) .put("org.osgi.framework.storage.clean", "onFirstInit") .put("felix.cache.rootdir", cacheRoot.getAbsolutePath()) .put("felix.cache.locking", Boolean.FALSE.toString()) .build(); LOG.info("Framework properties are: " + frameworkProps); FrameworkFactory frameworkFactory = ServiceLoader.load(FrameworkFactory.class).iterator().next(); m_framework = frameworkFactory.newFramework(frameworkProps); try { m_framework.start(); } catch (BundleException e) { LOG.error("Failed to start the felix OSGi framework", e); throw new SetUpException("Failed to start the felix OSGi framework", e); } m_bundles = new BundleRef(m_framework); } /** * Gets the service from the given bundle jar uri. Loads and starts the bundle if it isn't yet * loaded * * @param bundleURI bundle jar URI * @param svcClazz the service class exposed by the bundle jar * @return a reference to an instance of the service class */ public <T> T getService(URI bundleURI, Class<T> svcClazz) { return m_bundles.getService(bundleURI, svcClazz); } public void unload(URI bundleURI) { m_bundles.stopBundle(bundleURI); } public void unload(Set<URI> uris) { m_bundles.stopBundles(uris); } public void uninstall(URI bundleURI) { m_bundles.uninstallBundle(bundleURI); } public void uninstall(Set<URI> uris) { m_bundles.uninstallBundles(uris); } public static class SetUpException extends RuntimeException { private static final long serialVersionUID = 8197183357774453653L; public SetUpException() {} public SetUpException(String message, Throwable cause) { super(message, cause); } public SetUpException(String message) { super(message); } public SetUpException(Throwable cause) { super(cause); } } static class BundleRef extends AtomicReference<NavigableMap<URI, Bundle>> { private static final long serialVersionUID = -3691039780541403034L; static NavigableMap<URI, Bundle> EMPTY_MAP = ImmutableSortedMap.of(); final Framework m_framework; public BundleRef(Framework framework, NavigableMap<URI, Bundle> initialRef) { super(initialRef); m_framework = framework; } public BundleRef(Framework framework) { this(framework, EMPTY_MAP); } private Bundle startBundle(URI bundleURI) { NavigableMap<URI, Bundle> expect, update; Bundle bundle = null; do { expect = get(); if (expect.containsKey(bundleURI)) break; BundleContext ctx = m_framework.getBundleContext(); bundle = ctx.getBundle(bundleURI.toASCIIString()); if (bundle != null) { try { bundle.update(); } catch (BundleException e) { String msg = e.getMessage(); throw loggedModularException(e, "Unable to update bundle %s. %s", bundleURI, msg); } catch (Throwable t) { throw loggedModularException(t, "Unable to update bundle %s", bundleURI); } } else { try { bundle = ctx.installBundle(bundleURI.toASCIIString()); } catch (BundleException e) { String msg = e.getMessage(); throw loggedModularException(e, "Unable to install bundle %s. %s", bundleURI, msg); } catch (Throwable t) { throw loggedModularException(t, "Unable to instal bundle %s", bundleURI); } } try { bundle.start(); } catch (BundleException e) { String msg = e.getMessage(); throw loggedModularException(e, "Unable to start bundle %s. %s", bundleURI, msg); } catch (Throwable t) { throw loggedModularException(t, "Unable to start bundle %s", bundleURI); } update = ImmutableSortedMap.<URI, Bundle>naturalOrder() .putAll(expect) .put(bundleURI, bundle) .build(); } while (!compareAndSet(expect, update)); return get().get(bundleURI); } <T> T getService(URI bundleURI, Class<T> svcClazz) { Bundle bundle = get().get(bundleURI); if (bundle == null) { synchronized (this) { bundle = startBundle(bundleURI); } } BundleContext ctx = bundle.getBundleContext(); for (ServiceReference<?> ref : bundle.getRegisteredServices()) { if (ref.isAssignableTo(bundle, svcClazz.getName())) { return svcClazz.cast(ctx.getService(ref)); } } return null; } Optional<Bundle> stopBundle(URI bundleURI) { NavigableMap<URI, Bundle> expect, update; do { expect = get(); update = ImmutableSortedMap.<URI, Bundle>naturalOrder() .putAll(Maps.filterKeys(expect, not(equalTo(bundleURI)))) .build(); } while (expect.containsKey(bundleURI) && !compareAndSet(expect, update)); Bundle bundle = expect.get(bundleURI); if (bundle != null) { try { bundle.stop(); } catch (BundleException e) { throw loggedModularException(e, "Failed to stop bundle %s", bundleURI); } } return Optional.ofNullable(bundle); } void uninstallBundle(URI bundleURI) { stopBundle(bundleURI) .ifPresent( (Bundle b) -> { try { b.uninstall(); } catch (Throwable t) { throw loggedModularException(t, "Failed to uninstall %s", b.getLocation()); } }); } NavigableMap<URI, Bundle> stopBundles(Set<URI> bundles) { NavigableMap<URI, Bundle> expect, update; do { expect = get(); update = ImmutableSortedMap.<URI, Bundle>naturalOrder() .putAll(Maps.filterKeys(expect, not(in(bundles)))) .build(); } while (!compareAndSet(expect, update)); List<URI> couldNotStop = new ArrayList<>(); NavigableMap<URI, Bundle> stopped = Maps.filterKeys(expect, in(bundles)); for (Map.Entry<URI, Bundle> e : stopped.entrySet()) { URI bundleURI = e.getKey(); Bundle bundle = e.getValue(); try { bundle.stop(); } catch (BundleException exc) { LOG.error("Failed to stop bundle " + bundleURI, exc); couldNotStop.add(bundleURI); } } if (!couldNotStop.isEmpty()) { throw new ModularException("Failed to stop bundles %s", couldNotStop); } return stopped; } void uninstallBundles(Set<URI> bundles) { List<URI> couldNotUninstall = new ArrayList<>(); for (Map.Entry<URI, Bundle> e : stopBundles(bundles).entrySet()) { URI bundleURI = e.getKey(); Bundle bundle = e.getValue(); try { bundle.uninstall(); } catch (BundleException exc) { LOG.error("Failed to uninstall bundle " + bundleURI, exc); couldNotUninstall.add(bundleURI); } if (!couldNotUninstall.isEmpty()) { throw new ModularException("Failed to uninstall bundles %s", couldNotUninstall); } } } } public static final <T> Predicate<T> in(final Set<T> set) { return new Predicate<T>() { @Override public boolean apply(T m) { return set.contains(m); } }; } }