Fixing and enhancing FelixPrettyPrinter
diff --git a/bom/pom.xml b/bom/pom.xml
index 385e118..d65e170 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -30,7 +30,7 @@
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-bom</artifactId>
- <version>4.0.0-M3</version>
+ <version>4.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>HK2 Bom Pom</name>
diff --git a/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/FelixPrettyPrinter.java b/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/FelixPrettyPrinter.java
index fe17d96..cba598d 100644
--- a/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/FelixPrettyPrinter.java
+++ b/osgi/adapter/src/main/java/org/jvnet/hk2/osgiadapter/FelixPrettyPrinter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022 Contributors to the Eclipse Foundation
+ * Copyright (c) 2022, 2026 Contributors to the Eclipse Foundation
* Copyright (c) 2008, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
@@ -17,8 +17,6 @@
package org.jvnet.hk2.osgiadapter;
-import static java.nio.charset.StandardCharsets.UTF_8;
-
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -26,14 +24,22 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
+import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
+import org.osgi.framework.wiring.BundleRevision;
+import org.osgi.resource.Capability;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.osgi.framework.namespace.PackageNamespace.PACKAGE_NAMESPACE;
/**
* Tools for obtaining readable information from the {@link BundleException}
@@ -43,25 +49,29 @@
private static final Pattern BUNDLE_PATTERN = Pattern.compile("\\[(\\d+)\\]", Pattern.MULTILINE);
public static void main(String[] args) {
- System.out.println(prettyPrintExceptionMessage("missing requirement [org.glassfish.hk2.osgi-adapter [142](R 142.0)] osgi.wiring.package; (&(osgi.wiring.package=com.sun.enterprise.module.bootstrap)(version>=3.0.0)(!(version>=4.0.0))) [caused by: Unable to resolve org.glassfish.hk2.core [232](R 232.0): missing requirement [org.glassfish.hk2.core [232](R 232.0)] osgi.wiring.package; (&(osgi.wiring.package=org.glassfish.hk2.utilities)(version>=3.0.0)(!(version>=4.0.0))) [caused by: Unable to resolve org.glassfish.hk2.api [3](R 3.0): missing requirement [org.glassfish.hk2.api [3](R 3.0)] osgi.wiring.package; (&(osgi.wiring.package=org.glassfish.hk2.utilities.reflection)(version>=3.0.0)(!(version>=4.0.0))) [caused by: Unable to resolve org.glassfish.hk2.utils [2](R 2.0): missing requirement [org.glassfish.hk2.utils [2](R 2.0)] osgi.wiring.package; (&(osgi.wiring.package=jakarta.annotation)(version>=2.1.0)(!(version>=3.0.0)))]]] Unresolved requirements: [[org.glassfish.hk2.osgi-adapter [142](R 142.0)] osgi.wiring.package; (&(osgi.wiring.package=com.sun.enterprise.module.bootstrap)(version>=3.0.0)(!(version>=4.0.0)))]"));
+ System.out.println(prettyPrintExceptionMessage("org.osgi.framework.BundleException: Unable to resolve org.glassfish.main.web.weld-integration [41](R 41.0): missing requirement [org.glassfish.main.web.weld-integration [41](R 41.0)] osgi.wiring.package; (&(osgi.wiring.package=jakarta.faces.application)(version>=4.1.0)(!(version>=5.0.0))) [caused by: Unable to resolve org.glassfish.jakarta.faces [291](R 291.0): missing requirement [org.glassfish.jakarta.faces [291](R 291.0)] osgi.wiring.package; (&(osgi.wiring.package=jakarta.enterprise.inject)(version>=4.1.0)(!(version>=5.0.0)))] Unresolved requirements: [[org.glassfish.main.web.weld-integration [41](R 41.0)] osgi.wiring.package; (&(osgi.wiring.package=jakarta.faces.application)(version>=4.1.0)(!(version>=5.0.0)))]"));
}
public static String prettyPrintFelixMessage(BundleContext context, final String bundleMessage) {
- final String prettyMessage = FelixPrettyPrinter.prettyPrintExceptionMessage(bundleMessage);
- List<Integer> bundleIDs = FelixPrettyPrinter.findBundleIds(prettyMessage);
- if (bundleIDs.isEmpty()) {
- return prettyMessage;
- }
+ final String prettyMessage = prettyPrintExceptionMessage(bundleMessage);
final StringBuilder bundleBuilder = new StringBuilder(1024);
bundleBuilder.append(prettyMessage);
- for (Integer bundleId : bundleIDs) {
- Bundle bundle = context.getBundle(bundleId);
- if (bundle != null) {
- bundleBuilder.append('[').append(bundleId).append("] \n");
- bundleBuilder.append("jar = ").append(bundle.getLocation());
- tryAddPomProperties(bundle, bundleBuilder);
- bundleBuilder.append('\n');
+
+ List<Long> bundleIDs = new ArrayList<>();
+
+ bundleIDs.addAll(addExportingBundles(context, prettyMessage, bundleBuilder));
+ bundleIDs.addAll(findBundleIds(prettyMessage));
+
+ if (!bundleIDs.isEmpty()) {
+ for (Long bundleId : bundleIDs) {
+ Bundle bundle = context.getBundle(bundleId);
+ if (bundle != null) {
+ bundleBuilder.append('[').append(bundleId).append("] \n");
+ bundleBuilder.append("jar = ").append(bundle.getLocation());
+ tryAddPomProperties(bundle, bundleBuilder);
+ bundleBuilder.append('\n');
+ }
}
}
@@ -107,13 +117,17 @@
int indexPackage = message.indexOf("osgi.wiring.package; ", index);
int indexHost = message.indexOf("osgi.wiring.host; ", index);
- boolean isPackage;
- if (indexPackage < indexHost) {
+ boolean hasPackage = indexPackage >= 0;
+ boolean hasHost = indexHost >= 0;
+
+ boolean isPackage = false;
+ if (hasPackage && (!hasHost || indexPackage < indexHost)) {
index = indexPackage;
isPackage = true;
- } else {
+ } else if (hasHost) {
index = indexHost;
- isPackage = false;
+ } else {
+ index = -1;
}
if (index >= 0) {
@@ -221,8 +235,69 @@
return bundleBuilder.toString();
}
+ private static List<Long> addExportingBundles(BundleContext context, String prettyMessage, StringBuilder bundleBuilder) {
+ Set<Bundle> exportingBundles = new HashSet<>();
+ List<Long> bundleIDs = new ArrayList<>();
+
+ int lastPackageindex = prettyMessage.lastIndexOf("package = ");
+ if (lastPackageindex != -1) {
+ String lastPackage = prettyMessage.substring(lastPackageindex + "package = ".length(), prettyMessage.indexOf(")", lastPackageindex));
+
+ exportingBundles.addAll(findExporters(context, lastPackage));
+
+ if (exportingBundles.isEmpty()) {
+ bundleBuilder.append("\nNo bundles found to export " + lastPackage + "\n");
+ } else {
+ bundleBuilder.append("\nThe following bundles export \"" + lastPackage + "\"\n");
+ for (Bundle bundle : exportingBundles) {
+ bundleIDs.add(bundle.getBundleId());
+
+ bundleBuilder.append(bundle.getSymbolicName())
+ .append(" ")
+ .append(bundle.getVersion())
+ .append(" [")
+ .append(bundle.getBundleId())
+ .append("]")
+ .append("\n")
+ ;
+ }
+ }
+ bundleBuilder.append("\n");
+ }
+
+ return bundleIDs;
+ }
+
+ private static List<Bundle> findExporters(BundleContext ctx, String packageName) {
+ List<Bundle> exporters = new ArrayList<>();
+
+ for (Bundle b : ctx.getBundles()) {
+ BundleRevision rev = b.adapt(BundleRevision.class);
+ if (rev == null) {
+ continue;
+ }
+
+ List<Capability> caps = rev.getCapabilities(PACKAGE_NAMESPACE);
+ for (Capability cap : caps) {
+ Map<String, Object> attrs = cap.getAttributes();
+ Object exportedPkg = attrs.get(PACKAGE_NAMESPACE);
+
+ if (packageName.equals(exportedPkg)) {
+ exporters.add(b);
+ break; // one match is enough per bundle
+ }
+ }
+ }
+
+ return exporters;
+ }
+
private static void tryAddPomProperties(Bundle bundle, StringBuilder bundleBuilder) {
Enumeration<URL> entries = bundle.findEntries("META-INF/maven/", "pom.properties", true);
+ if (entries == null) {
+ return;
+ }
+
while (entries.hasMoreElements()) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(entries.nextElement().openStream(), UTF_8))) {
reader.lines()
@@ -240,15 +315,15 @@
* @param message - error message from the exception
* @return list of bundle ids (are in square brackets in the message)
*/
- public static List<Integer> findBundleIds(final String message) {
+ public static List<Long> findBundleIds(final String message) {
if (message == null || message.isEmpty()) {
return Collections.emptyList();
}
- Set<Integer> bundleIds = new LinkedHashSet<>();
+ Set<Long> bundleIds = new LinkedHashSet<>();
Matcher bundlePattern = BUNDLE_PATTERN.matcher(message);
while (bundlePattern.find()) {
String number = bundlePattern.group(1);
- bundleIds.add(Integer.valueOf(number));
+ bundleIds.add(Long.valueOf(number));
}
return new ArrayList<>(bundleIds);
}