/****************************************************************************** * Copyright (c) 2006, 2010 VMware Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0 * is available at http://www.opensource.org/licenses/apache2.0.php. * You may elect to redistribute this code under either of these licenses. * * Contributors: * VMware Inc. *****************************************************************************/ package org.eclipse.gemini.blueprint.util; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Dictionary; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.Version; import org.springframework.util.Assert; import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils.FieldCallback; import org.springframework.util.ReflectionUtils.FieldFilter; /** * Utility class for OSGi {@link Bundle}s. Provides convenience methods for * interacting with a Bundle object. * * @author Adrian Colyer * @author Costin Leau * @see OsgiStringUtils */ public abstract class OsgiBundleUtils { /** * Whether Bundle#getBundleContext() method is available (even on 4.0 * platforms) */ private static final boolean getBundleContextAvailable; private static volatile BundleContextExtractor extractor; static { getBundleContextAvailable = (ReflectionUtils.findMethod(Bundle.class, "getBundleContext", new Class[0]) != null); if (getBundleContextAvailable) extractor = new Osgi41BundleContextExtractor(); } private interface BundleContextExtractor { BundleContext getBundleContext(Bundle bundle); } private static class Osgi41BundleContextExtractor implements BundleContextExtractor { public BundleContext getBundleContext(Bundle bundle) { return bundle.getBundleContext(); } } private static class ReflectionMethodInvocation implements BundleContextExtractor { private final Method method; private ReflectionMethodInvocation(Method method) { ReflectionUtils.makeAccessible(method); this.method = method; } public BundleContext getBundleContext(Bundle bundle) { return (BundleContext) ReflectionUtils.invokeMethod(method, bundle); } } private static class FieldExtractor implements BundleContextExtractor { private final Field field; private FieldExtractor(Field field) { ReflectionUtils.makeAccessible(field); this.field = field; } public BundleContext getBundleContext(Bundle bundle) { return (BundleContext) ReflectionUtils.getField(field, bundle); } } /** * Returns the underlying BundleContext for the given Bundle. This uses * reflection and highly dependent of the OSGi implementation. Should not be * used if OSGi 4.1 is being used. * * @param bundle OSGi bundle * @return the bundle context for this bundle */ public static BundleContext getBundleContext(final Bundle bundle) { if (bundle == null) return null; if (extractor == null) { // try getBundleContext (for non OSGi 4.1 platforms) Method method = ReflectionUtils.findMethod(bundle.getClass(), "getBundleContext", new Class[0]); if (method != null) { if (Modifier.isPublic(method.getModifiers())) { extractor = new Osgi41BundleContextExtractor(); } } else { if (method == null) { // try Equinox getContext method = ReflectionUtils.findMethod(bundle.getClass(), "getContext", new Class[0]); } if (method != null) { extractor = new ReflectionMethodInvocation(method); } else { final Field[] fields = new Field[1]; // fallback to field inspection (KF and Prosyst) ReflectionUtils.doWithFields(bundle.getClass(), new FieldCallback() { public void doWith(final Field field) throws IllegalArgumentException, IllegalAccessException { ReflectionUtils.makeAccessible(field); fields[0] = field; } }, new FieldFilter() { public boolean matches(Field field) { return fields[0] == null && BundleContext.class.isAssignableFrom(field.getType()); } }); if (fields[0] != null) { extractor = new FieldExtractor(fields[0]); } else { throw new IllegalArgumentException("Cannot extract bundleContext from bundle type " + bundle.getClass()); } } } } return extractor.getBundleContext(bundle); } /** * Indicates if the given bundle is active or not. * * @param bundle OSGi bundle * @return true if the given bundle is active, false otherwise * @see Bundle#ACTIVE */ public static boolean isBundleActive(Bundle bundle) { Assert.notNull(bundle, "bundle is required"); return (bundle.getState() == Bundle.ACTIVE); } /** * Indicates if the given bundle is resolved or not. * * @param bundle OSGi bundle * @return true if the given bundle is resolved, false otherwise * @see Bundle#RESOLVED */ public static boolean isBundleResolved(Bundle bundle) { Assert.notNull(bundle, "bundle is required"); return (bundle.getState() >= Bundle.RESOLVED); } /** * Indicates if the given bundle is lazily activated or not. That is, the * bundle has a lazy activation policy and a STARTING state. Bundles that * have been lazily started but have been activated will return false. * * <p/> * On OSGi R4.0 platforms, this method will always return false. * * @param bundle OSGi bundle * @return true if the bundle is lazily activated, false otherwise. */ @SuppressWarnings("unchecked") public static boolean isBundleLazyActivated(Bundle bundle) { Assert.notNull(bundle, "bundle is required"); if (OsgiPlatformDetector.isR41()) { if (bundle.getState() == Bundle.STARTING) { Dictionary<Object, Object> headers = bundle.getHeaders(); if (headers != null) { Object val = headers.get(Constants.BUNDLE_ACTIVATIONPOLICY); if (val instanceof String) { String value = ((String) val).trim(); return (value.startsWith(Constants.ACTIVATION_LAZY)); } } } } return false; } /** * Indicates if the given bundle is a fragment or not. * * @param bundle OSGi bundle * @return true if the given bundle is a fragment, false otherwise * @see Constants#FRAGMENT_HOST */ public static boolean isFragment(Bundle bundle) { Assert.notNull(bundle, "bundle is required"); return bundle.getHeaders().get(Constants.FRAGMENT_HOST) != null; } /** * Indicates if the given bundle is the system bundle or not. * * @param bundle OSGi bundle * @return true if the given bundle is a fragment, false otherwise */ public static boolean isSystemBundle(Bundle bundle) { Assert.notNull(bundle); return (bundle.getBundleId() == 0); } /** * Returns the given bundle version. * * @param bundle OSGi bundle * @return bundle version * @see Constants#BUNDLE_VERSION */ public static Version getBundleVersion(Bundle bundle) { return getHeaderAsVersion(bundle, Constants.BUNDLE_VERSION); } /** * Finds an install bundle based by its symbolic name. * * @param bundleContext OSGi bundle context * @param symbolicName bundle symbolic name * @return bundle matching the symbolic name (<code>null</code> if none is * found) */ public static Bundle findBundleBySymbolicName(BundleContext bundleContext, String symbolicName) { Assert.notNull(bundleContext, "bundleContext is required"); Assert.hasText(symbolicName, "a not-null/not-empty symbolicName isrequired"); Bundle[] bundles = bundleContext.getBundles(); for (int i = 0; i < bundles.length; i++) { if (symbolicName.equals(bundles[i].getSymbolicName())) { return bundles[i]; } } return null; } /** * Returns the version for a given bundle manifest header. * * @param bundle OSGi bundle * @param header bundle manifest header * @return the header value */ public static Version getHeaderAsVersion(Bundle bundle, String header) { Assert.notNull(bundle); return Version.parseVersion((String) bundle.getHeaders().get(header)); } }