diff options
author | pfullbright | 2012-01-24 22:12:01 +0000 |
---|---|---|
committer | pfullbright | 2012-01-24 22:12:01 +0000 |
commit | 8e36f87f2fc67a502886dd242d7a88cfc0f5c25a (patch) | |
tree | 2d2f88bb5a091f8c6b22c6e6d42901bb0a62b5ee | |
parent | 2737c7cf41a8b88e342d58b06b55699663420407 (diff) | |
download | webtools.dali-8e36f87f2fc67a502886dd242d7a88cfc0f5c25a.tar.gz webtools.dali-8e36f87f2fc67a502886dd242d7a88cfc0f5c25a.tar.xz webtools.dali-8e36f87f2fc67a502886dd242d7a88cfc0f5c25a.zip |
XmlPath form validation
8 files changed, 263 insertions, 4 deletions
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/property_files/el_jaxb_validation.properties b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/property_files/el_jaxb_validation.properties index 03baf7144d..124c79ddd6 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/property_files/el_jaxb_validation.properties +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/property_files/el_jaxb_validation.properties @@ -10,6 +10,12 @@ PROJECT_MISSING_ECLIPSELINK_JAXB_CONTEXT_FACTORY = Project is missing a jaxb.properties file specifying the EclipseLink JAXB context factory +XML_PATH__ROOT_NOT_SUPPORTED = Root XmlPath is not supported. +XML_PATH__INVALID_FORM_ILLEGAL_SEGMENT = Illegal XmlPath step \"{0}\". +XML_PATH__SELF_SEGMENT_MUST_BE_FIRST_SEGMENT = Self XmlPath step must be first step. +XML_PATH__TEXT_SEGMENT_MUST_BE_LAST_SEGMENT = Text XmlPath step must be last step. +XML_PATH__ATTRIBUTE_SEGMENT_MUST_BE_LAST_SEGMENT = An attribute XmlPath step must be the last step. + XML_PATH__INSUFFICIENT_XML_PATHS_FOR_XML_ELEMENTS = Insufficient XmlPaths specified. There must be an XmlPath for each XmlElement. XML_PATH__INSUFFICIENT_XML_ELEMENTS_FOR_XML_PATHS = There is no XmlElement to match this XmlPath. There must be an XmlElement for each Xmlpath. diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAnyAttributeMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAnyAttributeMapping.java index 2b21667dbe..a14f9532f0 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAnyAttributeMapping.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAnyAttributeMapping.java @@ -9,12 +9,16 @@ *******************************************************************************/ package org.eclipse.jpt.jaxb.eclipselink.core.internal.context.java; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jpt.jaxb.core.context.JaxbPersistentAttribute; import org.eclipse.jpt.jaxb.core.internal.context.java.GenericJavaXmlAnyAttributeMapping; import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlAnyAttributeMapping; import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlPath; import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.ELJaxb; import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlPathAnnotation; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; public class ELJavaXmlAnyAttributeMapping @@ -100,6 +104,22 @@ public class ELJavaXmlAnyAttributeMapping } + // ***** validation ***** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + + if (this.xmlPath != null) { + validateXmlPath(messages, reporter, astRoot); + } + } + + protected void validateXmlPath(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + this.xmlPath.validate(messages, reporter, astRoot); + } + + protected class XmlPathContext implements ELJavaXmlPath.Context { diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAnyElementMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAnyElementMapping.java index cbc415b741..9dd2812929 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAnyElementMapping.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAnyElementMapping.java @@ -126,7 +126,7 @@ public class ELJavaXmlAnyElementMapping } protected void validateXmlPath(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { - + this.xmlPath.validate(messages, reporter, astRoot); } diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAttributeMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAttributeMapping.java index 057dd496ce..6a04c97b77 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAttributeMapping.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlAttributeMapping.java @@ -111,6 +111,13 @@ public class ELJavaXmlAttributeMapping if (this.xmlPath == null) { super.validateQName(messages, reporter, astRoot); } + else { + validateXmlPath(messages, reporter, astRoot); + } + } + + protected void validateXmlPath(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + this.xmlPath.validate(messages, reporter, astRoot); } diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlElementMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlElementMapping.java index 635430de25..9855bdd718 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlElementMapping.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlElementMapping.java @@ -132,7 +132,7 @@ public class ELJavaXmlElementMapping } protected void validateXmlPath(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { - + this.xmlPath.validate(messages, reporter, astRoot); } diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlElementsMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlElementsMapping.java index 8eab9b7383..68ae49e7ce 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlElementsMapping.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlElementsMapping.java @@ -156,6 +156,10 @@ public class ELJavaXmlElementsMapping this, xmlPath.getValidationTextRange(astRoot))); } + + for (ELJavaXmlPath xmlPath : this.xmlPathContainer.getContextElements()) { + xmlPath.validate(messages, reporter, astRoot); + } } @Override diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlPath.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlPath.java index bfe149d049..9f3af73e35 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlPath.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlPath.java @@ -1,20 +1,32 @@ package org.eclipse.jpt.jaxb.eclipselink.core.internal.context.java; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.internal.utility.SimpleTextRange; import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.StringTools; import org.eclipse.jpt.jaxb.core.context.java.JavaContextNode; import org.eclipse.jpt.jaxb.core.internal.context.java.AbstractJavaContextNode; import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlPath; +import org.eclipse.jpt.jaxb.eclipselink.core.internal.validation.ELJaxbValidationMessageBuilder; +import org.eclipse.jpt.jaxb.eclipselink.core.internal.validation.ELJaxbValidationMessages; import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlPathAnnotation; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; public class ELJavaXmlPath extends AbstractJavaContextNode implements ELXmlPath { + + protected String value; - private String value; + protected Context context; - private Context context; + protected List<Step> steps; public ELJavaXmlPath(JavaContextNode parent, Context context) { @@ -52,10 +64,13 @@ public class ELJavaXmlPath protected void initValue() { this.value = getAnnotation().getValue(); + initSteps(); } protected void syncValue() { setValue_(getAnnotation().getValue()); + syncSteps(); + } protected XmlPathAnnotation getAnnotation() { @@ -63,15 +78,216 @@ public class ELJavaXmlPath } + // ***** steps ***** + + protected void initSteps() { + this.steps = new Vector<Step>(); + CollectionTools.addAll(this.steps, parse(this.value)); + } + + protected void syncSteps() { + String oldXpath = getCompleteXpath(); + if (! StringTools.stringsAreEqual(this.value, oldXpath)) { + this.steps.clear(); + CollectionTools.addAll(this.steps, parse(this.value)); + } + } + + protected String getCompleteXpath() { + StringBuffer sb = new StringBuffer(); + for (Iterator<Step> stream = this.steps.iterator(); stream.hasNext(); ) { + sb.append(stream.next().value); + if (stream.hasNext()) { + sb.append(DELIM); + } + } + return sb.toString(); + } + + + // ***** validation ***** + @Override public TextRange getValidationTextRange(CompilationUnit astRoot) { return getAnnotation().getTextRange(astRoot); } + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + + String completeXpath = getCompleteXpath(); + if (completeXpath.startsWith(DELIM)) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_PATH__ROOT_NOT_SUPPORTED, + new String[] { this.value }, + ELJavaXmlPath.this, + getValueTextRange(astRoot))); + return; + } + + IMessage firstFormError = null; + Iterator<Step> stream = this.steps.iterator(); + while (firstFormError == null && stream.hasNext() ) { + firstFormError = stream.next().getFirstFormError(messages, astRoot); + } + if (firstFormError != null) { + messages.add(firstFormError); + return; + } + } + + protected TextRange getValueTextRange(CompilationUnit astRoot) { + // should never be null + return getAnnotation().getValueTextRange(astRoot); + } + + protected TextRange buildTextRange(Step step, CompilationUnit astRoot) { + TextRange entireTextRange = getValueTextRange(astRoot); + int start = 1; // move to right one since initial text range includes first quote + for (Step each : this.steps) { + int length = each.value.length(); + if (each == step) { + if (length == 0) { + if (this.steps.size() > 1) { + // expand text range to include either leading or trailing "/" + length += 1; + if (step.index != 0) { + // if step is not first step, use leading "/" + start --; + } + } + else { + return entireTextRange; + } + } + return new SimpleTextRange(entireTextRange.getOffset() + start, length, entireTextRange.getLineNumber()); + } + else { + start += length + 1; // step plus "/" + } + } + throw new IllegalArgumentException("Step must be in list of this XmlPath's steps."); + } + + + // ***** xpath parsing ***** + + protected static String DELIM = "/"; + + protected static String TEXT = "text()"; + + protected static String SELF = "."; + + protected static String ATT_PREFIX = "@"; + + protected Step[] parse(String xpath) { + if (xpath == null) { + return new Step[0]; + } + String[] segments = xpath.split(DELIM, -1); + Step[] steps = new Step[segments.length]; + for (int i = 0; i < segments.length; i ++ ) { + steps[i] = new Step(segments[i], i); + } + return steps; + } + public interface Context { XmlPathAnnotation getAnnotation(); } + + + protected class Step { + + protected String value; + + protected int index; + + protected Flavor flavor; + + + protected Step(String value, int index) { + this.value = value; + this.index = index; + this.flavor = determineFlavor(); + } + + protected Flavor determineFlavor() { + if (StringTools.stringIsEmpty(this.value)) { + return Flavor.EMPTY; + } + else if (TEXT.equals(this.value)) { + return Flavor.TEXT; + } + else if (SELF.equals(this.value)) { + return Flavor.SELF; + } + else if (this.value.startsWith(ATT_PREFIX)) { + return Flavor.ATTRIBUTE; + } + else { + return Flavor.ELEMENT; + } + } + + protected IMessage getFirstFormError(List<IMessage> messages, CompilationUnit astRoot) { + switch (this.flavor) { + case EMPTY : + return ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_PATH__INVALID_FORM_ILLEGAL_SEGMENT, + new String[] { this.value }, + ELJavaXmlPath.this, + ELJavaXmlPath.this.buildTextRange(this, astRoot)); + case SELF : + if (this.index != 0) { + return ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_PATH__SELF_SEGMENT_MUST_BE_FIRST_SEGMENT, + ELJavaXmlPath.this, + ELJavaXmlPath.this.buildTextRange(this, astRoot)); + } + return null; + case TEXT : + if (this.index != ELJavaXmlPath.this.steps.size() - 1) { + return ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_PATH__TEXT_SEGMENT_MUST_BE_LAST_SEGMENT, + ELJavaXmlPath.this, + ELJavaXmlPath.this.buildTextRange(this, astRoot)); + } + return null; + case ATTRIBUTE : + if (this.index != ELJavaXmlPath.this.steps.size() - 1) { + return ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_PATH__ATTRIBUTE_SEGMENT_MUST_BE_LAST_SEGMENT, + ELJavaXmlPath.this, + ELJavaXmlPath.this.buildTextRange(this, astRoot)); + } + default : + return null; + } + } + } + + + protected enum Flavor { + + EMPTY, + + SELF, + + TEXT, + + ELEMENT, + + ATTRIBUTE + } } diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/validation/ELJaxbValidationMessages.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/validation/ELJaxbValidationMessages.java index eaa3efa01e..f89b1151fd 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/validation/ELJaxbValidationMessages.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/validation/ELJaxbValidationMessages.java @@ -20,6 +20,12 @@ public interface ELJaxbValidationMessages { String PROJECT_MISSING_ECLIPSELINK_JAXB_CONTEXT_FACTORY = "PROJECT_MISSING_ECLIPSELINK_JAXB_CONTEXT_FACTORY"; + String XML_PATH__ROOT_NOT_SUPPORTED = "XML_PATH__ROOT_NOT_SUPPORTED"; + String XML_PATH__INVALID_FORM_ILLEGAL_SEGMENT = "XML_PATH__INVALID_FORM_ILLEGAL_SEGMENT"; + String XML_PATH__SELF_SEGMENT_MUST_BE_FIRST_SEGMENT = "XML_PATH__SELF_SEGMENT_MUST_BE_FIRST_SEGMENT"; + String XML_PATH__TEXT_SEGMENT_MUST_BE_LAST_SEGMENT = "XML_PATH__TEXT_SEGMENT_MUST_BE_LAST_SEGMENT"; + String XML_PATH__ATTRIBUTE_SEGMENT_MUST_BE_LAST_SEGMENT = "XML_PATH__ATTRIBUTE_SEGMENT_MUST_BE_LAST_SEGMENT"; + // used on XmlElements mapping String XML_PATH__INSUFFICIENT_XML_PATHS_FOR_XML_ELEMENTS = "XML_PATH__INSUFFICIENT_XML_PATHS_FOR_XML_ELEMENTS"; String XML_PATH__INSUFFICIENT_XML_ELEMENTS_FOR_XML_PATHS = "XML_PATH__INSUFFICIENT_XML_ELEMENTS_FOR_XML_PATHS"; |