/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.aries.jmx.util; import static org.osgi.jmx.framework.BundleStateMBean.ACTIVE; import static org.osgi.jmx.framework.BundleStateMBean.INSTALLED; import static org.osgi.jmx.framework.BundleStateMBean.RESOLVED; import static org.osgi.jmx.framework.BundleStateMBean.STARTING; import static org.osgi.jmx.framework.BundleStateMBean.STOPPING; import static org.osgi.jmx.framework.BundleStateMBean.UNINSTALLED; import static org.osgi.jmx.framework.BundleStateMBean.UNKNOWN; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Dictionary; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.aries.util.ManifestHeaderUtils; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.packageadmin.ExportedPackage; import org.osgi.service.packageadmin.PackageAdmin; import org.osgi.service.packageadmin.RequiredBundle; /** * This class contains common utilities related to Framework operations for the MBean implementations * * @version $Rev$ $Date$ */ public class FrameworkUtils { private FrameworkUtils() { super(); } /** * * Returns the Bundle object for a given id * * @param bundleContext * @param bundleId * @return * @throws IllegalArgumentException * if no Bundle is found with matching bundleId */ public static Bundle resolveBundle(BundleContext bundleContext, long bundleId) throws IOException { if (bundleContext == null) { throw new IllegalArgumentException("Argument bundleContext cannot be null"); } Bundle bundle = bundleContext.getBundle(bundleId); if (bundle == null) { throw new IOException("Bundle with id [" + bundleId + "] not found"); } return bundle; } /** * Returns an array of bundleIds * * @param bundles * array of <code>Bundle</code> objects * @return bundleIds in sequence */ public static long[] getBundleIds(Bundle[] bundles) { long[] result; if (bundles == null) { result = new long[0]; } else { result = new long[bundles.length]; for (int i = 0; i < bundles.length; i++) { result[i] = bundles[i].getBundleId(); } } return result; } public static long[] getBundleIds(List<Bundle> bundles) { long[] result; if (bundles == null) { result = new long[0]; } else { result = new long[bundles.size()]; for (int i = 0; i < bundles.size(); i++) { result[i] = bundles.get(i).getBundleId(); } } return result; } /** * * Returns the ServiceReference object with matching service.id * * @param bundleContext * @param serviceId * @return ServiceReference with matching service.id property * @throws IllegalArgumentException if bundleContext is null * @throws IOException if no service is found with the given id */ public static ServiceReference resolveService(BundleContext bundleContext, long serviceId) throws IOException { if (bundleContext == null) { throw new IllegalArgumentException("Argument bundleContext cannot be null"); } ServiceReference result = null; try { ServiceReference[] references = bundleContext.getAllServiceReferences(null, "(" + Constants.SERVICE_ID + "=" + serviceId + ")"); if (references == null || references.length < 1) { throw new IOException("Service with id [" + serviceId + "] not found"); } else { result = references[0]; } } catch (InvalidSyntaxException e) { IOException ioex = new IOException("Failure when resolving service "); ioex.initCause(e); throw ioex; } return result; } /** * Returns an array of service.id values * * @param serviceReferences * array of <code>ServiceReference</code> objects * @return service.id values in sequence */ public static long[] getServiceIds(ServiceReference[] serviceReferences) { long result[] = (serviceReferences == null) ? new long[0] : new long[serviceReferences.length]; for (int i = 0; i < result.length; i++) { result[i] = (Long) serviceReferences[i].getProperty(Constants.SERVICE_ID); } return result; } /** * Returns the packages exported by the specified bundle * * @param bundle * @param packageAdmin * @return * @throws IllegalArgumentException * if bundle or packageAdmin are null */ public static String[] getBundleExportedPackages(Bundle bundle, PackageAdmin packageAdmin) throws IllegalArgumentException { if (bundle == null) { throw new IllegalArgumentException("Argument bundle cannot be null"); } if (packageAdmin == null) { throw new IllegalArgumentException("Argument packageAdmin cannot be null"); } String[] exportedPackages; ExportedPackage[] exported = packageAdmin.getExportedPackages(bundle); if (exported != null) { exportedPackages = new String[exported.length]; for (int i = 0; i < exported.length; i++) { exportedPackages[i] = exported[i].getName() + ";" + exported[i].getVersion().toString(); } } else { exportedPackages = new String[0]; } return exportedPackages; } /** * Returns the bundle ids of any resolved fragments * * @param bundle * @param packageAdmin * @return * @throws IllegalArgumentException * if bundle or packageAdmin are null */ public static long[] getFragmentIds(Bundle bundle, PackageAdmin packageAdmin) throws IllegalArgumentException { if (bundle == null) { throw new IllegalArgumentException("Argument bundle cannot be null"); } if (packageAdmin == null) { throw new IllegalArgumentException("Argument packageAdmin cannot be null"); } long[] fragmentIds; Bundle[] fragments = packageAdmin.getFragments(bundle); if (fragments != null) { fragmentIds = getBundleIds(fragments); } else { fragmentIds = new long[0]; } return fragmentIds; } /** * Returns the bundle ids of any resolved hosts * * @param fragment * @param packageAdmin * @return * @throws IllegalArgumentException * if fragment or packageAdmin are null */ public static long[] getHostIds(Bundle fragment, PackageAdmin packageAdmin) throws IllegalArgumentException { if (fragment == null) { throw new IllegalArgumentException("Argument bundle cannot be null"); } if (packageAdmin == null) { throw new IllegalArgumentException("Argument packageAdmin cannot be null"); } long[] hostIds; Bundle[] hosts = packageAdmin.getHosts(fragment); if (hosts != null) { hostIds = getBundleIds(hosts); } else { hostIds = new long[0]; } return hostIds; } /** * Returns the resolved package imports for the given bundle * * @param localBundleContext * BundleContext object of this bundle/caller * @param bundle * target Bundle object to query imported packages for * @param packageAdmin * * @return * @throws IllegalArgumentException * if fragment or packageAdmin are null */ public static String[] getBundleImportedPackages(BundleContext localBundleContext, Bundle bundle, PackageAdmin packageAdmin) throws IllegalArgumentException { if (bundle == null) { throw new IllegalArgumentException("Argument bundle cannot be null"); } if (packageAdmin == null) { throw new IllegalArgumentException("Argument packageAdmin cannot be null"); } List<String> result = new ArrayList<String>(); for (ExportedPackage ep : getBundleImportedPackagesRaw(localBundleContext, bundle, packageAdmin)) { result.add(ep.getName()+";"+ep.getVersion()); } return result.toArray(new String[0]); } @SuppressWarnings("unchecked") private static Collection<ExportedPackage> getBundleImportedPackagesRaw(BundleContext localBundleContext, Bundle bundle, PackageAdmin packageAdmin) throws IllegalArgumentException { List<ExportedPackage> result = new ArrayList<ExportedPackage>(); Dictionary<String, String> bundleHeaders = bundle.getHeaders(); String dynamicImportHeader = bundleHeaders.get(Constants.DYNAMICIMPORT_PACKAGE); // if DynamicImport-Package used, then do full iteration // else means no dynamic import or has dynamic import but no wildcard "*" in it. if (dynamicImportHeader != null && dynamicImportHeader.contains("*")) { Bundle[] bundles = localBundleContext.getBundles(); for (Bundle candidate : bundles) { if (candidate.equals(bundle)) { continue; } ExportedPackage[] candidateExports = packageAdmin.getExportedPackages(candidate); if (candidateExports != null) { for (ExportedPackage exportedPackage : candidateExports) { Bundle[] userBundles = exportedPackage.getImportingBundles(); if (userBundles != null && arrayContains(userBundles, bundle)) { result.add(exportedPackage); } }// end for candidateExports } }// end for bundles } else { // only query ExportPackage for package names declared as imported List<String> importPackages = new ArrayList<String>(); String importPackageHeader = bundleHeaders.get(Constants.IMPORT_PACKAGE); if (importPackageHeader != null && importPackageHeader.length() > 0) { importPackages.addAll(extractHeaderDeclaration(importPackageHeader)); } if (dynamicImportHeader != null) { importPackages.addAll(extractHeaderDeclaration(dynamicImportHeader)); } for (String packageName : importPackages) { ExportedPackage[] candidateExports = packageAdmin.getExportedPackages(packageName); if (candidateExports != null) { for (ExportedPackage exportedPackage : candidateExports) { Bundle[] userBundles = exportedPackage.getImportingBundles(); if (userBundles != null && arrayContains(userBundles, bundle)) { result.add(exportedPackage); } }// end for candidateExports } } } return result; } /** * Returns the service.id values for services registered by the given bundle * * @param bundle * @return * @throws IllegalArgumentException * if bundle is null * @throws IlleglStateException * if bundle has been uninstalled */ public static long[] getRegisteredServiceIds(Bundle bundle) throws IllegalArgumentException, IllegalStateException { if (bundle == null) { throw new IllegalArgumentException("Argument bundle cannot be null"); } long[] serviceIds; ServiceReference[] serviceReferences = bundle.getRegisteredServices(); if (serviceReferences != null) { serviceIds = new long[serviceReferences.length]; for (int i = 0; i < serviceReferences.length; i++) { serviceIds[i] = (Long) serviceReferences[i].getProperty(Constants.SERVICE_ID); } } else { serviceIds = new long[0]; } return serviceIds; } /** * Returns the service.id values of services being used by the given bundle * * @param bundle * @return * @throws IllegalArgumentException * if bundle is null * @throws IlleglStateException * if bundle has been uninstalled */ public static long[] getServicesInUseByBundle(Bundle bundle) throws IllegalArgumentException, IllegalStateException { if (bundle == null) { throw new IllegalArgumentException("Argument bundle cannot be null"); } long[] serviceIds; ServiceReference[] serviceReferences = bundle.getServicesInUse(); if (serviceReferences != null) { serviceIds = new long[serviceReferences.length]; for (int i = 0; i < serviceReferences.length; i++) { serviceIds[i] = (Long) serviceReferences[i].getProperty(Constants.SERVICE_ID); } } else { serviceIds = new long[0]; } return serviceIds; } /** * Returns the status of pending removal * * @param bundle * @return true if the bundle is pending removal * @throws IllegalArgumentException * if bundle or packageAdmin are null */ public static boolean isBundlePendingRemoval(Bundle bundle, PackageAdmin packageAdmin) throws IllegalArgumentException { if (bundle == null) { throw new IllegalArgumentException("Argument bundle cannot be null"); } if (packageAdmin == null) { throw new IllegalArgumentException("Argument packageAdmin cannot be null"); } boolean result = false; ExportedPackage[] exportedPackages = packageAdmin.getExportedPackages(bundle); if (exportedPackages != null) { for (ExportedPackage exportedPackage : exportedPackages) { if (exportedPackage.isRemovalPending()) { result = true; break; } } } if (!result) { RequiredBundle[] requiredBundles = packageAdmin.getRequiredBundles(bundle.getSymbolicName()); if (requiredBundles != null) { for (RequiredBundle requiredBundle : requiredBundles) { Bundle required = requiredBundle.getBundle(); if (required == bundle) { result = requiredBundle.isRemovalPending(); break; } } } } return result; } /** * Checks if the given bundle is currently required by other bundles * * @param bundle * @param packageAdmin * @return * @throws IllegalArgumentException * if bundle or packageAdmin are null */ public static boolean isBundleRequiredByOthers(Bundle bundle, PackageAdmin packageAdmin) throws IllegalArgumentException { if (bundle == null) { throw new IllegalArgumentException("Argument bundle cannot be null"); } if (packageAdmin == null) { throw new IllegalArgumentException("Argument packageAdmin cannot be null"); } boolean result = false; // Check imported packages (statically or dynamically) ExportedPackage[] exportedPackages = packageAdmin.getExportedPackages(bundle); if (exportedPackages != null) { for (ExportedPackage exportedPackage : exportedPackages) { Bundle[] importingBundles = exportedPackage.getImportingBundles(); if (importingBundles != null && importingBundles.length > 0) { result = true; break; } } } if (!result) { // Check required bundles RequiredBundle[] requiredBundles = packageAdmin.getRequiredBundles(bundle.getSymbolicName()); if (requiredBundles != null) { for (RequiredBundle requiredBundle : requiredBundles) { Bundle required = requiredBundle.getBundle(); if (required == bundle) { Bundle[] requiring = requiredBundle.getRequiringBundles(); if (requiring != null && requiring.length > 0) { result = true; break; } } } } } if (!result) { // Check fragment bundles Bundle[] fragments = packageAdmin.getFragments(bundle); if (fragments != null && fragments.length > 0) { result = true; } } return result; } /** * Returns an array of ids of bundles the given bundle depends on * * @param localBundleContext * BundleContext object of this bundle/caller * @param bundle * target Bundle object to query dependencies for * @param packageAdmin * * @return * @throws IllegalArgumentException * if bundle or packageAdmin are null */ @SuppressWarnings("unchecked") public static long[] getBundleDependencies(BundleContext localBundleContext, Bundle bundle, PackageAdmin packageAdmin) throws IllegalArgumentException { if (bundle == null) { throw new IllegalArgumentException("Argument bundle cannot be null"); } if (packageAdmin == null) { throw new IllegalArgumentException("Argument packageAdmin cannot be null"); } Set<Bundle> dependencies = new HashSet<Bundle>(); for (ExportedPackage ep : getBundleImportedPackagesRaw(localBundleContext, bundle, packageAdmin)) { dependencies.add(ep.getExportingBundle()); } // Handle required bundles Dictionary<String, String> bundleHeaders = bundle.getHeaders(); String requireBundleHeader = bundleHeaders.get(Constants.REQUIRE_BUNDLE); if (requireBundleHeader != null) { // only check if Require-Bundle is used List<String> bundleSymbolicNames = extractHeaderDeclaration(requireBundleHeader); for (String bundleSymbolicName: bundleSymbolicNames) { RequiredBundle[] candidateRequiredBundles = packageAdmin.getRequiredBundles(bundleSymbolicName); if (candidateRequiredBundles != null) { for (RequiredBundle candidateRequiredBundle : candidateRequiredBundles) { Bundle[] bundlesRequiring = candidateRequiredBundle.getRequiringBundles(); if (bundlesRequiring != null && arrayContains(bundlesRequiring, bundle)) { dependencies.add(candidateRequiredBundle.getBundle()); } } } } } // Handle fragment bundles Bundle[] hosts = packageAdmin.getHosts(bundle); if (hosts != null) { for (Bundle host : hosts) { dependencies.add(host); } } return getBundleIds(dependencies.toArray(new Bundle[dependencies.size()])); } /** * Returns an array of ids of bundles that depend on the given bundle * * @param bundle * @param packageAdmin * @return * @throws IllegalArgumentException * if bundle or packageAdmin are null */ public static long[] getDependentBundles(Bundle bundle, PackageAdmin packageAdmin) throws IllegalArgumentException { if (bundle == null) { throw new IllegalArgumentException("Argument bundle cannot be null"); } if (packageAdmin == null) { throw new IllegalArgumentException("Argument packageAdmin cannot be null"); } Set<Bundle> dependencies = new HashSet<Bundle>(); // Handle imported packages (statically or dynamically) ExportedPackage[] exportedPackages = packageAdmin.getExportedPackages(bundle); if (exportedPackages != null) { for (ExportedPackage exportedPackage : exportedPackages) { Bundle[] importingBundles = exportedPackage.getImportingBundles(); if (importingBundles != null) { for (Bundle importingBundle : importingBundles) { dependencies.add(importingBundle); } } } } // Handle required bundles RequiredBundle[] requiredBundles = packageAdmin.getRequiredBundles(bundle.getSymbolicName()); if (requiredBundles != null) { for (RequiredBundle requiredBundle : requiredBundles) { Bundle required = requiredBundle.getBundle(); if (required == bundle) { Bundle[] requiringBundles = requiredBundle.getRequiringBundles(); if (requiringBundles != null) { for (Bundle requiringBundle : requiringBundles) { dependencies.add(requiringBundle); } } } } } // Handle fragment bundles Bundle[] fragments = packageAdmin.getFragments(bundle); if (fragments != null) { for (Bundle fragment : fragments) { dependencies.add(fragment); } } return getBundleIds(dependencies.toArray(new Bundle[dependencies.size()])); } /** * Returns a String representation of the bundles state * * @param bundle * @return */ public static String getBundleState(Bundle bundle) { String state = UNKNOWN; switch (bundle.getState()) { case Bundle.INSTALLED: state = INSTALLED; break; case Bundle.RESOLVED: state = RESOLVED; break; case Bundle.STARTING: state = STARTING; break; case Bundle.ACTIVE: state = ACTIVE; break; case Bundle.STOPPING: state = STOPPING; break; case Bundle.UNINSTALLED: state = UNINSTALLED; } return state; } /* * Checks if an object exists in the given array (based on object equality) */ public static boolean arrayContains(Object[] array, Object value) { boolean result = false; if (array != null && value != null) { for (Object element : array) { if (value.equals(element)) { result = true; break; } } } return result; } /* * Will parse a header value, strip out trailing attributes and return a list of declarations */ public static List<String> extractHeaderDeclaration(String headerStatement) { List<String> result = new ArrayList<String>(); for (String headerDeclaration : ManifestHeaderUtils.split(headerStatement, ",")) { String name = headerDeclaration.contains(";") ? headerDeclaration.substring(0, headerDeclaration .indexOf(";")) : headerDeclaration; result.add(name); } return result; } }