/**
* 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;
}
}