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.BufferedInputStream; import java.io.ByteArrayInputStream; 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.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 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; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Utility class that helps load serialized objects found in various locations * such as files, URLs, and input streams. * <p> * 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. * </p><p> * 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. * </p> * @author Teodor Danciu (teodord@users.sourceforge.net) */ 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; FileInputStream fis = null; ObjectInputStream ois = null; try { fis = new FileInputStream(file); BufferedInputStream bufferedIn = new BufferedInputStream(fis); ois = new ContextClassLoaderObjectInputStream(jasperReportsContext, bufferedIn); 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); } finally { if (ois != null) { try { ois.close(); } catch (IOException e) { } } if (fis != null) { try { fis.close(); } catch (IOException 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; InputStream is = null; ObjectInputStream ois = null; try { is = url.openStream(); 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); } finally { if (ois != null) { try { ois.close(); } catch (IOException e) { } } if (is != null) { try { is.close(); } catch (IOException 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 { ByteArrayOutputStream baos = null; FileInputStream fis = null; try { fis = new FileInputStream(file); baos = new ByteArrayOutputStream(); byte[] bytes = new byte[10000]; int ln = 0; while ((ln = fis.read(bytes)) > 0) { baos.write(bytes, 0, ln); } baos.flush(); } catch (IOException e) { throw new JRException(EXCEPTION_MESSAGE_KEY_BYTE_DATA_LOADING_ERROR, new Object[] { file }, e); } finally { if (baos != null) { try { baos.close(); } catch (IOException e) { } } if (fis != null) { try { fis.close(); } catch (IOException e) { } } } return baos.toByteArray(); } /** * */ public static byte[] loadBytes(URL url) throws JRException { ByteArrayOutputStream baos = null; InputStream is = null; try { is = url.openStream(); baos = new ByteArrayOutputStream(); byte[] bytes = new byte[10000]; int ln = 0; while ((ln = is.read(bytes)) > 0) { baos.write(bytes, 0, ln); } baos.flush(); } catch (IOException e) { throw new JRException(EXCEPTION_MESSAGE_KEY_BYTE_DATA_LOADING_ERROR, new Object[] { url }, e); } finally { if (baos != null) { try { baos.close(); } catch (IOException e) { } } if (is != null) { try { is.close(); } catch (IOException e) { } } } return baos.toByteArray(); } /** * */ public static byte[] loadBytes(InputStream is) throws JRException { ByteArrayOutputStream baos = null; try { baos = new ByteArrayOutputStream(); byte[] bytes = new byte[10000]; int ln = 0; while ((ln = is.read(bytes)) > 0) { baos.write(bytes, 0, ln); } baos.flush(); } catch (IOException e) { throw new JRException(EXCEPTION_MESSAGE_KEY_BYTE_DATA_FROM_INPUT_STREAM_ERROR, null, e); } finally { if (baos != null) { try { baos.close(); } catch (IOException e) { } } } return baos.toByteArray(); } public static InputStream loadToMemoryInputStream(InputStream is) throws JRException { if (is instanceof ByteArrayInputStream) { return is; } try { byte[] bytes = loadBytes(is); return new ByteArrayInputStream(bytes); } finally { try { is.close(); } catch (IOException e) { if (log.isWarnEnabled()) { log.warn("Failed to close input stream " + is, e); } } } } /** * */ 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. * <p> * 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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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<URL> getResources(String resource) { //skip duplicated resources Set<URL> resources = new LinkedHashSet<URL>(); collectResources(resource, JRLoader.class.getClassLoader(), resources); collectResources(resource, Thread.currentThread().getContextClassLoader(), resources); return new ArrayList<URL>(resources); } protected static void collectResources(String resourceName, ClassLoader classLoader, Set<URL> resources) { if (classLoader != null) { try { Enumeration<URL> 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. * * <p> * 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. * </p> * * @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<ClassLoaderResource> getClassLoaderResources(String resource) { Map<URL, ClassLoaderResource> resources = new LinkedHashMap<URL, ClassLoaderResource>(); collectResources(resource, JRLoader.class.getClassLoader(), resources); //TODO check if the classloader is the same collectResources(resource, Thread.currentThread().getContextClassLoader(), resources); return new ArrayList<ClassLoaderResource>(resources.values()); } protected static void collectResources(String resourceName, ClassLoader classLoader, Map<URL, ClassLoaderResource> resources) { if (classLoader == null) { return; } try { // creating a list of parent classloaders, with the highest in the // hierarchy first LinkedList<ClassLoader> classloaders = new LinkedList<ClassLoader>(); 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<URL> 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 * <code>null</code> 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 <code>spec</code> 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() { } }