Author: vrubezhny
Date: 2011-09-23 08:12:37 -0400 (Fri, 23 Sep 2011)
New Revision: 34995
Added:
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/XHTMLValidator.java
Removed:
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/XHTMLSyntaxValidator.java
Modified:
trunk/jsf/plugins/org.jboss.tools.jsf/META-INF/MANIFEST.MF
trunk/jsf/plugins/org.jboss.tools.jsf/plugin.properties
trunk/jsf/plugins/org.jboss.tools.jsf/plugin.xml
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/JSFValidationMessage.java
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/messages.properties
Log:
JBIDE-9588
Poor performance of XHTML template validation
XHTML Syntax Validator is re-factored
Modified: trunk/jsf/plugins/org.jboss.tools.jsf/META-INF/MANIFEST.MF
===================================================================
--- trunk/jsf/plugins/org.jboss.tools.jsf/META-INF/MANIFEST.MF 2011-09-23 11:38:13 UTC
(rev 34994)
+++ trunk/jsf/plugins/org.jboss.tools.jsf/META-INF/MANIFEST.MF 2011-09-23 12:12:37 UTC
(rev 34995)
@@ -64,9 +64,9 @@
org.eclipse.wst.sse.ui;bundle-version="1.3.0",
org.eclipse.ltk.ui.refactoring;bundle-version="3.5.100",
org.eclipse.core.expressions;bundle-version="3.4.200",
- org.jboss.tools.common.text.ext;bundle-version="3.1.0",
+ org.jboss.tools.common.text.ext,
org.eclipse.jst.jsp.ui;bundle-version="1.1.600";visibility:=reexport,
- org.jboss.tools.jst.jsp;bundle-version="3.2.0",
+ org.jboss.tools.jst.jsp,
org.jboss.tools.common.validation
Bundle-Version: 3.3.0.qualifier
Bundle-ActivationPolicy: lazy
Modified: trunk/jsf/plugins/org.jboss.tools.jsf/plugin.properties
===================================================================
--- trunk/jsf/plugins/org.jboss.tools.jsf/plugin.properties 2011-09-23 11:38:13 UTC (rev
34994)
+++ trunk/jsf/plugins/org.jboss.tools.jsf/plugin.properties 2011-09-23 12:12:37 UTC (rev
34995)
@@ -20,4 +20,6 @@
JSFELValidationDelegate=JSF EL Validator
ComponentCompositeProblemName=JSF Composite Component Problem
-ComponentCompositeValidator=JSF Composite Component Validator
\ No newline at end of file
+ComponentCompositeValidator=JSF Composite Component Validator
+
+XHTMLSyntaxProblemName=XHTML Problem
\ No newline at end of file
Modified: trunk/jsf/plugins/org.jboss.tools.jsf/plugin.xml
===================================================================
--- trunk/jsf/plugins/org.jboss.tools.jsf/plugin.xml 2011-09-23 11:38:13 UTC (rev 34994)
+++ trunk/jsf/plugins/org.jboss.tools.jsf/plugin.xml 2011-09-23 12:12:37 UTC (rev 34995)
@@ -391,16 +391,15 @@
</listener>
</extension>
-<!-- TODO
https://issues.jboss.org/browse/JBIDE-9588
<extension id="xhtml" name="%XHTML_Validator.name"
point="org.eclipse.wst.validation.validatorV2">
<validator
build="true"
- class="org.jboss.tools.jsf.web.validation.XHTMLSyntaxValidator"
+ class="org.jboss.tools.jsf.web.validation.XHTMLValidator"
manual="true"
sourceid="org.eclipse.wst.xml.ui.internal.validation.DelegatingSourceValidatorForXML"
version="3"
- markerId="org.eclipse.wst.xml.core.validationMarker"
+ markerId="org.jboss.tools.jsf.xhtmlsyntaxproblem"
<include>
<rules>
@@ -421,7 +420,7 @@
</rules>
</include>
</validator>
- </extension -->
+ </extension>
<extension point="org.eclipse.wst.xml.core.catalogContributions">
<catalogContribution id="default">
@@ -499,6 +498,13 @@
</persistent>
</extension>
+ <extension id="xhtmlsyntaxproblem"
name="%XHTMLSyntaxProblemName"
point="org.eclipse.core.resources.markers">
+ <super type="org.eclipse.wst.xml.core.validationMarker">
+ </super>
+ <persistent value="true">
+ </persistent>
+ </extension>
+
<extension
id="CompositeComponentValidator"
point="org.jboss.tools.common.validation.validator">
Modified:
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/JSFValidationMessage.java
===================================================================
---
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/JSFValidationMessage.java 2011-09-23
11:38:13 UTC (rev 34994)
+++
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/JSFValidationMessage.java 2011-09-23
12:12:37 UTC (rev 34995)
@@ -14,8 +14,10 @@
public static String VALIDATING_PROJECT;
public static String XHTML_VALIDATION;
-
+ public static String XHTML_VALIDATION_NO_START_TAG;
+ public static String XHTML_VALIDATION_NO_END_TAG;
+
static {
NLS.initializeMessages(BUNDLE_NAME, JSFValidationMessage.class);
}
-}
\ No newline at end of file
+}
Deleted:
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/XHTMLSyntaxValidator.java
===================================================================
---
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/XHTMLSyntaxValidator.java 2011-09-23
11:38:13 UTC (rev 34994)
+++
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/XHTMLSyntaxValidator.java 2011-09-23
12:12:37 UTC (rev 34995)
@@ -1,304 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2009 Red Hat, Inc.
- * Distributed under license by Red Hat, Inc. All rights reserved.
- * This program is 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:
- * Red Hat, Inc. - initial API and implementation
- ******************************************************************************/
-
-package org.jboss.tools.jsf.web.validation;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.StringReader;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.wst.common.uriresolver.internal.provisional.URIResolverPlugin;
-import org.eclipse.wst.validation.ValidationResult;
-import org.eclipse.wst.validation.ValidationState;
-import org.eclipse.wst.xml.core.internal.validation.ValidatorHelper;
-import org.eclipse.wst.xml.core.internal.validation.XMLValidationConfiguration;
-import org.eclipse.wst.xml.core.internal.validation.XMLValidationInfo;
-import org.eclipse.wst.xml.core.internal.validation.XMLValidationReport;
-import org.eclipse.wst.xml.core.internal.validation.core.NestedValidatorContext;
-import org.eclipse.wst.xml.core.internal.validation.core.ValidationReport;
-import
org.eclipse.wst.xml.core.internal.validation.eclipse.ErrorCustomizationPluginRegistryReader;
-import org.eclipse.wst.xml.core.internal.validation.eclipse.Validator;
-import org.jboss.tools.jsf.JSFModelPlugin;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXNotRecognizedException;
-import org.xml.sax.SAXNotSupportedException;
-import org.xml.sax.SAXParseException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.ext.LexicalHandler;
-
-/**
- * Syntax Validator for XHTML files.
- * @author Victor Rubezhny
- */
-public class XHTMLSyntaxValidator extends Validator {
-
- IProgressMonitor monitor;
-
- /*
- * (non-Javadoc)
- * @see
org.eclipse.wst.xml.core.internal.validation.eclipse.Validator#validationStarting(org.eclipse.core.resources.IProject,
org.eclipse.wst.validation.ValidationState, org.eclipse.core.runtime.IProgressMonitor)
- */
- @Override
- public void validationStarting(IProject project, ValidationState state, IProgressMonitor
monitor) {
- super.validationStarting(project, state, monitor);
- this.monitor = monitor;
- }
-
- /*
- * (non-Javadoc)
- * @see
org.eclipse.wst.xml.core.internal.validation.core.AbstractNestedValidator#validate(org.eclipse.core.resources.IResource,
int, org.eclipse.wst.validation.ValidationState,
org.eclipse.core.runtime.IProgressMonitor)
- */
- @Override
- public ValidationResult validate(IResource resource, int kind, ValidationState state,
IProgressMonitor monitor) {
- displaySubtask(monitor, JSFValidationMessage.XHTML_VALIDATION,
resource.getFullPath());
- return super.validate(resource, kind, state, monitor);
- }
-
- private void displaySubtask(String message, Object... arguments) {
- displaySubtask(monitor, MessageFormat.format(message, arguments));
- }
-
- private void displaySubtask(IProgressMonitor monitor, String message, Object...
arguments) {
- if(monitor!=null) {
- monitor.subTask(MessageFormat.format(message, arguments));
- }
- }
-
- /**
- * The method is overridden to setup our own XMLValidator to be used
- */
- @Override
- public ValidationReport validate(String uri, InputStream inputstream,
- NestedValidatorContext context, ValidationResult result) {
-
- displaySubtask(JSFValidationMessage.XHTML_VALIDATION, uri);
-
- long ct = 0;
- if (JSFModelPlugin.getDefault().isDebugging()) {
- ct = System.currentTimeMillis();
- }
-
- XMLValidator validator = XMLValidator.getInstance();
-
- XMLValidationConfiguration configuration = new XMLValidationConfiguration();
- try {
- configuration.setFeature(XMLValidationConfiguration.INDICATE_NO_GRAMMAR, 0); // None.
No grammar indication is needed
- } catch (Exception e) {
- // Unable to set the preference. Log this problem.
- JSFModelPlugin.log("XHTMLSyntaxValidator was unable to set the preference",
e);
- }
-
- XMLValidationReport valreport = validator.validate(uri, inputstream,
configuration, context, result);
-
- if (JSFModelPlugin.getDefault().isDebugging()) {
- long et = System.currentTimeMillis() - ct;
- System.out.println("XHTMLSyntaxValidator: Elapsed time = " + (et) + "
ms for " + uri);
- }
- return valreport;
- }
-
- /**
- * An XML validator specific to XHTML-files validation. This validator will wrap the
internal
- * XML syntax validator.
- */
- public static class XMLValidator extends
org.eclipse.wst.xml.core.internal.validation.XMLValidator {
- private static XMLValidator instance = null;
-
- /**
- * Return the one and only instance of the XML validator. The validator
- * can be reused and cannot be customized so there should only be one instance of
it.
- *
- * @return The one and only instance of the XML validator.
- */
- public static XMLValidator getInstance() {
- if(instance == null) {
- instance = new XMLValidator();
- }
- return instance;
- }
-
- /**
- * Constructor. Create the XML validator, set the URI resolver and
- * get the extension error customizers from the registry.
- */
- protected XMLValidator() {
- setURIResolver(URIResolverPlugin.createResolver());
- new ErrorCustomizationPluginRegistryReader().readRegistry();
- }
-
- /**
- * 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
- * @return
- * Returns an XML validation report.
- */
- public XMLValidationReport validate(String uri, InputStream inputStream,
- XMLValidationConfiguration configuration, NestedValidatorContext context,
ValidationResult result) {
- String grammarFile = "";
- Reader reader1 = null; // Used for the preparse.
- Reader reader2 = null; // Used for validation parse.
-
- if (inputStream != null) {
- String string = createStringForInputStream(inputStream);
- reader1 = new StringReader(string);
- reader2 = new StringReader(string);
- }
-
- XMLValidationInfo valinfo = new XMLValidationInfo(uri);
- XHTMLEntityResolver entityResolver = new XHTMLEntityResolver(uriResolver,
context);
- XHTMLValidatorHelper helper = new XHTMLValidatorHelper(entityResolver);
-
- try {
- helper.computeValidationInformation(uri, reader1, uriResolver);
-
- // The syntax validation is to be performed
- valinfo.setDTDEncountered(false);
- valinfo.setElementDeclarationCount(0);
- valinfo.setNamespaceEncountered(false);
- valinfo.setGrammarEncountered(false);
-
- // No validation needed for native HTML files
- // The only XHTML files are to be validated here
- if (!helper.isXHTMLDoctype) {
- return valinfo;
- }
-
- XMLReader reader = createXMLReader(valinfo, entityResolver);
- XMLErrorHandler errorhandler = new XMLErrorHandler(valinfo);
- reader.setErrorHandler(errorhandler);
-
- InputSource inputSource = new InputSource(uri);
- inputSource.setCharacterStream(reader2);
- reader.parse(inputSource);
- } catch (SAXParseException saxParseException) {
- // These errors are caught by the error handler.
- //addValidationMessage(valinfo, saxParseException);
- } catch (IOException ioException) {
- addValidationMessage(valinfo, ioException);
- } catch (Exception exception) {
- JSFModelPlugin.log(exception.getLocalizedMessage(), exception);
- }
-
- // Now set up the dependencies
- // Wrap with try catch so that if something wrong happens, validation can
- // still proceed as before
- if (result != null) {
- try {
- IResource resource = getWorkspaceFileFromLocation(grammarFile);
- ArrayList resources = new ArrayList();
- if (resource != null)
- resources.add(resource);
- result.setDependsOn((IResource [])resources.toArray(new IResource [0]));
- } catch (Exception e) {
- JSFModelPlugin.log(e.getLocalizedMessage(), e);
- }
- }
- return valinfo;
- }
-
- final String createStringForInputStream(InputStream inputStream) {
- // Here we are reading the file and storing to a stringbuffer.
- StringBuilder fileString = new StringBuilder();
- try {
- InputStreamReader inputReader = new InputStreamReader(inputStream,
"UTF-8");
- BufferedReader reader = new BufferedReader(inputReader);
- char[] chars = new char[1024];
- int numberRead = reader.read(chars);
- while (numberRead != -1) {
- fileString.append(chars, 0, numberRead);
- numberRead = reader.read(chars);
- }
- } catch (Exception e) {
- JSFModelPlugin.log(e.getLocalizedMessage(), e);
- }
- return fileString.toString();
- }
-
- /*
- * Custom validation helper to be used
- */
- class XHTMLValidatorHelper extends ValidatorHelper {
- public boolean isXHTMLDoctype = false;
- private XHTMLEntityResolver entityResolver;
-
- public XHTMLValidatorHelper(XHTMLEntityResolver entityResolver) {
- this.entityResolver = entityResolver;
- }
-
- protected XMLReader createXMLReader(String uri) throws SAXNotRecognizedException,
SAXNotSupportedException
- {
- XMLReader reader = super.createXMLReader(uri);
-
-
reader.setFeature("http://xml.org/sax/features/namespaces", false);
-
reader.setFeature("http://xml.org/sax/features/namespace-prefixes",
false);
-
reader.setFeature("http://xml.org/sax/features/validation", false);
-
reader.setFeature("http://apache.org/xml/features/validation/schema&...;,
false);
-
reader.setFeature("http://apache.org/xml/features/validation/schema-...;,
false);
-
reader.setFeature("http://apache.org/xml/features/validation/dynamic...;,
false);
-
reader.setFeature("http://apache.org/xml/features/continue-after-fat...;,
false);
-
reader.setFeature("http://apache.org/xml/features/nonvalidating/load...;,
false);
-//
reader.setFeature("http://apache.org/xml/features/resolve-dtd-uris",
false);
-
- LexicalHandler lexicalHandler = new LexicalHandler()
- {
- public void startDTD (String name, String publicId, String systemId) {
- isGrammarEncountered = true;
- isDTDEncountered = true;
- if (publicId != null && publicId.indexOf("W3C") != -1
&&
- publicId.indexOf("DTD") != -1 &&
publicId.indexOf("XHTML") != -1) {
- isXHTMLDoctype = true;
- }
- }
-
- public void endDTD() throws SAXException {
- }
-
- public void startEntity(String name) throws SAXException {
- }
-
- public void endEntity(String name) throws SAXException {
- }
-
- public void startCDATA() throws SAXException {
- }
-
- public void endCDATA() throws SAXException {
- }
-
- public void comment (char ch[], int start, int length) throws SAXException {
- }
- };
-
reader.setProperty("http://xml.org/sax/properties/lexical-handler",
lexicalHandler); //$NON-NLS-1$
- if (entityResolver != null) {
-
reader.setProperty("http://apache.org/xml/properties/internal/entity...;,
entityResolver); //$NON-NLS-1$
- }
- return reader;
- }
- }
- }
-}
\ No newline at end of file
Added:
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/XHTMLValidator.java
===================================================================
---
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/XHTMLValidator.java
(rev 0)
+++
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/XHTMLValidator.java 2011-09-23
12:12:37 UTC (rev 34995)
@@ -0,0 +1,475 @@
+/*******************************************************************************
+ * Copyright (c) 2009-2011 Red Hat, Inc.
+ * Distributed under license by Red Hat, Inc. All rights reserved.
+ * This program is 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:
+ * Red Hat, Inc. - initial API and implementation
+ ******************************************************************************/
+package org.jboss.tools.jsf.web.validation;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.Document;
+import org.eclipse.jface.text.IDocument;
+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.validation.XMLValidationInfo;
+import org.eclipse.wst.xml.core.internal.validation.core.NestedValidatorContext;
+import org.eclipse.wst.xml.core.internal.validation.core.ValidationMessage;
+import org.eclipse.wst.xml.core.internal.validation.core.ValidationReport;
+import org.eclipse.wst.xml.core.internal.validation.eclipse.Validator;
+import org.jboss.tools.common.util.FileUtil;
+import org.jboss.tools.jsf.JSFModelPlugin;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.ext.LexicalHandler;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ *
+ * @author Victor V. Rubezhny
+ *
+ */
+@SuppressWarnings("restriction")
+public class XHTMLValidator extends Validator {
+ private static final String END_TAG_STRATEGY = "END_TAG";
+ private static final String START_TAG_STRATEGY = "START_TAG";
+ private static final String NO_START_TAG = "NO_START_TAG";
+ private static final String NO_END_TAG = "NO_END_TAG";
+
+ IProgressMonitor monitor;
+ IResource resource;
+
+ public boolean isXHTMLDoctype = false;
+
+ private String[] SAX_PARSER_FEATURES_TO_DISABLE = {
+ "http://xml.org/sax/features/namespaces",
+ "http://xml.org/sax/features/use-entity-resolver2",
+ "http://xml.org/sax/features/validation",
+ "http://apache.org/xml/features/validation/dynamic",
+ "http://apache.org/xml/features/validation/schema",
+ "http://apache.org/xml/features/validation/schema-full-checking",
+ "http://apache.org/xml/features/nonvalidating/load-external-dtd",
+ "http://apache.org/xml/features/nonvalidating/load-dtd-grammar",
+ "http://apache.org/xml/features/xinclude",
+ "http://xml.org/sax/features/resolve-dtd-uris"
+ };
+ private String[] SAX_PARSER_FEATURES_TO_ENABLE = {
+ "http://apache.org/xml/features/continue-after-fatal-error"
+ };
+
+ private void setSAXParserFeatures(SAXParser saxParser, String[] features, boolean set)
{
+ XMLReader reader;
+ try {
+ reader = saxParser.getXMLReader();
+ } catch (SAXException e) {
+ JSFModelPlugin.getDefault().logError(e);
+ return;
+ }
+ for (String feature : features) {
+ try {
+ reader.setFeature(feature, set);
+ } catch (SAXException e) {
+ JSFModelPlugin.getDefault().logError(e);
+ }
+ }
+ }
+
+ private void setSAXParserProperty(SAXParser saxParser, String property, Object value) {
+ XMLReader reader;
+ try {
+ reader = saxParser.getXMLReader();
+ reader.setProperty(property, value);
+ } catch (SAXException e) {
+ JSFModelPlugin.getDefault().logError(e);
+ }
+ }
+
+ private IDocument getDocument(IFile file) {
+ if (file == null)
+ return null;
+
+ String content;
+ try {
+ content = FileUtil.readStream(file);
+ } catch (CoreException e) {
+ JSFModelPlugin.getDefault().logError(e);
+ return null;
+ }
+
+ return (content == null ? null : new Document(content));
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see
org.eclipse.wst.xml.core.internal.validation.core.AbstractNestedValidator#validate(org.eclipse.core.resources.IResource,
int, org.eclipse.wst.validation.ValidationState,
org.eclipse.core.runtime.IProgressMonitor)
+ */
+ @Override
+ public ValidationResult validate(IResource resource, int kind, ValidationState state,
IProgressMonitor monitor) {
+ displaySubtask(monitor, JSFValidationMessage.XHTML_VALIDATION,
resource.getFullPath());
+ this.resource = resource;
+ return super.validate(resource, kind, state, monitor);
+ }
+
+ @Override
+ public ValidationReport validate(String uri, InputStream inputstream,
+ NestedValidatorContext context) {
+ displaySubtask(JSFValidationMessage.XHTML_VALIDATION, uri);
+ this.resource = null;
+ return super.validate(uri, inputstream, context);
+ }
+
+ @Override
+ public ValidationReport validate(String uri, InputStream inputstream,
+ NestedValidatorContext context, ValidationResult result) {
+ displaySubtask(JSFValidationMessage.XHTML_VALIDATION, uri);
+ XMLValidationInfo report = new XMLValidationInfo(uri);
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ XHTMLElementHandler handler = new XHTMLElementHandler(
+ (resource instanceof IFile ? getDocument((IFile)resource) : null),
+ report);
+ SAXParser saxParser = null;
+ try {
+ saxParser = factory.newSAXParser();
+ setSAXParserFeatures(saxParser, SAX_PARSER_FEATURES_TO_DISABLE, false);
+ setSAXParserFeatures(saxParser, SAX_PARSER_FEATURES_TO_ENABLE, true);
+ setSAXParserProperty(saxParser,
"http://xml.org/sax/properties/lexical-handler", handler);
+ isXHTMLDoctype = false;
+ if (inputstream != null) {
+ saxParser.parse(inputstream, handler);
+ } else {
+ saxParser.parse(uri, handler);
+ }
+ } catch (ParserConfigurationException e) {
+ JSFModelPlugin.getDefault().logError(e);
+ report.addError(e.getLocalizedMessage(), 0, 0, uri);
+ } catch (SAXException e) {
+ JSFModelPlugin.getDefault().logError(e);
+ report.addError(e.getLocalizedMessage(), 0, 0, uri);
+ } catch (IOException e) {
+ JSFModelPlugin.getDefault().logError(e);
+ report.addError(e.getLocalizedMessage(), 0, 0, uri);
+ }
+
+ List<ElementLocation> locations = handler.getNonPairedOpenElements();
+ if (!locations.isEmpty()) {
+ for (ElementLocation location : locations) {
+ String messageText =
MessageFormat.format(JSFValidationMessage.XHTML_VALIDATION_NO_END_TAG,
location.getName());
+ report.addError(messageText, location.getLine(), location.getColumn(), uri,
NO_END_TAG, new Object[] {location});
+ }
+ }
+
+ locations = handler.getNonPairedCloseElements();
+ if (!locations.isEmpty()) {
+ for (ElementLocation location : locations) {
+ String messageText =
MessageFormat.format(JSFValidationMessage.XHTML_VALIDATION_NO_START_TAG,
location.getName());
+ report.addError(messageText, location.getLine(), location.getColumn(), uri,
NO_START_TAG, new Object[] {location});
+ }
+ }
+
+ return report;
+ }
+
+ @Override
+ protected void addInfoToMessage(ValidationMessage validationMessage,
+ IMessage message) {
+ ElementLocation location = validationMessage.getMessageArguments() == null ||
validationMessage.getMessageArguments().length < 1 ?
+ null: (ElementLocation)validationMessage.getMessageArguments()[0];
+
+ String nameOrValue = location == null ? "" : location.getName();
+ String key = validationMessage.getKey();
+ if(key != null && (NO_START_TAG.equals(key) || NO_END_TAG.equals(key)) )
+ {
+ String selectionStrategy = START_TAG_STRATEGY;
+ if (NO_START_TAG.equals(key)) {
+ selectionStrategy = START_TAG_STRATEGY;
+ } else if (NO_END_TAG.equals(key)) {
+ selectionStrategy = END_TAG_STRATEGY;
+ }
+ message.setAttribute(COLUMN_NUMBER_ATTRIBUTE, new
Integer(validationMessage.getColumnNumber()));
+ message.setAttribute(SQUIGGLE_SELECTION_STRATEGY_ATTRIBUTE, selectionStrategy);
+ message.setAttribute(SQUIGGLE_NAME_OR_VALUE_ATTRIBUTE, nameOrValue);
+ if (location != null) {
+ message.setLineNo(location.getLine());
+ message.setOffset(location.getStart());
+ message.setLength(location.getLength());
+ }
+ } else {
+ super.addInfoToMessage(validationMessage, message);
+ }
+ }
+
+ @Override
+ public void validationStarting(IProject project, ValidationState state,
+ IProgressMonitor monitor) {
+ super.validationStarting(project, state, monitor);
+ this.monitor = monitor;
+ }
+
+ private void displaySubtask(String message, Object... arguments) {
+ displaySubtask(monitor, MessageFormat.format(message, arguments));
+ }
+
+ private void displaySubtask(IProgressMonitor monitor, String message, Object...
arguments) {
+ if(monitor!=null) {
+ monitor.subTask(MessageFormat.format(message, arguments));
+ }
+ }
+
+ class ElementLocation {
+ String name;
+ int line;
+ int column;
+ int start;
+ int length;
+
+ ElementLocation (String name, int line, int column, int start, int length) {
+ this.name = name;
+ this.line = line;
+ this.column = column;
+ this.start = start;
+ this.length = length;
+ }
+
+ String getName() {
+ return name;
+ }
+
+ int getLine() {
+ return line;
+ }
+
+ int getColumn() {
+ return column;
+ }
+
+ int getStart() {
+ return start;
+ }
+
+ int getLength() {
+ return length;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("'");
+ sb.append(name);
+ sb.append("', Line: ");
+ sb.append(line);
+ sb.append(", Column: ");
+ sb.append(column);
+ sb.append(", start: ");
+ sb.append(start);
+ sb.append(", end: ");
+ sb.append((start + length));
+ sb.append(", length: ");
+ sb.append(length);
+ return sb.toString();
+ }
+ }
+
+ class XHTMLElementHandler extends DefaultHandler implements LexicalHandler {
+ private Locator locator;
+ private IDocument document;
+ private XMLValidationInfo valinfo;
+
+ List<ElementLocation> elements = new ArrayList<ElementLocation>();
+ Stack<ElementLocation> nonPairedOpenElements = new
Stack<XHTMLValidator.ElementLocation>();
+ Stack<ElementLocation> nonPairedCloseElements = new
Stack<XHTMLValidator.ElementLocation>();
+
+ public XHTMLElementHandler(IDocument document, XMLValidationInfo valinfo) {
+ super();
+ this.document = document;
+ this.valinfo = valinfo;
+ }
+
+ @Override
+ public void setDocumentLocator(Locator locator) {
+ this.locator = locator;
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attrs)
throws SAXException {
+ if (!isXHTMLDoctype)
+ return;
+
+ int end = getCurrentLocation(), start = 0;
+ if(end > 0) {
+ start = document.get().lastIndexOf("<", end - 1);
+ }
+ currentElementLocation = new ElementLocation(qName, getLine(start), getColumn(start),
start, end - start);
+ nonPairedOpenElements.push(currentElementLocation);
+ }
+
+ ElementLocation currentElementLocation = null;
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException
{
+ if (!isXHTMLDoctype)
+ return;
+
+ int end = getCurrentLocation(), start = 0;
+ if(end > 0) {
+ start = document.get().lastIndexOf('<', end - 1);
+ }
+ if (document.get().charAt(end - 1) != '>') {
+ int newEnd = document.get().indexOf('>', end);
+ if (newEnd > 0) {
+ qName = getName(document.get().substring(start, newEnd));
+ end = newEnd+1;
+ }
+ }
+ currentElementLocation = new ElementLocation(qName, getLine(start), getColumn(start),
start, end - start);
+ // Try to find according pair open element
+ ElementLocation pairOpenElement = null;
+ for (int i = nonPairedOpenElements.size() - 1; i >= 0 && pairOpenElement ==
null; i--) {
+ ElementLocation openedElement = nonPairedOpenElements.get(i);
+ if (openedElement != null && openedElement.getName().equals(qName)) {
+ pairOpenElement = openedElement;
+ }
+ }
+ if (pairOpenElement == null) {
+ // There is no open element for the current closing element
+ nonPairedCloseElements.push(currentElementLocation);
+ } else {
+ // The pair open element is found for the current closing element
+ nonPairedOpenElements.remove(pairOpenElement);
+ }
+ }
+
+ private String getName(String text) {
+ if (text.startsWith("<"))
+ text = text.substring(1);
+ if (text.startsWith("/"))
+ text = text.substring(1);
+ StringBuilder qName = new StringBuilder();
+ int i = 0;
+ while(i < text.length() && (Character.isJavaIdentifierPart(text.charAt(i))
|| text.charAt(i) == ':')) {
+ qName.append(text.charAt(i));
+ i++;
+ }
+ return qName.toString();
+ }
+
+ @Override
+ public void error(SAXParseException e) throws SAXException {
+ }
+
+ @Override
+ public void fatalError(SAXParseException e) throws SAXException {
+ }
+
+ List<ElementLocation> getNonPairedOpenElements() {
+ return nonPairedOpenElements;
+ }
+
+ List<ElementLocation> getNonPairedCloseElements() {
+ return nonPairedCloseElements;
+ }
+
+ private int getCurrentLocation() {
+ if (locator == null)
+ return 0;
+
+ int line = locator.getLineNumber() - 1;
+ int lineOffset = locator.getColumnNumber() - 1;
+ try {
+ return document.getLineOffset(line) + lineOffset;
+ } catch (BadLocationException e) {
+ JSFModelPlugin.getDefault().logError(e);
+ }
+ return 0;
+ }
+
+ /**
+ * Returns line number in text for offset 'start'; the first line has number
1.
+ *
+ * @param start
+ * @return
+ */
+ private int getLine(int start) {
+ try {
+ return document.getLineOfOffset(start) + 1;
+ } catch (BadLocationException e) {
+ JSFModelPlugin.getPluginLog().logError(e);
+ return -1;
+ }
+ }
+
+ /**
+ * Returns line number in text for offset 'start'; the first line has number
1.
+ *
+ * @param start
+ * @return
+ */
+ private int getColumn(int start) {
+ try {
+ int line = getLine(start);
+ int lineStart = document.getLineOffset(line - 1);
+ return (start - lineStart) + 1;
+ } catch (BadLocationException e) {
+ JSFModelPlugin.getPluginLog().logError(e);
+ return -1;
+ }
+ }
+
+ @Override
+ public void startDTD(String name, String publicId, String systemId)
+ throws SAXException {
+ valinfo.setGrammarEncountered(true);
+ valinfo.setDTDEncountered(true);
+ if (publicId != null && publicId.indexOf("W3C") != -1 &&
+ publicId.indexOf("DTD") != -1 &&
publicId.indexOf("XHTML") != -1) {
+ isXHTMLDoctype = true;
+ }
+ }
+
+ @Override
+ public void endDTD() throws SAXException {
+ }
+
+ @Override
+ public void startEntity(String name) throws SAXException {
+ }
+
+ @Override
+ public void endEntity(String name) throws SAXException {
+ }
+
+ @Override
+ public void startCDATA() throws SAXException {
+ }
+
+ @Override
+ public void endCDATA() throws SAXException {
+ }
+
+ @Override
+ public void comment(char[] ch, int start, int length)
+ throws SAXException {
+ }
+ }
+}
Property changes on:
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/XHTMLValidator.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Modified:
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/messages.properties
===================================================================
---
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/messages.properties 2011-09-23
11:38:13 UTC (rev 34994)
+++
trunk/jsf/plugins/org.jboss.tools.jsf/src/org/jboss/tools/jsf/web/validation/messages.properties 2011-09-23
12:12:37 UTC (rev 34995)
@@ -7,4 +7,6 @@
VALIDATING_RESOURCE=project "{0}"; resource "{1}" (JSF Validator)
VALIDATING_PROJECT=project "{0}" (JSF Validator)
-XHTML_VALIDATION=XHTML Syntax Validation: {0}
\ No newline at end of file
+XHTML_VALIDATION=XHTML Syntax Validation: {0}
+XHTML_VALIDATION_NO_START_TAG=No start tag for element '{0}'
+XHTML_VALIDATION_NO_END_TAG=No end tag for element '{0}'
\ No newline at end of file