/*******************************************************************************
* Copyright (c) 2010-2011 SAP AG 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:
* Hristo Iliev, SAP AG - initial contribution
* Glyn Normington, VMware Inc. - bind commands to Gogo
*******************************************************************************/
package org.eclipse.virgo.shell.osgicommand.internal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.felix.service.command.Descriptor;
import org.eclipse.virgo.shell.osgicommand.helper.ClassLoadingHelper;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
/**
* Class loading commands for supportability and diagnostics
*/
public class GogoClassLoadingCommand {
private BundleContext bundleContext;
public GogoClassLoadingCommand(BundleContext context) {
this.bundleContext = context;
}
/**
* Lists all bundles that contain a class
*
*/
@Descriptor("list all bundles that contain a class or resource with the specified name")
public void clhas(@Descriptor("class or resource name") String className) {
className = ClassLoadingHelper.convertToResourcePath(className);
Map<Bundle, List<String>> foundBundles = ClassLoadingHelper.getBundlesContainingResource(bundleContext, className);
if (foundBundles.size() == 0) {
System.out.println("No bundle contains [" + className + "]");
return;
}
outputBundlesAndResources("Bundles containing [" + className + "]:", foundBundles);
}
@Descriptor("list all bundles that can load the specified class")
public void clload(@Descriptor("fully qualified class name") String className) {
doClload(className, null);
}
@Descriptor("try to load the specified class using the specified bundle")
public void clload(@Descriptor("fully qualified class name") String className, @Descriptor("bundle symbolic name") String bundleName) {
doClload(className, bundleName);
}
@Descriptor("try to load the specified class using the specified bundle")
public void clload(@Descriptor("fully qualified class name") String className, @Descriptor(" bundle id") long bundleId) {
doClload(className, String.valueOf(bundleId));
}
private void doClload(String className, String bundle) {
if (extractPackage(className) == null) {
System.out.println("Warning: the class name [" + className + "] has no package and is assumed to belong to the default package");
}
Map<Bundle, Bundle> foundBundles;
if (bundle == null) {
foundBundles = ClassLoadingHelper.getBundlesLoadingClass(bundleContext, className);
} else {
foundBundles = ClassLoadingHelper.getBundlesLoadingClass(bundleContext, className, bundle);
}
if (foundBundles.size() == 0) {
if (bundle == null) {
System.out.println("No bundle can load class [" + className + "]");
} else {
System.out.println("Bundle [" + bundle + "] cannot load class [" + className + "]");
}
return;
}
outputFoundBundlesAndRelations("Successfully loaded [" + className + "] " + ((bundle != null) ? "using class loader from:" : "from:"),
foundBundles, "provided by");
}
/**
* Lists all bundles that export a class
*
*/
@Descriptor("list all bundles that export a class with the specified name")
public void clexport(@Descriptor("fully qualified class name") String className) {
String classPackage = extractPackage(className);
if (classPackage == null) {
System.out.println("The class name [" + className + "] contains no package");
return;
}
Bundle[] bundles = bundleContext.getBundles();
HashMap<Long, String> foundBundles = new HashMap<Long, String>();
for (Bundle bundle : bundles) {
if (ClassLoadingHelper.isPackageExported(bundleContext, classPackage, bundle)) {
if (ClassLoadingHelper.tryToLoadClass(className, bundle) != null) {
foundBundles.put(bundle.getBundleId(), bundle.getSymbolicName());
} else {
foundBundles.put(bundle.getBundleId(), bundle.getSymbolicName() + " [class not found, package only]");
}
}
}
if (foundBundles.size() == 0) {
System.out.println("No bundle exports class [" + className + "]");
return;
}
System.out.println();
System.out.println("Bundles exporting [" + className + "]:");
for (Map.Entry<Long, String> entry : foundBundles.entrySet()) {
System.out.println(" " + entry.getKey() + "\t" + entry.getValue());
}
}
private String extractPackage(String className) {
int index = className.lastIndexOf(".");
return index == -1 ? null : className.substring(0, index);
}
/**
* Outputs a list with all found bundles
*
* @param message Message to print before the list
* @param foundBundles A map with ID and bundle details
* @param relation Relation between the bundles
*/
private void outputFoundBundlesAndRelations(String message, Map<Bundle, Bundle> foundBundles, String relation) {
System.out.println();
System.out.println(message);
for (Map.Entry<Bundle, Bundle> entry : foundBundles.entrySet()) {
Bundle testBundle = entry.getKey();
Bundle originalBundle = entry.getValue();
if (testBundle.equals(originalBundle)) {
System.out.println(" " + bundleToString(testBundle, false));
} else {
System.out.println(" " + bundleToString(testBundle, false));
if (relation != null)
System.out.println(" \t\t[" + relation + " " + bundleToString(originalBundle, true) + "]");
}
}
}
/**
* Outputs a list with all found bundles
*
* @param message Message to print before the list
* @param foundBundles A map with Bundle and found resources
*/
private void outputBundlesAndResources(String message, Map<Bundle, List<String>> foundBundles) {
System.out.println();
System.out.println(message);
for (Map.Entry<Bundle, List<String>> bundleListEntry : foundBundles.entrySet()) {
System.out.println(" " + bundleToString(bundleListEntry.getKey(), false));
for (String resource : bundleListEntry.getValue()) {
System.out.println(" \t\t" + resource);
}
}
}
/**
* Provides String representation of a Bundle
*
* @param b See {@link org.osgi.framework.Bundle}
* @param space Separate ID and symbolic name with space instead of tab character
* @return String containing ID and symbolic name of the bundle
*/
private String bundleToString(Bundle b, boolean space) {
return b.getBundleId() + (space ? " " : "\t") + b.getSymbolicName();
}
}