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

com.opensymphony.xwork2.util.finder.ResourceFinder Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package com.opensymphony.xwork2.util.finder;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.*;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * @author David Blevins
 */
public class ResourceFinder {
    private static final Logger LOG = LogManager.getLogger(ResourceFinder.class);

    private final URL[] urls;
    private final String path;
    private final ClassLoaderInterface classLoaderInterface;
    private final List resourcesNotLoaded = new ArrayList<>();

    public ResourceFinder(URL... urls) {
        this(null, new ClassLoaderInterfaceDelegate(Thread.currentThread().getContextClassLoader()), urls);
    }

    public ResourceFinder(String path) {
        this(path, new ClassLoaderInterfaceDelegate(Thread.currentThread().getContextClassLoader()), null);
    }

    public ResourceFinder(String path, URL... urls) {
        this(path, new ClassLoaderInterfaceDelegate(Thread.currentThread().getContextClassLoader()), urls);
    }

    public ResourceFinder(String path, ClassLoaderInterface classLoaderInterface) {
        this(path, classLoaderInterface, null);
    }

    /**
     * Create a ResourceFinder instance for looking up resources (via ClassLoader or via specific URLs
     * specifying resource locations).
     * 
     * This class was functional in Struts 2.3.x, but broken for Struts 2.5.x (before 2.5.24), when dealing with
     * JAR resources in certain circumstances.  The current logic permits the base path to be "" (empty string),
     * which is required to also match JAR entries rooted at "" and not just file entries rooted at "/".
     * 
     * @param path  Base path from which to look for resources (typically "xyz/abc/klm" form for file or
     *              jar contents).
     * @param classLoaderInterface  ClassLoader to perform the resource lookup.  If null, a default Thread
     *              ClassLoader will be used.
     * @param urls  URLs (typically file: or jar:) within which to search for resources, instead of the
     *              ClassLoader.  If null, fallback to a ClassLoader instead.
     */
    public ResourceFinder(String path, ClassLoaderInterface classLoaderInterface, URL... urls) {
        path = StringUtils.trimToEmpty(path);
        if (!path.isEmpty() && !StringUtils.endsWith(path, "/")) {
            path += "/";  // Only append terminator to nonempty paths, otherwise JAR entry lookups break.
        }
        this.path = path;

        this.classLoaderInterface = classLoaderInterface == null ? new ClassLoaderInterfaceDelegate(Thread.currentThread().getContextClassLoader()) : classLoaderInterface ;

        for (int i = 0; urls != null && i < urls.length; i++) {
            URL url = urls[i];
            if (url == null || isDirectory(url) || "jar".equals(url.getProtocol())) {
                continue;
            }
            try {
                urls[i] = new URL("jar", "", -1, url.toString() + "!/");
            } catch (MalformedURLException e) {
            }
        }
        this.urls = (urls == null || urls.length == 0)? null : urls;
    }

    private static boolean isDirectory(URL url) {
        String file = url.getFile();
        return (file.length() > 0 && file.charAt(file.length() - 1) == '/');
    }

    /**
     * 

* Returns a list of resources that could not be loaded in the last invoked findAvailable* or * mapAvailable* methods. *

* *

* The list will only contain entries of resources that match the requirements * of the last invoked findAvailable* or mapAvailable* methods, but were unable to be * loaded and included in their results. *

* *

* The list returned is unmodifiable and the results of this method will change * after each invocation of a findAvailable* or mapAvailable* methods. *

* * This method is not thread safe. * * @return not loaded resources */ public List getResourcesNotLoaded() { return Collections.unmodifiableList(resourcesNotLoaded); } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Find // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * public URL find(String uri) throws IOException { String fullUri = path + uri; return getResource(fullUri); } public List findAll(String uri) throws IOException { String fullUri = path + uri; Enumeration resources = getResources(fullUri); List list = new ArrayList<>(); while (resources.hasMoreElements()) { URL url = resources.nextElement(); list.add(url); } return list; } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Find String // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /** * Reads the contents of the URL as a {@link String}'s and returns it. * * @param uri URL * @return a stringified content of a resource * @throws IOException if a resource pointed out by the uri param could not be find * @see ClassLoader#getResource(String) */ public String findString(String uri) throws IOException { String fullUri = path + uri; URL resource = getResource(fullUri); if (resource == null) { throw new IOException("Could not find a resource in: " + fullUri); } return readContents(resource); } /** * Reads the contents of the found URLs as a list of {@link String}'s and returns them. * * @param uri URL * @return a list of the content of each resource URL found * @throws IOException if any of the found URLs are unable to be read. */ public List findAllStrings(String uri) throws IOException { String fulluri = path + uri; List strings = new ArrayList<>(); Enumeration resources = getResources(fulluri); while (resources.hasMoreElements()) { URL url = resources.nextElement(); String string = readContents(url); strings.add(string); } return strings; } /** * Reads the contents of the found URLs as a Strings and returns them. * Individual URLs that cannot be read are skipped and added to the * list of 'resourcesNotLoaded' * * @param uri URL * @return a list of the content of each resource URL found * @throws IOException if classLoader.getResources throws an exception */ public List findAvailableStrings(String uri) throws IOException { resourcesNotLoaded.clear(); String fulluri = path + uri; List strings = new ArrayList<>(); Enumeration resources = getResources(fulluri); while (resources.hasMoreElements()) { URL url = resources.nextElement(); try { String string = readContents(url); strings.add(string); } catch (IOException notAvailable) { resourcesNotLoaded.add(url.toExternalForm()); } } return strings; } /** *

* Reads the contents of all non-directory URLs immediately under the specified * location and returns them in a map keyed by the file name. *

* *

* Any URLs that cannot be read will cause an exception to be thrown. *

* *

* Example classpath: *

* *
     * META-INF/serializables/one
     * META-INF/serializables/two
     * META-INF/serializables/three
     * META-INF/serializables/four/foo.txt
     * 
* *
     * ResourceFinder finder = new ResourceFinder("META-INF/");
     * Map map = finder.mapAvailableStrings("serializables");
     * map.contains("one");  // true
     * map.contains("two");  // true
     * map.contains("three");  // true
     * map.contains("four");  // false
     * 
* * @param uri URL * @return a list of the content of each resource URL found * @throws IOException if any of the urls cannot be read */ public Map mapAllStrings(String uri) throws IOException { Map strings = new HashMap<>(); Map resourcesMap = getResourcesMap(uri); for (Map.Entry entry : resourcesMap.entrySet()) { String name = entry.getKey(); URL url = entry.getValue(); String value = readContents(url); strings.put(name, value); } return strings; } /** *

* Reads the contents of all non-directory URLs immediately under the specified * location and returns them in a map keyed by the file name. *

* *

* Individual URLs that cannot be read are skipped and added to the * list of 'resourcesNotLoaded' *

* *

* Example classpath: *

* *
     * META-INF/serializables/one
     * META-INF/serializables/two      # not readable
     * META-INF/serializables/three
     * META-INF/serializables/four/foo.txt
     * 
* *
     * ResourceFinder finder = new ResourceFinder("META-INF/");
     * Map map = finder.mapAvailableStrings("serializables");
     * map.contains("one");  // true
     * map.contains("two");  // false
     * map.contains("three");  // true
     * map.contains("four");  // false
     * 
* * @param uri URL * @return a list of the content of each resource URL found * @throws IOException if classLoader.getResources throws an exception */ public Map mapAvailableStrings(String uri) throws IOException { resourcesNotLoaded.clear(); Map strings = new HashMap<>(); Map resourcesMap = getResourcesMap(uri); for (Map.Entry entry : resourcesMap.entrySet()) { String name = entry.getKey(); URL url = entry.getValue(); try { String value = readContents(url); strings.put(name, value); } catch (IOException notAvailable) { resourcesNotLoaded.add(url.toExternalForm()); } } return strings; } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Find Class // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /** * Executes {@link #findString(String)} assuming the contents URL found is the name of * a class that should be loaded and returned. * * @param uri URL * @return class that should be loaded * @throws IOException in case of IO errors * @throws ClassNotFoundException when class is not found */ public Class findClass(String uri) throws IOException, ClassNotFoundException { String className = findString(uri); return (Class) classLoaderInterface.loadClass(className); } /** *

* Executes findAllStrings assuming the strings are * the names of a classes that should be loaded and returned. *

* *

* Any URL or class that cannot be loaded will cause an exception to be thrown. *

* * @param uri URL * @return classes that should be loaded * @throws IOException in case of IO errors * @throws ClassNotFoundException when class is not found */ public List findAllClasses(String uri) throws IOException, ClassNotFoundException { List classes = new ArrayList<>(); List strings = findAllStrings(uri); for (String className : strings) { Class clazz = classLoaderInterface.loadClass(className); classes.add(clazz); } return classes; } /** *

* Executes findAvailableStrings assuming the strings are * the names of a classes that should be loaded and returned. *

* *

* Any class that cannot be loaded will be skipped and placed in the * 'resourcesNotLoaded' collection. *

* * @param uri URL * @return list of available classes * @throws IOException if classLoader.getResources throws an exception */ public List findAvailableClasses(String uri) throws IOException { resourcesNotLoaded.clear(); List classes = new ArrayList<>(); List strings = findAvailableStrings(uri); for (String className : strings) { try { Class clazz = classLoaderInterface.loadClass(className); classes.add(clazz); } catch (Exception notAvailable) { resourcesNotLoaded.add(className); } } return classes; } /** *

* Executes mapAllStrings assuming the value of each entry in the * map is the name of a class that should be loaded. *

* *

* Any class that cannot be loaded will be cause an exception to be thrown. *

* *

* Example classpath: *

*
     * META-INF/xmlparsers/xerces
     * META-INF/xmlparsers/crimson
     * 
*
     * ResourceFinder finder = new ResourceFinder("META-INF/");
     * Map map = finder.mapAvailableStrings("xmlparsers");
     * map.contains("xerces");  // true
     * map.contains("crimson");  // true
     * Class xercesClass = map.get("xerces");
     * Class crimsonClass = map.get("crimson");
     * 
* * @param uri URL * @return map of all classes * @throws IOException in case of IO errors * @throws ClassNotFoundException when class is not found */ public Map mapAllClasses(String uri) throws IOException, ClassNotFoundException { Map classes = new HashMap<>(); Map map = mapAllStrings(uri); for (Map.Entry entry : map.entrySet()) { String string = entry.getKey(); String className = entry.getValue(); Class clazz = classLoaderInterface.loadClass(className); classes.put(string, clazz); } return classes; } /** *

* Executes mapAvailableStrings assuming the value of each entry in the * map is the name of a class that should be loaded. *

* *

* Any class that cannot be loaded will be skipped and placed in the * 'resourcesNotLoaded' collection. *

* *

* Example classpath: *

*
     * META-INF/xmlparsers/xerces
     * META-INF/xmlparsers/crimson
     * 
*
     * ResourceFinder finder = new ResourceFinder("META-INF/");
     * Map map = finder.mapAvailableStrings("xmlparsers");
     * map.contains("xerces");  // true
     * map.contains("crimson");  // true
     * Class xercesClass = map.get("xerces");
     * Class crimsonClass = map.get("crimson");
     * 
* * @param uri URL * @return map of available classes * @throws IOException if classLoader.getResources throws an exception */ public Map mapAvailableClasses(String uri) throws IOException { resourcesNotLoaded.clear(); Map classes = new HashMap<>(); Map map = mapAvailableStrings(uri); for (Map.Entry entry : map.entrySet()) { String string = entry.getKey(); String className = entry.getValue(); try { Class clazz = classLoaderInterface.loadClass(className); classes.put(string, clazz); } catch (Exception notAvailable) { resourcesNotLoaded.add(className); } } return classes; } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Find Implementation // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /** *

* Assumes the class specified points to a file in the classpath that contains * the name of a class that implements or is a subclass of the specfied class. *

* *

* Any class that cannot be loaded will be cause an exception to be thrown. *

* *

* Example classpath: *

* *
     * META-INF/java.io.InputStream    # contains the classname org.acme.AcmeInputStream
     * META-INF/java.io.OutputStream
     * 
*
     * ResourceFinder finder = new ResourceFinder("META-INF/");
     * Class clazz = finder.findImplementation(java.io.InputStream.class);
     * clazz.getName();  // returns "org.acme.AcmeInputStream"
     * 
* * @param interfase a superclass or interface * @return implementation class * @throws IOException if the URL cannot be read * @throws ClassNotFoundException if the class found is not loadable * @throws ClassCastException if the class found is not assignable to the specified superclass or interface */ public Class findImplementation(Class interfase) throws IOException, ClassNotFoundException { String className = findString(interfase.getName()); Class impl = classLoaderInterface.loadClass(className); if (!interfase.isAssignableFrom(impl)) { throw new ClassCastException("Class not of type: " + interfase.getName()); } return impl; } /** *

* Assumes the class specified points to a file in the classpath that contains * the name of a class that implements or is a subclass of the specfied class. *

* *

* Any class that cannot be loaded or assigned to the specified interface will be cause * an exception to be thrown. *

* *

* Example classpath: *

* *
     * META-INF/java.io.InputStream    # contains the classname org.acme.AcmeInputStream
     * META-INF/java.io.InputStream    # contains the classname org.widget.NeatoInputStream
     * META-INF/java.io.InputStream    # contains the classname com.foo.BarInputStream
     * 
* *
     * ResourceFinder finder = new ResourceFinder("META-INF/");
     * List classes = finder.findAllImplementations(java.io.InputStream.class);
     * classes.contains("org.acme.AcmeInputStream");  // true
     * classes.contains("org.widget.NeatoInputStream");  // true
     * classes.contains("com.foo.BarInputStream");  // true
     * 
* * @param interfase a superclass or interface * @return list of implementation classes * @throws IOException if the URL cannot be read * @throws ClassNotFoundException if the class found is not loadable * @throws ClassCastException if the class found is not assignable to the specified superclass or interface */ public List findAllImplementations(Class interfase) throws IOException, ClassNotFoundException { List implementations = new ArrayList<>(); List strings = findAllStrings(interfase.getName()); for (String className : strings) { Class impl = classLoaderInterface.loadClass(className); if (!interfase.isAssignableFrom(impl)) { throw new ClassCastException("Class not of type: " + interfase.getName()); } implementations.add(impl); } return implementations; } /** *

* Assumes the class specified points to a file in the classpath that contains * the name of a class that implements or is a subclass of the specfied class. *

* *

* Any class that cannot be loaded or are not assignable to the specified class will be * skipped and placed in the 'resourcesNotLoaded' collection. *

* *

* Example classpath: *

* *
     * META-INF/java.io.InputStream    # contains the classname org.acme.AcmeInputStream
     * META-INF/java.io.InputStream    # contains the classname org.widget.NeatoInputStream
     * META-INF/java.io.InputStream    # contains the classname com.foo.BarInputStream
     * 
* *
     * ResourceFinder finder = new ResourceFinder("META-INF/");
     * List classes = finder.findAllImplementations(java.io.InputStream.class);
     * classes.contains("org.acme.AcmeInputStream");  // true
     * classes.contains("org.widget.NeatoInputStream");  // true
     * classes.contains("com.foo.BarInputStream");  // true
     * 
* @param interfase a superclass or interface * @return list of implementation classes * @throws IOException if classLoader.getResources throws an exception */ public List findAvailableImplementations(Class interfase) throws IOException { resourcesNotLoaded.clear(); List implementations = new ArrayList<>(); List strings = findAvailableStrings(interfase.getName()); for (String className : strings) { try { Class impl = classLoaderInterface.loadClass(className); if (interfase.isAssignableFrom(impl)) { implementations.add(impl); } else { resourcesNotLoaded.add(className); } } catch (Exception notAvailable) { resourcesNotLoaded.add(className); } } return implementations; } /** *

* Assumes the class specified points to a directory in the classpath that holds files * containing the name of a class that implements or is a subclass of the specified class. *

* *

* Any class that cannot be loaded or assigned to the specified interface will be cause * an exception to be thrown. *

* *

* Example classpath: *

* *
     * META-INF/java.net.URLStreamHandler/jar
     * META-INF/java.net.URLStreamHandler/file
     * META-INF/java.net.URLStreamHandler/http
     * 
* *
     * ResourceFinder finder = new ResourceFinder("META-INF/");
     * Map map = finder.mapAllImplementations(java.net.URLStreamHandler.class);
     * Class jarUrlHandler = map.get("jar");
     * Class fileUrlHandler = map.get("file");
     * Class httpUrlHandler = map.get("http");
     * 
* * @param interfase a superclass or interface * @return map of implementation classes * @throws IOException if the URL cannot be read * @throws ClassNotFoundException if the class found is not loadable * @throws ClassCastException if the class found is not assignable to the specified superclass or interface */ public Map mapAllImplementations(Class interfase) throws IOException, ClassNotFoundException { Map implementations = new HashMap<>(); Map map = mapAllStrings(interfase.getName()); for (Map.Entry entry : map.entrySet()) { String string = entry.getKey(); String className = entry.getValue(); Class impl = classLoaderInterface.loadClass(className); if (!interfase.isAssignableFrom(impl)) { throw new ClassCastException("Class not of type: " + interfase.getName()); } implementations.put(string, impl); } return implementations; } /** *

* Assumes the class specified points to a directory in the classpath that holds files * containing the name of a class that implements or is a subclass of the specified class. *

* *

* Any class that cannot be loaded or are not assignable to the specified class will be * skipped and placed in the 'resourcesNotLoaded' collection. *

* *

* Example classpath: *

* *
     * META-INF/java.net.URLStreamHandler/jar
     * META-INF/java.net.URLStreamHandler/file
     * META-INF/java.net.URLStreamHandler/http
     * 
* *
     * ResourceFinder finder = new ResourceFinder("META-INF/");
     * Map map = finder.mapAllImplementations(java.net.URLStreamHandler.class);
     * Class jarUrlHandler = map.get("jar");
     * Class fileUrlHandler = map.get("file");
     * Class httpUrlHandler = map.get("http");
     * 
* * @param interfase a superclass or interface * @return list of available implementation classes * @throws IOException if classLoader.getResources throws an exception */ public Map mapAvailableImplementations(Class interfase) throws IOException { resourcesNotLoaded.clear(); Map implementations = new HashMap<>(); Map map = mapAvailableStrings(interfase.getName()); for (Map.Entry entry : map.entrySet()) { String string = entry.getKey(); String className = entry.getValue(); try { Class impl = classLoaderInterface.loadClass(className); if (interfase.isAssignableFrom(impl)) { implementations.put(string, impl); } else { resourcesNotLoaded.add(className); } } catch (Exception notAvailable) { resourcesNotLoaded.add(className); } } return implementations; } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Find Properties // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /** *

* Finds the corresponding resource and reads it in as a properties file *

* *

* Example classpath: *

* *
     * META-INF/widget.properties
     * 
* *
     * ResourceFinder finder = new ResourceFinder("META-INF/");
     * Properties widgetProps = finder.findProperties("widget.properties");
     * 
* * @param uri URL * @return corresponding resource as properties * @throws IOException if the URL cannot be read or is not in properties file format */ public Properties findProperties(String uri) throws IOException { String fulluri = path + uri; URL resource = getResource(fulluri); if (resource == null) { throw new IOException("Could not find command in : " + fulluri); } return loadProperties(resource); } /** *

* Finds the corresponding resources and reads them in as a properties files *

* *

* Any URL that cannot be read in as a properties file will cause an exception to be thrown. *

* *

* Example classpath: *

* *
     * META-INF/app.properties
     * META-INF/app.properties
     * META-INF/app.properties
     * 
* *
     * ResourceFinder finder = new ResourceFinder("META-INF/");
     * List<Properties> appProps = finder.findAllProperties("app.properties");
     * 
* * @param uri URL * @return corresponding resource as list of properties * @throws IOException if the URL cannot be read or is not in properties file format */ public List findAllProperties(String uri) throws IOException { String fulluri = path + uri; List properties = new ArrayList<>(); Enumeration resources = getResources(fulluri); while (resources.hasMoreElements()) { URL url = resources.nextElement(); Properties props = loadProperties(url); properties.add(props); } return properties; } /** *

* Finds the corresponding resources and reads them in as a properties files *

* *

* Any URL that cannot be read in as a properties file will be added to the * 'resourcesNotLoaded' collection. *

* *

* Example classpath: *

* *
     * META-INF/app.properties
     * META-INF/app.properties
     * META-INF/app.properties
     * 
* *
     * ResourceFinder finder = new ResourceFinder("META-INF/");
     * List<Properties> appProps = finder.findAvailableProperties("app.properties");
     * 
* * @param uri URL * @return corresponding resource as list of properties * @throws IOException if classLoader.getResources throws an exception */ public List findAvailableProperties(String uri) throws IOException { resourcesNotLoaded.clear(); String fulluri = path + uri; List properties = new ArrayList<>(); Enumeration resources = getResources(fulluri); while (resources.hasMoreElements()) { URL url = resources.nextElement(); try { Properties props = loadProperties(url); properties.add(props); } catch (Exception notAvailable) { resourcesNotLoaded.add(url.toExternalForm()); } } return properties; } /** *

* Finds the corresponding resources and reads them in as a properties files *

* *

* Any URL that cannot be read in as a properties file will cause an exception to be thrown. *

* *

* Example classpath: *

* *
     * META-INF/jdbcDrivers/oracle.properties
     * META-INF/jdbcDrivers/mysql.props
     * META-INF/jdbcDrivers/derby
     * 
* *
     * ResourceFinder finder = new ResourceFinder("META-INF/");
     * List<Properties> driversList = finder.findAvailableProperties("jdbcDrivers");
     * Properties oracleProps = driversList.get("oracle.properties");
     * Properties mysqlProps = driversList.get("mysql.props");
     * Properties derbyProps = driversList.get("derby");
     * 
* * @param uri URL * @return corresponding resource as map of properties * @throws IOException if the URL cannot be read or is not in properties file format */ public Map mapAllProperties(String uri) throws IOException { Map propertiesMap = new HashMap<>(); Map map = getResourcesMap(uri); for (Map.Entry entry : map.entrySet()) { String string = entry.getKey(); URL url = entry.getValue(); Properties properties = loadProperties(url); propertiesMap.put(string, properties); } return propertiesMap; } /** *

* Finds the corresponding resources and reads them in as a properties files *

* *

* Any URL that cannot be read in as a properties file will be added to the * 'resourcesNotLoaded' collection. *

* *

* Example classpath: *

* *
     * META-INF/jdbcDrivers/oracle.properties
     * META-INF/jdbcDrivers/mysql.props
     * META-INF/jdbcDrivers/derby
     * 
* *
     * ResourceFinder finder = new ResourceFinder("META-INF/");
     * List<Properties> driversList = finder.findAvailableProperties("jdbcDrivers");
     * Properties oracleProps = driversList.get("oracle.properties");
     * Properties mysqlProps = driversList.get("mysql.props");
     * Properties derbyProps = driversList.get("derby");
     * 
* * @param uri URL * @return corresponding resource as map of available properties * @throws IOException if classLoader.getResources throws an exception */ public Map mapAvailableProperties(String uri) throws IOException { resourcesNotLoaded.clear(); Map propertiesMap = new HashMap<>(); Map map = getResourcesMap(uri); for (Map.Entry entry : map.entrySet()) { String string = entry.getKey(); URL url = entry.getValue(); try { Properties properties = loadProperties(url); propertiesMap.put(string, properties); } catch (Exception notAvailable) { resourcesNotLoaded.add(url.toExternalForm()); } } return propertiesMap; } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Map Resources // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * public Map getResourcesMap(String uri) throws IOException { String basePath = path + uri; Map resources = new HashMap<>(); if (!basePath.endsWith("/")) { basePath += "/"; } Enumeration urls = getResources(basePath); while (urls.hasMoreElements()) { URL location = urls.nextElement(); try { if ("jar".equals(location.getProtocol())) { readJarEntries(location, basePath, resources); } else if ("file".equals(location.getProtocol())) { readDirectoryEntries(location, resources); } } catch (Exception e) { LOG.debug("Got exception loading resources for {}", uri, e); } } return resources; } /** * @param uri URL * @return set of subpackages from jars or dirs * * @throws IOException in case of IO errors */ public Set findPackages(String uri) throws IOException { String basePath = path + uri; Set resources = new HashSet<>(); if (!basePath.endsWith("/")) { basePath += "/"; } Enumeration urls = getResources(basePath); while (urls.hasMoreElements()) { URL location = urls.nextElement(); try { if ("jar".equals(location.getProtocol())) { readJarDirectoryEntries(location, basePath, resources); } else if ("file".equals(location.getProtocol())) { readSubDirectories(new File(location.toURI()), uri, resources); } } catch (Exception e) { LOG.debug("Got exception search for subpackages for {}", uri, e); } } return convertPathsToPackages(resources); } /** * @param uri URL * @return a map of subpackages from jars or dirs * * @throws IOException in case of IO errors */ public Map> findPackagesMap(String uri) throws IOException { String basePath = path + uri; LOG.trace(" basePath(initial): " + basePath); if (!basePath.endsWith("/")) { basePath += "/"; } LOG.trace(" basePath(final): " + basePath); Enumeration urls = getResources(basePath); Map> result = new HashMap<>(); if (! urls.hasMoreElements()) { LOG.debug(" urls enumeration for basePath is empty ?"); } while (urls.hasMoreElements()) { URL location = urls.nextElement(); LOG.debug(" url (location): " + location); try { if ("jar".equals(location.getProtocol())) { Set resources = new HashSet<>(); readJarDirectoryEntries(location, basePath, resources); result.put(location, convertPathsToPackages(resources)); } else if ("file".equals(location.getProtocol())) { Set resources = new HashSet<>(); readSubDirectories(new File(location.toURI()), uri, resources); result.put(location, convertPathsToPackages(resources)); } } catch (Exception e) { LOG.debug("Got exception finding subpackages for {}", uri, e); } } return result; } private Set convertPathsToPackages(Set resources) { Set packageNames = new HashSet<>(resources.size()); for(String resource : resources) { packageNames.add(StringUtils.removeEnd(StringUtils.replace(resource, "/", "."), ".")); } return packageNames; } private static void readDirectoryEntries(URL location, Map resources) throws MalformedURLException { File dir = new File(URLDecoder.decode(location.getPath())); if (dir.isDirectory()) { File[] files = dir.listFiles(); for (File file : files) { if (!file.isDirectory()) { String name = file.getName(); URL url = file.toURL(); resources.put(name, url); } } } } /** * Reads subdirectories of a file. The output is a list of subdirectories, relative to the basepath */ private static void readSubDirectories(File dir, String basePath, Set resources) throws MalformedURLException { if (dir.isDirectory()) { File[] files = dir.listFiles(); for (File file : files) { if (file.isDirectory()) { String name = file.getName(); String subName = StringUtils.removeEnd(basePath, "/") + "/" + name; resources.add(subName); readSubDirectories(file, subName, resources); } } } } private static void readJarEntries(URL location, String basePath, Map resources) throws IOException { JarURLConnection conn = (JarURLConnection) location.openConnection(); JarFile jarfile; jarfile = conn.getJarFile(); Enumeration entries = jarfile.entries(); while (entries != null && entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String name = entry.getName(); if (entry.isDirectory() || !name.startsWith(basePath) || name.length() == basePath.length()) { continue; } name = name.substring(basePath.length()); if (name.contains("/")) { continue; } URL resource = new URL(location, name); resources.put(name, resource); } } //read directories in the jar that start with the basePath private static void readJarDirectoryEntries(URL location, String basePath, Set resources) throws IOException { JarURLConnection conn = (JarURLConnection) location.openConnection(); JarFile jarfile; jarfile = conn.getJarFile(); Enumeration entries = jarfile.entries(); if (entries == null || ! entries.hasMoreElements()) { LOG.debug(" JAR entries null or empty"); } LOG.debug(" Looking for entries matching basePath: " + basePath); while (entries != null && entries.hasMoreElements()) { JarEntry entry = entries.nextElement(); String name = entry.getName(); if (entry.isDirectory() && StringUtils.startsWith(name, basePath)) { resources.add(name); } else if (entry.isDirectory()) { LOG.trace(" entry: " + name + " , isDirectory: " + entry.isDirectory() + " but does not start with basepath"); } } } private Properties loadProperties(URL resource) throws IOException { try (InputStream reader = new BufferedInputStream(resource.openStream())) { Properties properties = new Properties(); properties.load(reader); return properties; } } private String readContents(URL resource) throws IOException { StringBuilder sb = new StringBuilder(); try (InputStream reader = new BufferedInputStream(resource.openStream())) { int b = reader.read(); while (b != -1) { sb.append((char) b); b = reader.read(); } return sb.toString().trim(); } } private URL getResource(String fullUri) { if (urls == null){ return classLoaderInterface.getResource(fullUri); } return findResource(fullUri, urls); } private Enumeration getResources(String fulluri) throws IOException { if (urls == null) { LOG.debug(" urls (member) null, using classLoaderInterface to get resources"); return classLoaderInterface.getResources(fulluri); } LOG.debug(" urls (member) non-null, using findResource to get resources"); Vector resources = new Vector<>(); for (URL url : urls) { URL resource = findResource(fulluri, url); if (resource != null) { LOG.trace(" resource lookup non-null"); resources.add(resource); } else { LOG.trace(" resource lookup is null"); } } return resources.elements(); } private URL findResource(String resourceName, URL... search) { for (int i = 0; i < search.length; i++) { URL currentUrl = search[i]; if (currentUrl == null) { continue; } JarFile jarFile; try { String protocol = currentUrl.getProtocol(); if ("jar".equals(protocol)) { /* * If the connection for currentUrl or resURL is * used, getJarFile() will throw an exception if the * entry doesn't exist. */ URL jarURL = ((JarURLConnection) currentUrl.openConnection()).getJarFileURL(); try { JarURLConnection juc = (JarURLConnection) new URL("jar", "", jarURL.toExternalForm() + "!/").openConnection(); jarFile = juc.getJarFile(); } catch (IOException e) { // Don't look for this jar file again search[i] = null; throw e; } String entryName; if (currentUrl.getFile().endsWith("!/")) { entryName = resourceName; } else { String file = currentUrl.getFile(); int sepIdx = file.lastIndexOf("!/"); if (sepIdx == -1) { // Invalid URL, don't look here again search[i] = null; continue; } sepIdx += 2; StringBuilder sb = new StringBuilder(file.length() - sepIdx + resourceName.length()); sb.append(file.substring(sepIdx)); sb.append(resourceName); entryName = sb.toString(); } if ("META-INF/".equals(entryName) && jarFile.getEntry("META-INF/MANIFEST.MF") != null){ return targetURL(currentUrl, "META-INF/MANIFEST.MF"); } if (jarFile.getEntry(entryName) != null) { return targetURL(currentUrl, resourceName); } } else if ("file".equals(protocol)) { String baseFile = currentUrl.getFile(); String host = currentUrl.getHost(); int hostLength = 0; if (host != null) { hostLength = host.length(); } StringBuilder buf = new StringBuilder(2 + hostLength + baseFile.length() + resourceName.length()); if (hostLength > 0) { buf.append("//").append(host); } // baseFile always ends with '/' buf.append(baseFile); String fixedResName = resourceName; // Do not create a UNC path, i.e. \\host while (fixedResName.startsWith("/") || fixedResName.startsWith("\\")) { fixedResName = fixedResName.substring(1); } buf.append(fixedResName); String filename = buf.toString(); File file = new File(filename); File file2 = new File(URLDecoder.decode(filename)); if (file.exists() || file2.exists()) { return targetURL(currentUrl, fixedResName); } } else { URL resourceURL = targetURL(currentUrl, resourceName); URLConnection urlConnection = resourceURL.openConnection(); try { urlConnection.getInputStream().close(); } catch (SecurityException e) { return null; } // HTTP can return a stream on a non-existent file // So check for the return code; if (!"http".equals(resourceURL.getProtocol())) { return resourceURL; } int code = ((HttpURLConnection) urlConnection).getResponseCode(); if (code >= 200 && code < 300) { return resourceURL; } } } catch (IOException | SecurityException e) { // Keep iterating through the URL list } } return null; } private URL targetURL(URL base, String name) throws MalformedURLException { StringBuilder sb = new StringBuilder(base.getFile().length() + name.length()); sb.append(base.getFile()); sb.append(name); String file = sb.toString(); return new URL(base.getProtocol(), base.getHost(), base.getPort(), file, null); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy