blob: db75b269d5fc832e9249d63639864b320843688e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 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.jsp.core.internal.taglib;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jst.jsp.core.internal.Logger;
import org.eclipse.wst.sse.core.utils.StringUtils;
/**
* Custom ClassLoader backed by a Java Project.
*/
public class BuildPathClassLoader extends ClassLoader {
private static final boolean DEBUG = Boolean.valueOf(Platform.getDebugOption("org.eclipse.jst.jsp.core/debug/taglibclassloader")).booleanValue(); //$NON-NLS-1$
private IJavaProject fProject;
public BuildPathClassLoader(ClassLoader parent, IJavaProject project) {
super(parent);
fProject = project;
}
/**
* Closes the given file with "extreme prejudice".
*
* @param file the zip file to be closed
*/
public void closeJarFile(ZipFile file) {
if (file == null)
return;
try {
file.close();
}
catch (IOException ioe) {
// no cleanup can be done
Logger.logException("JarUtilities: Could not close file " + file.getName(), ioe); //$NON-NLS-1$
}
}
/*
* This may pose a runtime performance problem as it opens the containing
* .jar file for each class, but this is countered by no longer leaving
* file handles open nor having to directly interact the build path at
* all. If it is a problem, the TaglibHelper should control some
* "batching" whereby we leave the JarFiles open until directed to close
* them at the end of TaglibHelper.addTEIVariables(...).
*
* @see java.lang.ClassLoader#findClass(java.lang.String)
*/
protected Class findClass(String className) throws ClassNotFoundException {
if (DEBUG)
System.out.println("finding: [" + className + "]"); //$NON-NLS-1$ //$NON-NLS-2$
try {
IType type = fProject.findType(className.replace('$', '.'));
if (type != null) {
IPath path = null;
IResource resource = type.getResource();
if (resource != null)
path = resource.getLocation();
if (path == null)
path = type.getPath();
// needs to be compiled before we can load it
if ("class".equalsIgnoreCase(path.getFileExtension())) {
IFile file = null;
if (resource != null && resource.getType() == IResource.FILE)
file = (IFile) resource;
else
file = ResourcesPlugin.getWorkspace().getRoot().getFile(path);
if (file != null && file.isAccessible()) {
byte[] bytes = loadBytes(file);
return defineClass(className, bytes, 0, bytes.length);
}
}
// Look up the class file based on the output location of the java project
else if ("java".equalsIgnoreCase(path.getFileExtension()) && resource != null) { //$NON-NLS-1$
if (resource.getProject() != null) {
IJavaProject jProject = JavaCore.create(resource.getProject());
String outputClass = StringUtils.replace(type.getFullyQualifiedName(), ".", "/").concat(".class"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
IPath classPath = jProject.getOutputLocation().append(outputClass);
IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(classPath);
if (file != null && file.isAccessible()) {
byte[] bytes = loadBytes(file);
return defineClass(className, bytes, 0, bytes.length);
}
}
}
else if ("jar".equalsIgnoreCase(path.getFileExtension())) {
String expectedFileName = StringUtils.replace(className, ".", "/").concat(".class"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
byte[] bytes = getCachedInputStream(path.toOSString(), expectedFileName);
return defineClass(className, bytes, 0, bytes.length);
}
}
}
catch (JavaModelException e) {
Logger.logException(e);
}
return super.findClass(className);
}
/**
* Get the entry from the jarfile
* @param jarFilename the string path of the jarfile
* @param entryName the fully-qualified entry
* @return the bytes for the entry within the jarfile or a byte array of size 0
*/
private byte[] getCachedInputStream(String jarFilename, String entryName) {
ByteArrayOutputStream buffer = null;
File testFile = new File(jarFilename);
if (!testFile.exists())
return null;
ZipFile jarfile = null;
try {
jarfile = new ZipFile(jarFilename);
if (jarfile != null) {
ZipEntry zentry = jarfile.getEntry(entryName);
if (zentry != null) {
InputStream entryInputStream = null;
try {
entryInputStream = jarfile.getInputStream(zentry);
}
catch (IOException ioExc) {
Logger.logException("JarUtilities: " + jarFilename, ioExc); //$NON-NLS-1$
}
if (entryInputStream != null) {
int c;
if (zentry.getSize() > 0) {
buffer = new ByteArrayOutputStream((int) zentry.getSize());
}
else {
buffer = new ByteArrayOutputStream();
}
// array dim restriction?
byte bytes[] = new byte[2048];
try {
while ((c = entryInputStream.read(bytes)) >= 0) {
buffer.write(bytes, 0, c);
}
}
catch (IOException ioe) {
// no cleanup can be done
}
finally {
try {
entryInputStream.close();
}
catch (IOException e) {
}
}
}
}
}
}
catch (IOException ioExc) {
Logger.logException("JarUtilities: " + jarFilename, ioExc); //$NON-NLS-1$
}
finally {
closeJarFile(jarfile);
}
if (buffer != null) {
return buffer.toByteArray();
}
return new byte[0];
}
/**
* @param file
* @return
*/
private byte[] loadBytes(IFile file) {
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream in = null;
try {
in = file.getContents();
byte[] buffer = new byte[4096];
int read = 0;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
catch (CoreException e) {
Logger.logException(e);
}
catch (IOException e) {
Logger.logException(e);
}
finally {
try {
if (in != null)
in.close();
}
catch (IOException e) {
}
}
return out.toByteArray();
}
}