/*
* iReport - Visual Designer for JasperReports.
* Copyright (C) 2002 - 2009 Jaspersoft Corporation. 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 iReport.
*
* iReport is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iReport 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iReport. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jaspersoft.ireport.designer;
import com.jaspersoft.ireport.locale.I18n;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.*;
/**
* This special class loader is used when running a report.
* The main feature is that this classloader reload Scriptlet class every
* time the class is needed.
* This class is based on JUnit test case class loader.
* @author Administrator
*/
public class ReportClassLoader extends java.lang.ClassLoader {
/** scanned class path */
private ArrayList fPathItems;
/** scanned class path */
private ArrayList fPathChachedItems;
private HashMap cachedClasses;
/** default excluded paths */
/**
* Constructs a ReloadableTestClassLoader. It tokenizes the value of
* <code>reportPath</code> and adds it and any sub-paths to a list.
* Paths are searched for tests. All other classes are loaded
* by parent loaders, to which this classloader always delegates.
*
* This ClassLoader never looks into or knows about the system classpath.
* It should always refer to a path of repositories (jars or dirs)
* <em>not</em> on the system classpath (as retrieved via
* <code>reportPath</code>).
*
* @param classPath to scan and use for finding and reloading classes
*/
public ReportClassLoader() {
super( ReportClassLoader.class.getClassLoader() );
setup();
}
public ReportClassLoader(ClassLoader parent) {
super(parent);
setup();
}
private void setup()
{
fPathItems = new ArrayList();
fPathChachedItems = new ArrayList();
cachedClasses = new HashMap();
rescanLibDirectory();
}
/**
* Add to search paths list as no relodable jar/zip all new .jar,.zip not already in classpath
*/
public void rescanLibDirectory()
{
try {
rescanAdditionalClasspath();
} catch (Exception ex) {}
}
public java.util.List getCachedItems()
{
return fPathChachedItems;
}
public void clearCache()
{
cachedClasses.clear();
//System.out.println("Cached classes " + cachedClasses);
}
/**
* Add to search paths list as no relodable jar/zip all new .jar,.zip not already in classpath
*/
@SuppressWarnings("unchecked")
public void rescanAdditionalClasspath()
{
// Looking for jars or zip in lib directory not in classpath...
List<String> cp = IReportManager.getInstance().getClasspath();
cp.addAll(IReportManager.getInstance().getHiddenClasspath());
for (String path : cp)
{
File f = new File( path );
if (!f.exists()) continue;
try {
if (!fPathChachedItems.contains(f.getCanonicalPath()))
{
fPathChachedItems.add(f.getCanonicalPath());
}
} catch (Exception ex)
{
System.out.println(I18n.getString("ReportClassLoader.Warning.Path") + f);
}
}
}
/**
* Add a dir or a file (i.e. a jar or a zip) to the search path
*/
@SuppressWarnings("unchecked")
public void addNoRelodablePath(String path)
{
if (!fPathChachedItems.contains(path))
{
fPathChachedItems.add(path);
}
}
public void setRelodablePaths(String classPath)
{
scanPath(classPath);
}
@SuppressWarnings("unchecked")
private void scanPath(String classPath) {
String separator = System.getProperty("path.separator");
fPathItems = new ArrayList(31);
StringTokenizer st = new StringTokenizer(classPath, separator);
while (st.hasMoreTokens()) {
String pp = st.nextToken();
fPathItems.add(pp);
}
}
@Override
public URL getResource(String name) {
// We have to try to solve the name...
return this.findResource(name);
}
@Override
public InputStream getResourceAsStream(String name) {
// We have to try to solve the name...
for (int i = 0; i < fPathChachedItems.size(); i++) {
String path = (String) fPathChachedItems.get(i);
if (isJar(path))
{
InputStream is = getInputStreamFromJar(path, name);
if (is != null) return is;
}
else
{
File f = new File(path, name);
if (f.exists())
{
try {
return new FileInputStream( f );
} catch (Exception ex)
{}
}
}
}
// Else try to load from reloadable paths...
for (int i = 0; i < fPathItems.size(); i++) {
String path = (String) fPathItems.get(i);
if (isJar(path))
{
InputStream is = getInputStreamFromJar(path, name);
if (is != null) return is;
}
else
{
File f = new File(path, name);
if (f.exists())
{
try {
return new FileInputStream( f );
} catch (Exception ex)
{}
}
}
}
if (isInDefaultPackage(name)) return null;
return getParent().getResourceAsStream(name);
}
private InputStream getInputStreamFromJar(String archive_path, String fileName) {
ZipFile zipFile = null;
File archive = new File(archive_path);
if (!archive.exists())
{
//System.out.println("Il jar non esiste!");
return null;
}
try {
zipFile = new ZipFile(archive);
} catch (IOException io) {
//io.printStackTrace();
return null;
}
//System.out.println("Ricerca entry" + fileName );
ZipEntry entry = zipFile.getEntry(fileName);
if (entry == null)
{
//System.out.println("Entry null!");
return null;
}
try {
return zipFile.getInputStream(entry);
} catch (IOException e) {
} finally {
}
return null;
}
@Override
public synchronized Class findClass(String name) throws ClassNotFoundException {
Class c = null;
if (cachedClasses.containsKey( name ))
{
c = (Class)cachedClasses.get(name);
}
else
{
c = loadClassData(name);
}
return c;
}
// From here down is all code copied and pasted from JUnit's
// TestCaseClassLoader
@SuppressWarnings("unchecked")
private Class loadClassData(String className)
throws ClassNotFoundException {
// 1. Look for cached class...
//if we can't find the cached class, looking first in no relodable paths...
byte[] data = null;
if (!cachedClasses.containsKey(className))
{
for (int i = 0; i < fPathChachedItems.size(); i++) {
String path = (String) fPathChachedItems.get(i);
String fileName = className.replace('.', File.separatorChar) + ".class";
if (isJar(path)) {
//System.out.println("looking for " + fileName.replace(File.separatorChar,'/') + " in jar " +path);
data = loadJarData(path, fileName.replace(File.separatorChar,'/'));
} else {
//System.out.println("looking for " + fileName + " in dir " +path);
data = loadFileData(path, fileName.replace(File.separatorChar,'/'));
}
if (data != null)
{
Class c = defineClass(className, data, 0, data.length);
cachedClasses.put(className,c);
return c;
}
}
}
else
{
return (Class)cachedClasses.get(className);
}
// Else try to load from reloadable paths...
for (int i = 0; i < fPathItems.size(); i++) {
String path = (String) fPathItems.get(i);
String fileName = className.replace('.', File.separatorChar) + ".class";
if (isJar(path)) {
data = loadJarData(path, fileName);
} else {
data = loadFileData(path, fileName);
}
if (data != null)
{
Class c = defineClass(className, data, 0, data.length);
return c;
}
}
throw new ClassNotFoundException(className);
}
boolean isJar(String pathEntry) {
return pathEntry.toLowerCase().endsWith(".jar") || pathEntry.toLowerCase().endsWith(".zip");
}
private byte[] loadFileData(String path, String fileName) {
File file = new File(path, fileName);
//System.out.println("Final class name: " + file.getPath());
if (file.exists()) {
return getClassData(file);
}
return null;
}
private byte[] getClassData(File f) {
try {
FileInputStream stream = new FileInputStream(f);
ByteArrayOutputStream out = new ByteArrayOutputStream(1000);
byte[] b = new byte[1000];
int n;
while ((n = stream.read(b)) != -1)
out.write(b, 0, n);
stream.close();
out.close();
return out.toByteArray();
} catch (IOException e) {
}
return null;
}
private byte[] loadJarData(String path, String fileName) {
ZipFile zipFile = null;
InputStream stream = null;
File archive = new File(path);
if (!archive.exists())
{
//System.out.println("Il jar non esiste!");
return null;
}
try {
zipFile = new ZipFile(archive);
} catch (IOException io) {
io.printStackTrace();
return null;
}
//System.out.println("Ricerca entry" + fileName );
ZipEntry entry = zipFile.getEntry(fileName);
if (entry == null)
{
//System.out.println("Entry null!");
return null;
}
int size = (int) entry.getSize();
try {
stream = zipFile.getInputStream(entry);
byte[] data = new byte[size];
int pos = 0;
while (pos < size) {
int n = stream.read(data, pos, data.length - pos);
pos += n;
}
zipFile.close();
return data;
} catch (IOException e) {
} finally {
try {
if (stream != null)
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//System.out.println("Class not found really!");
return null;
}
@SuppressWarnings("unchecked")
@Override
public Enumeration findResources(String name) {
// We have to try to solve the name...
Vector urls = new Vector();
URL[] pathUrls = new URL[fPathChachedItems.size() + fPathItems.size()];
for (int i = 0; i < fPathChachedItems.size(); i++) {
String path = (String) fPathChachedItems.get(i);
try {
pathUrls[i] = (new File(path)).toURI().toURL();
} catch (Exception ex)
{
}
}
for (int i = 0; i < fPathItems.size(); i++) {
String path = (String) fPathItems.get(i);
try {
pathUrls[i + fPathChachedItems.size()] = (new File(path)).toURI().toURL();
} catch (Exception ex)
{
}
}
IRURLClassLoader urlCl = new IRURLClassLoader(pathUrls, null);
try {
return urlCl.findResources(name);
} catch (Exception ex)
{
}
return new Vector().elements();
}
@Override
public URL findResource(String name) {
if (name.startsWith("/")) name = name.substring(1);
URL[] pathUrls = new URL[fPathChachedItems.size() + fPathItems.size()];
for (int i = 0; i < fPathChachedItems.size(); i++) {
String path = (String) fPathChachedItems.get(i);
try {
pathUrls[i] = (new File(path)).toURI().toURL();
} catch (Exception ex)
{
}
}
for (int i = 0; i < fPathItems.size(); i++) {
String path = (String) fPathItems.get(i);
try {
pathUrls[i + fPathChachedItems.size()] = (new File(path)).toURI().toURL();
} catch (Exception ex)
{
}
}
IRURLClassLoader urlCl = new IRURLClassLoader(pathUrls, null);
try {
URL url = urlCl.findResource(name);
//System.out.println( url);
if (url != null) return url;
} catch (Exception ex)
{
//ex.printStackTrace();
}
// Avoid to look for resources that are in the root...
if (isInDefaultPackage(name)) return null;
return getParent().getResource(name);
}
public boolean isInDefaultPackage(String resource)
{
while (resource.startsWith("/"))
resource = resource.substring(1);
final int slashIdx = resource.lastIndexOf('/');
if (slashIdx == -1) {
return true;
}
return false;
}
// public String toString()
// {
// String s = "Report Class Loader:\n";
// for (int i = 0; i < fPathChachedItems.size(); i++) {
// s += fPathChachedItems.get(i) + "\n";
// }
// for (int i = 0; i < fPathItems.size(); i++) {
//
// s += fPathItems.get(i) + "\n";
// }
//
// return s;
// }
}
|