/* * Copyright (c) MuleSoft, Inc. All rights reserved. http://www.mulesoft.com * The software in this package is published under the terms of the CPAL v1.0 * license, a copy of which has been included with this distribution in the * LICENSE.txt file. */ package org.mule.runtime.container.internal; import static java.io.File.pathSeparatorChar; import static java.lang.String.format; import static org.mule.runtime.api.util.Preconditions.checkArgument; import org.mule.runtime.module.artifact.classloader.ExportedService; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** * Explores the content of the JRE used to run the container. */ public final class JreExplorer { private static final String META_INF_SERVICES_PATH = "META-INF/services/"; private JreExplorer() {} /** * Explores the content of the JRE being used * * @param packages will store the Java packages found on the environment. Non null. * @param resources will store the resources found on the environment. Non null. * @param services will store the services defined via SPI found on the environment. Non null. */ public static void exploreJdk(final Set<String> packages, Set<String> resources, List<ExportedService> services) { List<String> jdkPaths = new ArrayList<>(); jdkPaths.add(System.getProperty("sun.boot.class.path")); jdkPaths.add(System.getProperty("java.ext.dirs")); explorePaths(jdkPaths, packages, resources, services); } /** * Explores the provided paths searching for Java packages, resources and SPI service definitions * * @param jdkPaths paths to explore. Non null. * @param packages will store the Java packages found on the environment. Non null. * @param resources will store the resources found on the environment. Non null. * @param services will store the services defined via SPI found on the environment. Non null. */ static void explorePaths(final List<String> jdkPaths, final Set<String> packages, Set<String> resources, List<ExportedService> services) { checkArgument(jdkPaths != null && !jdkPaths.isEmpty(), "jdkPaths cannot be empty"); for (String jdkPath : jdkPaths) { explorePath(packages, resources, services, jdkPath); } } private static void explorePath(Set<String> packages, Set<String> resources, List<ExportedService> services, String jdkPath) { int fromIndex = 0; int endIndex; do { endIndex = jdkPath.indexOf(pathSeparatorChar, fromIndex); String item = endIndex == -1 ? jdkPath.substring(fromIndex) : jdkPath.substring(fromIndex, endIndex); final File file = new File(item); if (file.exists()) { if (file.isDirectory()) { exploreDirectory(packages, resources, services, file); } else { try { exploreJar(packages, resources, services, file); } catch (IOException e) { throw new IllegalStateException(createJarExploringError(file), e); } } } fromIndex = endIndex + 1; } while (endIndex != -1); } private static void exploreJar(Set<String> packages, Set<String> resources, List<ExportedService> services, File file) throws IOException { final ZipFile zipFile = new ZipFile(file); try { final Enumeration<? extends ZipEntry> entries = zipFile.entries(); while (entries.hasMoreElements()) { final ZipEntry entry = entries.nextElement(); final String name = entry.getName(); final int lastSlash = name.lastIndexOf('/'); if (lastSlash != -1 && name.endsWith(".class")) { packages.add(name.substring(0, lastSlash).replaceAll("/", ".")); } else if (!entry.isDirectory()) { if (name.startsWith(META_INF_SERVICES_PATH)) { String serviceInterface = name.substring(META_INF_SERVICES_PATH.length()); URL resource = getServiceResourceUrl(file.toURI().toURL(), name); services.add(new ExportedService(serviceInterface, resource)); } else { resources.add(name); } } } } finally { if (zipFile != null) try { zipFile.close(); } catch (Throwable ignored) { } } } private static void exploreDirectory(final Set<String> packages, Set<String> resources, List<ExportedService> services, final File file) { for (File entry : file.listFiles()) { if (entry.isDirectory()) { exploreDirectory(packages, resources, services, entry); } else if (entry.getName().endsWith(".jar")) { try { exploreJar(packages, resources, services, entry); } catch (IOException e) { throw new IllegalStateException(createJarExploringError(entry), e); } } } } private static String createJarExploringError(File file) { return format("Unable to explore '%s'", file.getAbsoluteFile()); } static URL getServiceResourceUrl(URL resource, String serviceInterface) throws MalformedURLException { return new URL("jar:" + resource + "!/" + serviceInterface); } }