[109721] JSP editor does not find taglib directives in include-prelude or jsp:include
diff --git a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contenttype/DeploymentDescriptorPropertyGroupCache.java b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contenttype/DeploymentDescriptorPropertyGroupCache.java
index da4ab99..f07906b 100644
--- a/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contenttype/DeploymentDescriptorPropertyGroupCache.java
+++ b/bundles/org.eclipse.jst.jsp.core/src/org/eclipse/jst/jsp/core/internal/contenttype/DeploymentDescriptorPropertyGroupCache.java
@@ -11,6 +11,9 @@
*******************************************************************************/
package org.eclipse.jst.jsp.core.internal.contenttype;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
@@ -18,6 +21,8 @@
import java.util.List;
import java.util.Map;
+import javax.xml.parsers.DocumentBuilder;
+
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
@@ -31,26 +36,32 @@
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jst.jsp.core.internal.Logger;
+import org.eclipse.jst.jsp.core.internal.util.CommonXML;
import org.eclipse.jst.jsp.core.taglib.TaglibIndex;
import org.eclipse.wst.sse.core.StructuredModelManager;
import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMDocument;
import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel;
+import org.w3c.dom.Document;
import org.w3c.dom.EntityReference;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
/**
* A cache fo property group information stored in web.xml files. Information
* is not persisted.
*/
public class DeploymentDescriptorPropertyGroupCache {
- private static class PropertyGroupContainer {
- long modificationStamp;
- PropertyGroup[] groups;
- }
-
- public static class PropertyGroup {
+ /**
+ * Represntation of the JSP 2.0 property-group definitions from a servlet
+ * deployment descriptor.
+ */
+ public static final class PropertyGroup {
static PropertyGroup createFrom(IPath path, Node propertyGroupNode) {
PropertyGroup group = new PropertyGroup(path);
Node propertyGroupID = propertyGroupNode.getAttributes().getNamedItem(ID);
@@ -61,6 +72,9 @@
while (node != null) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
String name = node.getLocalName();
+ if (name == null) {
+ name = node.getNodeName();
+ }
if (IS_XML.equals(name)) {
group.setIsXML(getContainedText(node));
}
@@ -90,20 +104,25 @@
return group;
}
+ private boolean el_ignored;
+
+ private String id;
+
+ private IPath[] include_coda = new IPath[0];
+
+ private IPath[] include_prelude = new IPath[0];
+ private boolean is_xml;
+ private StringMatcher matcher;
+ private String page_encoding;
+ private boolean scripting_invalid;
+ String url_pattern;
+ private IPath webxmlPath;
+
private PropertyGroup(IPath path) {
super();
this.webxmlPath = path;
}
- private void addPrelude(String containedText) {
- if (containedText.length() > 0) {
- IPath[] preludes = new IPath[include_prelude.length + 1];
- System.arraycopy(include_prelude, 0, preludes, 0, include_prelude.length);
- preludes[include_prelude.length] = webxmlPath.removeLastSegments(2).append(containedText);
- include_prelude = preludes;
- }
- }
-
private void addCoda(String containedText) {
if (containedText.length() > 0) {
IPath[] codas = new IPath[include_coda.length + 1];
@@ -113,17 +132,14 @@
}
}
- private boolean el_ignored;
- private String id;
- private IPath[] include_coda = new IPath[0];
- private IPath[] include_prelude = new IPath[0];
- private boolean is_xml;
- private String page_encoding;
- private boolean scripting_invalid;
- private StringMatcher matcher;
- private IPath webxmlPath;
-
- String url_pattern;
+ private void addPrelude(String containedText) {
+ if (containedText.length() > 0) {
+ IPath[] preludes = new IPath[include_prelude.length + 1];
+ System.arraycopy(include_prelude, 0, preludes, 0, include_prelude.length);
+ preludes[include_prelude.length] = webxmlPath.removeLastSegments(2).append(containedText);
+ include_prelude = preludes;
+ }
+ }
public String getId() {
return id;
@@ -191,6 +207,11 @@
}
}
+ private static class PropertyGroupContainer {
+ PropertyGroup[] groups;
+ long modificationStamp;
+ }
+
private static class ResourceChangeListener implements IResourceChangeListener {
public void resourceChanged(IResourceChangeEvent event) {
IResourceDelta delta = event.getDelta();
@@ -220,12 +241,32 @@
}
}
+ private static class ResourceErrorHandler implements ErrorHandler {
+ private IPath fPath;
+
+ public void error(SAXParseException exception) throws SAXException {
+ Logger.log(Logger.WARNING, "SAXParseException with " + fPath + " (error) while reading descriptor: " + exception.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ public void fatalError(SAXParseException exception) throws SAXException {
+ Logger.log(Logger.WARNING, "SAXParseException with " + fPath + " (fatalError) while reading descriptor: " + exception.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ public void setPath(IPath path) {
+ fPath = path;
+ }
+
+ public void warning(SAXParseException exception) throws SAXException {
+ Logger.log(Logger.WARNING, "SAXParseException with " + fPath + " (warning) while reading descriptor: " + exception.getMessage()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+
/**
* Copied from org.eclipse.core.internal.propertytester.StringMatcher, but
* should be replaced with a more accurate implementation of the rules in
* Servlet spec SRV.11.2
*/
- static class StringMatcher {
+ private static class StringMatcher {
private static final char SINGLE_WILD_CARD = '\u0000';
/**
@@ -520,10 +561,14 @@
ResourcesPlugin.getWorkspace().removeResourceChangeListener(getInstance().fResourceChangeListener);
}
+ private ResourceErrorHandler errorHandler;
+
private Map fPropertyGroupContainerReferences = new Hashtable();
private IResourceChangeListener fResourceChangeListener = new ResourceChangeListener();
+ private EntityResolver resolver;
+
private DeploymentDescriptorPropertyGroupCache() {
super();
}
@@ -535,76 +580,88 @@
}
/**
- * @param jspFilePath
- * @return a PropertyGroup containing the property group information
- * matching the given path or null
+ * parse the specified resource using Xerces, and if that fails, use the
+ * SSE XML parser to find the property groups.
*/
- public PropertyGroup getPropertyGroup(IPath jspFilePath) {
- IPath contextRoot = TaglibIndex.getContextRoot(jspFilePath);
- if (contextRoot == null)
- return null;
-
- IPath webxmlPath = contextRoot.append(WEB_INF_WEB_XML);
- Reference groupHolder = (Reference) fPropertyGroupContainerReferences.get(webxmlPath);
- PropertyGroupContainer groupContainer = null;
- IFile webxmlFile = ResourcesPlugin.getWorkspace().getRoot().getFile(webxmlPath);
-
- if (!webxmlFile.isAccessible())
- return null;
-
- if (groupHolder == null || ((groupContainer = (PropertyGroupContainer) groupHolder.get()) == null) || (groupContainer.modificationStamp == IResource.NULL_STAMP) || (groupContainer.modificationStamp != webxmlFile.getModificationStamp())) {
- groupContainer = fetchPropertyGroupContainer(webxmlPath, new NullProgressMonitor());
- }
-
- for (int i = 0; i < groupContainer.groups.length; i++) {
- if (groupContainer.groups[i].matches(jspFilePath.removeFirstSegments(contextRoot.segmentCount()).toString(), false)) {
- return groupContainer.groups[i];
- }
- }
- for (int i = 0; i < groupContainer.groups.length; i++) {
- if (groupContainer.groups[i].matches(jspFilePath.removeFirstSegments(contextRoot.segmentCount()).toString(), true)) {
- return groupContainer.groups[i];
- }
- }
- return null;
- }
-
- private PropertyGroupContainer fetchPropertyGroupContainer(IPath fullPath, IProgressMonitor monitor) {
+ private PropertyGroupContainer fetchPropertyGroupContainer(IFile file, IProgressMonitor monitor) {
monitor.beginTask("Reading Deployment Descriptor", 3);
PropertyGroup groups[] = null;
- IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(fullPath);
IStructuredModel model = null;
List groupList = new ArrayList();
SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, 2);
+ DocumentBuilder builder = CommonXML.getDocumentBuilder(false);
+ builder.setEntityResolver(getEntityResolver());
+ builder.setErrorHandler(getErrorHandler(file.getFullPath()));
+ InputStream is = null;
try {
- /**
- * Chiefly because the web.xml file itself is editable, use SSE to
- * get the DOM Document because it is more fault tolerant.
- */
- model = StructuredModelManager.getModelManager().getModelForRead(file);
- monitor.worked(1);
- if (model instanceof IDOMModel) {
- IDOMDocument document = ((IDOMModel) model).getDocument();
- NodeList propertyGroupElements = document.getElementsByTagName(JSP_PROPERTY_GROUP);
- int length = propertyGroupElements.getLength();
- subMonitor.beginTask("Reading Property Groups", length);
- for (int i = 0; i < length; i++) {
- PropertyGroup group = PropertyGroup.createFrom(fullPath, propertyGroupElements.item(i));
- subMonitor.worked(1);
- if (group != null) {
- groupList.add(group);
- }
+ InputSource inputSource = new InputSource();
+ is = file.getContents();
+ inputSource.setByteStream(is);
+ inputSource.setSystemId(file.getFullPath().toString());
+ Document document = builder.parse(inputSource);
+ NodeList propertyGroupElements = document.getElementsByTagName(JSP_PROPERTY_GROUP);
+ int length = propertyGroupElements.getLength();
+ subMonitor.beginTask("Reading Property Groups", length);
+ for (int i = 0; i < length; i++) {
+ PropertyGroup group = PropertyGroup.createFrom(file.getFullPath(), propertyGroupElements.item(i));
+ subMonitor.worked(1);
+ if (group != null) {
+ groupList.add(group);
}
}
}
- catch (Exception e) {
+ catch (SAXException e1) {
+ /* encountered a fatal parsing error, try our own parser */
+ try {
+ /**
+ * Chiefly because the web.xml file itself is editable, use
+ * SSE to get the DOM Document because it is more fault
+ * tolerant.
+ */
+ model = StructuredModelManager.getModelManager().getModelForRead(file);
+ monitor.worked(1);
+ if (model instanceof IDOMModel) {
+ IDOMDocument document = ((IDOMModel) model).getDocument();
+ NodeList propertyGroupElements = document.getElementsByTagName(JSP_PROPERTY_GROUP);
+ int length = propertyGroupElements.getLength();
+ subMonitor.beginTask("Reading Property Groups", length);
+ for (int i = 0; i < length; i++) {
+ PropertyGroup group = PropertyGroup.createFrom(file.getFullPath(), propertyGroupElements.item(i));
+ subMonitor.worked(1);
+ if (group != null) {
+ groupList.add(group);
+ }
+ }
+ }
+ }
+ catch (Exception e) {
+ Logger.logException(e);
+ }
+ finally {
+ if (model != null) {
+ model.releaseFromRead();
+ }
+ }
+ }
+ catch (IOException e1) {
+ /* file is unreadable, create no property groups */
+ }
+ catch (CoreException e) {
+ /*
+ * file is unreadable, create no property groups but log the
+ * exception
+ */
Logger.logException(e);
}
finally {
- if (model != null) {
- model.releaseFromRead();
- }
+ if (is != null)
+ try {
+ is.close();
+ }
+ catch (IOException e) {
+ // nothing to do
+ }
groups = (PropertyGroup[]) groupList.toArray(new PropertyGroup[groupList.size()]);
subMonitor.done();
}
@@ -612,14 +669,81 @@
if (groups == null) {
groups = new PropertyGroup[0];
}
+
PropertyGroupContainer propertyGroupContainer = new PropertyGroupContainer();
propertyGroupContainer.modificationStamp = file.getModificationStamp();
propertyGroupContainer.groups = groups;
monitor.done();
- fPropertyGroupContainerReferences.put(fullPath.makeAbsolute(), new SoftReference(propertyGroupContainer));
+ fPropertyGroupContainerReferences.put(file.getFullPath(), new SoftReference(propertyGroupContainer));
return propertyGroupContainer;
}
+ private EntityResolver getEntityResolver() {
+ if (resolver == null) {
+ resolver = new EntityResolver() {
+ public InputSource resolveEntity(String publicID, String systemID) throws SAXException, IOException {
+ InputSource result = new InputSource(new ByteArrayInputStream(new byte[0]));
+ result.setPublicId(publicID);
+ result.setSystemId(systemID != null ? systemID : "/_" + getClass().getName()); //$NON-NLS-1$
+ return result;
+ }
+ };
+ }
+ return resolver;
+ }
+
+ /**
+ * Returns an ErrorHandler that will not stop the parser on reported
+ * errors
+ */
+ private ErrorHandler getErrorHandler(IPath path) {
+ if (errorHandler == null) {
+ errorHandler = new ResourceErrorHandler();
+ }
+ errorHandler.setPath(path);
+ return errorHandler;
+ }
+
+ /**
+ * @param jspFilePath
+ * @return a PropertyGroup containing the property group information
+ * matching the file at the given path or null if no web.xml file
+ * exists or no matching property group was defined. A returned
+ * PropertyGroup object should be considered short-lived and not
+ * saved for later use.
+ */
+ public PropertyGroup getPropertyGroup(IPath jspFilePath) {
+ IPath contextRoot = TaglibIndex.getContextRoot(jspFilePath);
+ if (contextRoot == null)
+ return null;
+
+ IPath webxmlPath = contextRoot.append(WEB_INF_WEB_XML);
+ IFile webxmlFile = ResourcesPlugin.getWorkspace().getRoot().getFile(webxmlPath);
+ if (!webxmlFile.isAccessible())
+ return null;
+
+ PropertyGroup matchingGroup = null;
+
+ Reference groupHolder = (Reference) fPropertyGroupContainerReferences.get(webxmlPath);
+ PropertyGroupContainer groupContainer = null;
+
+ if (groupHolder == null || ((groupContainer = (PropertyGroupContainer) groupHolder.get()) == null) || (groupContainer.modificationStamp == IResource.NULL_STAMP) || (groupContainer.modificationStamp != webxmlFile.getModificationStamp())) {
+ groupContainer = fetchPropertyGroupContainer(webxmlFile, new NullProgressMonitor());
+ }
+
+ for (int i = 0; i < groupContainer.groups.length && matchingGroup == null; i++) {
+ if (groupContainer.groups[i].matches(jspFilePath.removeFirstSegments(contextRoot.segmentCount()).toString(), false)) {
+ matchingGroup = groupContainer.groups[i];
+ }
+ }
+ for (int i = 0; i < groupContainer.groups.length && matchingGroup == null; i++) {
+ if (groupContainer.groups[i].matches(jspFilePath.removeFirstSegments(contextRoot.segmentCount()).toString(), true)) {
+ matchingGroup = groupContainer.groups[i];
+ }
+ }
+ return matchingGroup;
+ }
+
private void updateCacheEntry(IPath fullPath) {
fPropertyGroupContainerReferences.remove(fullPath);
}