[243319] [validation] The XML Validator repeatedly tries to access inexistent remote resources
diff --git a/bundles/org.eclipse.wst.xml.core/META-INF/MANIFEST.MF b/bundles/org.eclipse.wst.xml.core/META-INF/MANIFEST.MF
index af632b8..ead58c4 100644
--- a/bundles/org.eclipse.wst.xml.core/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.wst.xml.core/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.wst.xml.core; singleton:=true
-Bundle-Version: 1.1.301.qualifier
+Bundle-Version: 1.1.302.qualifier
Bundle-Activator: org.eclipse.wst.xml.core.internal.XMLCorePlugin
Bundle-Vendor: %providerName
Bundle-Localization: plugin
diff --git a/bundles/org.eclipse.wst.xml.core/src-validation/org/eclipse/wst/xml/core/internal/validation/XMLNestedValidatorContext.java b/bundles/org.eclipse.wst.xml.core/src-validation/org/eclipse/wst/xml/core/internal/validation/XMLNestedValidatorContext.java
new file mode 100644
index 0000000..29c5e7e
--- /dev/null
+++ b/bundles/org.eclipse.wst.xml.core/src-validation/org/eclipse/wst/xml/core/internal/validation/XMLNestedValidatorContext.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2008 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.wst.xml.core.internal.validation;
+
+
+import java.util.HashSet;
+
+import org.eclipse.wst.xml.core.internal.validation.core.NestedValidatorContext;
+
+
+/**
+ * XMLNestedValidatorContext is used to store state data needed during an XML
+ * validation session.
+ */
+public class XMLNestedValidatorContext extends NestedValidatorContext
+{
+ /**
+ * A set of inaccessible locations URIs (String).
+ */
+ private HashSet inaccessibleLocationURIs = new HashSet();
+
+ /**
+ * Determines if a location URI was marked as inaccessible.
+ *
+ * @param locationURI
+ * the location URI to test. Must not be null.
+ * @return true if a location URI was marked as inaccessible, false otherwise.
+ */
+ public boolean isURIMarkedInaccessible(String locationURI)
+ {
+ return locationURI != null && inaccessibleLocationURIs.contains(locationURI);
+ }
+
+ /**
+ * Marks the given location URI as inaccessible.
+ *
+ * @param locationURI
+ * the location URI to mark as inaccessible. Must not be null.
+ */
+ public void markURIInaccessible(String locationURI)
+ {
+ if (locationURI != null)
+ {
+ inaccessibleLocationURIs.add(locationURI);
+ }
+ }
+}
diff --git a/bundles/org.eclipse.wst.xml.core/src-validation/org/eclipse/wst/xml/core/internal/validation/XMLValidator.java b/bundles/org.eclipse.wst.xml.core/src-validation/org/eclipse/wst/xml/core/internal/validation/XMLValidator.java
index 1a44faf..3b1f8dc 100644
--- a/bundles/org.eclipse.wst.xml.core/src-validation/org/eclipse/wst/xml/core/internal/validation/XMLValidator.java
+++ b/bundles/org.eclipse.wst.xml.core/src-validation/org/eclipse/wst/xml/core/internal/validation/XMLValidator.java
@@ -51,6 +51,7 @@
import org.eclipse.wst.validation.ValidationResult;
import org.eclipse.wst.xml.core.internal.Logger;
import org.eclipse.wst.xml.core.internal.validation.core.LazyURLInputStream;
+import org.eclipse.wst.xml.core.internal.validation.core.NestedValidatorContext;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
@@ -275,6 +276,27 @@
*/
public XMLValidationReport validate(String uri, InputStream inputStream, XMLValidationConfiguration configuration, ValidationResult result)
{
+ return validate(uri, inputStream, configuration, null, null);
+ }
+
+ /**
+ * Validate the inputStream
+ *
+ * @param uri
+ * The URI of the file to validate.
+ * @param inputstream
+ * The inputStream of the file to validate
+ * @param configuration
+ * A configuration for this validation session.
+ * @param result
+ * The validation result
+ * @param context
+ * The validation context
+ * @return
+ * Returns an XML validation report.
+ */
+ public XMLValidationReport validate(String uri, InputStream inputStream, XMLValidationConfiguration configuration, ValidationResult result, NestedValidatorContext context)
+ {
String grammarFile = "";
Reader reader1 = null; // Used for the preparse.
Reader reader2 = null; // Used for validation parse.
@@ -287,7 +309,7 @@
}
XMLValidationInfo valinfo = new XMLValidationInfo(uri);
- MyEntityResolver entityResolver = new MyEntityResolver(uriResolver);
+ MyEntityResolver entityResolver = new MyEntityResolver(uriResolver, context);
ValidatorHelper helper = new ValidatorHelper();
try
{
@@ -419,15 +441,18 @@
{
private URIResolver uriResolver;
private String resolvedDTDLocation;
+ private NestedValidatorContext context;
/**
* Constructor.
*
* @param uriResolver The URI resolver to use with this entity resolver.
+ * @param context The XML validator context.
*/
- public MyEntityResolver(URIResolver uriResolver)
+ public MyEntityResolver(URIResolver uriResolver, NestedValidatorContext context)
{
this.uriResolver = uriResolver;
+ this.context = context;
}
/* (non-Javadoc)
@@ -435,20 +460,12 @@
*/
public XMLInputSource resolveEntity(XMLResourceIdentifier rid) throws XNIException, IOException
{
- try
- {
- XMLInputSource inputSource = _internalResolveEntity(uriResolver, rid);
+ XMLInputSource inputSource = _internalResolveEntity(uriResolver, rid, context);
if (inputSource != null)
{
resolvedDTDLocation = inputSource.getSystemId();
}
return inputSource;
- }
- catch(IOException e)
- {
- //e.printStackTrace();
- }
- return null;
}
public String getLocation()
@@ -462,6 +479,11 @@
// identical code. In any case we should strive to ensure that the validators perform resolution consistently.
public static XMLInputSource _internalResolveEntity(URIResolver uriResolver, XMLResourceIdentifier rid) throws IOException
{
+ return _internalResolveEntity(uriResolver, rid, null);
+ }
+
+ public static XMLInputSource _internalResolveEntity(URIResolver uriResolver, XMLResourceIdentifier rid, NestedValidatorContext context) throws IOException
+ {
XMLInputSource is = null;
if (uriResolver != null)
@@ -481,6 +503,18 @@
if (location != null)
{
String physical = uriResolver.resolvePhysicalLocation(rid.getBaseSystemId(), id, location);
+
+ // if physical is already a known bad uri, just go ahead and throw an exception
+ if (context instanceof XMLNestedValidatorContext)
+ {
+ XMLNestedValidatorContext xmlContext = ((XMLNestedValidatorContext)context);
+
+ if (xmlContext.isURIMarkedInaccessible(physical))
+ {
+ throw new FileNotFoundException(physical);
+ }
+ }
+
is = new XMLInputSource(rid.getPublicId(), location, location);
// This block checks that the file exists. If it doesn't we need to throw
@@ -492,6 +526,16 @@
{
isTemp = new URL(physical).openStream();
}
+ catch (IOException e)
+ {
+ // physical was a bad url, so cache it so we know next time
+ if (context instanceof XMLNestedValidatorContext)
+ {
+ XMLNestedValidatorContext xmlContext = ((XMLNestedValidatorContext)context);
+ xmlContext.markURIInaccessible(physical);
+ }
+ throw e;
+ }
finally
{
if(isTemp != null)
diff --git a/bundles/org.eclipse.wst.xml.core/src-validation/org/eclipse/wst/xml/core/internal/validation/core/AbstractNestedValidator.java b/bundles/org.eclipse.wst.xml.core/src-validation/org/eclipse/wst/xml/core/internal/validation/core/AbstractNestedValidator.java
index 9a48579..5e2dfa4 100644
--- a/bundles/org.eclipse.wst.xml.core/src-validation/org/eclipse/wst/xml/core/internal/validation/core/AbstractNestedValidator.java
+++ b/bundles/org.eclipse.wst.xml.core/src-validation/org/eclipse/wst/xml/core/internal/validation/core/AbstractNestedValidator.java
@@ -64,12 +64,25 @@
public ValidationResult validate(IResource resource, int kind, ValidationState state, IProgressMonitor monitor){
ValidationResult result = new ValidationResult();
IReporter reporter = result.getReporter(monitor);
- NestedValidatorContext nestedcontext = new NestedValidatorContext();
- setupValidation(nestedcontext);
IFile file = null;
if (resource instanceof IFile)file = (IFile)resource;
- if (file != null)validate(file, null, result, reporter, nestedcontext);
- teardownValidation(nestedcontext);
+ if (file != null)
+ {
+ NestedValidatorContext nestedcontext = getNestedContext(state, false);
+ boolean teardownRequired = false;
+ if (nestedcontext == null)
+ {
+ // validationstart was not called, so manually setup and tear down
+ nestedcontext = getNestedContext(state, true);
+ setupValidation(nestedcontext);
+ teardownRequired = true;
+ }
+
+ validate(file, null, result, reporter, nestedcontext);
+
+ if (teardownRequired)
+ teardownValidation(nestedcontext);
+ }
return result;
}
@@ -421,9 +434,28 @@
*/
protected void addInfoToMessage (ValidationMessage validationmessage, IMessage message)
{
- // This method may be overidden by subclasses
+ // This method may be overridden by subclasses
}
-
+
+ /**
+ * Get the nested validation context.
+ *
+ * @param state
+ * the validation state.
+ * @param create
+ * when true, a new context will be created if one is not found
+ * @return the nested validation context.
+ */
+ protected NestedValidatorContext getNestedContext(ValidationState state, boolean create)
+ {
+ NestedValidatorContext context = null;
+ if (create)
+ {
+ context = new NestedValidatorContext();
+ }
+ return context;
+ }
+
/**
* A localized message is a specialized type of IMessage that allows setting
* and using a localized message string for a message.
diff --git a/bundles/org.eclipse.wst.xml.core/src-validation/org/eclipse/wst/xml/core/internal/validation/eclipse/Validator.java b/bundles/org.eclipse.wst.xml.core/src-validation/org/eclipse/wst/xml/core/internal/validation/eclipse/Validator.java
index 79acb37..4deafa1 100644
--- a/bundles/org.eclipse.wst.xml.core/src-validation/org/eclipse/wst/xml/core/internal/validation/eclipse/Validator.java
+++ b/bundles/org.eclipse.wst.xml.core/src-validation/org/eclipse/wst/xml/core/internal/validation/eclipse/Validator.java
@@ -13,10 +13,14 @@
import java.io.InputStream;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.wst.validation.ValidationResult;
+import org.eclipse.wst.validation.ValidationState;
import org.eclipse.wst.validation.internal.provisional.core.IMessage;
import org.eclipse.wst.xml.core.internal.XMLCorePlugin;
import org.eclipse.wst.xml.core.internal.preferences.XMLCorePreferenceNames;
+import org.eclipse.wst.xml.core.internal.validation.XMLNestedValidatorContext;
import org.eclipse.wst.xml.core.internal.validation.XMLValidationConfiguration;
import org.eclipse.wst.xml.core.internal.validation.XMLValidationReport;
import org.eclipse.wst.xml.core.internal.validation.core.AbstractNestedValidator;
@@ -26,6 +30,7 @@
public class Validator extends AbstractNestedValidator
{
+ private static final String XML_VALIDATOR_CONTEXT = "org.eclipse.wst.xml.core.validatorContext"; //$NON-NLS-1$
protected int indicateNoGrammar = 0;
/**
@@ -64,11 +69,11 @@
XMLValidationReport valreport = null;
if (inputstream != null)
{
- valreport = validator.validate(uri, inputstream, configuration, result);
+ valreport = validator.validate(uri, inputstream, configuration, result, context);
}
else
{
- valreport = validator.validate(uri, null, configuration, result);
+ valreport = validator.validate(uri, null, configuration, result, context);
}
return valreport;
@@ -96,4 +101,55 @@
message.setAttribute(SQUIGGLE_NAME_OR_VALUE_ATTRIBUTE, messageInfo[1]);
}
}
+
+ /**
+ * Get the nested validation context.
+ *
+ * @param state
+ * the validation state.
+ * @param create
+ * when true, a new context will be created if one is not found
+ * @return the nested validation context.
+ */
+ protected NestedValidatorContext getNestedContext(ValidationState state, boolean create)
+ {
+ NestedValidatorContext context = null;
+ Object o = state.get(XML_VALIDATOR_CONTEXT);
+ if (o instanceof XMLNestedValidatorContext)
+ context = (XMLNestedValidatorContext)o;
+ else if (create)
+ {
+ context = new XMLNestedValidatorContext();
+ }
+ return context;
+ }
+
+ public void validationStarting(IProject project, ValidationState state, IProgressMonitor monitor)
+ {
+ if (project != null)
+ {
+ NestedValidatorContext context = getNestedContext(state, false);
+ if (context == null)
+ {
+ context = getNestedContext(state, true);
+ setupValidation(context);
+ state.put(XML_VALIDATOR_CONTEXT, context);
+ }
+ super.validationStarting(project, state, monitor);
+ }
+ }
+
+ public void validationFinishing(IProject project, ValidationState state, IProgressMonitor monitor)
+ {
+ if (project != null)
+ {
+ super.validationFinishing(project, state, monitor);
+ NestedValidatorContext context = getNestedContext(state, false);
+ if (context != null)
+ {
+ teardownValidation(context);
+ state.put(XML_VALIDATOR_CONTEXT, null);
+ }
+ }
+ }
}