net.sf.jasperreports.engine.util.JRResourcesUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jasperreports Show documentation
Show all versions of jasperreports Show documentation
Free Java Reporting Library
/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
* http://www.jaspersoft.com
*
* Unless you have purchased a commercial license agreement from Jaspersoft,
* the following license terms apply:
*
* This program is part of JasperReports.
*
* JasperReports is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JasperReports is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with JasperReports. If not, see .
*/
package net.sf.jasperreports.engine.util;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.nio.file.InvalidPathException;
import java.nio.file.Paths;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.function.Function;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperReportsContext;
import net.sf.jasperreports.repo.RepositoryContext;
import net.sf.jasperreports.repo.RepositoryResourceContext;
import net.sf.jasperreports.repo.RepositoryUtil;
import net.sf.jasperreports.repo.ResourceBundleResource;
import net.sf.jasperreports.repo.SimpleRepositoryContext;
/**
* Provides methods for resource resolution via class loaders or URL stream handlers.
*
* @author Lucian Chirita ([email protected])
*/
public final class JRResourcesUtil
{
private static final Log log = LogFactory.getLog(JRResourcesUtil.class);
/**
*
*/
private static final String PROPERTIES_FILE_EXTENSION = ".properties";
/**
*
*/
private static ClassLoader globalClassLoader;
/**
*
*/
private static ThreadLocalStack localClassLoaderStack = new ThreadLocalStack();
/**
* Tries to parse a String
as an URL.
*
* @param spec the String
to parse
* @param urlHandlerFactory an URL stream handler factory to use
* @return an URL if the parsing is successful
* @see #getURLHandler(String, URLStreamHandlerFactory)
*/
public static URL createURL(String spec, URLStreamHandlerFactory urlHandlerFactory)
{
URLStreamHandler handler = getURLHandler(spec, urlHandlerFactory);
URL url;
try
{
if (handler == null)
{
url = new URL(spec);
}
else
{
url = new URL(null, spec, handler);
}
}
catch (MalformedURLException e)
{
url = null;
}
return url;
}
/**
* Returns an URL stream handler for an URL specified as a String
.
*
* @param spec the String
to parse as an URL
* @param urlHandlerFact an URL stream handler factory
* @return an URL stream handler if one was found for the protocol of the URL
*/
public static URLStreamHandler getURLHandler(String spec, URLStreamHandlerFactory urlHandlerFact)
{
URLStreamHandlerFactory urlHandlerFactory = urlHandlerFact;//getURLHandlerFactory(urlHandlerFact);
URLStreamHandler handler = null;
if (urlHandlerFactory != null)
{
String protocol = getURLProtocol(spec);
if (protocol != null)
{
handler = urlHandlerFactory.createURLStreamHandler(protocol);
}
}
return handler;
}
private static String getURLProtocol(String urlSpec)
{
String protocol = null;
String spec = urlSpec.trim();
int colon = spec.indexOf(':');
if (colon > 0)
{
String proto = spec.substring(0, colon);
if (protocolValid(proto))
{
protocol = proto;
}
}
return protocol;
}
private static boolean protocolValid(String protocol)
{
int length = protocol.length();
if (length < 1)
{
return false;
}
if (!Character.isLetter(protocol.charAt(0)))
{
return false;
}
for (int i = 1; i < length; ++i)
{
char c = protocol.charAt(i);
if (!(Character.isLetterOrDigit(c) || c == '+' || c == '-' || c == '.'))
{
return false;
}
}
return true;
}
/**
* Attempts to find a file using a file resolver.
*
* @param location file name
* @param fileRes a file resolver
* @return the file, if found
* @deprecated To be removed.
*/
public static File resolveFile(String location, FileResolver fileRes)
{
FileResolver fileResolver = fileRes;//getFileResolver(fileRes);
if (fileResolver != null)
{
return fileResolver.resolveFile(location);
}
return resolveFile(null, location);
}
public static File resolveFile(RepositoryContext context, String location)
{
return resolveFile(context, location, JRResourcesUtil::defaultLocateFile);
}
public static File resolveFile(RepositoryContext context, String location, Function rootLocator)
{
File file = locateFile(context == null ? null : context.getResourceContext(), location, rootLocator);
if (file != null && file.isFile())
{
return file;
}
return null;
}
protected static File defaultLocateFile(String location)
{
File file = new File(location);
if (file.exists())
{
return file;
}
return null;
}
protected static File locateFile(RepositoryResourceContext resourceContext, String location, Function rootLocator)
{
File file = rootLocator.apply(location);
if (file != null)
{
return file;
}
if (resourceContext != null)
{
RepositoryResourceContext context = resourceContext;
while (context != null)
{
File contextDir = locateContextDirectory(context, rootLocator);
if (contextDir != null)
{
file = new File(contextDir, location);
if (file.exists())
{
if (log.isDebugEnabled())
{
log.debug("resolved location " + location + " relative to the context " + contextDir);
}
return file;
}
}
context = context.getFallbackContext();
}
}
return null;
}
protected static File locateContextDirectory(RepositoryResourceContext resourceContext, Function rootLocator)
{
String contextLocation = resourceContext.getContextLocation();
if (contextLocation != null)
{
try
{
Paths.get(contextLocation);//valid patch check
File contextDir = rootLocator.apply(contextLocation);
if (contextDir != null && contextDir.isDirectory())
{
return contextDir;
}
}
catch (InvalidPathException e)
{
if (log.isDebugEnabled())
{
log.debug("location \"" + contextLocation + "\" is not a file path: " + e);
}
}
}
return null;
}
/**
* Returns a class loader.
*
* The first not null value from the following is returned:
*
* - the value of the parameter
* - the thread local class loader
* - the global class loader
*
*
* @param clsLoader a class loader that will be returned if not null
* @return a class loader.
* @see #setGlobalClassLoader(ClassLoader)
* @see #setThreadClassLoader(ClassLoader)
*/
public static ClassLoader getClassLoader(ClassLoader clsLoader)
{
ClassLoader classLoader = clsLoader;
if (classLoader == null)
{
classLoader = getThreadClassLoader();
if (classLoader == null)
{
classLoader = globalClassLoader;
}
}
return classLoader;
}
/**
* Returns the global class loader.
*
* @return the global class loader.
* @see #setGlobalClassLoader(ClassLoader)
*/
public static ClassLoader getGlobalClassLoader()
{
return globalClassLoader;
}
/**
* Returns the thread local class loader.
*
* @return the thread local class loader.
* @see #setThreadClassLoader(ClassLoader)
*/
public static ClassLoader getThreadClassLoader()
{
return (ClassLoader) localClassLoaderStack.top();
}
/**
* Sets the thread local class loader.
*
* @param classLoader a class loader
* @see #getClassLoader(ClassLoader)
*/
public static void setThreadClassLoader(ClassLoader classLoader)
{
localClassLoaderStack.push(classLoader);
}
/**
* Resets the the thread local class loader to its previous value.
*/
public static void resetClassLoader()
{
localClassLoaderStack.pop();
}
/**
* Sets a global class loader to be used for resource resolution.
*
* @param classLoader the class loader
* @see #getClassLoader(ClassLoader)
*/
public static void setGlobalClassLoader(ClassLoader classLoader)
{
globalClassLoader = classLoader;
}
/**
* Attempts to find a resource using a class loader.
*
* The following sources are tried:
*
* - the class loader returned by {@link #getClassLoader(ClassLoader) getClassLoader(ClassLoader)}
* - the context class loader
* clazz.getClassLoader()
* clazz.getResource()
*
*
* @param location the resource name
* @param clsLoader a class loader
* @param clazz a class
* @return the resource URL if found
* @deprecated Replaced by {@link #findClassLoaderResource(String, ClassLoader)}.
*/
public static URL findClassLoaderResource(String location, ClassLoader clsLoader, Class clazz)
{
ClassLoader classLoader = getClassLoader(clsLoader);
URL url = null;
if (classLoader != null)
{
url = classLoader.getResource(location);
}
if (url == null)
{
classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader != null)
{
url = classLoader.getResource(location);
}
if (url == null)
{
classLoader = clazz.getClassLoader();
if (classLoader == null)
{
url = clazz.getResource("/" + location);
}
else
{
url = classLoader.getResource(location);
}
}
}
return url;
}
/**
* Attempts to find a resource using a class loader.
*
* The following sources are tried:
*
* - the class loader returned by {@link #getClassLoader(ClassLoader) getClassLoader(ClassLoader)}
* - the context class loader
* JRLoader.class.getClassLoader()
* JRLoader.class.getResource()
*
*
* @param location the resource name
* @param clsLoader a class loader
* @return the resource URL if found
*/
public static URL findClassLoaderResource(String location, ClassLoader clsLoader)
{
ClassLoader classLoader = getClassLoader(clsLoader);
URL url = null;
if (classLoader != null)
{
url = classLoader.getResource(location);
}
if (url == null)
{
classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader != null)
{
url = classLoader.getResource(location);
}
if (url == null)
{
classLoader = JRLoader.class.getClassLoader();
if (classLoader == null)
{
url = JRLoader.class.getResource("/" + location);
}
else
{
url = classLoader.getResource(location);
}
}
}
return url;
}
/**
* Loads a resource bundle for a given base name and locale.
*
*
* This methods calls {@link #loadResourceBundle(String, Locale, ClassLoader)} with a null classloader.
*
*
* @param baseName the base name
* @param locale the locale
* @return the resource bundle for the given base name and locale
*/
public static ResourceBundle loadResourceBundle(JasperReportsContext jasperReportsContext, String baseName, Locale locale)
{
return loadResourceBundle(SimpleRepositoryContext.of(jasperReportsContext), baseName, locale);
}
public static ResourceBundle loadResourceBundle(RepositoryContext repositoryContext, String baseName, Locale locale)
{
ResourceBundle resourceBundle = null;
MissingResourceException ex = null;
try
{
resourceBundle = loadResourceBundle(baseName, locale, null);
}
catch (MissingResourceException e)
{
ex = e;
}
if (resourceBundle == null)
{
CustomControl control = new CustomControl();
List locales = control.getCandidateLocales(baseName, locale);
for (Locale lc : locales)
{
String suffix = lc.toString();
suffix = (suffix.trim().length() > 0 ? "_" : "") + suffix;
ResourceBundleResource resourceBundleResource = null;
try
{
resourceBundleResource =
RepositoryUtil.getInstance(repositoryContext).getResourceFromLocation(
baseName + suffix + PROPERTIES_FILE_EXTENSION,
ResourceBundleResource.class
);
}
catch (JRException e)
{
}
if (resourceBundleResource != null)
{
resourceBundle = resourceBundleResource.getResourceBundle();
break;
}
}
}
if (resourceBundle == null)
{
throw ex;
}
return resourceBundle;
}
/**
* Loads a resource bundle for a given base name and locale.
*
*
* This methods calls {@link #loadResourceBundle(String, Locale, ClassLoader)} with a null classloader.
*
*
* @param baseName the base name
* @param locale the locale
* @return the resource bundle for the given base name and locale
*/
public static ResourceBundle loadResourceBundle(String baseName, Locale locale)
{
return loadResourceBundle(baseName, locale, null);
}
/**
* Loads a resource bundle for a given base name and locale.
*
*
* The method attempts to load the resource bundle using the following classloaders
* (and stops at the first successful attempt):
*
* - the class loader returned by {@link #getClassLoader(ClassLoader) getClassLoader(ClassLoader)}
* - the context class loader
* JRClassLoader.class.getClassLoader()
*
*
*
* @param baseName the base name
* @param locale the locale
* @param clsLoader
* @return the resource bundle for the given base name and locale
* @see ResourceBundle#getBundle(String, Locale, ClassLoader)
*/
public static ResourceBundle loadResourceBundle(String baseName, Locale locale, ClassLoader clsLoader)
{
ResourceBundle resourceBundle = null;
ClassLoader classLoader = getClassLoader(clsLoader);
if (classLoader != null)
{
try
{
resourceBundle = ResourceBundle.getBundle(baseName, locale, classLoader);
}
catch (MissingResourceException e)
{
}
}
if (resourceBundle == null)
{
classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader != null)
{
try
{
resourceBundle = ResourceBundle.getBundle(baseName, locale, classLoader);
}
catch (MissingResourceException e)
{
}
}
}
if (resourceBundle == null)
{
classLoader = JRClassLoader.class.getClassLoader();
if (classLoader == null)
{
resourceBundle = ResourceBundle.getBundle(baseName, locale);
}
else
{
resourceBundle = ResourceBundle.getBundle(baseName, locale, classLoader);
}
}
return resourceBundle;
}
private JRResourcesUtil()
{
}
}
/**
*
*/
class CustomControl extends ResourceBundle.Control
{
public CustomControl()
{
}
}