net.sf.jasperreports.engine.util.JRLoader Maven / Gradle / Ivy
/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2023 Cloud Software Group, 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.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import net.sf.jasperreports.engine.DefaultJasperReportsContext;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRPropertiesUtil;
import net.sf.jasperreports.engine.JRRuntimeException;
import net.sf.jasperreports.engine.JRVirtualizationHelper;
import net.sf.jasperreports.engine.JRVirtualizer;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReportsContext;
/**
* Utility class that helps load serialized objects found in various locations
* such as files, URLs, and input streams.
*
* Many JasperReports processes, like report compilation, report filling and exporting,
* often work with serialized objects. Sometimes it is useful to manually load those
* serialized objects before submitting them to the desired JasperReport process.
*
* The most interesting method exposed by this class is
* {@link #getLocationInputStream(String) getLocationInputStream(String location)}.
* When calling this method to load an InputStream object from
* the supplied location, the program first tries to interpret the location as a valid resource name. If
* this fails, then the program assumes that the supplied location is the name of a file on
* disk and tries to read from it. If no file is found at that location, it will assume that the location
* represents a valid URL. Only after this third
* try fails an exception is thrown.
*
* @author Teodor Danciu ([email protected])
*/
public final class JRLoader
{
private static final Log log = LogFactory.getLog(JRLoader.class);
public static final String EXCEPTION_MESSAGE_KEY_BYTE_DATA_FROM_INPUT_STREAM_ERROR = "util.loader.byte.data.from.input.stream.error";
public static final String EXCEPTION_MESSAGE_KEY_BYTE_DATA_LOADING_ERROR = "util.loader.byte.data.loading.error";
public static final String EXCEPTION_MESSAGE_KEY_CLASS_NOT_FOUND_FROM_FILE = "util.loader.class.not.found.from.file";
public static final String EXCEPTION_MESSAGE_KEY_CLASS_NOT_FOUND_FROM_INPUT_STREAM = "util.loader.class.not.found.from.input.stream";
public static final String EXCEPTION_MESSAGE_KEY_CLASS_NOT_FOUND_FROM_URL = "util.loader.class.not.found.from.url";
public static final String EXCEPTION_MESSAGE_KEY_FILE_OPEN_ERROR = "util.loader.file.open.error";
public static final String EXCEPTION_MESSAGE_KEY_INPUT_STREAM_FROM_FILE_OPEN_ERROR = "util.loader.input.stream.from.file.open.error";
public static final String EXCEPTION_MESSAGE_KEY_INPUT_STREAM_FROM_URL_OPEN_ERROR = "util.loader.input.stream.from.url.open.error";
public static final String EXCEPTION_MESSAGE_KEY_OBJECT_FROM_FILE_LOADING_ERROR = "util.loader.object.from.file.loading.error";
public static final String EXCEPTION_MESSAGE_KEY_OBJECT_FROM_INPUT_STREAM_LOADING_ERROR = "util.loader.object.from.input.stream.loading.error";
public static final String EXCEPTION_MESSAGE_KEY_OBJECT_FROM_URL_LOADING_ERROR = "util.loader.object.from.url.loading.error";
public static final String EXCEPTION_MESSAGE_KEY_RESOURCE_NOT_FOUND = "util.loader.resource.not.found";
public static final String EXCEPTION_MESSAGE_KEY_URL_OPEN_ERROR = "util.loader.url.open.error";
/**
*
*/
//private static boolean wasWarning;
/**
*
*/
public static Object loadObjectFromFile(String fileName) throws JRException
{
return loadObject(new File(fileName));
}
/**
*
*/
public static Object loadObject(File file) throws JRException
{
return loadObject(DefaultJasperReportsContext.getInstance(), file);
}
/**
*
*/
public static Object loadObject(JasperReportsContext jasperReportsContext, File file) throws JRException
{
if (!file.exists() || !file.isFile())
{
throw new JRException( new FileNotFoundException(String.valueOf(file)) );
}
Object obj = null;
try (
InputStream is = new BufferedInputStream(new FileInputStream(file));
ObjectInputStream ois = new ContextClassLoaderObjectInputStream(jasperReportsContext, is)
)
{
obj = ois.readObject();
}
catch (IOException e)
{
throw
new JRException(
EXCEPTION_MESSAGE_KEY_OBJECT_FROM_FILE_LOADING_ERROR,
new Object[]{file},
e);
}
catch (ClassNotFoundException e)
{
throw
new JRException(
EXCEPTION_MESSAGE_KEY_CLASS_NOT_FOUND_FROM_FILE,
new Object[]{file},
e);
}
return obj;
}
/**
*
*/
public static Object loadObject(URL url) throws JRException
{
return loadObject(DefaultJasperReportsContext.getInstance(), url);
}
/**
*
*/
public static Object loadObject(JasperReportsContext jasperReportsContext, URL url) throws JRException
{
Object obj = null;
try (
InputStream is = url.openStream();
ObjectInputStream ois = new ContextClassLoaderObjectInputStream(jasperReportsContext, is)
)
{
obj = ois.readObject();
}
catch (IOException e)
{
throw
new JRException(
EXCEPTION_MESSAGE_KEY_OBJECT_FROM_URL_LOADING_ERROR,
new Object[]{url},
e);
}
catch (ClassNotFoundException e)
{
throw
new JRException(
EXCEPTION_MESSAGE_KEY_CLASS_NOT_FOUND_FROM_URL,
new Object[]{url},
e);
}
return obj;
}
/**
*
*/
public static Object loadObject(InputStream is) throws JRException
{
return loadObject(DefaultJasperReportsContext.getInstance(), is);
}
/**
*
*/
public static Object loadObject(JasperReportsContext jasperReportsContext, InputStream is) throws JRException
{
Object obj = null;
ObjectInputStream ois = null;
try
{
ois = new ContextClassLoaderObjectInputStream(jasperReportsContext, is);
obj = ois.readObject();
}
catch (IOException e)
{
throw
new JRException(
EXCEPTION_MESSAGE_KEY_OBJECT_FROM_INPUT_STREAM_LOADING_ERROR,
null,
e);
}
catch (ClassNotFoundException e)
{
throw
new JRException(
EXCEPTION_MESSAGE_KEY_CLASS_NOT_FOUND_FROM_INPUT_STREAM,
null,
e);
}
return obj;
}
/**
*
*/
public static InputStream getInputStream(File file) throws JRException
{
if (!file.exists() || !file.isFile())
{
throw new JRException( new FileNotFoundException(String.valueOf(file)) );//FIXMEREPO this probably useless
}
FileInputStream fis = null;
try
{
fis = new FileInputStream(file);
}
catch (IOException e)
{
throw
new JRException(
EXCEPTION_MESSAGE_KEY_INPUT_STREAM_FROM_FILE_OPEN_ERROR,
new Object[]{file},
e);
}
return fis;
}
/**
*
*/
public static InputStream getInputStream(URL url) throws JRException
{
InputStream is = null;
try
{
is = url.openStream();
}
catch (IOException e)
{
throw
new JRException(
EXCEPTION_MESSAGE_KEY_INPUT_STREAM_FROM_URL_OPEN_ERROR,
new Object[]{url},
e);
}
return is;
}
/**
*
*/
public static byte[] loadBytes(File file) throws JRException
{
try
{
return Files.readAllBytes(file.toPath());
}
catch (IOException e)
{
throw
new JRException(
EXCEPTION_MESSAGE_KEY_BYTE_DATA_LOADING_ERROR,
new Object[]{file},
e);
}
}
/**
*
*/
public static byte[] loadBytes(URL url) throws JRException
{
try (InputStream is = url.openStream())
{
return readBytes(is);
}
catch (IOException e)
{
throw
new JRException(
EXCEPTION_MESSAGE_KEY_BYTE_DATA_LOADING_ERROR,
new Object[]{url},
e);
}
}
/**
*
*/
public static byte[] loadBytes(InputStream is) throws JRException
{
try
{
return readBytes(is);
}
catch (IOException e)
{
throw
new JRException(
EXCEPTION_MESSAGE_KEY_BYTE_DATA_FROM_INPUT_STREAM_ERROR,
null,
e);
}
}
/**
*
*/
public static byte[] readBytes(InputStream is) throws IOException
{
try (ByteArrayOutputStream baos = new ByteArrayOutputStream())
{
byte[] bytes = new byte[10000];
int ln = 0;
while ((ln = is.read(bytes)) > 0)
{
baos.write(bytes, 0, ln);
}
baos.flush();
return baos.toByteArray();
}
}
/**
*
*/
public static byte[] loadBytesFromResource(String resourceName) throws JRException
{
return loadBytesFromResource(resourceName, null);
}
/**
*
*/
public static byte[] loadBytesFromResource(String resourceName, ClassLoader classLoader) throws JRException
{
URL url = JRResourcesUtil.findClassLoaderResource(resourceName, classLoader);
if (url != null)
{
return loadBytes(url);
}
throw
new JRException(
EXCEPTION_MESSAGE_KEY_RESOURCE_NOT_FOUND,
new Object[]{resourceName});
}
/**
* Tries to open an input stream for a location.
*
* The method tries to interpret the location as a file name, a resource name or
* an URL. If any of these succeed, an input stream is created and returned.
*
* @param location the location
* @return an input stream if the location is an existing file name, a resource name on
* the classpath or an URL or null
otherwise.
*
* @throws JRException
*/
public static InputStream getLocationInputStream(String location) throws JRException//FIXME deprecate this?
{
InputStream is = null;
is = getResourceInputStream(location);
if (is == null)
{
is = getFileInputStream(location);
}
if (is == null)
{
is = getURLInputStream(location);
}
return is;
}
/**
* Tries to open a file for reading.
*
* @param filename the file name
* @return an input stream for the file or null
if the file was not found
* @throws JRException
*/
public static InputStream getFileInputStream(String filename) throws JRException
{
InputStream is = null;
File file = new File(filename);
if (file.exists() && file.isFile())
{
try
{
is = new FileInputStream(file);
}
catch (FileNotFoundException e)
{
throw
new JRException(
EXCEPTION_MESSAGE_KEY_FILE_OPEN_ERROR,
new Object[]{filename},
e);
}
}
return is;
}
/**
* Tries to open an input stream for a resource.
*
* @param resource the resource name
* @return an input stream for the resource or null
if the resource was not found
*/
public static InputStream getResourceInputStream(String resource)
{
InputStream is = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader != null)
{
is = classLoader.getResourceAsStream(resource);
}
if (is == null)
{
classLoader = JRLoader.class.getClassLoader();
if (classLoader != null)
{
is = classLoader.getResourceAsStream(resource);
}
if (is == null)
{
is = JRPropertiesUtil.class.getResourceAsStream("/" + resource);
}
}
return is;
}
/**
* Scans the context classloader and the classloader of this class for all
* resources that have a specified name, and returns a list of
* {@link URL}s for the found resources.
*
* @param resource the resource names
* @return a list of {@link URL}s of resources with the specified name;
* the list is empty if no resources have been found for the name
* @see ClassLoader#getResources(String)
*/
public static List getResources(String resource)
{
//skip duplicated resources
Set resources = new LinkedHashSet<>();
collectResources(resource, JRLoader.class.getClassLoader(),
resources);
collectResources(resource, Thread.currentThread().getContextClassLoader(),
resources);
return new ArrayList<>(resources);
}
protected static void collectResources(String resourceName,
ClassLoader classLoader, Set resources)
{
if (classLoader != null)
{
try
{
Enumeration urls = classLoader.getResources(resourceName);
if (urls != null)
{
while (urls.hasMoreElements()) // class loaders should never return null on getResources, according to specs, but we've seen cases, so we protect our code here
{
URL url = urls.nextElement();
resources.add(url);
}
}
}
catch (IOException e)
{
throw new JRRuntimeException(e);
}
}
}
/**
* Scans the context classloader and the classloader of this class for all
* resources that have a specified name, and returns a list of
* {@link ClassLoaderResource} objects for the found resources.
*
*
* The returned list contains the URLs of the resources, and for each resource
* the highest classloader in the classloader hierarchy on which the resource
* was found.
*
*
* @param resource the resource names
* @return a list of resources with the specified name;
* the list is empty if no resources have been found for the name
* @see ClassLoader#getResources(String)
*/
public static List getClassLoaderResources(
String resource)
{
Map resources = new LinkedHashMap<>();
collectResources(resource, JRLoader.class.getClassLoader(), resources);
//TODO check if the classloader is the same
collectResources(resource, Thread.currentThread()
.getContextClassLoader(), resources);
return new ArrayList<>(resources.values());
}
protected static void collectResources(String resourceName,
ClassLoader classLoader, Map resources)
{
if (classLoader == null)
{
return;
}
try
{
// creating a list of parent classloaders, with the highest in the
// hierarchy first
LinkedList classloaders = new LinkedList<>();
ClassLoader ancestorLoader = classLoader;
while (ancestorLoader != null)
{
classloaders.addFirst(ancestorLoader);
try
{
ancestorLoader = ancestorLoader.getParent();
}
catch (SecurityException e)
{
// if we're not allowed to get the parent, stop here.
// resources will be listed with the first classloader that
// we're allowed to access.
// one case when this happens is applets.
// FIXME revisit logging on SecurityException for applet
ancestorLoader = null;
}
}
for (ClassLoader ancestor : classloaders)
{
Enumeration urls = ancestor.getResources(resourceName);
if (urls != null) // class loaders should never return null on getResources, according to specs, but we've seen cases, so we protect our code here
{
while (urls.hasMoreElements())
{
URL url = urls.nextElement();
// if this is the first time we see this resource, add it
// with the current classloader.
// this way a resource will be added with the most first
// ancestor classloader that has it.
if (!resources.containsKey(url))
{
if (log.isDebugEnabled())
{
log.debug("Found resource " + resourceName
+ " at "+ url + " in classloader " + ancestor);
}
ClassLoaderResource resource = new ClassLoaderResource(
url, ancestor);
resources.put(url, resource);
}
}
}
}
} catch (IOException e)
{
throw new JRRuntimeException(e);
}
}
/**
* Returns the resource URL for a specified resource name.
*
* @param resource the resource name
* @return the URL of the resource having the specified name, or
* null
if none found
* @see ClassLoader#getResource(String)
*/
public static URL getResource(String resource)
{
URL location = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader != null)
{
location = classLoader.getResource(resource);
}
if (location == null)
{
classLoader = JRLoader.class.getClassLoader();
if (classLoader != null)
{
location = classLoader.getResource(resource);
}
if (location == null)
{
location = JRPropertiesUtil.class.getResource("/" + resource);
}
}
return location;
}
/**
* Tries to open an input stream for an URL.
*
* @param spec the string to parse as an URL
* @return an input stream for the URL or null if spec
is not a valid URL
* @throws JRException
*/
public static InputStream getURLInputStream(String spec) throws JRException
{
InputStream is = null;
try
{
URL url = new URL(spec);
is = url.openStream();
}
catch (MalformedURLException e)
{
}
catch (IOException e)
{
throw
new JRException(
EXCEPTION_MESSAGE_KEY_URL_OPEN_ERROR,
new Object[]{spec},
e);
}
return is;
}
/**
* Loads a JasperPrint object from a file, optionally using a virtualizer for
* the object.
*
* @param fileName the file name
* @param virtualizer the virtualizer
* @return a JasperPrint object
* @throws JRException
* @see JRVirtualizationHelper#setThreadVirtualizer(JRVirtualizer)
*/
public static JasperPrint loadJasperPrintFromFile(String fileName, JRVirtualizer virtualizer) throws JRException
{
if (virtualizer != null)
{
JRVirtualizationHelper.setThreadVirtualizer(virtualizer);
}
try
{
return (JasperPrint) loadObjectFromFile(fileName);
}
finally
{
if (virtualizer != null)
{
JRVirtualizationHelper.clearThreadVirtualizer();
}
}
}
/**
* Loads a JasperPrint object from a file, optionally using a virtualizer for
* the object.
*
* @param file the file
* @param virtualizer the virtualizer
* @return a JasperPrint object
* @throws JRException
* @see JRVirtualizationHelper#setThreadVirtualizer(JRVirtualizer)
*/
public static JasperPrint loadJasperPrint(File file, JRVirtualizer virtualizer) throws JRException
{
if (virtualizer != null)
{
JRVirtualizationHelper.setThreadVirtualizer(virtualizer);
}
try
{
return (JasperPrint) loadObject(file);
}
finally
{
if (virtualizer != null)
{
JRVirtualizationHelper.clearThreadVirtualizer();
}
}
}
/**
* Loads a JasperPrint object from a URL, optionally using a virtualizer for
* the object.
*
* @param url the URL
* @param virtualizer the virtualizer
* @return a JasperPrint object
* @throws JRException
* @see JRVirtualizationHelper#setThreadVirtualizer(JRVirtualizer)
*/
public static JasperPrint loadJasperPrint(URL url, JRVirtualizer virtualizer) throws JRException
{
if (virtualizer != null)
{
JRVirtualizationHelper.setThreadVirtualizer(virtualizer);
}
try
{
return (JasperPrint) loadObject(url);
}
finally
{
if (virtualizer != null)
{
JRVirtualizationHelper.clearThreadVirtualizer();
}
}
}
/**
* Loads a JasperPrint object from a stream, optionally using a virtualizer for
* the object.
*
* @param is the stream
* @param virtualizer the virtualizer
* @return a JasperPrint object
* @throws JRException
* @see JRVirtualizationHelper#setThreadVirtualizer(JRVirtualizer)
*/
public static JasperPrint loadJasperPrint(InputStream is, JRVirtualizer virtualizer) throws JRException
{
if (virtualizer != null)
{
JRVirtualizationHelper.setThreadVirtualizer(virtualizer);
}
try
{
return (JasperPrint) loadObject(is);
}
finally
{
if (virtualizer != null)
{
JRVirtualizationHelper.clearThreadVirtualizer();
}
}
}
private JRLoader()
{
}
}