From scm-return-45840-apmail-geronimo-scm-archive=geronimo.apache.org@geronimo.apache.org Tue Mar 15 20:38:41 2011 Return-Path: Delivered-To: apmail-geronimo-scm-archive@www.apache.org Received: (qmail 19863 invoked from network); 15 Mar 2011 20:38:41 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 15 Mar 2011 20:38:41 -0000 Received: (qmail 67044 invoked by uid 500); 15 Mar 2011 20:38:41 -0000 Delivered-To: apmail-geronimo-scm-archive@geronimo.apache.org Received: (qmail 67005 invoked by uid 500); 15 Mar 2011 20:38:41 -0000 Mailing-List: contact scm-help@geronimo.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: dev@geronimo.apache.org List-Id: Delivered-To: mailing list scm@geronimo.apache.org Received: (qmail 66998 invoked by uid 99); 15 Mar 2011 20:38:41 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 15 Mar 2011 20:38:41 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED,T_FILL_THIS_FORM_SHORT X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 15 Mar 2011 20:38:40 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 9F636238890D; Tue, 15 Mar 2011 20:38:17 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1081933 - /geronimo/server/trunk/framework/modules/geronimo-shell-diagnose/src/main/java/org/apache/geronimo/shell/diagnose/DiagnoseCommand.java Date: Tue, 15 Mar 2011 20:38:17 -0000 To: scm@geronimo.apache.org From: gawor@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20110315203817.9F636238890D@eris.apache.org> Author: gawor Date: Tue Mar 15 20:38:17 2011 New Revision: 1081933 URL: http://svn.apache.org/viewvc?rev=1081933&view=rev Log: GERONIMO-5779: Updated diagnose command to perform deeper analysis of some resolver problems Modified: geronimo/server/trunk/framework/modules/geronimo-shell-diagnose/src/main/java/org/apache/geronimo/shell/diagnose/DiagnoseCommand.java Modified: geronimo/server/trunk/framework/modules/geronimo-shell-diagnose/src/main/java/org/apache/geronimo/shell/diagnose/DiagnoseCommand.java URL: http://svn.apache.org/viewvc/geronimo/server/trunk/framework/modules/geronimo-shell-diagnose/src/main/java/org/apache/geronimo/shell/diagnose/DiagnoseCommand.java?rev=1081933&r1=1081932&r2=1081933&view=diff ============================================================================== --- geronimo/server/trunk/framework/modules/geronimo-shell-diagnose/src/main/java/org/apache/geronimo/shell/diagnose/DiagnoseCommand.java (original) +++ geronimo/server/trunk/framework/modules/geronimo-shell-diagnose/src/main/java/org/apache/geronimo/shell/diagnose/DiagnoseCommand.java Tue Mar 15 20:38:17 2011 @@ -17,14 +17,27 @@ package org.apache.geronimo.shell.diagnose; +import static org.eclipse.osgi.service.resolver.ResolverError.IMPORT_PACKAGE_USES_CONFLICT; +import static org.eclipse.osgi.service.resolver.ResolverError.MISSING_FRAGMENT_HOST; +import static org.eclipse.osgi.service.resolver.ResolverError.MISSING_IMPORT_PACKAGE; +import static org.eclipse.osgi.service.resolver.ResolverError.MISSING_REQUIRE_BUNDLE; +import static org.eclipse.osgi.service.resolver.ResolverError.REQUIRE_BUNDLE_USES_CONFLICT; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; import org.apache.felix.gogo.commands.Argument; import org.apache.felix.gogo.commands.Command; +import org.apache.felix.gogo.commands.Option; import org.apache.karaf.shell.console.OsgiCommandSupport; import org.eclipse.osgi.service.resolver.BundleDescription; import org.eclipse.osgi.service.resolver.BundleSpecification; +import org.eclipse.osgi.service.resolver.ExportPackageDescription; import org.eclipse.osgi.service.resolver.HostSpecification; import org.eclipse.osgi.service.resolver.ImportPackageSpecification; import org.eclipse.osgi.service.resolver.PlatformAdmin; @@ -44,6 +57,9 @@ public class DiagnoseCommand extends Osg @Argument(index = 0, name = "ids", description = "The list of bundle IDs separated by whitespaces", required = true, multiValued = true) List ids; + @Option(name = "-s", aliases = { "--simple" }, description = "Do not perform deeper analysis of resolver problems") + boolean simple = false; + private boolean hasPlatformAdmin() { try { bundleContext.getBundle().loadClass("org.eclipse.osgi.service.resolver.PlatformAdmin"); @@ -86,52 +102,22 @@ public class DiagnoseCommand extends Osg } private void diagnose(BundleDescription bundle, PlatformAdmin platformAdmin) { - System.out.println(bundle.getLocation() + " [" + bundle.getBundleId() + "]"); + System.out.println(bundleInfo(bundle)); StateHelper stateHelper = platformAdmin.getStateHelper(); - VersionConstraint[] unsatisfied = stateHelper.getUnsatisfiedConstraints(bundle); - ResolverError[] resolverErrors = platformAdmin.getState(false).getResolverErrors(bundle); - for (int i = 0; i < resolverErrors.length; i++) { - if ((resolverErrors[i].getType() & (ResolverError.MISSING_FRAGMENT_HOST - | ResolverError.MISSING_GENERIC_CAPABILITY - | ResolverError.MISSING_IMPORT_PACKAGE - | ResolverError.MISSING_REQUIRE_BUNDLE)) != 0) { - continue; - } - System.out.print(" "); - System.out.println(resolverErrors[i].toString()); - } - + VersionConstraint[] unsatisfied = stateHelper.getUnsatisfiedConstraints(bundle); + ResolverError[] resolverErrors = analyzeErrors(bundle, platformAdmin.getState(false)); + if (unsatisfied.length == 0 && resolverErrors.length == 0) { - System.out.print(" "); - System.out.println("No unresolved constraints."); + System.out.println(" No unresolved constraints."); } if (unsatisfied.length > 0) { - System.out.print(" "); - System.out.println("Unresolved direct constraints:"); + System.out.println(" Unresolved constraints:"); for (int i = 0; i < unsatisfied.length; i++) { System.out.print(" "); System.out.println(getResolutionFailureMessage(unsatisfied[i])); } } - - VersionConstraint[] unsatisfiedLeaves = stateHelper.getUnsatisfiedLeaves(new BundleDescription[] { bundle }); - boolean foundLeaf = false; - for (int i = 0; i < unsatisfiedLeaves.length; i++) { - BundleDescription leafBundle = unsatisfiedLeaves[i].getBundle(); - if (leafBundle == bundle) { - continue; - } - if (!foundLeaf) { - foundLeaf = true; - System.out.print(" "); - System.out.println("Unresolved constraints in dependency chain:"); - } - System.out.print(" "); - System.out.println(leafBundle.getLocation() + " [" + leafBundle.getBundleId() + "]"); - System.out.print(" "); - System.out.println(getResolutionFailureMessage(unsatisfiedLeaves[i])); - } } public static String getResolutionFailureMessage(VersionConstraint unsatisfied) { @@ -159,20 +145,216 @@ public class DiagnoseCommand extends Osg } } + private static String error(String msg) { + return Ansi.ansi().fg(Color.RED).a(msg).reset().toString(); + } + + private static String warning(String msg) { + return Ansi.ansi().fg(Color.YELLOW).a(msg).reset().toString(); + } + + public ResolverError[] analyzeErrors(BundleDescription bundle, State state) { + return analyzeErrors(bundle, state, new HashSet(), 2); + } + + private ResolverError[] analyzeErrors(BundleDescription bundle, State state, Set bundles, int level) { + if (bundles.contains(bundle)) { + return null; + } + bundles.add(bundle); + ResolverError[] errors = state.getResolverErrors(bundle); + if (level == 2 && errors.length > 0) { + System.out.println(" Resolver errors:"); + } + for (ResolverError error : errors) { + displayError(bundle, level, error.toString()); + VersionConstraint constraint = error.getUnsatisfiedConstraint(); + switch (error.getType()) { + case MISSING_IMPORT_PACKAGE: + ImportPackageSpecification pkgSpec = (ImportPackageSpecification)constraint; + for (BundleDescription b : state.getBundles()) { + for (ExportPackageDescription pkg : b.getExportPackages()) { + if (pkg.getName().equals(pkgSpec.getName())) { + if (pkgSpec.getVersionRange().isIncluded(pkg.getVersion())) { + if (!pkg.getExporter().isResolved()) { + displayError(b, level + 1, "Bundle unresolved: " + pkg); + analyzeErrors(pkg.getExporter(), state, bundles, level + 1); + } + } else { + displayError(b, level + 1, "Version mismatch: " + pkgSpec + " " + pkg); + } + } + } + } + break; + case MISSING_REQUIRE_BUNDLE: + case MISSING_FRAGMENT_HOST: + for (BundleDescription b : state.getBundles()) { + if (b == bundle) { + continue; + } + if (b.getSymbolicName() == null) { + displayError(b, level, "No SymbolicName for " + b.getLocation()); + continue; + } + if (constraint.getName() == null) { + displayError(bundle, level, "No constraint name: " + constraint); + } + if (b.getSymbolicName().equals(constraint.getName())) { + if (constraint.getVersionRange().isIncluded(b.getVersion())) { + // There must be something wrong in the bundle + analyzeErrors(b, state, bundles, level + 1); + } else { + displayError(bundle, level, "Version mismatch: " + constraint + " " + b); + } + } + } + break; + case IMPORT_PACKAGE_USES_CONFLICT: + ImportPackageSpecification importPackage = (ImportPackageSpecification)constraint; + ExportPackageDescription pkg = findExportPackage(importPackage, state.getExportedPackages()); + if (pkg != null) { + if (simple) { + displayError(pkg.getExporter(), level + 1, pkg.toString()); + } else { + String[] uses = (String[]) pkg.getDirective("uses"); + if (uses != null) { + for (String usePackageName : uses) { + checkPackageConflict(importPackage, pkg, usePackageName, state, level + 1); + } + } + } + } + break; + case REQUIRE_BUNDLE_USES_CONFLICT: + default: + // error is already logged + break; + } + } + return errors; + } + + private void checkPackageConflict(ImportPackageSpecification importPackage, ExportPackageDescription wiredExportPackage, String usePackageName, State state, int level) { + + BundleDescription importing = importPackage.getBundle(); + BundleDescription exporting = wiredExportPackage.getExporter(); + + // find import package the importing bundle has + ImportPackageSpecification useImportPackage = findImportPackage(usePackageName, importing.getImportPackages()); + + if (useImportPackage != null) { + + /* + * Find exported package the exporting bundle is wired to. + * A package in "uses" clause can refer to an imported package or exported package so + * need to check both places. + */ + ExportPackageDescription exportPackage = findExportPackage(usePackageName, exporting.getResolvedImports()); + if (exportPackage == null) { + exportPackage = findExportPackage(usePackageName, exporting.getExportPackages()); + } + + ExportPackageDescription highestExportPackage = findExportPackage(useImportPackage, state.getExportedPackages()); + + if (exportPackage.getExporter().getBundleId() != highestExportPackage.getExporter().getBundleId()) { + + displayError(null, level, "Found possible conflict for " + usePackageName + " package which is used by " + importPackage.getName() + " package:"); + + displayError(importing, level + 1, useImportPackage + " is wiring to " + bundleInfo(highestExportPackage.getExporter())); + displayError(importing, level + 1, importPackage + " is wiring to " + bundleInfo(wiredExportPackage.getExporter())); + + ImportPackageSpecification eImportPackage = findImportPackage(usePackageName, exporting.getImportPackages()); + if (eImportPackage == null) { + displayError(exporting, level + 2, exportPackage.toString()); + } else { + displayError(exporting, level + 2, eImportPackage + " is wiring to " + bundleInfo(exportPackage.getExporter())); + } + + } + } + + } + + private static ExportPackageDescription findExportPackage(String packageName, ExportPackageDescription[] exports) { + for (ExportPackageDescription pkg : exports) { + if (pkg.getName().equals(packageName)) { + return pkg; + } + } + return null; + } + + private static ImportPackageSpecification findImportPackage(String packageName, ImportPackageSpecification[] imports) { + for (ImportPackageSpecification pkg : imports) { + if (pkg.getName().equals(packageName)) { + return pkg; + } + } + return null; + } + + private static ExportPackageDescription findExportPackage(ImportPackageSpecification packageName, ExportPackageDescription[] exports) { + List matches = new ArrayList(2); + for (ExportPackageDescription pkg : exports) { + if (packageName.getName().equals(pkg.getName()) && packageName.getVersionRange().isIncluded(pkg.getVersion())) { + matches.add(pkg); + } + } + int size = matches.size(); + if (size == 0) { + return null; + } else if (size == 1) { + return matches.get(0); + } else { + Collections.sort(matches, ExportPackageComparator.INSTANCE); + return matches.get(0); + } + } + + private static class ExportPackageComparator implements Comparator { + + static final ExportPackageComparator INSTANCE = new ExportPackageComparator(); + + public int compare(ExportPackageDescription object1, ExportPackageDescription object2) { + return object2.getVersion().compareTo(object1.getVersion()); + } + } + + private static void displayError(BundleDescription bundle, int level, String object) { + StringBuilder msg = new StringBuilder(); + for (int i = 0; i < level; i++) { + msg.append(" "); + } + if (bundle != null) { + msg.append(error(bundleInfo(bundle))); + } + if (object != null) { + if (bundle != null) { + msg.append(" "); + } + msg.append(error(object)); + } + System.out.println(msg.toString()); + } + + private static String bundleInfo(BundleDescription bundle) { + return bundle.getSymbolicName() + " [" + bundle.getBundleId() + "]"; + } + private static String toString(VersionConstraint constraint) { VersionRange versionRange = constraint.getVersionRange(); if (versionRange == null) { return constraint.getName(); } else { - return constraint.getName() + '_' + versionRange; + String versionAttribute; + if (constraint instanceof ImportPackageSpecification) { + versionAttribute = "version=\"" + versionRange + "\""; + } else { + versionAttribute = "bundle-version=\"" + versionRange + "\""; + } + return constraint.getName() + "; " + versionAttribute; } } - - private static String error(String msg) { - return Ansi.ansi().fg(Color.RED).a(msg).reset().toString(); - } - private static String warning(String msg) { - return Ansi.ansi().fg(Color.YELLOW).a(msg).reset().toString(); - } }