diff options
Diffstat (limited to 'jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src')
9 files changed, 762 insertions, 20 deletions
diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELClassMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELClassMapping.java index c1fb95d5bb..253472585f 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELClassMapping.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELClassMapping.java @@ -46,4 +46,14 @@ public interface ELClassMapping ELXmlDiscriminatorValue addXmlDiscriminatorValue(); void removeXmlDiscriminatorValue(); + + + // ***** misc ***** + + /** + * Return an {@link Iterable} of XPaths that represent the attributes annotated with XmlID or + * XmlKey. (Includes those attributes that are not annotated with XmlPath - those XPaths + * will be calculated.) + */ + Iterable<String> getKeyXPaths(); } diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlJoinNode.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlJoinNode.java new file mode 100644 index 0000000000..0166f05684 --- /dev/null +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlJoinNode.java @@ -0,0 +1,58 @@ +package org.eclipse.jpt.jaxb.eclipselink.core.context.java; + +import org.eclipse.jpt.jaxb.core.context.java.JavaContextNode; + +/** + * Represents an @XmlJoinNode, whether at top level or nested in @XmlJoinNodes + * <p> + * Provisional API: This interface is part of an interim API that is still + * under development and expected to change significantly before reaching + * stability. It is available at this early stage to solicit feedback from + * pioneering adopters on the understanding that any code that uses this API + * will almost certainly be broken (repeatedly) as the API evolves. + * + * @version 3.2 + * @since 3.2 + */ +public interface ELXmlJoinNode + extends JavaContextNode { + + // ***** xmlPath ***** + + /** + * String associated with changes to the xmlPath property + */ + String XML_PATH_PROPERTY = "xmlPath"; ///$NON-NLS-1$ + + /** + * Return the xmlPath property value. + * A null indicates it is not specified. + */ + String getXmlPath(); + + /** + * Set the xmlPath property value. + * Null unspecifies the value. + */ + void setXmlPath(String value); + + + // ***** referencedXmlPath ***** + + /** + * String associated with changes to the referencedXmlPath property + */ + String REFERENCED_XML_PATH_PROPERTY = "referencedXmlPath"; ///$NON-NLS-1$ + + /** + * Return the referencedXmlPath property value. + * A null indicates it is not specified. + */ + String getReferencedXmlPath(); + + /** + * Set the referencedXmlPath property value. + * Null unspecifies the value. + */ + void setReferencedXmlPath(String value); +} diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlJoinNodesMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlJoinNodesMapping.java index e65f928ff2..f821fa18fb 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlJoinNodesMapping.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/context/java/ELXmlJoinNodesMapping.java @@ -9,7 +9,9 @@ *******************************************************************************/ package org.eclipse.jpt.jaxb.eclipselink.core.context.java; +import org.eclipse.jpt.common.utility.internal.iterables.ListIterable; import org.eclipse.jpt.jaxb.core.context.JaxbAttributeMapping; +import org.eclipse.jpt.jaxb.core.xsd.XsdTypeDefinition; /** * Represents an EclipseLink XmlJoinNodes attribute mapping in either @@ -27,4 +29,25 @@ import org.eclipse.jpt.jaxb.core.context.JaxbAttributeMapping; public interface ELXmlJoinNodesMapping extends JaxbAttributeMapping { + + // ***** XmlJoinNodes ***** + + String XML_JOIN_NODES_LIST = "xmlJoinNodes"; //$NON-NLS-1$ + + ListIterable<ELXmlJoinNode> getXmlJoinNodes(); + + int getXmlJoinNodesSize(); + + ELXmlJoinNode addXmlJoinNode(int index); + + void removeXmlJoinNode(int index); + + void moveXmlJoinNode(int targetIndex, int sourceIndex); + + + // ***** misc ***** + + ELClassMapping getReferencedClassMapping(); + + XsdTypeDefinition getReferencedXsdTypeDefinition(); } diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaClassMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaClassMapping.java index 2fcc36fcd6..1065f4fd69 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaClassMapping.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaClassMapping.java @@ -4,12 +4,20 @@ import java.util.List; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jpt.common.utility.Filter; import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.NotNullFilter; import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable; +import org.eclipse.jpt.common.utility.internal.iterables.FilteringIterable; +import org.eclipse.jpt.common.utility.internal.iterables.SubIterableWrapper; +import org.eclipse.jpt.common.utility.internal.iterables.TransformationIterable; +import org.eclipse.jpt.jaxb.core.MappingKeys; +import org.eclipse.jpt.jaxb.core.context.JaxbAttributeMapping; import org.eclipse.jpt.jaxb.core.context.JaxbClass; +import org.eclipse.jpt.jaxb.core.context.JaxbPersistentAttribute; import org.eclipse.jpt.jaxb.core.internal.context.java.GenericJavaClassMapping; import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELClassMapping; import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlDiscriminatorNode; import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlDiscriminatorValue; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlNamedNodeMapping; import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.ELJaxb; import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlDiscriminatorNodeAnnotation; import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlDiscriminatorValueAnnotation; @@ -180,6 +188,43 @@ public class ELJavaClassMapping } + // ***** misc ***** + + public Iterable<String> getKeyXPaths() { + return new FilteringIterable( + new TransformationIterable<ELXmlNamedNodeMapping, String>(getAllKeyMappings()) { + @Override + protected String transform(ELXmlNamedNodeMapping o) { + return o.getXPath(); + } + }, + NotNullFilter.instance()); + } + + protected Iterable<ELXmlNamedNodeMapping> getAllKeyMappings() { + return new FilteringIterable<ELXmlNamedNodeMapping>( + new SubIterableWrapper<JaxbAttributeMapping, ELXmlNamedNodeMapping>( + new FilteringIterable<JaxbAttributeMapping>( + new TransformationIterable<JaxbPersistentAttribute, JaxbAttributeMapping>(getAllAttributes()) { + @Override + protected JaxbAttributeMapping transform(JaxbPersistentAttribute o) { + return o.getMapping(); + } + }) { + @Override + protected boolean accept(JaxbAttributeMapping o) { + return (o.getKey() == MappingKeys.XML_ELEMENT_ATTRIBUTE_MAPPING_KEY + || o.getKey() == MappingKeys.XML_ATTRIBUTE_ATTRIBUTE_MAPPING_KEY); + } + })) { + @Override + protected boolean accept(ELXmlNamedNodeMapping o) { + return o.getXmlID() != null || o.getXmlKey() != null; + } + }; + } + + // ***** content assist ***** @Override diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNode.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNode.java new file mode 100644 index 0000000000..8c7a989c4a --- /dev/null +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNode.java @@ -0,0 +1,314 @@ +/******************************************************************************* + * Copyright (c) 2012 Oracle. 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: + * Oracle - initial API and implementation + *******************************************************************************/ +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.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.StringTools; +import org.eclipse.jpt.common.utility.internal.iterables.CompositeIterable; +import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable; +import org.eclipse.jpt.jaxb.core.JaxbNode; +import org.eclipse.jpt.jaxb.core.context.JaxbClassMapping; +import org.eclipse.jpt.jaxb.core.context.JaxbPackage; +import org.eclipse.jpt.jaxb.core.context.java.JavaContextNode; +import org.eclipse.jpt.jaxb.core.internal.context.java.AbstractJavaContextNode; +import org.eclipse.jpt.jaxb.core.xsd.XsdTypeDefinition; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELClassMapping; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlJoinNode; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlJoinNodesMapping; +import org.eclipse.jpt.jaxb.eclipselink.core.internal.context.xpath.java.XPath; +import org.eclipse.jpt.jaxb.eclipselink.core.internal.context.xpath.java.XPathFactory; +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.XmlJoinNodeAnnotation; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + + +public class ELJavaXmlJoinNode + extends AbstractJavaContextNode + implements ELXmlJoinNode { + + protected String xmlPath; + + protected String referencedXmlPath; + + protected Context context; + + + public ELJavaXmlJoinNode(JavaContextNode parent, Context context) { + super(parent); + this.context = context; + initXmlPath(); + initReferencedXmlPath(); + } + + + protected JaxbPackage getJaxbPackage() { + return getClassMapping().getJaxbType().getJaxbPackage(); + } + + + // ***** sync/update ***** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + syncXmlPath(); + syncReferencedXmlPath(); + } + + + // ***** xmlPath ***** + + public String getXmlPath() { + return this.xmlPath; + } + + public void setXmlPath(String xmlPath) { + getAnnotation().setXmlPath(xmlPath); + setXmlPath_(xmlPath); + } + + protected void setXmlPath_(String xmlPath) { + String old = this.xmlPath; + this.xmlPath = xmlPath; + firePropertyChanged(XML_PATH_PROPERTY, old, this.xmlPath); + } + + protected void initXmlPath() { + this.xmlPath = getAnnotation().getXmlPath(); + } + + protected void syncXmlPath() { + setXmlPath_(getAnnotation().getXmlPath()); + } + + + // ***** referencedXmlPath ***** + + public String getReferencedXmlPath() { + return this.referencedXmlPath; + } + + public void setReferencedXmlPath(String referencedXmlPath) { + getAnnotation().setReferencedXmlPath(referencedXmlPath); + setReferencedXmlPath_(referencedXmlPath); + } + + protected void setReferencedXmlPath_(String referencedXmlPath) { + String old = this.referencedXmlPath; + this.referencedXmlPath = referencedXmlPath; + firePropertyChanged(REFERENCED_XML_PATH_PROPERTY, old, this.referencedXmlPath); + } + + protected void initReferencedXmlPath() { + this.referencedXmlPath = getAnnotation().getReferencedXmlPath(); + } + + protected void syncReferencedXmlPath() { + setReferencedXmlPath_(getAnnotation().getReferencedXmlPath()); + } + + + protected XmlJoinNodeAnnotation getAnnotation() { + return this.context.getAnnotation(); + } + + protected ELXmlJoinNodesMapping getAttributeMapping() { + return this.context.getAttributeMapping(); + } + + protected JaxbClassMapping getClassMapping() { + return getAttributeMapping().getClassMapping(); + } + + + // ***** content assist ***** + + @Override + public Iterable<String> getJavaCompletionProposals( + int pos, Filter<String> filter, CompilationUnit astRoot) { + + if (getAnnotation().xmlPathTouches(pos, astRoot) && this.xmlPath != null) { + XsdTypeDefinition xsdType = getClassMapping().getXsdTypeDefinition(); + XPath xpath = XPathFactory.instance().getXpath(this.xmlPath); + return xpath.getCompletionProposals(new XmlPathContext(astRoot), xsdType, pos, filter); + } + + if (getAnnotation().referencedXmlPathTouches(pos, astRoot) && this.referencedXmlPath != null) { + + + XsdTypeDefinition xsdType = getAttributeMapping().getReferencedXsdTypeDefinition(); + XPath xpath = XPathFactory.instance().getXpath(this.referencedXmlPath); + Iterable<String> result = xpath.getCompletionProposals(new ReferencedXmlPathContext(astRoot), xsdType, pos, filter); + + ELClassMapping referencedClassMapping = this.context.getAttributeMapping().getReferencedClassMapping(); + if (referencedClassMapping != null) { + result = new CompositeIterable<String>( + result, + StringTools.convertToJavaStringLiterals(referencedClassMapping.getKeyXPaths())); + } + + return CollectionTools.sortedSet(result); + } + + return EmptyIterable.instance(); + } + + + // ***** 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); + + validateXmlPath(messages, astRoot); + validateReferencedXmlPath(messages, astRoot); + } + + protected void validateXmlPath(List<IMessage> messages, CompilationUnit astRoot) { + if (StringTools.stringIsEmpty(this.xmlPath)) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_JOIN_NODE__XML_PATH_NOT_SPECIFIED, + ELJavaXmlJoinNode.this, + getXmlPathTextRange(astRoot))); + return; + } + + if (this.xmlPath.startsWith(XPath.DELIM)) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XPATH__ROOT_NOT_SUPPORTED, + ELJavaXmlJoinNode.this, + getXmlPathTextRange(astRoot))); + return; + } + + XsdTypeDefinition xsdType = getClassMapping().getXsdTypeDefinition(); + XPath xpath = XPathFactory.instance().getXpath(this.xmlPath); + xpath.validate(new XmlPathContext(astRoot), xsdType, messages); + } + + protected void validateReferencedXmlPath(List<IMessage> messages, CompilationUnit astRoot) { + if (StringTools.stringIsEmpty(this.referencedXmlPath)) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_JOIN_NODE__REFERENCED_XML_PATH_NOT_SPECIFIED, + ELJavaXmlJoinNode.this, + getReferencedXmlPathTextRange(astRoot))); + return; + } + + if (this.referencedXmlPath.startsWith(XPath.DELIM)) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XPATH__ROOT_NOT_SUPPORTED, + ELJavaXmlJoinNode.this, + getReferencedXmlPathTextRange(astRoot))); + return; + } + + ELClassMapping referencedClassMapping = this.context.getAttributeMapping().getReferencedClassMapping(); + if (referencedClassMapping != null && + ! CollectionTools.contains(referencedClassMapping.getKeyXPaths(), this.referencedXmlPath)) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_JOIN_NODE__REFERENCED_XML_PATH_NOT_IN_REFERENCED_CLASS_KEYS, + new String[] { referencedClassMapping.getJaxbType().getFullyQualifiedName(), this.referencedXmlPath }, + ELJavaXmlJoinNode.this, + getReferencedXmlPathTextRange(astRoot))); + } + + XsdTypeDefinition xsdType = getAttributeMapping().getReferencedXsdTypeDefinition(); + XPath xpath = XPathFactory.instance().getXpath(this.referencedXmlPath); + xpath.validate(new ReferencedXmlPathContext(astRoot), xsdType, messages); + } + + protected TextRange getXmlPathTextRange(CompilationUnit astRoot) { + // should never be null + return getAnnotation().getXmlPathTextRange(astRoot); + } + + protected TextRange getReferencedXmlPathTextRange(CompilationUnit astRoot) { + // should never be null + return getAnnotation().getReferencedXmlPathTextRange(astRoot); + } + + + public interface Context { + + XmlJoinNodeAnnotation getAnnotation(); + + ELXmlJoinNodesMapping getAttributeMapping(); + } + + + protected abstract class XPathContext + implements XPath.Context { + + protected CompilationUnit astRoot; + + protected XPathContext(CompilationUnit astRoot) { + this.astRoot = astRoot; + } + + + public JaxbNode getContextObject() { + return ELJavaXmlJoinNode.this; + } + + public JaxbPackage getJaxbPackage() { + return ELJavaXmlJoinNode.this.getJaxbPackage(); + } + } + + + protected class XmlPathContext + extends XPathContext { + + protected XmlPathContext(CompilationUnit astRoot) { + super(astRoot); + } + + + public TextRange getTextRange() { + return ELJavaXmlJoinNode.this.getXmlPathTextRange(this.astRoot); + } + } + + + protected class ReferencedXmlPathContext + extends XPathContext { + + protected ReferencedXmlPathContext(CompilationUnit astRoot) { + super(astRoot); + } + + + public TextRange getTextRange() { + return ELJavaXmlJoinNode.this.getReferencedXmlPathTextRange(this.astRoot); + } + } +} diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNodesMapping.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNodesMapping.java index 7715ef9dd4..2752036b04 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNodesMapping.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/java/ELJavaXmlJoinNodesMapping.java @@ -9,20 +9,47 @@ *******************************************************************************/ 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.common.core.resource.java.Annotation; +import org.eclipse.jpt.common.core.resource.java.NestableAnnotation; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.Bag; import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.HashBag; +import org.eclipse.jpt.common.utility.internal.StringTools; +import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable; +import org.eclipse.jpt.common.utility.internal.iterables.ListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.SubListIterableWrapper; +import org.eclipse.jpt.common.utility.internal.iterables.SuperListIterableWrapper; +import org.eclipse.jpt.jaxb.core.context.JaxbClassMapping; import org.eclipse.jpt.jaxb.core.context.JaxbPersistentAttribute; import org.eclipse.jpt.jaxb.core.internal.context.java.AbstractJavaAttributeMapping; +import org.eclipse.jpt.jaxb.core.xsd.XsdTypeDefinition; import org.eclipse.jpt.jaxb.eclipselink.core.ELJaxbMappingKeys; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELClassMapping; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlElementsMapping; +import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlJoinNode; import org.eclipse.jpt.jaxb.eclipselink.core.context.java.ELXmlJoinNodesMapping; +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.ELJaxb; +import org.eclipse.jpt.jaxb.eclipselink.core.resource.java.XmlJoinNodeAnnotation; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; public class ELJavaXmlJoinNodesMapping extends AbstractJavaAttributeMapping implements ELXmlJoinNodesMapping { + protected final ContextListContainer<ELJavaXmlJoinNode, XmlJoinNodeAnnotation> xmlJoinNodeContainer; + + public ELJavaXmlJoinNodesMapping(JaxbPersistentAttribute parent) { super(parent); + this.xmlJoinNodeContainer = buildXmlJoinNodeContainer(); } @@ -43,4 +70,230 @@ public class ELJavaXmlJoinNodesMapping return getAnnotation() == null && CollectionTools.isEmpty(getPersistentAttribute().getJavaResourceAttribute().getAnnotations(ELJaxb.XML_JOIN_NODE)); } + + + // ***** sync/update ***** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.xmlJoinNodeContainer.synchronizeWithResourceModel(); + } + + @Override + public void update() { + super.update(); + this.xmlJoinNodeContainer.update(); + } + + + // ***** xmlJoinNodes ***** + + public ListIterable<ELXmlJoinNode> getXmlJoinNodes() { + return new SuperListIterableWrapper<ELXmlJoinNode>(this.xmlJoinNodeContainer.getContextElements()); + } + + public int getXmlJoinNodesSize() { + return this.xmlJoinNodeContainer.getContextElementsSize(); + } + + public ELXmlJoinNode addXmlJoinNode(int index) { + XmlJoinNodeAnnotation annotation = + (XmlJoinNodeAnnotation) getJavaResourceAttribute().addAnnotation(index, ELJaxb.XML_JOIN_NODE); + return this.xmlJoinNodeContainer.addContextElement(index, annotation); + } + + public void removeXmlJoinNode(int index) { + getJavaResourceAttribute().removeAnnotation(index, ELJaxb.XML_JOIN_NODE); + this.xmlJoinNodeContainer.removeContextElement(index); + } + + public void moveXmlJoinNode(int targetIndex, int sourceIndex) { + getJavaResourceAttribute().moveAnnotation(targetIndex, sourceIndex, ELJaxb.XML_JOIN_NODE); + this.xmlJoinNodeContainer.moveContextElement(targetIndex, sourceIndex); + } + + protected ELJavaXmlJoinNode buildXmlJoinNode(XmlJoinNodeAnnotation xmlJoinNodeAnnotation) { + return new ELJavaXmlJoinNode(this, new XmlJoinNodeContext(xmlJoinNodeAnnotation)); + } + + protected ContextListContainer<ELJavaXmlJoinNode, XmlJoinNodeAnnotation> buildXmlJoinNodeContainer() { + XmlJoinNodeContainer container = new XmlJoinNodeContainer(); + container.initialize(); + return container; + } + + protected ListIterable<XmlJoinNodeAnnotation> getXmlJoinNodeAnnotations() { + return new SubListIterableWrapper<NestableAnnotation, XmlJoinNodeAnnotation>( + getJavaResourceAttribute().getAnnotations(ELJaxb.XML_JOIN_NODE)); + } + + + // ***** misc ***** + + public ELClassMapping getReferencedClassMapping() { + String valueType = getValueTypeName(); + if (StringTools.stringIsEmpty(valueType)) { + return null; + } + + return (ELClassMapping) getContextRoot().getClassMapping(valueType); + } + + public XsdTypeDefinition getReferencedXsdTypeDefinition() { + JaxbClassMapping classMapping = getReferencedClassMapping(); + return (classMapping == null) ? null : classMapping.getXsdTypeDefinition(); + } + + + // ***** content assist ***** + + @Override + public Iterable<String> getJavaCompletionProposals( + int pos, Filter<String> filter, CompilationUnit astRoot) { + + Iterable<String> result = super.getJavaCompletionProposals(pos, filter, astRoot); + if (! CollectionTools.isEmpty(result)) { + return result; + } + + for (ELJavaXmlJoinNode xmlJoinNode : this.xmlJoinNodeContainer.getContextElements()) { + result = xmlJoinNode.getJavaCompletionProposals(pos, filter, astRoot); + if (! CollectionTools.isEmpty(result)) { + return result; + } + } + + return EmptyIterable.instance(); + } + + + // ***** validation ***** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + + JaxbClassMapping referencedClass = getReferencedClassMapping(); + + if (referencedClass == null) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_JOIN_NODES__INVALID_REFERENCED_CLASS, + new String[] { getValueTypeName() }, + ELJavaXmlJoinNodesMapping.this, + getValidationTextRange(astRoot))); + } + + validateDuplicateXmlPaths(messages, reporter, astRoot); + + for (ELJavaXmlJoinNode xmlJoinNode : this.xmlJoinNodeContainer.getContextElements()) { + xmlJoinNode.validate(messages, reporter, astRoot); + } + } + + protected void validateDuplicateXmlPaths(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + Bag<String> xmlPaths = new HashBag<String>(); + Bag<String> referencedXmlPaths = new HashBag<String>(); + + for (ELJavaXmlJoinNode joinNode : this.xmlJoinNodeContainer.getContextElements()) { + String xmlPath = joinNode.getXmlPath(); + if (! StringTools.stringIsEmpty(xmlPath)) { + xmlPaths.add(xmlPath); + } + String referencedXmlPath = joinNode.getReferencedXmlPath(); + if (! StringTools.stringIsEmpty(referencedXmlPath)) { + referencedXmlPaths.add(referencedXmlPath); + } + } + + for (ELJavaXmlJoinNode joinNode : this.xmlJoinNodeContainer.getContextElements()) { + validateDuplicateXmlPath(joinNode, xmlPaths, messages, astRoot); + validateDuplicateReferencedXmlPath(joinNode, referencedXmlPaths, messages, astRoot); + } + } + + protected void validateDuplicateXmlPath(ELJavaXmlJoinNode joinNode, Bag<String> xmlPaths, + List<IMessage> messages, CompilationUnit astRoot) { + String xmlPath = joinNode.getXmlPath(); + if (xmlPaths.count(xmlPath) > 1) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_JOIN_NODES__DUPLICATE_XML_PATH, + new String[] { xmlPath }, + joinNode, + joinNode.getXmlPathTextRange(astRoot))); + } + } + + protected void validateDuplicateReferencedXmlPath(ELJavaXmlJoinNode joinNode, Bag<String> referencedXmlPaths, + List<IMessage> messages, CompilationUnit astRoot) { + String referencedXmlPath = joinNode.getReferencedXmlPath(); + if (referencedXmlPaths.count(referencedXmlPath) > 1) { + messages.add( + ELJaxbValidationMessageBuilder.buildMessage( + IMessage.HIGH_SEVERITY, + ELJaxbValidationMessages.XML_JOIN_NODES__DUPLICATE_REFERENCED_XML_PATH, + new String[] { referencedXmlPath }, + joinNode, + joinNode.getReferencedXmlPathTextRange(astRoot))); + } + } + + @Override + public TextRange getValidationTextRange(CompilationUnit astRoot) { + Annotation annotation = getAnnotation(); + if (annotation == null) { + annotation = getJavaResourceAttribute().getAnnotation(0, ELJaxb.XML_JOIN_NODE); + } + return annotation.getTextRange(astRoot); + } + + + protected class XmlJoinNodeContainer + extends ContextListContainer<ELJavaXmlJoinNode, XmlJoinNodeAnnotation> { + + @Override + protected String getContextElementsPropertyName() { + return ELXmlElementsMapping.XML_PATHS_LIST; + } + + @Override + protected ELJavaXmlJoinNode buildContextElement(XmlJoinNodeAnnotation resourceElement) { + return ELJavaXmlJoinNodesMapping.this.buildXmlJoinNode(resourceElement); + } + + @Override + protected ListIterable<XmlJoinNodeAnnotation> getResourceElements() { + return ELJavaXmlJoinNodesMapping.this.getXmlJoinNodeAnnotations(); + } + + @Override + protected XmlJoinNodeAnnotation getResourceElement(ELJavaXmlJoinNode contextElement) { + // in the context of this mapping, there will never be an ELXmlJoinNode without an annotation + return contextElement.getAnnotation(); + } + } + + + protected class XmlJoinNodeContext + implements ELJavaXmlJoinNode.Context { + + protected XmlJoinNodeAnnotation annotation; + + + protected XmlJoinNodeContext(XmlJoinNodeAnnotation annotation) { + this.annotation = annotation; + } + + public XmlJoinNodeAnnotation getAnnotation() { + return this.annotation; + } + + public ELXmlJoinNodesMapping getAttributeMapping() { + return ELJavaXmlJoinNodesMapping.this; + } + } } diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/xpath/java/XPath.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/xpath/java/XPath.java index c451848dbe..0415dbb21d 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/xpath/java/XPath.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/internal/context/xpath/java/XPath.java @@ -52,6 +52,21 @@ public class XPath { public static char CLOSE_BRACKET = ']'; + public static String attributeXPath(String prefix, String localName) { + if (prefix == null) { + return StringTools.concatenate(ATT_PREFIX, localName); + } + return StringTools.concatenate(ATT_PREFIX, prefix, COLON, localName); + } + + public static String elementXPath(String prefix, String localName) { + if (prefix == null) { + return localName; + } + return StringTools.concatenate(prefix, COLON, localName); + } + + List<Step> steps; @@ -224,7 +239,7 @@ public class XPath { messages.add( ELJaxbValidationMessageBuilder.buildMessage( IMessage.HIGH_SEVERITY, - ELJaxbValidationMessages.XML_PATH__ATTRIBUTE_SEGMENT_MUST_BE_LAST_SEGMENT, + ELJaxbValidationMessages.XPATH__ATTRIBUTE_SEGMENT_MUST_BE_LAST_SEGMENT, context.getContextObject(), getTextRange(context))); return; @@ -242,7 +257,7 @@ public class XPath { messages.add( ELJaxbValidationMessageBuilder.buildMessage( IMessage.HIGH_SEVERITY, - ELJaxbValidationMessages.XML_PATH__UNRESOLVED_ATTRIBUTE, + ELJaxbValidationMessages.XPATH__UNRESOLVED_ATTRIBUTE, new String[] { namespace, this.localName }, context.getContextObject(), getTextRange(context))); @@ -292,7 +307,7 @@ public class XPath { messages.add( ELJaxbValidationMessageBuilder.buildMessage( IMessage.HIGH_SEVERITY, - ELJaxbValidationMessages.XML_PATH__UNRESOLVED_ELEMENT, + ELJaxbValidationMessages.XPATH__UNRESOLVED_ELEMENT, new String[] { namespace, this.localName }, context.getContextObject(), getTextRange(context))); @@ -339,7 +354,7 @@ public class XPath { messages. add(ELJaxbValidationMessageBuilder.buildMessage( IMessage.HIGH_SEVERITY, - ELJaxbValidationMessages.XML_PATH__INVALID_FORM_ILLEGAL_SEGMENT, + ELJaxbValidationMessages.XPATH__INVALID_FORM_ILLEGAL_SEGMENT, new String[] { getValue() }, context.getContextObject(), getTextRange(context))); @@ -402,7 +417,7 @@ public class XPath { messages.add( ELJaxbValidationMessageBuilder.buildMessage( IMessage.HIGH_SEVERITY, - ELJaxbValidationMessages.XML_PATH__INVALID_NS_PREFIX, + ELJaxbValidationMessages.XPATH__INVALID_NS_PREFIX, new String[] { this.nsPrefix }, context.getContextObject(), getTextRange(context))); @@ -451,7 +466,7 @@ public class XPath { messages.add( ELJaxbValidationMessageBuilder.buildMessage( IMessage.HIGH_SEVERITY, - ELJaxbValidationMessages.XML_PATH__SELF_SEGMENT_MUST_BE_FIRST_SEGMENT, + ELJaxbValidationMessages.XPATH__SELF_SEGMENT_MUST_BE_FIRST_SEGMENT, context.getContextObject(), getTextRange(context))); return; @@ -486,7 +501,7 @@ public class XPath { new FilteringIterable<String>( new TransformationIterable<String, String>( new CompositeIterable<String>( - new SingleElementIterable(TEXT), + getTextProposals(context, previousType), getAttributeProposals(context, previousType), getElementProposals(context, previousType))) { @Override @@ -506,6 +521,10 @@ public class XPath { return new SingleElementIterable(TEXT); } + protected Iterable<String> getTextProposals(Context context, final XsdTypeDefinition xsdType) { + return (xsdType.hasTextContent()) ? new SingleElementIterable(TEXT) : EmptyIterable.instance(); + } + protected Iterable<String> getAttributeProposals(Context context, final XsdTypeDefinition xsdType) { return new CompositeIterable<String>( new CompositeIterable<String>( @@ -515,7 +534,7 @@ public class XPath { return new TransformationIterable<String, String>(xsdType.getAttributeNames(xmlns.getNamespaceURI())) { @Override protected String transform(String o) { - return StringTools.concatenate(ATT_PREFIX, xmlns.getPrefix(), COLON, o); + return XPath.attributeXPath(xmlns.getPrefix(), o); } }; } @@ -523,7 +542,7 @@ public class XPath { new TransformationIterable<String, String>(xsdType.getAttributeNames("")) { @Override protected String transform(String o) { - return StringTools.concatenate(ATT_PREFIX, o); + return XPath.attributeXPath(null, o); } }); } @@ -537,7 +556,7 @@ public class XPath { return new TransformationIterable<String, String>(xsdType.getElementNames(xmlns.getNamespaceURI(), false)) { @Override protected String transform(String o) { - return StringTools.concatenate(xmlns.getPrefix(), COLON, o); + return XPath.elementXPath(xmlns.getPrefix(), o); } }; } @@ -587,7 +606,7 @@ public class XPath { messages.add( ELJaxbValidationMessageBuilder.buildMessage( IMessage.HIGH_SEVERITY, - ELJaxbValidationMessages.XML_PATH__TEXT_SEGMENT_MUST_BE_LAST_SEGMENT, + ELJaxbValidationMessages.XPATH__TEXT_SEGMENT_MUST_BE_LAST_SEGMENT, context.getContextObject(), getTextRange(context))); } 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 45f25e7d65..cbf6e5780e 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,21 +20,20 @@ public interface ELJaxbValidationMessages { String PROJECT_MISSING_ECLIPSELINK_JAXB_CONTEXT_FACTORY = "PROJECT_MISSING_ECLIPSELINK_JAXB_CONTEXT_FACTORY"; String XML_DISCRIMINATOR_NODE__NOT_SPECIFIED = "XML_DISCRIMINATOR_NODE__NOT_SPECIFIED"; - String XML_DISCRIMINATOR_NODE__ROOT_NOT_SUPPORTED = "XML_DISCRIMINATOR_NODE__ROOT_NOT_SUPPORTED"; String XML_DISCRIMINATOR_VALUE__NOT_SPECIFIED = "XML_DISCRIMINATOR_VALUE__NOT_SPECIFIED"; String XML_ELEMENT_DECL__INVALID_METHOD_SIGNATURE_RETURN_TYPE = "XML_ELEMENT_DECL__INVALID_METHOD_SIGNATURE_RETURN_TYPE"; + String XML_JOIN_NODE__XML_PATH_NOT_SPECIFIED = "XML_JOIN_NODE__XML_PATH_NOT_SPECIFIED"; + String XML_JOIN_NODE__REFERENCED_XML_PATH_NOT_SPECIFIED = "XML_JOIN_NODE__REFERENCED_XML_PATH_NOT_SPECIFIED"; + String XML_JOIN_NODE__REFERENCED_XML_PATH_NOT_IN_REFERENCED_CLASS_KEYS = "XML_JOIN_NODE__REFERENCED_XML_PATH_NOT_IN_REFERENCED_CLASS_KEYS"; + + String XML_JOIN_NODES__INVALID_REFERENCED_CLASS = "XML_JOIN_NODES__INVALID_REFERENCED_CLASS"; + String XML_JOIN_NODES__DUPLICATE_XML_PATH = "XML_JOIN_NODES__DUPLICATE_XML_PATH"; + String XML_JOIN_NODES__DUPLICATE_REFERENCED_XML_PATH = "XML_JOIN_NODES__DUPLICATE_REFERENCED_XML_PATH"; + String XML_PATH__NOT_SPECIFIED = "XML_PATH__NOT_SPECIFIED"; - 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"; - String XML_PATH__INVALID_NS_PREFIX = "XML_PATH__INVALID_NS_PREFIX"; - String XML_PATH__UNRESOLVED_ELEMENT = "XML_PATH__UNRESOLVED_ELEMENT"; - String XML_PATH__UNRESOLVED_ATTRIBUTE = "XML_PATH__UNRESOLVED_ATTRIBUTE"; // used on XmlElements mapping String XML_PATH__INSUFFICIENT_XML_PATHS_FOR_XML_ELEMENTS = "XML_PATH__INSUFFICIENT_XML_PATHS_FOR_XML_ELEMENTS"; @@ -43,4 +42,14 @@ public interface ELJaxbValidationMessages { String XML_INVERSE_REFERENCE__MAPPED_BY_NOT_SPECIFIED = "XML_INVERSE_REFERENCE__MAPPED_BY_NOT_SPECIFIED"; String XML_INVERSE_REFERENCE__MAPPED_BY_NOT_RESOLVED = "XML_INVERSE_REFERENCE__MAPPED_BY_NOT_RESOLVED"; String XML_INVERSE_REFERENCE__MAPPED_BY_ILLEGAL_MAPPING_TYPE = "XML_INVERSE_REFERENCE__MAPPED_BY_ILLEGAL_MAPPING_TYPE"; + + // for all XPath usage + String XPATH__INVALID_FORM_ILLEGAL_SEGMENT = "XPATH__INVALID_FORM_ILLEGAL_SEGMENT"; + String XPATH__ROOT_NOT_SUPPORTED = "XPATH__ROOT_NOT_SUPPORTED"; + String XPATH__SELF_SEGMENT_MUST_BE_FIRST_SEGMENT = "XPATH__SELF_SEGMENT_MUST_BE_FIRST_SEGMENT"; + String XPATH__TEXT_SEGMENT_MUST_BE_LAST_SEGMENT = "XPATH__TEXT_SEGMENT_MUST_BE_LAST_SEGMENT"; + String XPATH__ATTRIBUTE_SEGMENT_MUST_BE_LAST_SEGMENT = "XPATH__ATTRIBUTE_SEGMENT_MUST_BE_LAST_SEGMENT"; + String XPATH__INVALID_NS_PREFIX = "XPATH__INVALID_NS_PREFIX"; + String XPATH__UNRESOLVED_ELEMENT = "XPATH__UNRESOLVED_ELEMENT"; + String XPATH__UNRESOLVED_ATTRIBUTE = "XPATH__UNRESOLVED_ATTRIBUTE"; } diff --git a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/resource/java/XmlJoinNodeAnnotation.java b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/resource/java/XmlJoinNodeAnnotation.java index 1b4b37c6f3..7e8ff12345 100644 --- a/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/resource/java/XmlJoinNodeAnnotation.java +++ b/jaxb/plugins/org.eclipse.jpt.jaxb.eclipselink.core/src/org/eclipse/jpt/jaxb/eclipselink/core/resource/java/XmlJoinNodeAnnotation.java @@ -53,6 +53,12 @@ public interface XmlJoinNodeAnnotation TextRange getXmlPathTextRange(CompilationUnit astRoot); /** + * Return whether the specified text position is within the 'xmlPath' element. + */ + boolean xmlPathTouches(int pos, CompilationUnit astRoot); + + + /** * String associated with change events to the 'referencedXmlPath' property */ String REFERENCED_XML_PATH_PROPERTY = "referencedXmlPath"; //$NON-NLS-1$ @@ -74,4 +80,9 @@ public interface XmlJoinNodeAnnotation * Return the text range of this annotation if the element is absent. */ TextRange getReferencedXmlPathTextRange(CompilationUnit astRoot); + + /** + * Return whether the specified text position is within the 'referencedXmlPath' element. + */ + boolean referencedXmlPathTouches(int pos, CompilationUnit astRoot); } |