/* * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Bogdan Stefanescu * Ian Smith * Florent Guillaume */ package org.eclipse.ecr.runtime.osgi; import java.util.IllegalFormatException; import java.util.LinkedList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuxeo.common.utils.StringUtils; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; import org.osgi.framework.SynchronousBundleListener; /** * @author Bogdan Stefanescu * @author Ian Smith * @author Florent Guillaume */ public class OSGiComponentLoader implements SynchronousBundleListener { private static final Log log = LogFactory.getLog(OSGiComponentLoader.class); private final OSGiRuntimeService runtime; public OSGiComponentLoader(OSGiRuntimeService runtime) { this.runtime = runtime; install(); } public void install() { BundleContext ctx = runtime.getBundleContext(); ctx.addBundleListener(this); Bundle[] bundles = ctx.getBundles(); int mask = Bundle.RESOLVED | Bundle.STARTING | Bundle.ACTIVE; for (Bundle bundle : bundles) { String name = bundle.getSymbolicName(); runtime.bundles.put(name, bundle); int state = bundle.getState(); bundleDebug("Install bundle: %s " + bundleStateAsString(state), name); if ((state & mask) != 0) { // check only resolved bundles if (OSGiRuntimeService.getComponentsList(bundle) != null) { bundleDebug("Install bundle: %s component list: " + OSGiRuntimeService.getComponentsList(bundle), name); // check only bundles containing nuxeo comp. try { runtime.createContext(bundle); } catch (Throwable e) { log.warn("Failed to load components for bundle: " + name, e); } } else { bundleDebug("Install bundle: %s has no components", name); } } else { bundleDebug("Install bundle: %s is not RESOLVED, STARTING " + "or ACTIVE, so no context was created", name); } } } public void uninstall() { runtime.getBundleContext().removeBundleListener(this); } @Override public void bundleChanged(BundleEvent event) { String name = event.getBundle().getSymbolicName(); int type = event.getType(); bundleDebug("Bundle changed: %s " + bundleEventAsString(type), name); try { Bundle bundle = event.getBundle(); String componentsList = OSGiRuntimeService.getComponentsList(bundle); switch (type) { case BundleEvent.INSTALLED: runtime.bundles.put(bundle.getSymbolicName(), bundle); break; case BundleEvent.UNINSTALLED: runtime.bundles.remove(bundle.getSymbolicName()); break; case BundleEvent.RESOLVED: if (componentsList != null) { bundleDebug( "Bundle changed: %s RESOLVED with components: " + componentsList, name); runtime.createContext(bundle); } else { bundleDebug( "Bundle changed: %s RESOLVED with no components", name); } break; case BundleEvent.UNRESOLVED: if (componentsList != null) { bundleDebug( "Bundle changed: %s UNRESOLVED with components: " + componentsList, name); runtime.destroyContext(bundle); } else { bundleDebug( "Bundle changed: %s UNRESOLVED with no components", name); } break; } } catch (Exception e) { log.error(e); } } /** * Used for generating good debug info. Convert bit vector into printable * string. * * @param state bitwise-or of UNINSTALLED, INSTALLED, RESOLVED, STARTING, * STOPPING, and ACTIVE * @return printable version of bits that are on */ public static String bundleStateAsString(int state) { List<String> list = new LinkedList<String>(); if ((state & Bundle.UNINSTALLED) != 0) { list.add("UNINSTALLED"); } if ((state & Bundle.INSTALLED) != 0) { list.add("INSTALLED"); } if ((state & Bundle.RESOLVED) != 0) { list.add("RESOLVED"); } if ((state & Bundle.STARTING) != 0) { list.add("STARTING"); } if ((state & Bundle.STOPPING) != 0) { list.add("STOPPING"); } if ((state & Bundle.ACTIVE) != 0) { list.add("ACTIVE"); } return '[' + StringUtils.join(list, ',') + ']'; } /** * Used for generating good debug info. Convert event type into printable * string. * * @param eventType INSTALLED, STARTED,STOPPED, UNINSTALLED,UPDATED * @return printable version of event type */ public static String bundleEventAsString(int eventType) { switch (eventType) { case BundleEvent.INSTALLED: return "INSTALLED"; case BundleEvent.STARTED: return "STARTED"; case BundleEvent.STARTING: return "STARTING"; case BundleEvent.STOPPED: return "STOPPED"; case BundleEvent.UNINSTALLED: return "UNINSTALLED"; case BundleEvent.UPDATED: return "UPDATED"; case BundleEvent.LAZY_ACTIVATION: return "LAZY_ACTIVATION"; case BundleEvent.RESOLVED: return "RESOLVED"; case BundleEvent.UNRESOLVED: return "UNRESOLVED"; case BundleEvent.STOPPING: return "STOPPING"; default: return "UNKNOWN_OSGI_EVENT_TYPE_" + eventType; } } /** * Prints out a debug message for debugging bundles. * * @param msg the debug message with a %s in it which will be replaced by * the component name * @param name the component name */ public static void bundleDebug(String msg, String name) { if (log.isDebugEnabled()) { try { msg = String.format(msg, name); } catch (IllegalFormatException e) { // don't fail for this } log.debug(msg); } } }