You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by ge...@apache.org on 2010/10/04 20:26:30 UTC
svn commit: r1004351 - in /karaf/branches/karaf-2.0.x/shell/osgi: pom.xml
src/main/java/org/apache/karaf/shell/osgi/Headers.java
Author: gertv
Date: Mon Oct 4 18:26:30 2010
New Revision: 1004351
URL: http://svn.apache.org/viewvc?rev=1004351&view=rev
Log:
KARAF-196 - Improve the output of osgi:headers command
Modified:
karaf/branches/karaf-2.0.x/shell/osgi/pom.xml
karaf/branches/karaf-2.0.x/shell/osgi/src/main/java/org/apache/karaf/shell/osgi/Headers.java
Modified: karaf/branches/karaf-2.0.x/shell/osgi/pom.xml
URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.0.x/shell/osgi/pom.xml?rev=1004351&r1=1004350&r2=1004351&view=diff
==============================================================================
--- karaf/branches/karaf-2.0.x/shell/osgi/pom.xml (original)
+++ karaf/branches/karaf-2.0.x/shell/osgi/pom.xml Mon Oct 4 18:26:30 2010
@@ -1,4 +1,5 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<!--
@@ -51,7 +52,11 @@
<artifactId>org.osgi.core</artifactId>
<scope>provided</scope>
</dependency>
-
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.utils</artifactId>
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>org.springframework.osgi</groupId>
<artifactId>spring-osgi-core</artifactId>
@@ -89,7 +94,7 @@
<DynamicImport-Package>
org.springframework.*
</DynamicImport-Package>
- <Private-Package>!*</Private-Package>
+ <Private-Package>org.apache.felix.utils.version,!*</Private-Package>
<_versionpolicy>${bnd.version.policy}</_versionpolicy>
</instructions>
</configuration>
Modified: karaf/branches/karaf-2.0.x/shell/osgi/src/main/java/org/apache/karaf/shell/osgi/Headers.java
URL: http://svn.apache.org/viewvc/karaf/branches/karaf-2.0.x/shell/osgi/src/main/java/org/apache/karaf/shell/osgi/Headers.java?rev=1004351&r1=1004350&r2=1004351&view=diff
==============================================================================
--- karaf/branches/karaf-2.0.x/shell/osgi/src/main/java/org/apache/karaf/shell/osgi/Headers.java (original)
+++ karaf/branches/karaf-2.0.x/shell/osgi/src/main/java/org/apache/karaf/shell/osgi/Headers.java Mon Oct 4 18:26:30 2010
@@ -16,39 +16,70 @@
*/
package org.apache.karaf.shell.osgi;
-import java.util.Dictionary;
-import java.util.Enumeration;
-import java.util.List;
-
-import org.apache.karaf.shell.console.OsgiCommandSupport;
import org.apache.felix.gogo.commands.Argument;
import org.apache.felix.gogo.commands.Command;
+import org.apache.felix.utils.version.VersionRange;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+import org.fusesource.jansi.Ansi;
import org.osgi.framework.Bundle;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+
+import java.util.*;
@Command(scope = "osgi", name = "headers", description = "Displays OSGi headers of a given bundle")
public class Headers extends OsgiCommandSupport {
+ protected final static String BUNDLE_PREFIX = "Bundle-";
+ protected final static String PACKAGE_SUFFFIX = "-Package";
+ protected final static String SERVICE_SUFFIX = "-Service";
+ protected final static String USES_ATTRIB = "uses:=";
+ protected final static String VERSION_ATTRIB = "version=";
+ protected final static String RESOLUTION_ATTRIB = "resolution:=";
+ protected final static String IMPORT_PACKAGES_ATTRIB = "Import-Package";
+ protected final static String REQUIRE_BUNDLE_ATTRIB = "Require-Bundle";
+
+ private ServiceReference ref;
+ private PackageAdmin admin;
+
@Argument(index = 0, name = "ids", description = "A list of bundle IDs separated by whitespaces", required = false, multiValued = true)
List<Long> ids;
protected Object doExecute() throws Exception {
- if (ids != null && !ids.isEmpty()) {
- for (long id : ids) {
- Bundle bundle = getBundleContext().getBundle(id);
- if (bundle != null) {
- printHeaders(bundle);
+ // Get package admin service.
+ ref = getBundleContext().getServiceReference(PackageAdmin.class.getName());
+ if (ref == null) {
+ System.out.println("PackageAdmin service is unavailable.");
+ return null;
+ }
+
+ try {
+ admin = (PackageAdmin) getBundleContext().getService(ref);
+ if (admin == null) {
+ System.out.println("PackageAdmin service is unavailable.");
+ return null;
+ }
+
+ if (ids != null && !ids.isEmpty()) {
+ for (long id : ids) {
+ Bundle bundle = getBundleContext().getBundle(id);
+ if (bundle != null) {
+ printHeaders(bundle);
+ } else {
+ System.err.println("Bundle ID " + id + " is invalid.");
+ }
}
- else {
- System.err.println("Bundle ID " + id + " is invalid.");
+ } else {
+ Bundle[] bundles = getBundleContext().getBundles();
+ for (int i = 0; i < bundles.length; i++) {
+ printHeaders(bundles[i]);
}
}
+ } finally {
+ getBundleContext().ungetService(ref);
}
- else {
- Bundle[] bundles = getBundleContext().getBundles();
- for (int i = 0; i < bundles.length; i++) {
- printHeaders(bundles[i]);
- }
- }
+
return null;
}
@@ -56,14 +87,475 @@ public class Headers extends OsgiCommand
String title = Util.getBundleName(bundle);
System.out.println("\n" + title);
System.out.println(Util.getUnderlineString(title));
+ System.out.println(generateFormattedOutput(bundle));
+ }
+
+ protected String generateFormattedOutput(Bundle bundle) {
+ StringBuffer output = new StringBuffer();
+ Map<String, Object> otherAttribs = new HashMap<String, Object>();
+ Map<String, Object> bundleAttribs = new HashMap<String, Object>();
+ Map<String, Object> serviceAttribs = new HashMap<String, Object>();
+ Map<String, Object> packagesAttribs = new HashMap<String, Object>();
Dictionary dict = bundle.getHeaders();
Enumeration keys = dict.keys();
- while (keys.hasMoreElements())
- {
- Object k = (String) keys.nextElement();
+
+ // do an initial loop and separate the attributes in different groups
+ while (keys.hasMoreElements()) {
+ String k = (String) keys.nextElement();
Object v = dict.get(k);
- System.out.println(k + " = " + Util.getValueString(v));
+ if (k.startsWith(BUNDLE_PREFIX)) {
+ // starts with Bundle-xxx
+ bundleAttribs.put(k, v);
+ } else if (k.endsWith(SERVICE_SUFFIX)) {
+ // ends with xxx-Service
+ serviceAttribs.put(k, v);
+ } else if (k.endsWith(PACKAGE_SUFFFIX)) {
+ // ends with xxx-Package
+ packagesAttribs.put(k, v);
+ } else if (k.endsWith(REQUIRE_BUNDLE_ATTRIB)) {
+ // require bundle statement
+ packagesAttribs.put(k, v);
+ } else {
+ // the remaining attribs
+ otherAttribs.put(k, v);
+ }
+ }
+
+ // we will display the formatted result like this:
+ // Bundle-Name (ID)
+ // -----------------------
+ // all other attributes
+ //
+ // all Bundle attributes
+ //
+ // all Service attributes
+ //
+ // all Package attributes
+ Iterator<Map.Entry<String, Object>> it = otherAttribs.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<String, Object> e = it.next();
+ output.append(String.format("%s = %s\n", e.getKey(), Util.getValueString(e.getValue())));
}
+ if (otherAttribs.size() > 0) {
+ output.append('\n');
+ }
+
+ it = bundleAttribs.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<String, Object> e = it.next();
+ output.append(String.format("%s = %s\n", e.getKey(), Util.getValueString(e.getValue())));
+ }
+ if (bundleAttribs.size() > 0) {
+ output.append('\n');
+ }
+
+ it = serviceAttribs.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<String, Object> e = it.next();
+ output.append(String.format("%s = %s\n", e.getKey(), Util.getValueString(e.getValue())));
+ }
+ if (serviceAttribs.size() > 0) {
+ output.append('\n');
+ }
+
+ it = packagesAttribs.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<String, Object> e = it.next();
+ if (e.getKey().equals(REQUIRE_BUNDLE_ATTRIB)) {
+ output.append(String.format("%s = %s\n", e.getKey(), getFormattedBundles(Util.getValueString(e.getValue()))));
+ } else {
+ output.append(String.format("%s = \n%s\n", e.getKey(), getFormattedPackages(Util.getValueString(e.getValue()), e.getKey().trim().equals(IMPORT_PACKAGES_ATTRIB))));
+ }
+ }
+ if (packagesAttribs.size() > 0) {
+ output.append('\n');
+ }
+
+ return output.toString();
}
+ protected String getFormattedPackages(String packagesString, boolean colorize) {
+ StringBuffer output = new StringBuffer();
+
+ List<PackageDefinition> packages = splitPackages(packagesString, colorize);
+ boolean first = true;
+ for (PackageDefinition def : packages) {
+ if (first) {
+ first = false;
+ } else {
+ output.append(",\n");
+ }
+ output.append(def.toString());
+ }
+ return output.toString();
+ }
+
+ protected String getFormattedBundles(String bundlesString) {
+ StringBuffer output = new StringBuffer();
+
+ List<BundleDefinition> bundles = splitBundles(bundlesString);
+ boolean first = true;
+ for (BundleDefinition def : bundles) {
+ if (first) {
+ first = false;
+ } else {
+ output.append(",\n");
+ }
+ output.append(def.toString());
+ }
+ return output.toString();
+ }
+
+ protected List<PackageDefinition> splitPackages(String packagesString, boolean colorize) {
+ boolean inQuotes = false;
+ List<PackageDefinition> parts = new ArrayList<PackageDefinition>();
+ StringBuffer statement = new StringBuffer();
+ for (int index = 0; index < packagesString.length(); index++) {
+ char c = packagesString.charAt(index);
+
+ if (c == '"') {
+ // quote switcher
+ inQuotes = !inQuotes;
+ }
+
+ if (c == ',' && !inQuotes) {
+ // package statement ends here
+ parts.add(new PackageDefinition(statement.toString(), colorize));
+ statement.setLength(0);
+ } else {
+ statement.append(c);
+ }
+ }
+
+ if (statement.length() > 0) {
+ parts.add(new PackageDefinition(statement.toString(), colorize));
+ }
+
+ return parts;
+ }
+
+ protected List<BundleDefinition> splitBundles(String bundlesString) {
+ boolean inQuotes = false;
+ List<BundleDefinition> parts = new ArrayList<BundleDefinition>();
+ StringBuffer statement = new StringBuffer();
+ for (int index = 0; index < bundlesString.length(); index++) {
+ char c = bundlesString.charAt(index);
+
+ if (c == '"') {
+ // quote switcher
+ inQuotes = !inQuotes;
+ }
+
+ if (c == ',' && !inQuotes) {
+ // package statement ends here
+ parts.add(new BundleDefinition(statement.toString()));
+ statement.setLength(0);
+ } else {
+ statement.append(c);
+ }
+ }
+
+ if (statement.length() > 0) {
+ parts.add(new BundleDefinition(statement.toString()));
+ }
+
+ return parts;
+ }
+
+ class PackageDefinition {
+ private String packageStr;
+ private String nameStr;
+ private String usesStr;
+ private String versionStr;
+ private String resolutionStr;
+ private List<String> usesItems;
+ private List<String> parameters;
+ private boolean colorize;
+
+ public PackageDefinition(String packageString, boolean colorize) {
+ this.packageStr = packageString;
+ this.colorize = colorize;
+ this.usesItems = new LinkedList<String>();
+ this.parameters = new LinkedList<String>();
+ parse();
+ }
+
+ private void parse() {
+ boolean inQuotes = false;
+ StringBuffer statement = new StringBuffer();
+ boolean first = true;
+ for (int index = 0; index < packageStr.length(); index++) {
+ char c = packageStr.charAt(index);
+
+ if (c == '"') {
+ // quote switcher
+ inQuotes = !inQuotes;
+ }
+
+ if (c == ';' && !inQuotes) {
+ // part finished
+ apply(statement.toString(), first);
+ first = false;
+ statement.setLength(0);
+ } else {
+ statement.append(c);
+ }
+ }
+
+ if (statement.length() > 0) {
+ apply(statement.toString(), first);
+ }
+ }
+
+ private void apply(String part, boolean first) {
+ if (part.startsWith(USES_ATTRIB)) {
+ // uses definition
+ this.usesStr = part;
+ StringTokenizer usesTok = new StringTokenizer(this.usesStr.substring(this.usesStr.indexOf(USES_ATTRIB) + USES_ATTRIB.length()).replaceAll("\"", ""), ",");
+ while (usesTok.hasMoreTokens()) {
+ this.usesItems.add(usesTok.nextToken());
+ }
+ } else if (part.startsWith(VERSION_ATTRIB)) {
+ // version definition
+ this.versionStr = part;
+ } else if (part.startsWith(RESOLUTION_ATTRIB)) {
+ // resolution definition
+ this.resolutionStr = part;
+ } else {
+ if (first) {
+ // must be package name
+ this.nameStr = part;
+ } else {
+ parameters.add(part);
+ }
+ }
+ }
+
+ public String getName() {
+ return this.nameStr;
+ }
+
+ public String getResolution() {
+ return this.resolutionStr;
+ }
+
+ public String getVersion() {
+ return this.versionStr;
+ }
+
+ public List<String> getUsesItems() {
+ return this.usesItems;
+ }
+
+ public String toString() {
+ StringBuffer output = new StringBuffer();
+
+ // output should look like this...
+ // <package>;
+ // uses:=<package>,
+ // <anotherPackage>,
+ // <etc>;
+ // <parameters>;
+ // version="<version>",
+ // resolution:="<resolution>",
+ // <blank line>
+ output.append(String.format("\t%s", this.getName()));
+
+ // we do a line feed if there are uses defined
+ if (this.usesItems.size() > 0) {
+ output.append(String.format(";\n\t%s \"", USES_ATTRIB));
+ boolean first = true;
+ for (String usesItem : this.usesItems) {
+ if (first) {
+ first = false;
+ } else {
+ output.append(",\n\t\t");
+ }
+ output.append(usesItem);
+ }
+ output.append("\"");
+
+ for (String param : this.parameters) {
+ if (first) {
+ first = false;
+ } else {
+ output.append(";\n\t");
+ }
+ output.append(String.format("%s", param));
+ }
+
+ if (this.getVersion() != null) {
+ output.append(String.format(";\n\t%s", this.getVersion()));
+ }
+ if (this.getResolution() != null) {
+ output.append(String.format(";\n\t%s", this.getResolution()));
+ }
+ } else {
+ // if there are no uses defined we put all on a single line
+ boolean first = true;
+ for (String param : this.parameters) {
+ if (first) {
+ first = false;
+ } else {
+ output.append(",\n\t\t");
+ }
+ output.append(String.format(";%s", param));
+ }
+
+ if (this.getVersion() != null) {
+ output.append(String.format(";%s", this.getVersion()));
+ }
+ if (this.getResolution() != null) {
+ output.append(String.format(";%s", this.getResolution()));
+ }
+ }
+
+ String retVal;
+
+ if (colorize) {
+ boolean isSatisfied = checkPackage(getName(), getVersion());
+ if (isSatisfied) {
+ // color it green
+ retVal = Ansi.ansi().fg(Ansi.Color.GREEN).a(output.toString()).reset().toString();
+ } else {
+ // color it red
+ retVal = Ansi.ansi().fg(Ansi.Color.RED).a(output.toString()).reset().toString();
+ }
+ } else {
+ retVal = output.toString();
+ }
+
+ return retVal;
+ }
+
+ private boolean checkPackage(String packageName, String versionInfo) {
+ boolean satisfied = false;
+ String version = versionInfo == null ? null : versionInfo.substring(versionInfo.indexOf('"') + 1, versionInfo.lastIndexOf('"'));
+ VersionRange range = version == null ? null : VersionRange.parseVersionRange(version);
+
+ if (admin != null) {
+ ExportedPackage[] packages = admin.getExportedPackages(packageName);
+ if (version == null) {
+ satisfied = packages != null && packages.length > 0;
+ } else {
+ if (packages != null) {
+ for (ExportedPackage export : packages) {
+ if (range.contains(export.getVersion())) {
+ satisfied = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return satisfied;
+ }
+ }
+
+ class BundleDefinition {
+ private String bundleStr;
+ private String nameStr;
+ private String versionStr;
+ private String resolutionStr;
+
+ public BundleDefinition(String bundleString) {
+ this.bundleStr = bundleString;
+ parse();
+ }
+
+ private void parse() {
+ boolean inQuotes = false;
+ StringBuffer statement = new StringBuffer();
+ for (int index = 0; index < this.bundleStr.length(); index++) {
+ char c = this.bundleStr.charAt(index);
+
+ if (c == '"') {
+ // quote switcher
+ inQuotes = !inQuotes;
+ }
+
+ if (c == ';' && !inQuotes) {
+ // part finished
+ apply(statement.toString());
+ statement.setLength(0);
+ } else {
+ statement.append(c);
+ }
+ }
+
+ if (statement.length() > 0) {
+ apply(statement.toString());
+ }
+ }
+
+ private void apply(String part) {
+ if (part.startsWith(VERSION_ATTRIB)) {
+ // version definition
+ this.versionStr = part;
+ } else if (part.startsWith(RESOLUTION_ATTRIB)) {
+ // resolution definition
+ this.resolutionStr = part;
+ } else {
+ // must be bundle name
+ this.nameStr = part;
+ }
+ }
+
+ public String getName() {
+ return this.nameStr;
+ }
+
+ public String getResolution() {
+ return this.resolutionStr;
+ }
+
+ public String getVersion() {
+ return this.versionStr;
+ }
+
+ public String toString() {
+ StringBuffer output = new StringBuffer();
+
+ // output should look like this...
+ // <bundle>;
+ // version="<version>",
+ // resolution:="<resolution>",
+ // <blank line>
+ output.append(String.format("\t%s", this.getName()));
+
+ // if there are no uses defined we put all on a single line
+ if (this.getVersion() != null) {
+ output.append(String.format(";%s", this.getVersion()));
+ }
+ if (this.getResolution() != null) {
+ output.append(String.format(";%s", this.getResolution()));
+ }
+
+ String retVal;
+
+ boolean isSatisfied = checkBundle(getName(), getVersion());
+ if (isSatisfied) {
+ // color it green
+ retVal = Ansi.ansi().fg(Ansi.Color.GREEN).a(output.toString()).reset().toString();
+ } else {
+ // color it red
+ retVal = Ansi.ansi().fg(Ansi.Color.RED).a(output.toString()).reset().toString();
+ }
+
+ return retVal;
+ }
+
+ private boolean checkBundle(String bundleName, String versionInfo) {
+ boolean satisfied = false;
+ String version = versionInfo == null ? null : versionInfo.substring(versionInfo.indexOf('"') + 1, versionInfo.lastIndexOf('"'));
+
+ if (admin != null) {
+ Bundle[] bundles = admin.getBundles(bundleName, version);
+ satisfied = bundles != null && bundles.length > 0;
+ }
+
+ return satisfied;
+ }
+ }
}