blob: f519c9a0e940563586b02eaf23aa8c6d762f1ab3 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 1998, 2013 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 v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.internal.oxm;
import java.nio.charset.Charset;
import java.util.StringTokenizer;
import javax.xml.namespace.QName;
import org.eclipse.persistence.internal.oxm.mappings.Field;
/**
* INTERNAL:
* <p><b>Purpose</b>: Represents a token from an XPath statement.</p>
* <p>For example the following XPath statment a/b[2]/text() corresponds to three
* XPathFragments: "a", "b[2]", and "text()".</p>
* <p><b>Responsibilities</b>:<ul>
* <li>Maintain name, namespace, and prefix information.</li>
* <li>Maintain information about the corresponding node type.</li>
* <li>Maintain index information if any. The XPathFragment corresponding to
* b[2] would have an index value of 2.</li>
* </ul>
*/
public class XPathFragment <
XML_FIELD extends Field
>{
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;
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 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.valueOf(indexString).intValue();
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;
}
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;
}
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;
}
}