Java tutorial
/* * 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 <http://www.gnu.org/licenses/>. */ 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 (lucianc@users.sourceforge.net) */ 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 <code>String</code> as an URL. * * @param spec the <code>String</code> 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 <code>String</code>. * * @param spec the <code>String</code> 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<String, File> 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<String, File> 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<String, File> 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. * <p/> * The first not null value from the following is returned: * <ul> * <li>the value of the parameter</li> * <li>the thread local class loader</li> * <li>the global class loader</li> * </ul> * * @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. * <p/> * The following sources are tried: * <ul> * <li>the class loader returned by {@link #getClassLoader(ClassLoader) getClassLoader(ClassLoader)}</li> * <li>the context class loader</li> * <li><code>clazz.getClassLoader()</code></li> * <li><code>clazz.getResource()</code></li> * </ul> * * @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. * <p/> * The following sources are tried: * <ul> * <li>the class loader returned by {@link #getClassLoader(ClassLoader) getClassLoader(ClassLoader)}</li> * <li>the context class loader</li> * <li><code>JRLoader.class.getClassLoader()</code></li> * <li><code>JRLoader.class.getResource()</code></li> * </ul> * * @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. * * <p> * This methods calls {@link #loadResourceBundle(String, Locale, ClassLoader)} with a null classloader. * </p> * * @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<Locale> 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. * * <p> * This methods calls {@link #loadResourceBundle(String, Locale, ClassLoader)} with a null classloader. * </p> * * @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. * * <p> * The method attempts to load the resource bundle using the following classloaders * (and stops at the first successful attempt): * <ul> * <li>the class loader returned by {@link #getClassLoader(ClassLoader) getClassLoader(ClassLoader)}</li> * <li>the context class loader</li> * <li><code>JRClassLoader.class.getClassLoader()</code></li> * </ul> * </p> * * @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() { } }