001: /*
002: * Copyright (C) 2005 - 2008 JasperSoft Corporation. All rights reserved.
003: * http://www.jaspersoft.com.
004: *
005: * Unless you have purchased a commercial license agreement from JasperSoft,
006: * the following license terms apply:
007: *
008: * This program is free software; you can redistribute it and/or modify
009: * it under the terms of the GNU General Public License version 2 as published by
010: * the Free Software Foundation.
011: *
012: * This program is distributed WITHOUT ANY WARRANTY; and without the
013: * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
014: * See the GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, see http://www.gnu.org/licenses/gpl.txt
018: * or write to:
019: *
020: * Free Software Foundation, Inc.,
021: * 59 Temple Place - Suite 330,
022: * Boston, MA USA 02111-1307
023: *
024: *
025: *
026: *
027: * ReportClassLoader.java
028: *
029: * Created on 24 maggio 2004, 12.56
030: *
031: */
032:
033: package it.businesslogic.ireport;
034:
035: import java.io.ByteArrayOutputStream;
036: import java.io.File;
037: import java.io.FileInputStream;
038: import java.io.IOException;
039: import java.io.InputStream;
040: import java.net.URL;
041: import java.net.URLClassLoader;
042: import java.util.ArrayList;
043: import java.util.HashMap;
044: import java.util.StringTokenizer;
045: import java.util.zip.ZipEntry;
046: import java.util.zip.ZipFile;
047: import java.util.*;
048:
049: /**
050: * This special class loader is used when running a report.
051: * The main feature is that this classloader reload Scriptlet class every
052: * time the class is needed.
053: * This class is based on JUnit test case class loader.
054: * @author Administrator
055: */
056: public class ReportClassLoader extends java.lang.ClassLoader {
057:
058: /** scanned class path */
059: private ArrayList fPathItems;
060:
061: /** scanned class path */
062: private ArrayList fPathChachedItems;
063: private HashMap cachedClasses;
064:
065: /** default excluded paths */
066:
067: /**
068: * Constructs a ReloadableTestClassLoader. It tokenizes the value of
069: * <code>reportPath</code> and adds it and any sub-paths to a list.
070: * Paths are searched for tests. All other classes are loaded
071: * by parent loaders, to which this classloader always delegates.
072: *
073: * This ClassLoader never looks into or knows about the system classpath.
074: * It should always refer to a path of repositories (jars or dirs)
075: * <em>not</em> on the system classpath (as retrieved via
076: * <code>reportPath</code>).
077: *
078: * @param classPath to scan and use for finding and reloading classes
079: */
080: public ReportClassLoader() {
081: super (ReportClassLoader.class.getClassLoader());
082: setup();
083: }
084:
085: public ReportClassLoader(ClassLoader parent) {
086:
087: super (parent);
088: setup();
089: }
090:
091: private void setup() {
092: fPathItems = new ArrayList();
093: fPathChachedItems = new ArrayList();
094: cachedClasses = new HashMap();
095: rescanLibDirectory();
096: }
097:
098: /**
099: * Add to search paths list as no relodable jar/zip all new .jar,.zip not already in classpath
100: */
101: public void rescanLibDirectory() {
102: try {
103: rescanAdditionalClasspath();
104: } catch (Exception ex) {
105: }
106:
107: if (it.businesslogic.ireport.gui.MainFrame.getMainInstance() == null)
108: return;
109: // Looking for jars or zip in lib directory not in classpath...
110: String irHome = it.businesslogic.ireport.gui.MainFrame
111: .getMainInstance().IREPORT_HOME_DIR;
112: if (irHome == null)
113: irHome = System.getProperty("ireport.home", ".");
114: File lib_dir = new File(irHome, "lib");
115: String classpath = it.businesslogic.ireport.util.Misc.nvl(
116: System.getProperty("java.class.path"), "");
117: if (!lib_dir.exists()) {
118: System.out
119: .println("Cannot find lib in iReport home directory ("
120: + it.businesslogic.ireport.gui.MainFrame
121: .getMainInstance().IREPORT_HOME_DIR
122: + ")");
123: return;
124: }
125:
126: //System.out.println("Rescan lib...");
127: File[] new_libs = lib_dir.listFiles();
128:
129: for (int i = 0; i < new_libs.length; ++i) {
130: if (!new_libs[i].getName().toLowerCase().endsWith("jar")
131: && !new_libs[i].getName().toLowerCase().endsWith(
132: "zip"))
133: continue;
134:
135: if (classpath.indexOf(new_libs[i].getName()) < 0) {
136: try {
137: if (!fPathChachedItems.contains(new_libs[i]
138: .getCanonicalPath())) {
139: //if ( new File(new_libs[i].getAbsolutePath()).exists())
140: //{
141: //System.out.println("Added lib " + new_libs[i].getCanonicalPath() + " to ireport class path\n");
142: fPathChachedItems.add(new_libs[i]
143: .getCanonicalPath());
144: //}
145: }
146: } catch (Exception ex) {
147: System.out.println("Invalid path: " + new_libs[i]);
148: }
149: }
150: }
151: }
152:
153: public java.util.List getCachedItems() {
154: return fPathChachedItems;
155: }
156:
157: public void clearCache() {
158: cachedClasses.clear();
159: //System.out.println("Cached classes " + cachedClasses);
160: }
161:
162: /**
163: * Add to search paths list as no relodable jar/zip all new .jar,.zip not already in classpath
164: */
165: public void rescanAdditionalClasspath() {
166: if (it.businesslogic.ireport.gui.MainFrame.getMainInstance() == null)
167: return;
168: // Looking for jars or zip in lib directory not in classpath...
169: Vector cp = it.businesslogic.ireport.gui.MainFrame
170: .getMainInstance().getClasspath();
171: for (int i = 0; i < cp.size(); ++i) {
172: File f = new File(cp.elementAt(i) + "");
173: if (!f.exists())
174: continue;
175: try {
176: if (!fPathChachedItems.contains(f.getCanonicalPath())) {
177: //System.out.println("Added dynamically " + f.getCanonicalPath() + " to ireport class path");
178: fPathChachedItems.add(f.getCanonicalPath());
179: }
180: } catch (Exception ex) {
181: System.out.println("Invalid path: " + f);
182: }
183:
184: }
185: }
186:
187: /**
188: * Add a dir or a file (i.e. a jar or a zip) to the search path
189: */
190: public void addNoRelodablePath(String path) {
191: if (!fPathChachedItems.contains(path)) {
192: fPathChachedItems.add(path);
193: }
194: }
195:
196: public void setRelodablePaths(String classPath) {
197: scanPath(classPath);
198: }
199:
200: private void scanPath(String classPath) {
201: String separator = System.getProperty("path.separator");
202: fPathItems = new ArrayList(31);
203: StringTokenizer st = new StringTokenizer(classPath, separator);
204: while (st.hasMoreTokens()) {
205: String pp = st.nextToken();
206: //System.out.println("add " + pp);
207: fPathItems.add(pp);
208: }
209: }
210:
211: public URL getResource(String name) {
212: // We have to try to solve the name...
213: return this .findResource(name);
214: /*
215: for (int i = 0; i < fPathChachedItems.size(); i++) {
216: String path = (String) fPathChachedItems.get(i);
217:
218: if (isJar(path))
219: {
220: InputStream is = getInputStreamFromJar(path, name);
221: if (is != null)
222: {
223: try {
224: is.close();
225: File f = new File(path);
226: System.out.println("jar:" + f.toURL() + "!" + name);
227: return new URL("jar:" + f.toURL() + "!" + name);
228: //return new URL("jar:file:/" + path + "!" + name);
229: } catch (Exception ex)
230: {}
231: }
232: }
233: else
234: {
235: File f = new File(path, name);
236: if (f.exists())
237: {
238: try {
239: return f.toURL();
240: //return new URL("file:/" + f);
241: } catch (Exception ex)
242: {}
243: }
244: }
245: }
246:
247: // Else try to load from reloadable paths...
248: for (int i = 0; i < fPathItems.size(); i++) {
249:
250: String path = (String) fPathItems.get(i);
251:
252: if (isJar(path))
253: {
254: InputStream is = getInputStreamFromJar(path, name);
255: if (is != null)
256: {
257: try {
258: is.close();
259: File f = new File(path);
260: System.out.println("jar:" + f.toURL() + "!" + name);
261: return new URL("jar:" + f.toURL() + "!" + name);
262: } catch (Exception ex)
263: {}
264: }
265: }
266: else
267: {
268: File f = new File(path, name);
269: if (f.exists())
270: {
271: try {
272: return f.toURL();
273: //return new URL("file:/" + f);
274: } catch (Exception ex)
275: {}
276: }
277: }
278: }
279:
280: return ClassLoader.getSystemResource(name);
281: **/
282: }
283:
284: public InputStream getResourceAsStream(String name) {
285:
286: // We have to try to solve the name...
287: for (int i = 0; i < fPathChachedItems.size(); i++) {
288: String path = (String) fPathChachedItems.get(i);
289:
290: if (isJar(path)) {
291: InputStream is = getInputStreamFromJar(path, name);
292: if (is != null)
293: return is;
294: } else {
295: File f = new File(path, name);
296: if (f.exists()) {
297: try {
298: return new FileInputStream(f);
299: } catch (Exception ex) {
300: }
301: }
302: }
303: }
304:
305: // Else try to load from reloadable paths...
306: for (int i = 0; i < fPathItems.size(); i++) {
307:
308: String path = (String) fPathItems.get(i);
309:
310: if (isJar(path)) {
311: InputStream is = getInputStreamFromJar(path, name);
312: if (is != null)
313: return is;
314: } else {
315: File f = new File(path, name);
316: if (f.exists()) {
317: try {
318: return new FileInputStream(f);
319: } catch (Exception ex) {
320: }
321: }
322: }
323: }
324:
325: return ClassLoader.getSystemResourceAsStream(name);
326: }
327:
328: private InputStream getInputStreamFromJar(String archive_path,
329: String fileName) {
330: ZipFile zipFile = null;
331: InputStream stream = null;
332: File archive = new File(archive_path);
333: if (!archive.exists()) {
334: //System.out.println("Il jar non esiste!");
335: return null;
336: }
337: try {
338: zipFile = new ZipFile(archive);
339: } catch (IOException io) {
340: //io.printStackTrace();
341: return null;
342: }
343:
344: //System.out.println("Ricerca entry" + fileName );
345: ZipEntry entry = zipFile.getEntry(fileName);
346: if (entry == null) {
347: //System.out.println("Entry null!");
348: return null;
349: }
350: try {
351: return zipFile.getInputStream(entry);
352: } catch (IOException e) {
353: } finally {
354: }
355:
356: return null;
357: }
358:
359: public synchronized Class findClass(String name)
360: throws ClassNotFoundException {
361:
362: Class c = null;
363:
364: if (cachedClasses.containsKey(name)) {
365: c = (Class) cachedClasses.get(name);
366:
367: } else {
368: c = loadClassData(name);
369: }
370:
371: return c;
372: /*
373: if (cachedClasses.containsKey( name ))
374: {
375: return (Class)cachedClasses.get(name);
376: }
377:
378: return defineClass(name, b, 0, b.length);
379: */
380: }
381:
382: // From here down is all code copied and pasted from JUnit's
383: // TestCaseClassLoader
384: private Class loadClassData(String className)
385: throws ClassNotFoundException {
386:
387: // 1. Look for cached class...
388:
389: // if we can't find the cached class, looking first in no relodable paths...
390:
391: byte[] data = null;
392:
393: if (!cachedClasses.containsKey(className)) {
394:
395: for (int i = 0; i < fPathChachedItems.size(); i++) {
396:
397: String path = (String) fPathChachedItems.get(i);
398: String fileName = className.replace('.',
399: File.separatorChar)
400: + ".class";
401:
402: if (isJar(path)) {
403: //System.out.println("looking for " + fileName.replace(File.separatorChar,'/') + " in jar " +path);
404: data = loadJarData(path, fileName.replace(
405: File.separatorChar, '/'));
406: } else {
407: //System.out.println("looking for " + fileName + " in dir " +path);
408: data = loadFileData(path, fileName.replace(
409: File.separatorChar, '/'));
410: }
411: if (data != null) {
412: Class c = defineClass(className, data, 0,
413: data.length);
414: cachedClasses.put(className, c);
415:
416: return c;
417: }
418: }
419: } else {
420: return (Class) cachedClasses.get(className);
421: }
422:
423: // Else try to load from reloadable paths...
424: for (int i = 0; i < fPathItems.size(); i++) {
425:
426: String path = (String) fPathItems.get(i);
427: String fileName = className
428: .replace('.', File.separatorChar)
429: + ".class";
430:
431: if (isJar(path)) {
432: data = loadJarData(path, fileName);
433: } else {
434: data = loadFileData(path, fileName);
435: }
436: if (data != null) {
437: Class c = defineClass(className, data, 0, data.length);
438: return c;
439: }
440: }
441:
442: throw new ClassNotFoundException(className);
443: }
444:
445: boolean isJar(String pathEntry) {
446: return pathEntry.toLowerCase().endsWith(".jar")
447: || pathEntry.toLowerCase().endsWith(".zip");
448: }
449:
450: private byte[] loadFileData(String path, String fileName) {
451: File file = new File(path, fileName);
452: //System.out.println("Final class name: " + file.getPath());
453: if (file.exists()) {
454: return getClassData(file);
455: }
456: return null;
457: }
458:
459: private byte[] getClassData(File f) {
460: try {
461: FileInputStream stream = new FileInputStream(f);
462: ByteArrayOutputStream out = new ByteArrayOutputStream(1000);
463: byte[] b = new byte[1000];
464: int n;
465: while ((n = stream.read(b)) != -1)
466: out.write(b, 0, n);
467: stream.close();
468: out.close();
469: return out.toByteArray();
470:
471: } catch (IOException e) {
472: }
473: return null;
474: }
475:
476: private byte[] loadJarData(String path, String fileName) {
477: ZipFile zipFile = null;
478: InputStream stream = null;
479: File archive = new File(path);
480: if (!archive.exists()) {
481: //System.out.println("Il jar non esiste!");
482: return null;
483: }
484: try {
485: zipFile = new ZipFile(archive);
486: } catch (IOException io) {
487: //io.printStackTrace();
488: return null;
489: }
490:
491: //System.out.println("Ricerca entry" + fileName );
492: ZipEntry entry = zipFile.getEntry(fileName);
493: if (entry == null) {
494: //System.out.println("Entry null!");
495: return null;
496: }
497: int size = (int) entry.getSize();
498: try {
499: stream = zipFile.getInputStream(entry);
500: byte[] data = new byte[size];
501: int pos = 0;
502: while (pos < size) {
503: int n = stream.read(data, pos, data.length - pos);
504: pos += n;
505: }
506: zipFile.close();
507: return data;
508: } catch (IOException e) {
509: } finally {
510: try {
511: if (stream != null)
512: stream.close();
513: } catch (IOException e) {
514: //e.printStackTrace();
515: }
516: }
517: //System.out.println("Class not found really!");
518: return null;
519: }
520:
521: public Enumeration findResources(String name) {
522: // We have to try to solve the name...
523: Vector urls = new Vector();
524:
525: URL[] pathUrls = new URL[fPathChachedItems.size()
526: + fPathItems.size()];
527:
528: for (int i = 0; i < fPathChachedItems.size(); i++) {
529: String path = (String) fPathChachedItems.get(i);
530: try {
531: pathUrls[i] = (new File(path)).toURL();
532: } catch (Exception ex) {
533: }
534: }
535:
536: for (int i = 0; i < fPathItems.size(); i++) {
537: String path = (String) fPathItems.get(i);
538: try {
539: pathUrls[i + fPathChachedItems.size()] = (new File(path))
540: .toURL();
541: } catch (Exception ex) {
542: }
543: }
544:
545: URLClassLoader urlCl = new URLClassLoader(pathUrls, null);
546: try {
547: return urlCl.findResources(name);
548: } catch (Exception ex) {
549:
550: }
551:
552: return new Vector().elements();
553:
554: }
555:
556: public URL findResource(String name) {
557:
558: if (name.startsWith("/"))
559: name = name.substring(1);
560: URL[] pathUrls = new URL[fPathChachedItems.size()
561: + fPathItems.size()];
562:
563: for (int i = 0; i < fPathChachedItems.size(); i++) {
564: String path = (String) fPathChachedItems.get(i);
565: try {
566: pathUrls[i] = (new File(path)).toURL();
567: } catch (Exception ex) {
568: }
569: }
570:
571: for (int i = 0; i < fPathItems.size(); i++) {
572: String path = (String) fPathItems.get(i);
573: try {
574: pathUrls[i + fPathChachedItems.size()] = (new File(path))
575: .toURL();
576: } catch (Exception ex) {
577: }
578: }
579:
580: URLClassLoader urlCl = new URLClassLoader(pathUrls, null);
581: try {
582: URL url = urlCl.findResource(name);
583: //System.out.println( url);
584: if (url != null)
585: return url;
586: } catch (Exception ex) {
587: ex.printStackTrace();
588: }
589:
590: return ClassLoader.getSystemResource(name);
591:
592: }
593: }
|