blob: eb86a98e6bc46abc55ff154a6042e470f50f707e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2001, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jst.j2ee.commonarchivecore.internal.util;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.jst.j2ee.commonarchivecore.internal.Archive;
import org.eclipse.jst.j2ee.commonarchivecore.internal.CommonArchiveResourceHandler;
import org.eclipse.jst.j2ee.commonarchivecore.internal.EARFile;
import org.eclipse.jst.j2ee.commonarchivecore.internal.File;
import org.eclipse.jst.j2ee.commonarchivecore.internal.exception.ArchiveRuntimeException;
/**
* Class loader which loads a given set of classes stored in byte arrays. (Assumption: System
* classes and those in the set are the only classes needed to resolve each one)
*/
public class ArchiveFileDynamicClassLoader extends ClassLoader {
protected Archive archive = null;
protected ClassLoader extraClassLoader;
protected boolean inEARFile;
public ArchiveFileDynamicClassLoader(Archive anArchive, ClassLoader parentCl, ClassLoader extraCl) {
super(parentCl);
setArchive(anArchive);
setExtraClassLoader(extraCl);
inEARFile = anArchive.getContainer() != null && anArchive.getContainer().isEARFile();
}
/**
* Loads a specified class. This gets called only after the parent class loader has had it's
* chance, based on the Java2 delegation model
*/
protected Class findClass(String name) throws ClassNotFoundException {
Class result;
// Load class bytes from current set of class byte[]'s
byte[] bytes = getClassBytesFor(name);
if (bytes != null) {
result = defineClass(name, bytes, 0, bytes.length);
if (result == null) {
throw new ClassNotFoundException(name);
} // endif
} else {
throw new ClassNotFoundException(name);
} // endif
return result;
}
/**
* Insert the method's description here. Creation date: (12/17/00 9:59:57 PM)
*
* @return com.ibm.etools.commonarchive.Archive
*/
public Archive getArchive() {
return archive;
}
protected byte[] getClassBytesFor(String className) {
if (className == null)
return null;
// Change the class name to a jar entry name
String jarEntryName = ArchiveUtil.classNameToUri(className);
try {
InputStream in = getArchive().getInputStream(jarEntryName);
return ArchiveUtil.inputStreamToBytes(in);
} catch (java.io.FileNotFoundException ex) {
return null;
} catch (java.io.IOException ex) {
throw new ArchiveRuntimeException(CommonArchiveResourceHandler.getString("io_ex_loading_EXC_", (new Object[]{className})), ex); //$NON-NLS-1$ = "An IO exception occurred loading "
}
}
protected EARFile getEARFile() {
return (EARFile) getArchive().getContainer();
}
/**
* Insert the method's description here. Creation date: (11/21/00 6:58:05 PM)
*
* @return java.lang.ClassLoader
*/
public java.lang.ClassLoader getExtraClassLoader() {
return extraClassLoader;
}
/**
* Used for dynamic class loading in dependent jars in ears; the set is used to terminate a
* cycle if one exists; the cycle is invalid, but you never know what people might try...
*/
protected synchronized Class loadClass(String name, Set visitedArchives) throws ClassNotFoundException {
if (visitedArchives.contains(getArchive()))
throw new ClassNotFoundException(name);
visitedArchives.add(getArchive());
try {
return super.loadClass(name, false);
} catch (ClassNotFoundException ex) {
return loadClassInDependentJarInEAR(name, visitedArchives);
}
}
protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
try {
return super.loadClass(name, resolve);
} catch (ClassNotFoundException ex) {
Class c = loadClassInDependentJar(name);
if (c != null && resolve)
resolveClass(c);
return c;
}
}
protected Class loadClassInDependentJar(String name) throws ClassNotFoundException {
if (inEARFile) {
return loadClassInDependentJarInEAR(name);
} else if (getExtraClassLoader() != null) {
return getExtraClassLoader().loadClass(name);
}
throw new ClassNotFoundException(name);
}
protected Class loadClassInDependentJarInEAR(String name) throws ClassNotFoundException {
Set visitedArchives = new HashSet(5);
visitedArchives.add(getArchive());
return loadClassInDependentJarInEAR(name, visitedArchives);
}
protected Class loadClassInDependentJarInEAR(String name, Set visitedArchives) throws ClassNotFoundException {
String[] classpath = archive.getManifest().getClassPathTokenized();
for (int i = 0; i < classpath.length; i++) {
try {
String uri = ArchiveUtil.deriveEARRelativeURI(classpath[i], archive);
if (uri == null)
continue;
File file = getEARFile().getFile(uri);
if (file.isArchive()) {
Archive dep = (Archive) file;
try {
return ((ArchiveFileDynamicClassLoader) dep.getArchiveClassLoader()).loadClass(name, visitedArchives);
} catch (ClassNotFoundException noDice) {
continue;
}
}
} catch (java.io.FileNotFoundException depJarNotInEAR) {
//Ignore
}
}
throw new ClassNotFoundException(name);
}
/**
* Insert the method's description here. Creation date: (12/17/00 9:59:57 PM)
*
* @param newArchive
* com.ibm.etools.commonarchive.Archive
*/
public void setArchive(Archive newArchive) {
archive = newArchive;
}
/**
* Insert the method's description here. Creation date: (11/21/00 6:58:05 PM)
*
* @param newExtraClassLoader
* java.lang.ClassLoader
*/
public void setExtraClassLoader(java.lang.ClassLoader newExtraClassLoader) {
extraClassLoader = newExtraClassLoader;
}
}