[159888] TaglibHelper.addTEIVariables() opens same jar file about 70 times during project creation
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/BuildPathClassLoader.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/BuildPathClassLoader.java
new file mode 100644
index 0000000..db75b26
--- /dev/null
+++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/BuildPathClassLoader.java
@@ -0,0 +1,228 @@
+/*******************************************************************************
+ * 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();
+ }
+
+}
\ No newline at end of file
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibHelper.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibHelper.java
index 9ce0fc7..0f2925f 100644
--- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibHelper.java
+++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibHelper.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2004, 2008 IBM Corporation and others.
+ * Copyright (c) 2004, 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
@@ -11,16 +11,13 @@
package org.eclipse.jst.jsp.core.internal.taglib;
-import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import javax.servlet.jsp.tagext.TagAttributeInfo;
import javax.servlet.jsp.tagext.TagData;
@@ -30,16 +27,10 @@
import javax.servlet.jsp.tagext.ValidationMessage;
import javax.servlet.jsp.tagext.VariableInfo;
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Platform;
-import org.eclipse.jdt.core.IClasspathContainer;
-import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
@@ -83,17 +74,14 @@
}
private IProject fProject = null;
- private TaglibClassLoader fLoader = null;
+ private ClassLoader fLoader = null;
- private Set fProjectEntries = null;
private Map fTranslationProblems = null;
- private Set fContainerEntries = null;
private IJavaProject fJavaProject;
public TaglibHelper(IProject project) {
+ super();
setProject(project);
- fProjectEntries = new HashSet();
- fContainerEntries = new HashSet();
fTranslationProblems = new HashMap();
}
@@ -178,7 +166,6 @@
* @param node
*/
private void addVariables(List results, CMNode node, ITextRegionCollection customTag) {
-
List list = ((TLDElementDeclaration) node).getVariables();
Iterator it = list.iterator();
while (it.hasNext()) {
@@ -240,7 +227,7 @@
if (teiClassname == null || teiClassname.length() == 0 || fJavaProject == null)
return;
- TaglibClassLoader loader = getClassloader();
+ ClassLoader loader = getClassloader();
Class teiClass = null;
try {
@@ -611,207 +598,14 @@
return tagDataTable;
}
- private TaglibClassLoader getClassloader() {
+ private ClassLoader getClassloader() {
if (fLoader == null) {
- fLoader = new TaglibClassLoader(this.getClass().getClassLoader());
- fProjectEntries.clear();
- fContainerEntries.clear();
- addClasspathEntriesForProject(getProject(), fLoader);
+ fLoader = new BuildPathClassLoader(this.getClass().getClassLoader(), fJavaProject);
}
return fLoader;
}
/**
- * @param loader
- */
- private void addClasspathEntriesForProject(IProject p, TaglibClassLoader loader) {
-
- // avoid infinite recursion and closed project
- if (!p.isAccessible() || fProjectEntries.contains(p.getFullPath().toString()))
- return;
- fProjectEntries.add(p.getFullPath().toString());
-
- // add things on classpath that we are interested in
- try {
- if (p.hasNature(JavaCore.NATURE_ID)) {
-
- IJavaProject project = JavaCore.create(p);
-
- try {
- IClasspathEntry[] entries = project.getResolvedClasspath(true);
- addDefaultDirEntry(loader, project);
- addClasspathEntries(loader, project, entries);
- }
- catch (JavaModelException e) {
- Logger.logException(e);
- }
- }
- }
- catch (CoreException e) {
- Logger.logException(e);
- }
- }
-
- private void addClasspathEntries(TaglibClassLoader loader, IJavaProject project, IClasspathEntry[] entries) throws JavaModelException {
- IClasspathEntry entry;
- for (int i = 0; i < entries.length; i++) {
-
- entry = entries[i];
- if (DEBUG)
- System.out.println("current entry is: " + entry); //$NON-NLS-1$
-
- switch (entry.getEntryKind()) {
- case IClasspathEntry.CPE_SOURCE :
- addSourceEntry(loader, entry);
- break;
- case IClasspathEntry.CPE_LIBRARY :
- addLibraryEntry(loader, entry.getPath());
- break;
- case IClasspathEntry.CPE_PROJECT :
- addProjectEntry(loader, entry);
- break;
- case IClasspathEntry.CPE_VARIABLE :
- addVariableEntry(loader, entry);
- break;
- case IClasspathEntry.CPE_CONTAINER :
- addContainerEntry(loader, project, entry);
- break;
- }
- }
- }
-
- /**
- * @param loader
- * @param entry
- */
- private void addVariableEntry(TaglibClassLoader loader, IClasspathEntry entry) {
- if (DEBUG)
- System.out.println(" -> adding variable entry: [" + entry + "]"); //$NON-NLS-1$ //$NON-NLS-2$
-
- // variable should either be a project or a library entry
-
- // BUG 169431
- String variableName = entry.getPath().toString();
- IPath variablePath = JavaCore.getResolvedVariablePath(entry.getPath());
- variablePath = JavaCore.getClasspathVariable(variableName);
-
- // RATLC01076854
- // variable paths may not exist
- // in that case null will be returned
- if (variablePath != null) {
- if (variablePath.segments().length == 1) {
- IProject varProj = ResourcesPlugin.getWorkspace().getRoot().getProject(variablePath.toString());
- if (varProj != null && varProj.exists()) {
- addClasspathEntriesForProject(varProj, loader);
- return;
- }
- }
- addLibraryEntry(loader, variablePath);
- }
- }
-
- /**
- * @param loader
- * @param project
- * @param entry
- * @throws JavaModelException
- */
- private void addContainerEntry(TaglibClassLoader loader, IJavaProject project, IClasspathEntry entry) throws JavaModelException {
-
- IClasspathContainer container = JavaCore.getClasspathContainer(entry.getPath(), project);
- if (container != null) {
- String uniqueProjectAndContainerPath = project.getProject().getFullPath().append(container.getPath()).toString();
- /*
- * Avoid infinite recursion, but track containers for each project
- * separately as they may return different values. This may mean
- * indexing JREs multiple times, however.
- */
- if (!fContainerEntries.contains(uniqueProjectAndContainerPath)) {
- fContainerEntries.add(uniqueProjectAndContainerPath);
-
- IClasspathEntry[] cpes = container.getClasspathEntries();
- // recursive call here
- addClasspathEntries(loader, project, cpes);
- }
- }
- }
-
- /**
- * @param loader
- * @param entry
- */
- private void addProjectEntry(TaglibClassLoader loader, IClasspathEntry entry) {
- if (DEBUG)
- System.out.println(" -> project entry: [" + entry + "]"); //$NON-NLS-1$ //$NON-NLS-2$
-
- IPath path = entry.getPath();
- IProject referenceProject = ResourcesPlugin.getWorkspace().getRoot().getProject(path.segment(0));
- if (referenceProject != null && referenceProject.isAccessible()) {
- addClasspathEntriesForProject(referenceProject, loader);
- }
- }
-
- /**
- * @param loader
- * @param project
- * @param projectLocation
- * @throws JavaModelException
- */
- private void addDefaultDirEntry(TaglibClassLoader loader, IJavaProject project) throws JavaModelException {
- // add default bin directory for the project
- IPath outputPath = project.getOutputLocation();
- loader.addFolder(outputPath);
- }
-
- /**
- * @param loader
- * @param entry
- */
- private void addLibraryEntry(TaglibClassLoader loader, IPath libPath) {
- String libPathString = libPath.toString();
- File file = new File(libPathString);
-
- if (file.exists()) {
- if (file.isDirectory()) {
- loader.addDirectory(libPathString);
- }
- else {
- loader.addJar(libPathString);
- }
- }
- else {
- if (libPath.segmentCount() > 1) {
- IFile ifile = ResourcesPlugin.getWorkspace().getRoot().getFile(libPath);
- if (ifile != null && ifile.isAccessible()) {
- loader.addFile(libPath);
- }
- else {
- IFolder ifolder = ResourcesPlugin.getWorkspace().getRoot().getFolder(libPath);
- if (ifolder != null && ifolder.isAccessible()) {
- loader.addFolder(libPath);
- }
- }
- }
- else {
- loader.addFolder(libPath);
- }
- }
- }
-
- /**
- * @param loader
- * @param entry
- */
- private void addSourceEntry(TaglibClassLoader loader, IClasspathEntry entry) {
- // add bin directory for specific entry if it has
- // one
- IPath outputLocation = entry.getOutputLocation();
- if (outputLocation != null) {
- loader.addFolder(outputLocation);
- }
- }
-
- /**
* @return Returns the fModelQuery.
*/
public ModelQuery getModelQuery(IDocument doc) {
@@ -880,4 +674,14 @@
}
}
}
+
+ /**
+ *
+ */
+ public void dispose() {
+ fLoader = null;
+ fJavaProject = null;
+ fProject = null;
+ fTranslationProblems = null;
+ }
}
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibHelperCache.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibHelperCache.java
index acf1e30..05f086d 100644
--- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibHelperCache.java
+++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibHelperCache.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2005, 2008 IBM Corporation and others.
+ * Copyright (c) 2005, 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
@@ -129,9 +129,10 @@
}
if(fHelpers.size() > MAX_SIZE) {
// one too many, remove last
- Object removed = fHelpers.remove(fHelpers.size()-1);
+ Entry removed = (Entry) fHelpers.remove(fHelpers.size()-1);
+ removed.getHelper().dispose();
if(DEBUG) {
- Logger.log(Logger.INFO, "(-) TaglibHelperCache removed: " + removed); //$NON-NLS-1$
+ Logger.log(Logger.INFO, "(-) TaglibHelperCache removed: " + removed.getProjectName()); //$NON-NLS-1$
printCacheContents();
}
}
@@ -144,6 +145,7 @@
while(it.hasNext()) {
entry = (Entry)it.next();
if(entry.getProjectName().equals(projectName)) {
+ entry.getHelper().dispose();
fHelpers.remove(entry);
if(DEBUG) {
Logger.log(Logger.INFO, "(-) TaglibHelperCache removed: " + entry); //$NON-NLS-1$