/*
* 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);
}
}