[87143] JSP does not respect TEI VariableInfo
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslationAdapter.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslationAdapter.java index 2a2b502..f0ba288 100644 --- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslationAdapter.java +++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslationAdapter.java
@@ -37,11 +37,7 @@ public class JSPTranslationAdapter implements INodeAdapter, IDocumentListener { // for debugging - private static final boolean DEBUG; - static { - String value = Platform.getDebugOption("org.eclipse.jst.jsp.core/debug/jsptranslation"); //$NON-NLS-1$ - DEBUG = value != null && value.equalsIgnoreCase("true"); //$NON-NLS-1$ - } + private static final boolean DEBUG = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.jst.jsp.core/debug/jsptranslation")); //$NON-NLS-1$ //$NON-NLS-2$ private IDocument fJspDocument = null; private IDocument fJavaDocument = null; @@ -131,7 +127,6 @@ translator.translate(); StringBuffer javaContents = translator.getTranslation(); fJavaDocument = new Document(javaContents.toString()); - } else { // empty document case
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslator.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslator.java index f3e2708..979333a 100644 --- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslator.java +++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/JSPTranslator.java
@@ -12,6 +12,7 @@ import java.io.BufferedInputStream; import java.io.BufferedReader; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -21,17 +22,23 @@ import java.util.Iterator; import java.util.List; import java.util.Stack; -import com.ibm.icu.util.StringTokenizer; + +import javax.servlet.jsp.tagext.VariableInfo; import org.eclipse.core.filebuffers.FileBuffers; +import org.eclipse.core.filebuffers.ITextFileBuffer; +import org.eclipse.core.filebuffers.ITextFileBufferManager; import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.QualifiedName; @@ -65,6 +72,8 @@ import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode; import org.eclipse.wst.xml.core.internal.regions.DOMRegionContext; +import com.ibm.icu.util.StringTokenizer; + /** * Translates a JSP document into a HttpServlet. Keeps two way mapping from * java translation to the original JSP source, which can be obtained through @@ -87,6 +96,7 @@ // for debugging private static final boolean DEBUG; + private static final boolean DEBUG_SAVE_OUTPUT = "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.jst.jsp.core/debug/jsptranslationstodisk")); //$NON-NLS-1$ //$NON-NLS-2$ private IJSPELTranslator fELTranslator = null; @@ -142,6 +152,12 @@ /** user defined imports */ private StringBuffer fUserImports = new StringBuffer(); + /** + * A map of tag names to tag library variable information; used to store + * the ones needed for AT_END variable support. + */ + private HashMap fTagToVariableMap = null; + private StringBuffer fResult; // the final traslated java document // string buffer private StringBuffer fCursorOwner = null; // the buffer where the cursor @@ -330,7 +346,8 @@ } } catch (CoreException e) { - // ISSUE: why do we log this here? Instead of allowing to throwup? + // ISSUE: why do we log this here? Instead of allowing to + // throwup? Logger.logException(e); } @@ -669,6 +686,29 @@ Logger.log(Logger.INFO_DEBUG, debugString.toString()); } + if (DEBUG_SAVE_OUTPUT) { + IProject project = getFile().getProject(); + String shortenedClassname = StringUtils.replace(getFile().getName(), ".", "_"); + String filename = shortenedClassname + ".java"; + IPath path = project.getFullPath().append("src/" + filename); + try { + IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path); + if (!file.exists()) { + file.create(new ByteArrayInputStream(new byte[0]), true, new NullProgressMonitor()); + } + ITextFileBufferManager textFileBufferManager = FileBuffers.getTextFileBufferManager(); + textFileBufferManager.connect(path, new NullProgressMonitor()); + ITextFileBuffer javaOutputBuffer = textFileBufferManager.getTextFileBuffer(path); + javaOutputBuffer.getDocument().set(StringUtils.replace(fResult.toString(), getClassname(), shortenedClassname)); + javaOutputBuffer.commit(new NullProgressMonitor(), true); + textFileBufferManager.disconnect(path, new NullProgressMonitor()); + } + catch (Exception e) { + // this is just for debugging, ignore + } + System.out.println("Updated translation: " + path); + } + return fResult; } @@ -690,11 +730,74 @@ TaglibHelper helper = TaglibHelperManager.getInstance().getTaglibHelper(f); IStructuredDocumentRegion customTag = getCurrentNode(); - TaglibVariable[] taglibVars = helper.getTaglibVariables(tagToAdd, getStructuredDocument(), customTag); + /* + * Variables can declare as available when NESTED, AT_BEGIN, or + * AT_END. For AT_END variables, store the entire list of variables in + * the map field so it can be used on the end tag. + */ String decl = ""; //$NON-NLS-1$ - for (int i = 0; i < taglibVars.length; i++) { - decl = taglibVars[i].getDeclarationString(); - appendToBuffer(decl, fUserCode, false, fCurrentNode); + if (customTag.getFirstRegion().getType().equals(DOMRegionContext.XML_TAG_OPEN)) { + TaglibVariable[] taglibVars = helper.getTaglibVariables(tagToAdd, getStructuredDocument(), customTag); + /* + * These loops are duplicated intentionally to keep the nesting + * scoped variables from interfering with the others + */ + for (int i = 0; i < taglibVars.length; i++) { + if (taglibVars[i].getScope() == VariableInfo.AT_BEGIN) { + decl = taglibVars[i].getDeclarationString(); + appendToBuffer(decl, fUserCode, false, fCurrentNode); + } + if (taglibVars[i].getScope() == VariableInfo.AT_END) { + decl = taglibVars[i].getDeclarationString(); + fTagToVariableMap.put(tagToAdd, taglibVars); + } + } + for (int i = 0; i < taglibVars.length; i++) { + if (taglibVars[i].getScope() == VariableInfo.NESTED) { + decl = taglibVars[i].getDeclarationString(); + appendToBuffer("{", fUserCode, false, fCurrentNode); + appendToBuffer(decl, fUserCode, false, fCurrentNode); + fTagToVariableMap.put(tagToAdd, taglibVars); + } + } + if (customTag.getLastRegion().getType().equals(DOMRegionContext.XML_EMPTY_TAG_CLOSE)) { + /* + * Process NESTED variables backwards so the scopes "unroll" + * correctly. + */ + for (int i = taglibVars.length; i > 0; i--) { + if (taglibVars[i-1].getScope() == VariableInfo.NESTED) { + appendToBuffer("}", fUserCode, false, fCurrentNode); + } + } + /* Treat this as the end for empty tags */ + for (int i = 0; i < taglibVars.length; i++) { + if (taglibVars[i].getScope() == VariableInfo.AT_END) { + decl = taglibVars[i].getDeclarationString(); + appendToBuffer(decl, fUserCode, false, fCurrentNode); + } + } + } + } + /* + * Process NESTED variables for an end tag backwards so the scopes + * "unroll" correctly. + */ + else if (customTag.getFirstRegion().getType().equals(DOMRegionContext.XML_END_TAG_OPEN)) { + TaglibVariable[] taglibVars = (TaglibVariable[]) fTagToVariableMap.remove(tagToAdd); + if (taglibVars != null) { + for (int i = taglibVars.length; i > 0; i--) { + if (taglibVars[i-1].getScope() == VariableInfo.NESTED) { + appendToBuffer("}", fUserCode, false, fCurrentNode); + } + } + for (int i = 0; i < taglibVars.length; i++) { + if (taglibVars[i].getScope() == VariableInfo.AT_END) { + decl = taglibVars[i].getDeclarationString(); + appendToBuffer(decl, fUserCode, false, fCurrentNode); + } + } + } } } @@ -726,6 +829,10 @@ * structuredDocument nodes */ public void translate() { + if (fTagToVariableMap == null) { + fTagToVariableMap = new HashMap(2); + } + setCurrentNode(fStructuredDocument.getFirstStructuredDocumentRegion()); while (getCurrentNode() != null && !isCanceled()) { @@ -744,6 +851,8 @@ advanceNextNode(); } buildResult(); + + fTagToVariableMap.clear(); } protected void setDocumentContent(IDocument document, InputStream contentStream, String charset) { @@ -846,7 +955,7 @@ // translateJSPNode(region, regions, type, JSPType); translateJSPNode(containerRegion, regions, type, JSPType); } - else if (type != null && type == DOMRegionContext.XML_TAG_OPEN) { + else if (type != null && (type == DOMRegionContext.XML_TAG_OPEN || type == DOMRegionContext.XML_END_TAG_OPEN)) { translateXMLNode(containerRegion, regions); } } @@ -854,6 +963,9 @@ } private void handleScopingIfNecessary(ITextRegionCollection containerRegion) { + if (true) + return; + // code within a custom tag gets its own scope // so if we encounter a start of a custom tag, we add '{' // and for the end of a custom tag we add '}' @@ -999,9 +1111,10 @@ if (r.getType() == DOMRegionContext.XML_TAG_NAME || r.getType() == DOMJSPRegionContexts.JSP_DIRECTIVE_NAME) { - String fullTagName = container.getFullText(r).trim(); + String fullTagName = container.getText(r); if (fullTagName.indexOf(':') > -1) { - addTaglibVariables(fullTagName); // it may be a taglib + addTaglibVariables(fullTagName); // it may be a custom + // tag } StringTokenizer st = new StringTokenizer(fullTagName, ":.", false); //$NON-NLS-1$ if (st.hasMoreTokens() && st.nextToken().equals("jsp")) //$NON-NLS-1$ @@ -1099,30 +1212,37 @@ // tag name is not jsp // handle embedded jsp attributes... ITextRegion embedded = null; - //Iterator attrRegions = null; - //ITextRegion attrChunk = null; + // Iterator attrRegions = null; + // ITextRegion attrChunk = null; while (regions.hasNext()) { embedded = (ITextRegion) regions.next(); if (embedded instanceof ITextRegionContainer) { // parse out container - + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=130606 // fix exponential iteration problem w/ embedded expressions translateEmbeddedJSPInAttribute((ITextRegionContainer) embedded); -// attrRegions = ((ITextRegionContainer) embedded).getRegions().iterator(); -// while (attrRegions.hasNext()) { -// attrChunk = (ITextRegion) attrRegions.next(); -// String type = attrChunk.getType(); -// // embedded JSP in attribute support only want to -// // translate one time per -// // embedded region so we only translate on the JSP open -// // tags (not content) -// if (type == DOMJSPRegionContexts.JSP_EXPRESSION_OPEN || type == DOMJSPRegionContexts.JSP_SCRIPTLET_OPEN || type == DOMJSPRegionContexts.JSP_DECLARATION_OPEN || type == DOMJSPRegionContexts.JSP_DIRECTIVE_OPEN || type == DOMJSPRegionContexts.JSP_EL_OPEN) { -// // now call jsptranslate -// translateEmbeddedJSPInAttribute((ITextRegionContainer) embedded); -// break; -// } -// } + // attrRegions = ((ITextRegionContainer) + // embedded).getRegions().iterator(); + // while (attrRegions.hasNext()) { + // attrChunk = (ITextRegion) attrRegions.next(); + // String type = attrChunk.getType(); + // // embedded JSP in attribute support only want to + // // translate one time per + // // embedded region so we only translate on the JSP open + // // tags (not content) + // if (type == DOMJSPRegionContexts.JSP_EXPRESSION_OPEN || + // type == + // DOMJSPRegionContexts.JSP_SCRIPTLET_OPEN || type == + // DOMJSPRegionContexts.JSP_DECLARATION_OPEN || type == + // DOMJSPRegionContexts.JSP_DIRECTIVE_OPEN || type == + // DOMJSPRegionContexts.JSP_EL_OPEN) { + // // now call jsptranslate + // translateEmbeddedJSPInAttribute((ITextRegionContainer) + // embedded); + // break; + // } + // } } } } @@ -1649,7 +1769,10 @@ if (!getIncludes().contains(fileLocation) && getBaseLocation() != null && !fileLocation.equals(getBaseLocation())) { getIncludes().push(fileLocation); JSPIncludeRegionHelper helper = new JSPIncludeRegionHelper(this); - helper.parse(fileLocation); + boolean parsed = helper.parse(fileLocation); + if (!parsed) { + Logger.log(Logger.ERROR_DEBUG, "Error: included file " + filename + " not found {" + getBaseLocation() + ")"); + } getIncludes().pop(); } } @@ -1819,7 +1942,7 @@ // https://bugs.eclipse.org/bugs/show_bug.cgi?id=128490 // length of 11 is the length of jsp:useBean // and saves the expensive getText.equals call - if(r.getType() == DOMRegionContext.XML_TAG_NAME) { + if (r.getType() == DOMRegionContext.XML_TAG_NAME) { if (r.getTextLength() == 11 && jspReferenceRegion.getText(r).equals("jsp:useBean")) { //$NON-NLS-1$ isUseBean = true; }
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/XMLJSPRegionHelper.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/XMLJSPRegionHelper.java index 583ec8c..0f1b416 100644 --- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/XMLJSPRegionHelper.java +++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/java/XMLJSPRegionHelper.java
@@ -87,17 +87,24 @@ /* * parse an entire file + * + * @param filename + * @return */ - public void parse(String filename) { + public boolean parse(String filename) { // from outer class List blockMarkers = this.fTranslator.getBlockMarkers(); - reset(getContents(filename)); + String contents = getContents(filename); + if(contents == null) + return false; + reset(contents); // this adds the current markers from the outer class list // to this parser so parsing works correctly for (int i = 0; i < blockMarkers.size(); i++) { addBlockMarker((BlockMarker) blockMarkers.get(i)); } forceParse(); + return true; } @@ -167,7 +174,10 @@ } } + private void handleScopingIfNecessary(IStructuredDocumentRegion sdRegion) { + if(true) + return; // fix to make sure custom tag block have their own scope // we add '{' for custom tag open and '}' for custom tag close @@ -441,8 +451,11 @@ return nameStr.trim(); } - /* + /** * get the contents of a file as a String + * + * @param fileName + * @return the contents, null if the file could not be found */ protected String getContents(String fileName) { StringBuffer s = new StringBuffer(); @@ -462,6 +475,10 @@ s.append((char) c); } } + else { + // error condition, file could not be found + return null; + } } catch (Exception e) { if (Debug.debugStructuredDocument)
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibClassLoader.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibClassLoader.java index 2df3104..9823b3c 100644 --- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibClassLoader.java +++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibClassLoader.java
@@ -7,8 +7,10 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; @@ -37,7 +39,7 @@ private List usedJars = new ArrayList(); private List usedDirs = new ArrayList(); - private List failedClasses = new ArrayList(); // CL: added to optimize + private Map failedClasses = new HashMap(); // CL: added to optimize // failed loading // private List loadedClassFilenames = new ArrayList(); @@ -58,7 +60,7 @@ // don't add the same entry twice, or search times will get even worse if (!jarsList.contains(filename)) { jarsList.add(filename); - failedClasses = new ArrayList(); + failedClasses = new HashMap(); if (DEBUG) System.out.println(" + [" + filename + "] added to classpath"); //$NON-NLS-1$ //$NON-NLS-2$ } @@ -72,7 +74,7 @@ */ public void removeJar(String filename) { jarsList.remove(filename); - failedClasses = new ArrayList(); + failedClasses = new HashMap(); if (DEBUG) System.out.println("removed: [" + filename + "] from classpath"); //$NON-NLS-1$ //$NON-NLS-2$ } @@ -80,7 +82,7 @@ public void addDirectory(String dirPath) { if (!dirsList.contains(dirPath)) { dirsList.add(dirPath); - failedClasses = new ArrayList(); + failedClasses = new HashMap(); if (DEBUG) System.out.println("added: [" + dirPath + "] to classpath"); //$NON-NLS-1$ //$NON-NLS-2$ } @@ -94,7 +96,7 @@ */ public void removeDirectory(String dirPath) { dirsList.remove(dirPath); - failedClasses = new ArrayList(); + failedClasses = new HashMap(); if (DEBUG) System.out.println("removed: [" + dirPath + "] from classpath"); //$NON-NLS-1$ //$NON-NLS-2$ } @@ -119,6 +121,10 @@ public List getDirectoriesInUse() { return usedDirs; } + + Map getFailures() { + return failedClasses; + } /** * Returns a list of filenames for loose classes that have been loaded out @@ -145,7 +151,7 @@ System.out.println(">> TaglibClassLoader " + this + " returning existing class: " + className); //$NON-NLS-1$ //$NON-NLS-2$ return oldClass; } - if (failedClasses.contains(className)) { + if (failedClasses.containsKey(className)) { if (DEBUG) System.out.println(">> TaglibClassLoader " + this + " known missing class: " + className); //$NON-NLS-1$ //$NON-NLS-2$ throw new ClassNotFoundException(); @@ -186,8 +192,12 @@ if (stream != null) { // found a class from a directory ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[2048]; while (stream.available() > 0) { - byteStream.write(stream.read()); + int amountRead = stream.read(buffer); + if(amountRead > 0) { + byteStream.write(buffer, 0, amountRead); + } } byte[] byteArray = byteStream.toByteArray(); @@ -198,6 +208,7 @@ resolveClass(newClass); } catch (Throwable t) { + Logger.logException("Error loading TEI class " + className, t); // j9 can give ClassCircularityError // parent should already have the class then @@ -286,6 +297,7 @@ resolveClass(newClass); } catch (Throwable t) { + Logger.logException("Error loading TEI class " + className, t); // j9 can give ClassCircularityError // parent should already have the class then @@ -299,6 +311,7 @@ catch (ClassNotFoundException cnf) { if (DEBUG) cnf.printStackTrace(); + failedClasses.put(className, cnf); } } stream.close(); @@ -307,7 +320,7 @@ } } catch (Throwable t) { - failedClasses.add(className); + failedClasses.put(className, t); return null; } finally { @@ -331,7 +344,7 @@ return newClass; } - failedClasses.add(className); +// failedClasses.add(className); throw new ClassNotFoundException(); }
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 2315f4c..6f30f74 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
@@ -171,7 +171,7 @@ if (var.getVariableClass() != null) { varClass = var.getVariableClass(); } - results.add(new TaglibVariable(varClass, varName)); + results.add(new TaglibVariable(varClass, varName, var.getScope())); } } } @@ -196,7 +196,7 @@ if (teiClassname == null || teiClassname.length() == 0) return; - ClassLoader loader = getClassloader(); + TaglibClassLoader loader = getClassloader(); Class teiClass = null; try { @@ -216,7 +216,7 @@ VariableInfo[] vInfos = tei.getVariableInfo(td); if (vInfos != null) { for (int i = 0; i < vInfos.length; i++) { - results.add(new TaglibVariable(vInfos[i].getClassName(), vInfos[i].getVarName())); + results.add(new TaglibVariable(vInfos[i].getClassName(), vInfos[i].getVarName(), vInfos[i].getScope())); } } } @@ -344,7 +344,7 @@ return tagDataTable; } - private ClassLoader getClassloader() { + private TaglibClassLoader getClassloader() { if (fLoader == null) { fLoader = new TaglibClassLoader(this.getClass().getClassLoader());
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibVariable.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibVariable.java index 0e0cecc..b43d6dd 100644 --- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibVariable.java +++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/taglib/TaglibVariable.java
@@ -1,5 +1,7 @@ package org.eclipse.jst.jsp.core.internal.taglib; +import javax.servlet.jsp.tagext.VariableInfo; + /** * Contains info about a TaglibVariable: classname, variablename. @@ -9,13 +11,25 @@ private String fVarClass = null; private String fVarName = null; + private int fScope; private final String ENDL = "\n"; //$NON-NLS-1$ + + private final static String AT_END = "AT_END"; + private final static String AT_BEGIN = "AT_BEGIN"; + private final static String NESTED = "NESTED"; /** * */ - public TaglibVariable(String varClass, String varName) { + public TaglibVariable(String varClass, String varName, int scope) { setVarClass(varClass); setVarName(varName); + setScope(scope); + } + + public TaglibVariable(String varClass, String varName, String scope) { + setVarClass(varClass); + setVarName(varName); + setScope(scope); } /** * @return Returns the fVarClass. @@ -49,4 +63,26 @@ public final String getDeclarationString() { return getVarClass() + " " + getVarName() + " = null;" + ENDL; //$NON-NLS-1$ //$NON-NLS-2$ } + public int getScope() { + return fScope; + } + public void setScope(int scope) { + fScope = scope; + } + public void setScope(String scopeString) { + int scope = VariableInfo.AT_BEGIN; + + String trimmedScope = scopeString.trim(); + if (NESTED.equals(trimmedScope)) { + scope = VariableInfo.NESTED; + } + else if (AT_BEGIN.equals(trimmedScope)) { + scope = VariableInfo.AT_BEGIN; + } + else if (AT_END.equals(trimmedScope)) { + scope = VariableInfo.AT_END; + } + + fScope = scope; + } }
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/taglib/ProjectDescription.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/taglib/ProjectDescription.java index a58ad95..8d2aabe 100644 --- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/taglib/ProjectDescription.java +++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/taglib/ProjectDescription.java
@@ -25,11 +25,14 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Locale; -import java.util.Stack; +import java.util.Map; +import java.util.Set; import org.eclipse.core.filebuffers.FileBuffers; import org.eclipse.core.filebuffers.ITextFileBuffer; @@ -69,6 +72,7 @@ import org.eclipse.wst.xml.core.internal.XMLCorePlugin; import org.eclipse.wst.xml.core.internal.catalog.provisional.ICatalog; import org.eclipse.wst.xml.core.internal.catalog.provisional.ICatalogEntry; +import org.eclipse.wst.xml.core.internal.catalog.provisional.INextCatalog; import org.w3c.dom.Document; import org.w3c.dom.EntityReference; import org.w3c.dom.Node; @@ -147,6 +151,7 @@ TaglibInfo info; IPath location; List urlRecords; + boolean isExported = true; public boolean equals(Object obj) { if (!(obj instanceof JarRecord)) @@ -257,7 +262,7 @@ } public String toString() { - return "TaglibInfo|" + shortName + "|" + tlibVersion + "|" + smallIcon + "|" + largeIcon + "|" + jspVersion + "|" + uri + "|" + description; + return "TaglibInfo|" + shortName + "|" + tlibVersion + "|" + smallIcon + "|" + largeIcon + "|" + jspVersion + "|" + uri + "|" + description; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ } } @@ -340,6 +345,7 @@ String baseLocation; TaglibInfo info; URL url; + boolean isExported = true; public URLRecord() { super(); @@ -433,8 +439,9 @@ private static final String WEB_INF = "WEB-INF"; //$NON-NLS-1$ private static final IPath WEB_INF_PATH = new Path(WEB_INF); + private static final String BUILDPATH_PROJECT = "BUILDPATH_PROJECT"; //$NON-NLS-1$ private static final String WEB_XML = "web.xml"; //$NON-NLS-1$ - private static final String SAVE_FORMAT_VERSION = "1.0.1"; + private static final String SAVE_FORMAT_VERSION = "Tag Library Index 1.0.1"; //$NON-NLS-1$ private static final String BUILDPATH_DIRTY = "BUILDPATH_DIRTY"; //$NON-NLS-1$ /* @@ -449,7 +456,12 @@ */ boolean fBuildPathIsDirty = false; - Stack fClasspathProjects = null; + /** + * A set of the projects that are in this project's build path. + * Lookups/enumerations will be redirected to the corresponding + * ProjectDescription instances + */ + Set fClasspathProjects = null; // holds references by URI to JARs Hashtable fClasspathReferences; @@ -485,6 +497,7 @@ fWebXMLReferences = new Hashtable(0); fImplicitReferences = new Hashtable(0); fClasspathReferences = new Hashtable(0); + fClasspathProjects = new HashSet(); restoreReferences(); } @@ -502,6 +515,48 @@ } /** + * Adds the list of known references from this project's build path to the + * map, appending any processed projects into the list to avoid + * build-path-cycles. + * + * @see https://bugs.eclipse.org/bugs/show_bug.cgi?id=142408 + * + * @param references - + * the map of references to ITaglibRecords + * @param projectsProcessed - + * the list of projects already considered + * @param exportedOnly - + * Whether to only add references derived from exported build + * path containers. This method calls itself recursively with + * this parameter as false. + */ + void addBuildPathReferences(Map references, List projectsProcessed, boolean exportedOnly) { + ensureUpTodate(); + + Enumeration keys = fClasspathReferences.keys(); + while (keys.hasMoreElements()) { + Object key = keys.nextElement(); + URLRecord urlRecord = (URLRecord) fClasspathReferences.get(key); + if (exportedOnly) { + if (urlRecord.isExported) { + references.put(key, urlRecord); + } + } + else { + references.put(key, urlRecord); + } + } + IProject[] buildpathProjects = (IProject[]) fClasspathProjects.toArray(new IProject[fClasspathProjects.size()]); + for (int i = 0; i < buildpathProjects.length; i++) { + if (!projectsProcessed.contains(buildpathProjects[i]) && buildpathProjects[i].isAccessible()) { + projectsProcessed.add(buildpathProjects[i]); + ProjectDescription description = TaglibIndex._instance.createDescription(buildpathProjects[i]); + description.addBuildPathReferences(references, projectsProcessed, true); + } + } + } + + /** * Erases all known tables */ void clear() { @@ -741,21 +796,44 @@ synchronized List getAvailableTaglibRecords(IPath path) { ensureUpTodate(); - Collection implicitReferences = getImplicitReferences(path.toString()).values(); + Collection implicitReferences = new HashSet(getImplicitReferences(path.toString()).values()); List records = new ArrayList(fTLDReferences.size() + fTagDirReferences.size() + fJARReferences.size() + fWebXMLReferences.size()); records.addAll(fTLDReferences.values()); records.addAll(fTagDirReferences.values()); records.addAll(_getJSP11AndWebXMLJarReferences(fJARReferences.values())); - records.addAll(fClasspathReferences.values()); records.addAll(implicitReferences); - ICatalog catalog = XMLCorePlugin.getDefault().getDefaultXMLCatalog(); - if (catalog != null) { - ICatalogEntry[] entries = catalog.getCatalogEntries(); - for (int i = 0; i < entries.length; i++) { - ITaglibRecord record = createCatalogRecord(entries[i].getURI()); + Map buildPathReferences = new HashMap(); + List projectsProcessed = new ArrayList(fClasspathProjects.size() + 1); + projectsProcessed.add(fProject); + addBuildPathReferences(buildPathReferences, projectsProcessed, false); + records.addAll(buildPathReferences.values()); + + ICatalog defaultCatalog = XMLCorePlugin.getDefault().getDefaultXMLCatalog(); + if (defaultCatalog != null) { + // Process default catalog + ICatalogEntry[] entries = defaultCatalog.getCatalogEntries(); + for (int entry = 0; entry < entries.length; entry++) { + ITaglibRecord record = createCatalogRecord(entries[entry].getURI()); records.add(record); } + + // Process declared OASIS nextCatalogs catalog + INextCatalog[] nextCatalogs = defaultCatalog.getNextCatalogs(); + for (int nextCatalog = 0; nextCatalog < nextCatalogs.length; nextCatalog++) { + ICatalog catalog = nextCatalogs[nextCatalog].getReferencedCatalog(); + ICatalogEntry[] entries2 = catalog.getCatalogEntries(); + for (int entry = 0; entry < entries2.length; entry++) { + String uri = entries2[entry].getURI(); + if (uri != null) { + uri = uri.toLowerCase(Locale.US); + if (uri.endsWith((".jar")) || uri.endsWith((".tld"))) { + ITaglibRecord record = createCatalogRecord(uri); + records.add(record); + } + } + } + } } return records; @@ -913,7 +991,14 @@ libPath = element.getPath().toString(); } if (libPath != null) { - updateClasspathLibrary(libPath, taglibRecordEventKind); + boolean fragmentisExported = true; + try { + fragmentisExported = ((IPackageFragmentRoot) element).getRawClasspathEntry().isExported(); + } + catch (JavaModelException e) { + Logger.logException("Problem handling build path entry for " + element.getPath(), e); //$NON-NLS-1$ + } + updateClasspathLibrary(libPath, taglibRecordEventKind, fragmentisExported); } if (_debugIndexTime) Logger.log(Logger.INFO, "processed build path delta for " + fProject.getName() + "(" + element.getPath() + ") in " + (System.currentTimeMillis() - time0) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ @@ -940,14 +1025,24 @@ } void indexClasspath() { - time0 = System.currentTimeMillis(); - fClasspathProjects = new Stack(); - + if (_debugIndexTime) + time0 = System.currentTimeMillis(); + fClasspathProjects.clear(); fClasspathReferences.clear(); fClasspathJars.clear(); IJavaProject javaProject = JavaCore.create(fProject); - indexClasspath(javaProject); + /* + * If the Java nature isn't present (or something else is wrong), + * don't check the build path. + */ + if (javaProject.exists()) { + indexClasspath(javaProject); + } + // else { + // Logger.log(Logger.WARNING, "TaglibIndex was asked to index non-Java + // Project " + fProject.getName()); //$NON-NLS-1$ + // } if (_debugIndexTime) Logger.log(Logger.INFO, "indexed " + fProject.getName() + " classpath in " + (System.currentTimeMillis() - time0) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ @@ -974,7 +1069,7 @@ IPath libPath = entry.getPath(); if (!fClasspathJars.containsKey(libPath.toString())) { if (libPath.toFile().exists()) { - updateClasspathLibrary(libPath.toString(), ITaglibRecordEvent.ADDED); + updateClasspathLibrary(libPath.toString(), ITaglibRecordEvent.ADDED, entry.isExported()); } else { /* @@ -985,7 +1080,7 @@ */ IFile libFile = ResourcesPlugin.getWorkspace().getRoot().getFile(libPath); if (libFile != null && libFile.exists()) { - updateClasspathLibrary(libFile.getLocation().toString(), ITaglibRecordEvent.ADDED); + updateClasspathLibrary(libFile.getLocation().toString(), ITaglibRecordEvent.ADDED, entry.isExported()); } } } @@ -994,14 +1089,12 @@ break; case IClasspathEntry.CPE_PROJECT : { /* - * Ignore required projects of required projects that are not - * exported + * We're currently ignoring whether the project exports all of + * its build path */ - if (fClasspathProjects.size() < 2 || entry.isExported()) { - IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(entry.getPath().lastSegment()); - if (project != null && !fClasspathProjects.contains(project.getName())) { - indexClasspath(JavaCore.create(project)); - } + IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(entry.getPath().lastSegment()); + if (project != null) { + fClasspathProjects.add(project); } } break; @@ -1027,8 +1120,11 @@ * @param javaProject */ private void indexClasspath(IJavaProject javaProject) { - if (javaProject != null && javaProject.exists() && !fClasspathProjects.contains(javaProject.getElementName())) { - fClasspathProjects.push(javaProject.getElementName()); + if (javaProject == null) + return; + + IProject project = javaProject.getProject(); + if (project.equals(fProject)) { try { IClasspathEntry[] entries = javaProject.getResolvedClasspath(true); for (int i = 0; i < entries.length; i++) { @@ -1038,7 +1134,6 @@ catch (JavaModelException e) { Logger.logException("Error searching Java Build Path + (" + fProject.getName() + ") for tag libraries", e); //$NON-NLS-1$ //$NON-NLS-2$ } - fClasspathProjects.pop(); } } @@ -1149,6 +1244,13 @@ if (record == null) { record = (ITaglibRecord) fClasspathReferences.get(reference); } + if (record == null) { + Map buildPathReferences = new HashMap(); + List projectsProcessed = new ArrayList(fClasspathProjects.size() + 1); + projectsProcessed.add(fProject); + addBuildPathReferences(buildPathReferences, projectsProcessed, false); + record = (ITaglibRecord) buildPathReferences.get(reference); + } // Check the XML Catalog if (record == null) { @@ -1199,7 +1301,7 @@ // resources first index(); // now build path - + // ================ test reload time ======================== boolean restored = false; File savedState = new File(fSaveStateFilename); @@ -1217,18 +1319,21 @@ String lineText = doc.get(line.getOffset(), line.getLength()); JarRecord libraryRecord = null; if (SAVE_FORMAT_VERSION.equals(lineText)) { + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + for (int i = 1; i < lines; i++) { line = doc.getLineInformation(i); lineText = doc.get(line.getOffset(), line.getLength()); - StringTokenizer toker = new StringTokenizer(lineText, "|"); + StringTokenizer toker = new StringTokenizer(lineText, "|"); //$NON-NLS-1$ if (toker.hasMoreTokens()) { String tokenType = toker.nextToken(); - if ("JAR".equalsIgnoreCase(tokenType)) { + if ("JAR".equalsIgnoreCase(tokenType)) { //$NON-NLS-1$ //$NON-NLS-2$ boolean has11TLD = Boolean.valueOf(toker.nextToken()).booleanValue(); + boolean exported = Boolean.valueOf(toker.nextToken()).booleanValue(); // make the rest the libraryLocation String libraryLocation = toker.nextToken(); while (toker.hasMoreTokens()) { - libraryLocation = libraryLocation + "|" + toker.nextToken(); + libraryLocation = libraryLocation + "|" + toker.nextToken(); //$NON-NLS-1$ //$NON-NLS-2$ } libraryLocation = libraryLocation.trim(); if (libraryRecord != null) { @@ -1237,6 +1342,7 @@ // Create a new JarRecord libraryRecord = createJARRecord(libraryLocation); libraryRecord.has11TLD = has11TLD; + libraryRecord.isExported = exported; // Add a URLRecord for the 1.1 TLD if (has11TLD) { @@ -1245,19 +1351,22 @@ TaglibInfo info = extractInfo(libraryLocation, contents); if (info != null && info.uri != null && info.uri.length() > 0) { - URLRecord record = new URLRecord(); - record.info = info; - record.baseLocation = libraryLocation; + URLRecord urlRecord = new URLRecord(); + urlRecord.info = info; + urlRecord.isExported = exported; + urlRecord.baseLocation = libraryLocation; try { - record.url = new URL("jar:file:" + libraryLocation + "!/" + JarUtilities.JSP11_TAGLIB); //$NON-NLS-1$ //$NON-NLS-2$ - libraryRecord.urlRecords.add(record); - fClasspathReferences.put(record.getURI(), record); + urlRecord.url = new URL("jar:file:" + libraryLocation + "!/" + JarUtilities.JSP11_TAGLIB); //$NON-NLS-1$ //$NON-NLS-2$ + libraryRecord.urlRecords.add(urlRecord); + fClasspathReferences.put(urlRecord.getURI(), urlRecord); if (_debugIndexCreation) - Logger.log(Logger.INFO, "created record for " + record.getURI() + "@" + record.getURL()); //$NON-NLS-1$ //$NON-NLS-2$ + Logger.log(Logger.INFO, "created record for " + urlRecord.getURI() + "@" + urlRecord.getURL()); //$NON-NLS-1$ //$NON-NLS-2$ } catch (MalformedURLException e) { - // don't record this - // URI + /* + * don't record this + * URI + */ Logger.logException(e); } } @@ -1271,16 +1380,18 @@ fClasspathJars.put(libraryLocation, libraryRecord); } - else if ("URL".equalsIgnoreCase(tokenType)) { + else if ("URL".equalsIgnoreCase(tokenType)) { //$NON-NLS-1$ + boolean exported = Boolean.valueOf(toker.nextToken()).booleanValue(); // make the rest the URL String urlString = toker.nextToken(); while (toker.hasMoreTokens()) { - urlString = urlString + "|" + toker.nextToken(); + urlString = urlString + "|" + toker.nextToken(); //$NON-NLS-1$ //$NON-NLS-2$ } urlString = urlString.trim(); // Append a URLrecord URLRecord urlRecord = new URLRecord(); urlRecord.url = new URL(urlString); //$NON-NLS-1$ //$NON-NLS-2$ + urlRecord.isExported = exported; urlRecord.baseLocation = libraryRecord.location.toString(); libraryRecord.urlRecords.add(urlRecord); @@ -1327,25 +1438,35 @@ } fClasspathReferences.put(urlRecord.getURI(), urlRecord); } + else if (BUILDPATH_PROJECT.equalsIgnoreCase(tokenType)) { + String projectName = toker.nextToken(); + if (Path.ROOT.isValidSegment(projectName)) { + IProject project = workspaceRoot.getProject(projectName); + /* do not check if "open" here */ + if (project != null) { + fClasspathProjects.add(project); + } + } + } // last since only occurs once else if (BUILDPATH_DIRTY.equalsIgnoreCase(tokenType)) { fBuildPathIsDirty = Boolean.valueOf(toker.nextToken()).booleanValue(); } } + if (libraryRecord != null) { + TaglibIndex.fireTaglibRecordEvent(new TaglibRecordEvent(libraryRecord, ITaglibRecordEvent.ADDED)); + } } - if (libraryRecord != null) { - TaglibIndex.fireTaglibRecordEvent(new TaglibRecordEvent(libraryRecord, ITaglibRecordEvent.ADDED)); - } + restored = true; } } - restored = true; if (_debugIndexTime) - Logger.log(Logger.INFO, "time spent reloading " + fProject.getName() + " build path: " + (System.currentTimeMillis() - time0)); + Logger.log(Logger.INFO, "time spent reloading " + fProject.getName() + " build path: " + (System.currentTimeMillis() - time0)); //$NON-NLS-1$ //$NON-NLS-2$ } catch (Exception e) { restored = false; if (_debugIndexTime) - Logger.log(Logger.INFO, "failure reloading " + fProject.getName() + " build path index", e); + Logger.log(Logger.INFO, "failure reloading " + fProject.getName() + " build path index", e); //$NON-NLS-1$ //$NON-NLS-2$ } finally { try { @@ -1377,34 +1498,46 @@ /** * <pre> - * 1.0 - * Save classpath information (| is field delimiter) - * Jars are saved as "JAR:"+ has11TLD + jar path - * URLRecords as "URL:"+URL + * 1.0.1 + * Save classpath information (| is field delimiter) + * Jars are saved as "JAR:"+ has11TLD + jar path + * URLRecords as "URL:"+URL * </pre> */ try { - writer = new OutputStreamWriter(new FileOutputStream(fSaveStateFilename), "utf8"); + writer = new OutputStreamWriter(new FileOutputStream(fSaveStateFilename), "utf16"); //$NON-NLS-1$ writer.write(SAVE_FORMAT_VERSION); - writer.write('\n'); - writer.write(BUILDPATH_DIRTY + "|" + fBuildPathIsDirty); - writer.write('\n'); + writer.write('\n'); //$NON-NLS-1$ + writer.write(BUILDPATH_DIRTY + "|" + fBuildPathIsDirty); //$NON-NLS-1$ + writer.write('\n'); //$NON-NLS-1$ + + IProject[] projects = (IProject[]) fClasspathProjects.toArray(new IProject[0]); + for (int i = 0; i < projects.length; i++) { + writer.write(BUILDPATH_PROJECT); + writer.write("|"); //$NON-NLS-1$ + writer.write(projects[i].getName()); + writer.write('\n'); //$NON-NLS-1$ + } Enumeration jars = fClasspathJars.keys(); while (jars.hasMoreElements()) { String jarPath = jars.nextElement().toString(); JarRecord jarRecord = (JarRecord) fClasspathJars.get(jarPath); - writer.write("JAR|"); + writer.write("JAR|"); //$NON-NLS-1$ writer.write(Boolean.toString(jarRecord.has11TLD)); - writer.write('|'); + writer.write('|'); //$NON-NLS-1$ + writer.write(Boolean.toString(jarRecord.isExported)); + writer.write('|'); //$NON-NLS-1$ writer.write(jarPath); - writer.write('\n'); + writer.write('\n'); //$NON-NLS-1$ Iterator i = jarRecord.urlRecords.iterator(); while (i.hasNext()) { - IURLRecord urlRecord = (IURLRecord) i.next(); - writer.write("URL|"); + URLRecord urlRecord = (URLRecord) i.next(); + writer.write("URL|"); //$NON-NLS-1$ + writer.write(String.valueOf(urlRecord.isExported)); + writer.write("|"); //$NON-NLS-1$ writer.write(urlRecord.getURL().toExternalForm()); - writer.write('\n'); + writer.write('\n'); //$NON-NLS-1$ } } } @@ -1421,14 +1554,14 @@ } if (_debugIndexTime) - Logger.log(Logger.INFO, "time spent saving index for " + fProject.getName() + ": " + (System.currentTimeMillis() - time0)); + Logger.log(Logger.INFO, "time spent saving index for " + fProject.getName() + ": " + (System.currentTimeMillis() - time0)); //$NON-NLS-1$ } - + void setBuildPathIsDirty() { fBuildPathIsDirty = true; } - void updateClasspathLibrary(String libraryLocation, int deltaKind) { + void updateClasspathLibrary(String libraryLocation, int deltaKind, boolean isExported) { JarRecord libraryRecord = null; if (deltaKind == ITaglibRecordEvent.REMOVED || deltaKind == ITaglibRecordEvent.CHANGED) { libraryRecord = (JarRecord) fClasspathJars.remove(libraryLocation); @@ -1443,6 +1576,7 @@ String[] entries = JarUtilities.getEntryNames(libraryLocation); libraryRecord = createJARRecord(libraryLocation); + libraryRecord.isExported = isExported; fClasspathJars.put(libraryLocation, libraryRecord); for (int i = 0; i < entries.length; i++) { if (entries[i].endsWith(".tld")) { //$NON-NLS-1$ @@ -1454,15 +1588,16 @@ TaglibInfo info = extractInfo(libraryLocation, contents); if (info != null && info.uri != null && info.uri.length() > 0) { - URLRecord record = new URLRecord(); - record.info = info; - record.baseLocation = libraryLocation; + URLRecord urlRecord = new URLRecord(); + urlRecord.info = info; + urlRecord.baseLocation = libraryLocation; try { - record.url = new URL("jar:file:" + libraryLocation + "!/" + entries[i]); //$NON-NLS-1$ //$NON-NLS-2$ - libraryRecord.urlRecords.add(record); - fClasspathReferences.put(record.getURI(), record); + urlRecord.isExported = isExported; + urlRecord.url = new URL("jar:file:" + libraryLocation + "!/" + entries[i]); //$NON-NLS-1$ //$NON-NLS-2$ + libraryRecord.urlRecords.add(urlRecord); + fClasspathReferences.put(urlRecord.getURI(), urlRecord); if (_debugIndexCreation) - Logger.log(Logger.INFO, "created record for " + record.getURI() + "@" + record.getURL()); //$NON-NLS-1$ //$NON-NLS-2$ + Logger.log(Logger.INFO, "created record for " + urlRecord.getURI() + "@" + urlRecord.getURL()); //$NON-NLS-1$ //$NON-NLS-2$ } catch (MalformedURLException e) { // don't record this URI
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/taglib/TaglibIndex.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/taglib/TaglibIndex.java index f7b257e..02e52b7 100644 --- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/taglib/TaglibIndex.java +++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/taglib/TaglibIndex.java
@@ -18,7 +18,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Stack; import java.util.zip.CRC32; import org.eclipse.core.filebuffers.FileBuffers; @@ -45,7 +44,6 @@ import org.eclipse.jst.jsp.core.internal.JSPCorePlugin; import org.eclipse.jst.jsp.core.internal.Logger; import org.eclipse.jst.jsp.core.internal.contentmodel.tld.TLDCMDocumentManager; -import org.eclipse.wst.sse.core.utils.StringUtils; import org.osgi.framework.Bundle; /** @@ -63,7 +61,6 @@ */ public final class TaglibIndex { class ClasspathChangeListener implements IElementChangedListener { - Stack classpathStack = new Stack(); List projectsIndexed = new ArrayList(1); public void elementChanged(ElementChangedEvent event) { @@ -71,16 +68,15 @@ return; try { LOCK.acquire(); - classpathStack.clear(); projectsIndexed.clear(); - elementChanged(event.getDelta()); + elementChanged(event.getDelta(), true); } finally { LOCK.release(); } } - private void elementChanged(IJavaElementDelta delta) { + private void elementChanged(IJavaElementDelta delta, boolean forceUpdate) { if (frameworkIsShuttingDown()) return; @@ -88,19 +84,25 @@ if (element.getElementType() == IJavaElement.JAVA_MODEL) { IJavaElementDelta[] changed = delta.getAffectedChildren(); for (int i = 0; i < changed.length; i++) { - elementChanged(changed[i]); + elementChanged(changed[i], forceUpdate); } } // Handle any changes at the project level else if (element.getElementType() == IJavaElement.JAVA_PROJECT) { if ((delta.getFlags() & IJavaElementDelta.F_CLASSPATH_CHANGED) != 0) { IJavaElement proj = element; - handleClasspathChange((IJavaProject) proj); + handleClasspathChange((IJavaProject) proj, forceUpdate); } else { IJavaElementDelta[] deltas = delta.getAffectedChildren(); - for (int i = 0; i < deltas.length; i++) { - elementChanged(deltas[i]); + if (deltas.length == 0) { + IJavaElement proj = element; + handleClasspathChange((IJavaProject) proj, forceUpdate); + } + else { + for (int i = 0; i < deltas.length; i++) { + elementChanged(deltas[i], false); + } } } } @@ -126,51 +128,39 @@ affectedDescription.handleElementChanged(delta); } } + projectsIndexed.add(affectedProject.getProject()); } } } - private void handleClasspathChange(IJavaProject project) { + private void handleClasspathChange(IJavaProject project, boolean forceUpdate) { if (frameworkIsShuttingDown()) return; - /* - * Loops in the build paths could cause us to pop more than we - * push - */ - if (classpathStack.contains(project.getElementName())) - return; - - classpathStack.push(project.getElementName()); try { /* Handle large changes to this project's build path */ IResource resource = project.getCorrespondingResource(); if (resource.getType() == IResource.PROJECT && !projectsIndexed.contains(resource)) { - ProjectDescription description = getDescription((IProject) resource); + /* + * Use get instead of create since the downstream + * (upstream?) project wasn't itself modified. + */ + ProjectDescription description = null; + if (forceUpdate) { + description = createDescription((IProject) resource); + } + else { + description = getDescription((IProject) resource); + } if (description != null && !frameworkIsShuttingDown()) { projectsIndexed.add(resource); description.setBuildPathIsDirty(); } } - /* - * Update indeces for projects who include this project in - * their build path (e.g. toggling the "exportation" of a - * taglib JAR in this project affects the JAR's visibility in - * other projects) - */ - IJavaProject[] projects = project.getJavaModel().getJavaProjects(); - for (int i = 0; i < projects.length; i++) { - IJavaProject otherProject = projects[i]; - if (StringUtils.contains(otherProject.getRequiredProjectNames(), project.getElementName(), false) && !classpathStack.contains(otherProject.getElementName()) && !frameworkIsShuttingDown()) { - handleClasspathChange(otherProject); - } - } } catch (JavaModelException e) { Logger.logException(e); } - classpathStack.pop(); - } } @@ -324,7 +314,8 @@ private static final String CLEAN = "CLEAN"; private static final String DIRTY = "DIRTY"; static boolean ENABLED = false; - static ILock LOCK = null; + + static ILock LOCK = Platform.getJobManager().newLock(); /** * NOT API. @@ -335,7 +326,8 @@ public static void addTaglibIndexListener(ITaglibIndexListener listener) { try { LOCK.acquire(); - _instance.internalAddTaglibIndexListener(listener); + if (_instance != null) + _instance.internalAddTaglibIndexListener(listener); } finally { LOCK.release(); @@ -352,14 +344,16 @@ */ TLDCMDocumentManager.getSharedDocumentCache().remove(TLDCMDocumentManager.getUniqueIdentifier(event.getTaglibRecord())); - ITaglibIndexListener[] listeners = _instance.fTaglibIndexListeners; - if (listeners != null) { - for (int i = 0; i < listeners.length; i++) { - try { - listeners[i].indexChanged(event); - } - catch (Exception e) { - Logger.log(Logger.WARNING, e.getMessage()); + if (_instance != null) { + ITaglibIndexListener[] listeners = _instance.fTaglibIndexListeners; + if (listeners != null) { + for (int i = 0; i < listeners.length; i++) { + try { + listeners[i].indexChanged(event); + } + catch (Exception e) { + Logger.log(Logger.WARNING, e.getMessage()); + } } } } @@ -378,8 +372,18 @@ * @return All of the visible ITaglibRecords from the given path. */ public static ITaglibRecord[] getAvailableTaglibRecords(IPath fullPath) { - ITaglibRecord[] records = _instance.internalGetAvailableTaglibRecords(fullPath); - return records; + try { + LOCK.acquire(); + ITaglibRecord[] records = null; + if (_instance != null) + records = _instance.internalGetAvailableTaglibRecords(fullPath); + else + records = new ITaglibRecord[0]; + return records; + } + finally { + LOCK.release(); + } } /** @@ -417,7 +421,8 @@ public static void removeTaglibIndexListener(ITaglibIndexListener listener) { try { LOCK.acquire(); - _instance.internalRemoveTaglibIndexListener(listener); + if (_instance != null) + _instance.internalRemoveTaglibIndexListener(listener); } finally { LOCK.release(); @@ -446,7 +451,8 @@ ITaglibRecord result = null; try { LOCK.acquire(); - result = _instance.internalResolve(basePath, reference, crossProjects); + if (_instance != null) + result = _instance.internalResolve(basePath, reference, crossProjects); } finally { LOCK.release(); @@ -526,10 +532,16 @@ * changes, and to forget all information about the workspace. */ public static synchronized void shutdown() { - if (_instance != null) { - _instance.stop(); + try { + LOCK.acquire(); + if (_instance != null) { + _instance.stop(); + } + _instance = null; } - _instance = null; + finally { + LOCK.release(); + } } /** @@ -537,8 +549,14 @@ * changes. */ public static synchronized void startup() { - ENABLED = !"false".equalsIgnoreCase(System.getProperty(TaglibIndex.class.getName())); //$NON-NLS-1$ - _instance = new TaglibIndex(); + try { + LOCK.acquire(); + ENABLED = !"false".equalsIgnoreCase(System.getProperty(TaglibIndex.class.getName())); //$NON-NLS-1$ + _instance = new TaglibIndex(); + } + finally { + LOCK.release(); + } } private ClasspathChangeListener fClasspathChangeListener = null; @@ -563,7 +581,6 @@ removeIndexes(false); } - LOCK = Platform.getJobManager().newLock(); fProjectDescriptions = new Hashtable(); fResourceChangeListener = new ResourceChangeListener(); fClasspathChangeListener = new ClasspathChangeListener(); @@ -656,20 +673,22 @@ ProjectDescription description = createDescription(project); List availableRecords = description.getAvailableTaglibRecords(path); -// ICatalog catalog = XMLCorePlugin.getDefault().getDefaultXMLCatalog(); -// while (catalog != null) { -// ICatalogEntry[] entries = catalog.getCatalogEntries(); -// for (int i = 0; i < entries.length; i++) { -// // System.out.println(entries[i].getURI()); -// } -// INextCatalog[] nextCatalogs = catalog.getNextCatalogs(); -// for (int i = 0; i < nextCatalogs.length; i++) { -// ICatalogEntry[] entries2 = nextCatalogs[i].getReferencedCatalog().getCatalogEntries(); -// for (int j = 0; j < entries2.length; j++) { -// // System.out.println(entries2[j].getURI()); -// } -// } -// } + // ICatalog catalog = + // XMLCorePlugin.getDefault().getDefaultXMLCatalog(); + // while (catalog != null) { + // ICatalogEntry[] entries = catalog.getCatalogEntries(); + // for (int i = 0; i < entries.length; i++) { + // // System.out.println(entries[i].getURI()); + // } + // INextCatalog[] nextCatalogs = catalog.getNextCatalogs(); + // for (int i = 0; i < nextCatalogs.length; i++) { + // ICatalogEntry[] entries2 = + // nextCatalogs[i].getReferencedCatalog().getCatalogEntries(); + // for (int j = 0; j < entries2.length; j++) { + // // System.out.println(entries2[j].getURI()); + // } + // } + // } records = (ITaglibRecord[]) availableRecords.toArray(records); }