org.eclipse.persistence.internal.oxm.XPathFragment Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* Copyright (c) 1998, 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.internal.oxm;
import java.nio.charset.Charset;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
import javax.xml.namespace.QName;
import org.eclipse.persistence.internal.oxm.mappings.Field;
/**
* INTERNAL:
* Purpose: Represents a token from an XPath statement.
* For example the following XPath statment a/b[2]/text() corresponds to three
* XPathFragments: "a", "b[2]", and "text()".
* Responsibilities:
* - Maintain name, namespace, and prefix information.
* - Maintain information about the corresponding node type.
* - Maintain index information if any. The XPathFragment corresponding to
* b[2] would have an index value of 2.
*
*/
public class XPathFragment {
public static final XPathFragment TEXT_FRAGMENT = new XPathFragment(Constants.TEXT);
public static final String SELF_XPATH = ".";
public static final XPathFragment SELF_FRAGMENT = new XPathFragment(SELF_XPATH);
public static final XPathFragment ANY_FRAGMENT = null;
public static final Charset CHARSET = Charset.forName(Constants.DEFAULT_XML_ENCODING);
private XPathFragment nextFragment;
private XML_FIELD xmlField;
private String xpath;
protected boolean hasAttribute = false;
private boolean hasText = false;
private boolean hasNamespace = false;
private boolean containsIndex = false;
private int indexValue = -1;//if containsIndex, then this is the value of the index.
private boolean shouldExecuteSelectNodes = false;
private String shortName;
private String prefix;
private byte[] prefixBytes;
private String localName;
private byte[] localNameBytes;
private String namespaceURI;
protected boolean nameIsText = false;
protected boolean isSelfFragment = false;
private QName leafElementType;
private boolean generatedPrefix = false;
private XPathPredicate predicate;
private boolean namespaceAware;
private char namespaceSeparator;
private Set attributeCollisionSet;
private Set nonAttributeCollisionSet;
public XPathFragment() {
setNamespaceAware(true);
namespaceSeparator = Constants.COLON;
}
public XPathFragment(String xpathString) {
this(xpathString, Constants.COLON, true);
}
public XPathFragment(String xpathString, char namespaceSeparator, boolean namespaceAware) {
this.namespaceSeparator = namespaceSeparator;
setNamespaceAware(namespaceAware);
setXPath(xpathString);
}
public void setPredicate(XPathPredicate condition) {
this.predicate = condition;
}
public boolean isNamespaceAware() {
return namespaceAware;
}
public void setNamespaceAware(boolean isNamespaceAware) {
this.namespaceAware = isNamespaceAware;
}
public char getNamespaceSeparator() {
return this.namespaceSeparator;
}
public void setNamespaceSeparator(char namespaceSeparator) {
this.namespaceSeparator = namespaceSeparator;
}
public XPathPredicate getPredicate() {
return predicate;
}
public XPathFragment getNextFragment() {
return nextFragment;
}
public void setNextFragment(XPathFragment nextFragment) {
this.nextFragment = nextFragment;
}
public void setXPath(String xpathString) {
xpath = xpathString;
shortName = xpathString;
// handle case: company[name/text()="Oracle"]
if(xpathString.length() > 0){
if ((xpath.indexOf('[') != -1) && (xpath.indexOf(']') == -1)) {
setShouldExecuteSelectNodes(true);
return;
}
// handle case: ancestor::*/jaxb:class/@name
if (xpath.indexOf("::") != -1) {
setShouldExecuteSelectNodes(true);
return;
}
if (xpathString.charAt(0) == '@') {
hasAttribute = true;
shortName = xpathString.substring(1).intern();
indexValue = hasIndex(xpathString);
setupNamespaceInformation(shortName);
return;
}
if (xpathString.charAt(0) == '/') {
setShouldExecuteSelectNodes(true);
shortName = xpathString.substring(xpathString.lastIndexOf('/') + 1).intern();
indexValue = hasIndex(xpathString);
setupNamespaceInformation(shortName);
return;
}
}
if (xpathString.equals(Constants.TEXT)) {
nameIsText = true;
shortName = xpathString.intern();
return;
} else {
nameIsText = false;
}
// handle "self" xpath
if (xpathString.equals(SELF_XPATH)) {
isSelfFragment = true;
shortName = xpathString.intern();
return;
}
indexValue = hasIndex(xpathString);
setupNamespaceInformation(shortName);
}
private void setupNamespaceInformation(String xpathString) {
int nsindex = xpathString.indexOf(namespaceSeparator);
if (nsindex != -1) {
hasNamespace = true;
localName = xpathString.substring(nsindex + 1).intern();
prefix = xpathString.substring(0, nsindex).intern();
} else {
localName = xpathString.intern();
}
}
public boolean isAttribute() {
return hasAttribute;
}
public void setAttribute(boolean isAttribute) {
hasAttribute = isAttribute;
}
public String getShortName() {
if(shortName == null){
if(prefix !=null && prefix.length() >0){
shortName = prefix + Constants.COLON + localName;
}else{
shortName = localName;
}
}
return shortName;
}
public String getPrefix() {
return prefix;
}
public byte[] getPrefixBytes() {
if(null == prefixBytes && null != prefix) {
prefixBytes = prefix.getBytes(CHARSET);
}
return prefixBytes;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
resetShortName();
}
public String getLocalName() {
return localName;
}
public byte[] getLocalNameBytes() {
if(null == localNameBytes && null != localName) {
localNameBytes = localName.getBytes(CHARSET);
}
return localNameBytes;
}
public void setLocalName(String localName) {
this.localName = localName;
resetShortName();
}
public String getNamespaceURI() {
return namespaceURI;
}
public void setNamespaceURI(String namespaceURI) {
if (isSelfFragment || namespaceURI !=null && namespaceURI.length() == 0) {
this.namespaceURI = null;
} else {
this.namespaceURI = namespaceURI;
}
}
private int hasIndex(String xpathString) {
int index = -1;
int startindex = xpathString.lastIndexOf('[');
if ((startindex != -1) && (xpathString.lastIndexOf(']') != -1)) {
StringTokenizer st = new StringTokenizer(xpathString, "[]");
String element = st.nextToken();
while(st.hasMoreTokens()) {
String indexString = st.nextToken();
try {
index = Integer.parseInt(indexString);
setContainsIndex(true);
} catch (NumberFormatException e) {
int equalsOffset = indexString.indexOf('=');
if (equalsOffset >= 0) {
XPathFragment xPathFragment = new XPathFragment(indexString.substring(0, equalsOffset));
String value = indexString.substring(equalsOffset + 2, indexString.length() - 1);
predicate = new XPathPredicate(xPathFragment, value);
} else {
setContainsIndex(true);
}
setShouldExecuteSelectNodes(true);
}
}
shortName = element;
} else {
index = -1;
}
return index;
}
public int getIndexValue() {
return indexValue;
}
public void setIndexValue(int indexValue) {
this.indexValue = indexValue;
}
public String getXPath() {
return xpath;
}
public boolean hasNamespace() {
return hasNamespace;
}
/**
* INTERNAL:
* Indicates if the xpath is "."
*
* @return true if the xpath is ".", false otherwise
*/
public boolean isSelfFragment() {
return isSelfFragment;
}
public boolean nameIsText() {
return nameIsText;
}
public void setHasText(boolean hasText) {
this.hasText = hasText;
}
public boolean getHasText() {
return hasText;
}
public void setContainsIndex(boolean containsIndex) {
this.containsIndex = containsIndex;
}
public boolean containsIndex() {
return containsIndex;
}
public void setShouldExecuteSelectNodes(boolean newShouldExecuteSelectNodes) {
this.shouldExecuteSelectNodes = newShouldExecuteSelectNodes;
}
public boolean shouldExecuteSelectNodes() {
return shouldExecuteSelectNodes;
}
@Override
public boolean equals(Object object) {
return equals(object, false);
}
public boolean equals(Object object, boolean ignorePredicate) {
if (null == object) {
return false;
} else if (this == object) {
return true;
}
try {
XPathFragment xPathFragment = (XPathFragment) object;
if (hasAttribute && !xPathFragment.hasAttribute) {
return false;
}
if (nameIsText && xPathFragment.nameIsText) {
return true;
}
if (nameIsText != xPathFragment.nameIsText) {
return false;
}
if ((null == localName && null != xPathFragment.localName) || (null != localName && null == xPathFragment.localName)) {
return false;
}
if (null != localName && !localName.equals(xPathFragment.localName)) {
return false;
}
if (namespaceAware && xPathFragment.isNamespaceAware()) {
if ((null == namespaceURI && null != xPathFragment.namespaceURI) || (null != namespaceURI && null == xPathFragment.namespaceURI)) {
return false;
}
if (null != namespaceURI && !namespaceURI.equals(xPathFragment.namespaceURI)) {
return false;
}
}
if (indexValue != xPathFragment.indexValue) {
return false;
}
if(!ignorePredicate) {
if (null == predicate && null != xPathFragment.predicate) {
return false;
}
if (null != predicate && !predicate.equals(xPathFragment.predicate)) {
return false;
}
}
} catch (ClassCastException e) {
return false;
}
return true;
}
@Override
public int hashCode() {
if(null == localName) {
return 1;
} else {
return localName.hashCode();
}
}
public QName getLeafElementType() {
return leafElementType;
}
public boolean hasLeafElementType() {
return leafElementType != null;
}
public void setLeafElementType(QName type) {
leafElementType = type;
}
public void setGeneratedPrefix(boolean isGenerated) {
generatedPrefix = isGenerated;
}
public boolean isGeneratedPrefix() {
return generatedPrefix;
}
public XML_FIELD getXMLField() {
return this.xmlField;
}
public void setXMLField(XML_FIELD field) {
this.xmlField = field;
}
private void resetShortName(){
shortName = null;
prefixBytes = null;
localNameBytes = null;
}
/**
* INTERNAL:
* Gets auxiliary set for determining collisions during case insensitive unmarshalling.
*
* @param isAttribute Determine if retrieving an element or an attribute collision set.
* @return
* Set containing localNames of attributes or elements of an XPathFragment.
*/
public Set getChildrenCollisionSet(boolean isAttribute) {
return isAttribute ? getAttributeCollisionSet() : getNonAttributeCollisionSet();
}
private Set getAttributeCollisionSet() {
if (attributeCollisionSet == null)
attributeCollisionSet = new HashSet<>();
return attributeCollisionSet;
}
private Set getNonAttributeCollisionSet() {
if (nonAttributeCollisionSet == null)
nonAttributeCollisionSet = new HashSet<>();
return nonAttributeCollisionSet;
}
}