All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.oracle.tools.runtime.java.ClassPath Maven / Gradle / Ivy

/*
 * File: ClassPath.java
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * The contents of this file are subject to the terms and conditions of 
 * the Common Development and Distribution License 1.0 (the "License").
 *
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the License by consulting the LICENSE.txt file
 * distributed with this file, or by consulting https://oss.oracle.com/licenses/CDDL
 *
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file LICENSE.txt.
 *
 * MODIFICATIONS:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 */

package com.oracle.tools.runtime.java;

import com.oracle.tools.Option;
import com.oracle.tools.Options;

import com.oracle.tools.lang.StringHelper;

import com.oracle.tools.runtime.options.PlatformSeparators;

import com.oracle.tools.table.Table;
import com.oracle.tools.table.Tabular;

import java.io.File;
import java.io.IOException;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;

/**
 * A local immutable representation of a Java class path.
 * 

* Copyright (c) 2013. All Rights Reserved. Oracle Corporation.
* Oracle is a registered trademark of Oracle Corporation and/or its affiliates. * * @author Brian Oliver */ public class ClassPath implements Iterable, Tabular { /** * The known of Java Archives Types, typically used in class-paths and * file names. (strictly in ascending order). */ public static final String[] JAVA_ARCHIVE_TYPES = new String[] {"aar", "car", "ear", "gar", "jar", "rar", "sar", "war", "zip"}; /** * The paths that make up the {@link ClassPath}. */ private final ArrayList paths; /** * Constructs an empty {@link ClassPath} using the system default * {@link File#separator} and {@link File#pathSeparator}s. */ public ClassPath() { paths = new ArrayList(); } /** * Constructs a {@link ClassPath} based zero or more other {@link ClassPath}s. * (ie: a copy constructor) * * @param classPaths the {@link ClassPath}s to copy */ public ClassPath(ClassPath... classPaths) { paths = new ArrayList(); if (classPaths != null && classPaths.length > 0) { for (ClassPath classPath : classPaths) { for (String path : classPath) { path = sanitizePath(path); paths.add(path); } } } } /** * Constructs a {@link ClassPath} based zero or more other {@link ClassPath}s. * (ie: a copy constructor) * * @param classPaths the {@link ClassPath}s to copy */ public ClassPath(Iterable classPaths) { paths = new ArrayList(); if (classPaths != null) { for (ClassPath classPath : classPaths) { for (String path : classPath) { path = sanitizePath(path); paths.add(path); } } } } /** * Constructs a {@link ClassPath} from zero or more standard Java class-paths * (using the system defined path and file separators). * * @param classPaths zero or more Java class-paths */ public ClassPath(String... classPaths) { paths = new ArrayList(); if (classPaths != null) { for (String classPath : classPaths) { // sanitize the entire classpath classPath = classPath == null ? "" : classPath.trim(); // remove quotes classPath = StringHelper.dequote(classPath); if (!classPath.isEmpty()) { // separate the individual paths from the class path String[] paths = classPath.split(File.pathSeparator); for (String path : paths) { // sanitize the each path as well path = sanitizePath(path); if (!path.isEmpty()) { this.paths.add(path); } } } } } } /** * Obtain the number of path elements in the {@link ClassPath} * * @return the number of path elements */ public int size() { return paths.size(); } /** * Determines if the {@link ClassPath} is empty (contains no path definitions). * * @return true iff the {@link ClassPath} is empty */ public boolean isEmpty() { return paths.isEmpty(); } /** * Obtains the paths defined by the {@link ClassPath} as an array of URLs. * * @return an array of URLs representing the paths defined by the {@link ClassPath} */ public URL[] getURLs() { URL[] urls = new URL[paths.size()]; int i = 0; for (String path : paths) { try { urls[i++] = new File(path).toURI().toURL(); } catch (MalformedURLException e) { throw new RuntimeException("Failed to convert the path [" + path + "] into a URL", e); } } return urls; } /** * Determines if the {@link ClassPath} contains the specified path element. * * @param path the path element * * @return true iff the {@link ClassPath} contains the specified path element * (exact match) */ public boolean contains(String path) { if (path == null) { return false; } else { // sanitize the path path = sanitizePath(path); for (String aPath : paths) { if (aPath.equals(path)) { return true; } } return false; } } /** * Determines if the {@link ClassPath} contains all of the path elements defined * by the specified {@link ClassPath}. * * @param classPath the {@link ClassPath} containing the path elements to confirm * that are in this {@link ClassPath} * * @return true iff the specified {@link ClassPath} is contained in this {@link ClassPath} */ public boolean contains(ClassPath classPath) { if (classPath == null) { return false; } else { for (String path : classPath) { if (!contains(path)) { return false; } } return true; } } @Override public Iterator iterator() { return paths.iterator(); } /** * Obtains a String representation of the {@link ClassPath} that is suitable * for using as a Java class-path property (using the system defined * file and path separators). * * @return the Java class-path */ @Override public String toString() { return toString(PlatformSeparators.autoDetect()); } /** * Obtains a String representation of the {@link ClassPath} that is suitable * for using as a Java class-path property (using the specified * file and path separators). *

* Note: The returned String may contain spaces in which case the caller should * appropriate double-quote the String for their appropriate Platform. * * @return the Java class-path */ public String toString(Option... options) { StringBuilder builder = new StringBuilder(); Options opts = new Options(options); PlatformSeparators separators = opts.get(PlatformSeparators.class, PlatformSeparators.autoDetect()); ClassPathModifier modifier = opts.get(ClassPathModifier.class, ClassPathModifier.none()); String pathSeparator = separators.getPathSeparator(); for (String path : paths) { if (builder.length() > 0) { builder.append(pathSeparator); } // NOTE: DON'T BE TEMPTED TO DOUBLE QUOTE THESE PATH STRINGS! // (on certain platforms they may be double quoted again!) builder.append(path); } // NOTE: DON'T BE TEMPTED TO DOUBLE QUOTE THESE PATH STRINGS! // (on certain platforms they may be double quoted again!) return modifier.modify(builder.toString()); } @Override public Table getTable() { Table table = new Table(); for (String path : paths) { File file = new File(path); String parent = file.getParent(); table.addRow(file.getName(), parent == null ? "" : "(" + parent + ")"); } return table; } @Override public boolean equals(Object other) { if (this == other) { return true; } if (other == null || getClass() != other.getClass()) { return false; } ClassPath classPath = (ClassPath) other; return paths.equals(classPath.paths); } @Override public int hashCode() { return toString().hashCode(); } /** * Sanitizes a class-path element (a single path) by removing unnecessary * pre and post fix spaces, together with single and double quotes. * * @param path the path element to sanitize * * @return a sanitized non-null path */ private static String sanitizePath(String path) { if (path == null) { return ""; } else { // remove unnecessary white space path = path.trim(); // remove quotes path = StringHelper.unquote(path); if (!path.isEmpty()) { // add a file separator iff it's not an archive path = isResourceAnArchive(path) || path.endsWith(File.separator) || path.endsWith("*") ? path : path + File.separator; } return path; } } /** * Attempts to determine if the specified resource represents a known Java * Archive (based on the resource name, not attempting to load or unpack * it). * * @see #getResourceArchiveType(String) * @see #JAVA_ARCHIVE_TYPES * * @param resourceName the resource name * * @return true if the resource name is a known Java Archive. */ public static boolean isResourceAnArchive(String resourceName) { return getResourceArchiveType(resourceName) != null; } /** * Attempts to determine if the specified resource Java Archive type * (based on the resource name, not attempting to load or unpack it). *

* The algorithm succeeds if the specified resource ends in a * known Java Archive type extension (eg: .jar). Alternatively it succeeds * if the specified resource uses a Java Archive type as a URI protocol * (eg: jar://example.jar!MyClass). * * @see #JAVA_ARCHIVE_TYPES * * @param resourceName the resource name * * @return the Java Archive extension or null if the * resource is not a Java Archive */ public static String getResourceArchiveType(String resourceName) { // ensure we remove leading and trailing spaces resourceName = resourceName == null ? "" : resourceName.trim(); // attempt to determine the archive type based on the extension int index = resourceName.lastIndexOf("."); if (index >= 0) { String extension = resourceName.substring(index + 1).toLowerCase(); // search for the archive extension index = Arrays.binarySearch(JAVA_ARCHIVE_TYPES, extension); if (index >= 0) { return JAVA_ARCHIVE_TYPES[index]; } } // attempt to determine the archive type based on a prefix for (String archiveType : JAVA_ARCHIVE_TYPES) { if (resourceName.startsWith(archiveType + ":")) { return archiveType; } } // not found, so we assume it's not an archive return null; } /** * Obtains the {@link ClassPath} for the specified resource using the provided ClassLoader. * * @param resourceName the resource to locate * @param classLoader the ClassLoader (or null indicating the current * Thread getContextClassLoader()) * * @return a {@link ClassPath} representing the location of the specified resource * * @throws IOException when the resource can't be located */ public static ClassPath ofResource(String resourceName, ClassLoader classLoader) throws IOException { // ensure we have a resource name if (resourceName == null) { throw new NullPointerException("Resource name must not be null"); } else { // ensure we have a ClassLoader classLoader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader; // attempt to locate the resource Enumeration resources = classLoader.getResources(resourceName); if (resources.hasMoreElements()) { URL url = resources.nextElement(); // decode the URL to remove possible encoded characters String location = URLDecoder.decode(url.toExternalForm(), "UTF-8"); // encode spaces as %20 so we can create a valid URI location = location.replace(" ", "%20"); // remove the resource from the location // (as we want the location of the resource not the resource) location = location.substring(0, location.length() - resourceName.length() - 1); // determine the archive type String archiveType = getResourceArchiveType(location); if (archiveType != null && location.startsWith(archiveType + ":")) { location = location.substring(archiveType.length() + 1, location.length() - 1); } try { return new ClassPath(new File(new URI(location)).getAbsolutePath()); } catch (URISyntaxException e) { throw new IOException("Unable to create a ClassPath for [" + location + "] using ClassLoader [" + classLoader + "] as an illegal URI was encountered", e); } } else { throw new IOException("Unable to locate the specified resource [" + resourceName + "] using ClassLoader [" + classLoader + "] with ClassPath [" + ClassPath.ofSystem() + "]"); } } } /** * Obtains the {@link ClassPath} for the specified resource using the current Thread * context ClassLoader * * @param resourceName the resource to locate * * @return a {@link ClassPath} representing the location of the specified resource * * @throws IOException when the resource can't be located */ public static ClassPath ofResource(String resourceName) throws IOException { return ofResource(resourceName, Thread.currentThread().getContextClassLoader()); } /** * Obtains the {@link ClassPath} for the specified Class. * * @param clazz the class * * @return a {@link ClassPath} representing the location of the specified Class * * @throws IOException when the resource can't be located */ public static ClassPath ofClass(Class clazz) throws IOException { // ensure we have a class name if (clazz == null) { throw new NullPointerException("Class must not be null"); } else { // create a resource name for the class (must use a / here) String resourceName = clazz.getCanonicalName().replace(".", "/") + ".class"; // determine the location as a resource return ofResource(resourceName, clazz.getClassLoader()); } } /** * Obtains a {@link ClassPath} containing only absolute path of the specified File * * @param file the file */ public static ClassPath ofFile(File file) { if (file == null) { throw new NullPointerException("File must not be null"); } else { return new ClassPath(file.toString()); } } /** * Obtains Java System class-path. * * @return a {@link ClassPath} representing the System java.class.path property. */ public static ClassPath ofSystem() { return new ClassPath(System.getProperty("java.class.path")); } /** * Obtains a {@link ClassPath} for the specified {@link Iterable} of * path elements. * * @param paths the paths for the {@link ClassPath} * * @return a {@link ClassPath} representing the paths */ public static ClassPath of(Iterable paths) { if (paths == null) { return new ClassPath(); } else { ArrayList classPaths = new ArrayList(); for (String path : paths) { classPaths.add(new ClassPath(path)); } return new ClassPath(classPaths); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy