ResourceUtil.java
/*******************************************************************************
* Copyright (c) 2015 Eclipse RDF4J contributors, Aduna, and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Distribution License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/
package org.eclipse.rdf4j.common.io;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;
/**
* ResourceUtil is a utility class for retrieving resources (images, property-files, etc) from the classpath.
*/
public class ResourceUtil {
/**
* The URL to the specified resource
*
* @param resourceName the name of the resource
* @return the URL to the specified resource, or null if the resource could not be found
*/
public static URL getURL(String resourceName) {
// most likely to succeed
URL result = Thread.currentThread().getContextClassLoader().getResource(resourceName);
if (result == null) {
// try the caller's class/classloader
Class<?> caller = getCaller();
result = caller.getResource(resourceName);
if (result == null) {
result = caller.getClassLoader().getResource(resourceName);
if (result == null) {
// last resort: the system classloader
result = ClassLoader.getSystemResource(resourceName);
}
}
}
return result;
}
/**
* Get an inputstream on the specified resource.
*
* @param resourceName the name of the resource
* @return an inputstream on the specified resource, or null if the resource could not be found
*/
public static InputStream getInputStream(String resourceName) {
// most likely to succeed
InputStream result = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName);
if (result == null) {
// try the caller's class/classloader
Class<?> caller = getCaller();
result = caller.getResourceAsStream(resourceName);
if (result == null) {
result = caller.getClassLoader().getResourceAsStream(resourceName);
if (result == null) {
// last resort: the system classloader
result = ClassLoader.getSystemResourceAsStream(resourceName);
}
}
}
return result;
}
/**
* Retrieve the String contents of the specified resource, obtained by opening in inputstream on the resource and
* then interpreting the bytes contained in the inputstream as if they represented characters. This may not make
* sense on all resources. There is no "magic" in this method to read anything other than plain text.
*
* @param resourceName the name of the resource
* @return the String contents of the specified resource, or null if the specified resource could not be found
* @throws IOException when something goes wrong trying to read the resource
*/
public static String getString(String resourceName) throws IOException {
try (InputStream in = ResourceUtil.getInputStream(resourceName)) {
if (in == null) {
return null;
}
return IOUtil.readString(in);
}
}
/**
* Retrieve a properties resource.
*
* @param resourceName the name of the resource
* @return a Properties object representing the contents of the resource, or null if the specified resource could
* not be found
* @throws IOException
*/
public static Properties getProperties(String resourceName) throws IOException {
URL resourceURL = getURL(resourceName);
if (resourceURL != null) {
try (InputStream in = resourceURL.openStream()) {
Properties result = new Properties();
result.load(in);
return result;
}
}
return null;
}
/**
* Retrieve the calling class of a method in this class.
*
* @return the calling class of a method in this class, or this class if no other class could be determined.
*/
private static Class<?> getCaller() {
Class<?> result = ResourceUtil.class;
Class<?>[] callStack = CallerResolver.INSTANCE.getClassContext();
if (callStack.length > 0) {
int index = 0;
// look for the first class on the stack that isn't this class or the
// inner utility class (it's most likely stack[2], but we don't want to
// count on that and find out it isn't)
while (index < callStack.length && (result == ResourceUtil.class || result == CallerResolver.class)) {
result = callStack[index];
index = index + 1;
}
}
return result;
}
/**
* A helper class to get the call context. It subclasses SecurityManager to make getClassContext() accessible. An
* instance of CallerResolver only needs to be created, not installed as an actual security manager. We use our own
* class instead of System.getSecurityManager(), because that may be set to null.
*/
private static final class CallerResolver extends SecurityManager {
private static final CallerResolver INSTANCE;
static {
try {
INSTANCE = new CallerResolver();
} catch (SecurityException se) {
throw new RuntimeException("Could not create CallerResolver: " + se);
}
}
@Override
protected Class<?>[] getClassContext() {
return super.getClassContext();
}
}
}