csutherl commented on code in PR #919:
URL: https://github.com/apache/tomcat/pull/919#discussion_r2528070046


##########
java/org/apache/catalina/util/ServerInfo.java:
##########
@@ -129,6 +138,175 @@ public static void main(String[] args) {
         System.out.println("Architecture:   " + System.getProperty("os.arch"));
         System.out.println("JVM Version:    " + 
System.getProperty("java.runtime.version"));
         System.out.println("JVM Vendor:     " + 
System.getProperty("java.vm.vendor"));
+
+        // Get CATALINA_HOME for library scanning (already displayed in 
catalina script output preface)
+        String catalinaHome = System.getProperty("catalina.home");
+
+        // Display APR/Tomcat Native information if available
+        boolean aprLoaded = false;
+        try {
+            // Try to initialize APR by creating an instance and calling 
isAprAvailable()
+            // Creating an instance sets the instance flag which allows 
initialization
+            Class<?> aprLifecycleListenerClass = 
Class.forName("org.apache.catalina.core.AprLifecycleListener");
+            aprLifecycleListenerClass.getConstructor().newInstance();
+            Boolean aprAvailable = (Boolean) 
aprLifecycleListenerClass.getMethod("isAprAvailable").invoke(null);
+            if (aprAvailable != null && aprAvailable.booleanValue()) {
+                // APR is available, get version information using public 
methods
+                String tcnVersion = (String) 
aprLifecycleListenerClass.getMethod("getInstalledTcnVersion").invoke(null);
+                String aprVersion = (String) 
aprLifecycleListenerClass.getMethod("getInstalledAprVersion").invoke(null);
+
+                System.out.println("APR loaded:     true");
+                System.out.println("APR Version:    " + aprVersion);
+                System.out.println("Tomcat Native:  " + tcnVersion);
+                aprLoaded = true;
+
+                // Check if installed version is older than recommended
+                try {
+                    String warning = (String) 
aprLifecycleListenerClass.getMethod("getTcnVersionWarning").invoke(null);
+
+                    if (warning != null) {
+                        System.out.println("                " + warning);
+                    }
+                } catch (Exception e) {
+                    // Failed to check version - ignore
+                }
+
+                // Display OpenSSL version if available
+                try {
+                    String openSSLVersion = (String) 
aprLifecycleListenerClass.getMethod("getInstalledOpenSslVersion").invoke(null);
+
+                    if (openSSLVersion != null && !openSSLVersion.isEmpty()) {
+                        System.out.println("OpenSSL (APR):  " + 
openSSLVersion);
+                    }
+                } catch (Exception e) {
+                    // SSL not initialized or not available
+                }
+            }
+        } catch (ClassNotFoundException | NoClassDefFoundError e) {
+            // APR/Tomcat Native classes not available on classpath
+        } catch (Exception e) {
+            // Error checking APR status
+        }
+
+        if (!aprLoaded) {
+            System.out.println("APR loaded:     false");
+        }
+
+        // Display FFM OpenSSL information if available
+        try {
+            // Try to initialize FFM OpenSSL by creating an instance and 
calling isAvailable()
+            // Creating an instance sets the instance flag which allows 
initialization
+            Class<?> openSSLLifecycleListenerClass = 
Class.forName("org.apache.catalina.core.OpenSSLLifecycleListener");
+            openSSLLifecycleListenerClass.getConstructor().newInstance();
+            Boolean ffmAvailable = (Boolean) 
openSSLLifecycleListenerClass.getMethod("isAvailable").invoke(null);
+
+            if (ffmAvailable != null && ffmAvailable.booleanValue()) {
+                // FFM OpenSSL is available, get version information using 
public method
+                String versionString = (String) 
openSSLLifecycleListenerClass.getMethod("getInstalledOpenSslVersion").invoke(null);
+
+                if (versionString != null && !versionString.isEmpty()) {
+                    System.out.println("OpenSSL (FFM):  " + versionString);
+                }
+            }
+        } catch (ClassNotFoundException | NoClassDefFoundError e) {
+            // FFM OpenSSL classes not available on classpath
+        } catch (Exception e) {
+            // Error checking FFM OpenSSL status
+        }
+
+        // Display third-party libraries in CATALINA_HOME/lib
+        if (catalinaHome != null) {
+            File libDir = new File(catalinaHome, "lib");
+            if (libDir.exists() && libDir.isDirectory()) {
+                File[] allJars = libDir.listFiles((dir, name) -> 
name.endsWith(".jar"));
+
+                if (allJars != null && allJars.length > 0) {
+                    // First pass: collect third-party JARs and find longest 
name
+                    List<File> thirdPartyJars = new ArrayList<>();
+                    int maxNameLength = 0;
+                    for (File jar : allJars) {
+                        if (!isTomcatCoreJar(jar)) {
+                            thirdPartyJars.add(jar);
+                            maxNameLength = Math.max(maxNameLength, 
jar.getName().length());
+                        }
+                    }
+
+                    // Second pass: print with aligned formatting
+                    if (!thirdPartyJars.isEmpty()) {
+                        System.out.println();
+                        System.out.println("Third-party libraries:");
+                        for (File jar : thirdPartyJars) {
+                            String version = getJarVersion(jar);
+                            String jarName = jar.getName();
+                            // Colon right after name, then pad to align 
version numbers
+                            String nameWithColon = jarName + ":";
+                            String paddedName = String.format("%-" + 
(maxNameLength + 1) + "s", nameWithColon);
+                            if (version != null) {
+                                System.out.println("  " + paddedName + " " + 
version);
+                            } else {
+                                System.out.println("  " + paddedName + " 
(unknown)");
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private static boolean isTomcatCoreJar(File jarFile) {
+        try (JarFile jar = new JarFile(jarFile)) {
+            Manifest manifest = jar.getManifest();
+
+            if (manifest != null) {
+                // Check Bundle-SymbolicName to identify Tomcat core JARs
+                String bundleName = 
manifest.getMainAttributes().getValue("Bundle-SymbolicName");
+                if (bundleName != null) {
+                    // Tomcat core JARs have Bundle-SymbolicName starting with 
org.apache.tomcat,
+                    // org.apache.catalina, or jakarta.
+                    if (bundleName.startsWith("org.apache.tomcat") ||
+                            bundleName.startsWith("org.apache.catalina") ||
+                            bundleName.startsWith("jakarta.")) {
+                        return true;
+                    }
+                }
+
+                // Fallback: Check Implementation-Vendor and 
Implementation-Title
+                String implVendor = 
manifest.getMainAttributes().getValue("Implementation-Vendor");
+                String implTitle = 
manifest.getMainAttributes().getValue("Implementation-Title");
+
+                if ("Apache Software Foundation".equals(implVendor) && "Apache 
Tomcat".equals(implTitle)) {
+                    return true;
+                }
+            }
+        } catch (Exception e) {
+            // Ignore errors reading JAR manifest
+        }
+
+        return false;
+    }
+
+    private static String getJarVersion(File jarFile) {

Review Comment:
   That's better.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to