All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.internal.oxm.XPathNode Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1998, 2023 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 org.eclipse.persistence.core.queries.CoreAttributeGroup;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;
import org.eclipse.persistence.internal.oxm.mappings.Mapping;
import org.eclipse.persistence.internal.oxm.record.MarshalContext;
import org.eclipse.persistence.internal.oxm.record.MarshalRecord;
import org.eclipse.persistence.internal.oxm.record.ObjectMarshalContext;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * INTERNAL:
 * 

Purpose: XPathNodes are used together to build a tree. The tree * is built from all of the XPath statements specified in the mapping metadata * (mappings and policies). This tree is then navigated by an * EventObjectBuilder to perform marshal and unmarshal operations.

*

The XPaths "a/b" and "a/c" would result in a tree with the root "a" and * two child nodes "b" and "c".

*

Responsibilities:

    *
  • All tree relationships must be bi-directional.
  • *
  • Reference a NodeValue, XPathNodes without a Node value represent grouping * elements.
  • *
  • Reference an XPathFragment, XPathFragments contain name and namespace * information.
  • *
  • Must differentiate between child nodes that correspond to elements and * those that do not.
  • *
  • Must represent special mapping situations like any and self mappings.
  • *
*/ public class XPathNode { private NodeValue unmarshalNodeValue; private NodeValue marshalNodeValue; private boolean isMarshalOnlyNodeValue; private XPathFragment xPathFragment; private XPathNode parent; private List attributeChildren; private List nonAttributeChildren; private List selfChildren; private Map attributeChildrenMap; private Map attributeChildrenLookupTable; private boolean isAttributeChildrenLookupTableFilled = false; private Map nonAttributeChildrenMap; private Map nonAttributeChildrenLookupTable; private boolean isNonAttributeChildrenLookupTableFilled = false; private MappingNodeValue anyAttributeNodeValue; private XPathNode anyAttributeNode; private XPathNode textNode; private XPathNode anyNode; private XPathNode nextNode; private boolean hasTypeChild; private boolean hasPredicateSiblings; private boolean hasPredicateChildren; private NullCapableValue nullCapableValue; public XPathFragment getXPathFragment() { return xPathFragment; } public void setXPathFragment(XPathFragment xPathFragment) { this.xPathFragment = xPathFragment; } public NodeValue getNodeValue() { return unmarshalNodeValue; } public void setNodeValue(NodeValue nodeValue) { this.marshalNodeValue = nodeValue; this.unmarshalNodeValue = nodeValue; if (null != nodeValue) { nodeValue.setXPathNode(this); isMarshalOnlyNodeValue = nodeValue.isMarshalOnlyNodeValue(); } } public NodeValue getUnmarshalNodeValue() { return unmarshalNodeValue; } public void setUnmarshalNodeValue(NodeValue nodeValue) { if (null != nodeValue) { nodeValue.setXPathNode(this); } this.unmarshalNodeValue = nodeValue; } public NodeValue getMarshalNodeValue() { return marshalNodeValue; } public void setMarshalNodeValue(NodeValue nodeValue) { if (null != nodeValue) { nodeValue.setXPathNode(this); } this.marshalNodeValue = nodeValue; isMarshalOnlyNodeValue = marshalNodeValue.isMarshalOnlyNodeValue(); } public NullCapableValue getNullCapableValue() { return nullCapableValue; } public void setNullCapableValue(NullCapableValue nullCapableValue) { this.nullCapableValue = nullCapableValue; } public XPathNode getParent() { return parent; } public void setParent(XPathNode parent) { this.parent = parent; } public List getAttributeChildren() { return this.attributeChildren; } public List getNonAttributeChildren() { return this.nonAttributeChildren; } public List getSelfChildren() { return this.selfChildren; } public Map getNonAttributeChildrenMap() { return this.nonAttributeChildrenMap; } public Map getAttributeChildrenMap() { return this.attributeChildrenMap; } public boolean isChildrenLookupTableFilled(boolean isAttribute) { return isAttribute ? isAttributeChildrenLookupTableFilled : isNonAttributeChildrenLookupTableFilled; } public void setChildrenLookupTableFilled(boolean isAttribute) { if (isAttribute) this.isAttributeChildrenLookupTableFilled = true; else this.isNonAttributeChildrenLookupTableFilled = true; } public Map getChildrenLookupTable(boolean isAttribute) { return isAttribute ? getAttributeChildrenLookupTable() : getNonAttributeChildrenLookupTable(); } private Map getAttributeChildrenLookupTable() { if (attributeChildrenLookupTable == null) attributeChildrenLookupTable = new HashMap<>(); return attributeChildrenLookupTable; } private Map getNonAttributeChildrenLookupTable() { if (nonAttributeChildrenLookupTable == null) nonAttributeChildrenLookupTable = new HashMap<>(); return nonAttributeChildrenLookupTable; } public void setAnyAttributeNodeValue(MappingNodeValue nodeValue) { this.anyAttributeNodeValue = nodeValue; } public MappingNodeValue getAnyAttributeNodeValue() { return this.anyAttributeNodeValue; } public XPathNode getAnyAttributeNode() { return this.anyAttributeNode; } public XPathNode getAnyNode() { return this.anyNode; } public void setAnyNode(XPathNode xPathNode) { this.anyNode = xPathNode; } public XPathNode getNextNode() { return nextNode; } public XPathNode getTextNode() { return this.textNode; } public void setTextNode(XPathNode xPathNode) { this.textNode = xPathNode; } public boolean hasTypeChild() { return hasTypeChild; } @Override public boolean equals(Object object) { try { XPathFragment perfNodeXPathFragment = ((XPathNode)object).getXPathFragment(); if(xPathFragment == perfNodeXPathFragment) { return true; } else if(null == xPathFragment) { return false; } else if(null == perfNodeXPathFragment) { return false; } return xPathFragment.equals(perfNodeXPathFragment); // turn fix off for now until we re-enable XMLAnyObjectAndAnyCollectionTestCases // } catch (NullPointerException npe) { // b5259059 all cases X0X1 (1mapping xpath=null, 2nd mapping xpath=filled // catch when object.getXPathFragment() == null // (this will also catch case where perfNode XPath is null) // return false; } catch (ClassCastException e) { return false; } } @Override public int hashCode() { return xPathFragment != null ? xPathFragment.hashCode() : 0; } public XPathNode addChild(XPathFragment anXPathFragment, NodeValue aNodeValue, NamespaceResolver namespaceResolver) { if (null != anXPathFragment && anXPathFragment.nameIsText()) { if (aNodeValue.isOwningNode(anXPathFragment)) { XPathNode textXPathNode = this.getTextNode(); if(textXPathNode == null) { textXPathNode = new XPathNode(); } textXPathNode.setParent(this); textXPathNode.setXPathFragment(anXPathFragment); if (aNodeValue.isMarshalNodeValue()) { textXPathNode.setMarshalNodeValue(aNodeValue); } if (aNodeValue.isUnmarshalNodeValue()) { textXPathNode.setUnmarshalNodeValue(aNodeValue); } this.setTextNode(textXPathNode); if(null != nonAttributeChildren && !nonAttributeChildren.contains(textXPathNode)) { nonAttributeChildren.add(textXPathNode); } if(aNodeValue instanceof XMLCompositeObjectMappingNodeValue) { if (null == selfChildren) { selfChildren = new ArrayList<>(); } selfChildren.add(textXPathNode); } return textXPathNode; } } if (anXPathFragment != null && namespaceResolver != null && anXPathFragment.getNamespaceURI() == null && !anXPathFragment.nameIsText()) { if(!anXPathFragment.isAttribute()) { anXPathFragment.setNamespaceURI(namespaceResolver.resolveNamespacePrefix(anXPathFragment.getPrefix())); } else if(anXPathFragment.hasNamespace()) { anXPathFragment.setNamespaceURI(namespaceResolver.resolveNamespacePrefix(anXPathFragment.getPrefix())); } } XPathNode xPathNode = new XPathNode(); xPathNode.setXPathFragment(anXPathFragment); List children; Map childrenMap; if ((anXPathFragment != null) && anXPathFragment.isAttribute()) { if (null == attributeChildren) { attributeChildren = new ArrayList(); } if (null == attributeChildrenMap) { attributeChildrenMap = new HashMap(); } children = attributeChildren; childrenMap = attributeChildrenMap; } else { if (null == nonAttributeChildren) { nonAttributeChildren = new ArrayList(); if(null != textNode) { nonAttributeChildren.add(textNode); } } if (null == nonAttributeChildrenMap) { //The reason behind LinkedHashMap is the order of items when for-cycling HashMap.getEntrySet() or HashMap.getKeySet(). //This change fixes non-determinism (implementation in JDK8 has changed so the order is different (sometimes) than in JDK6 and JDK7). nonAttributeChildrenMap = new LinkedHashMap(); } if(anXPathFragment !=null && Constants.SCHEMA_TYPE_ATTRIBUTE.equals(anXPathFragment.getLocalName())){ hasTypeChild = true; } children = nonAttributeChildren; childrenMap = nonAttributeChildrenMap; } if (null == anXPathFragment) { if(aNodeValue.isMarshalNodeValue()) { xPathNode.setMarshalNodeValue(aNodeValue); } if(aNodeValue.isUnmarshalNodeValue() && xPathNode.getUnmarshalNodeValue() == null) { xPathNode.setUnmarshalNodeValue(aNodeValue); } xPathNode.setParent(this); if (aNodeValue instanceof XMLAnyAttributeMappingNodeValue || (aNodeValue instanceof XMLVariableXPathObjectMappingNodeValue && ((XMLVariableXPathObjectMappingNodeValue)aNodeValue).getMapping().isAttribute() ) || (aNodeValue instanceof XMLVariableXPathCollectionMappingNodeValue && ((XMLVariableXPathCollectionMappingNodeValue)aNodeValue).getMapping().isAttribute() )) { setAnyAttributeNodeValue((MappingNodeValue)aNodeValue); anyAttributeNode = xPathNode; } else { if(!children.contains(xPathNode)) { children.add(xPathNode); } setAnyNode(xPathNode); } return xPathNode; } this.hasPredicateChildren = hasPredicateChildren || anXPathFragment.getPredicate() != null; if(this.getNonAttributeChildren() != null && this.hasPredicateChildren) { for(XPathNode nextChild: this.getNonAttributeChildren()) { XPathFragment nextFrag = nextChild.getXPathFragment(); if(nextFrag != null && nextFrag.equals(anXPathFragment, true)) { if(nextFrag.getPredicate() == null && anXPathFragment.getPredicate() != null) { nextChild.setHasPredicateSiblings(true); } else if(anXPathFragment.getPredicate() == null && nextFrag.getPredicate() != null) { xPathNode.setHasPredicateSiblings(true); } } } } boolean isSelfFragment = XPathFragment.SELF_FRAGMENT.equals(anXPathFragment); if(isSelfFragment){ children.add(xPathNode); if (null == selfChildren) { selfChildren = new ArrayList<>(); } selfChildren.add(xPathNode); }else{ int index = children.indexOf(xPathNode); if (index >= 0) { xPathNode = children.get(index); } else { xPathNode.setParent(this); if(!children.contains(xPathNode)) { int childrenSize = children.size(); if (childrenSize > 0) { children.get(childrenSize - 1).nextNode = xPathNode; } children.add(xPathNode); } childrenMap.put(anXPathFragment, xPathNode); } } if (aNodeValue.isOwningNode(anXPathFragment)) { if(aNodeValue.isMarshalNodeValue()) { xPathNode.setMarshalNodeValue(aNodeValue); } if(aNodeValue.isUnmarshalNodeValue() && xPathNode.getUnmarshalNodeValue() == null) { xPathNode.setUnmarshalNodeValue(aNodeValue); } } else { XPathFragment nextFragment = anXPathFragment.getNextFragment(); xPathNode.addChild(nextFragment, aNodeValue, namespaceResolver); } return xPathNode; } private void setHasPredicateSiblings(boolean b) { this.hasPredicateSiblings = b; } public boolean hasPredicateSiblings() { return this.hasPredicateSiblings; } public boolean marshal(MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver, Marshaller marshaller, MarshalContext marshalContext, XPathFragment rootFragment) { if ((null == marshalNodeValue) || isMarshalOnlyNodeValue) { if(marshalRecord.isWrapperAsCollectionName() && null != nonAttributeChildren && nonAttributeChildren.size() == 1) { XPathNode childXPathNode = nonAttributeChildren.get(0); NodeValue childXPathNodeUnmarshalNodeValue = childXPathNode.getUnmarshalNodeValue(); if(childXPathNodeUnmarshalNodeValue != null && childXPathNodeUnmarshalNodeValue.isContainerValue()) { ContainerValue containerValue = (ContainerValue) childXPathNodeUnmarshalNodeValue; if(containerValue.isWrapperAllowedAsCollectionName()) { XPathNode wrapperXPathNode = new XPathNode(); wrapperXPathNode.setXPathFragment(this.getXPathFragment()); wrapperXPathNode.setMarshalNodeValue(childXPathNode.getMarshalNodeValue()); return wrapperXPathNode.marshal(marshalRecord, object, session, namespaceResolver, marshaller, marshalContext, rootFragment); } } } marshalRecord.addGroupingElement(this); boolean hasValue = false; if (null != attributeChildren) { for (int x = 0, size = attributeChildren.size(); x < size; x++) { XPathNode xPathNode = attributeChildren.get(x); hasValue = xPathNode.marshal(marshalRecord, object, session, namespaceResolver, marshaller, ObjectMarshalContext.getInstance(), this.xPathFragment) || hasValue; } } if (anyAttributeNode != null) { hasValue = anyAttributeNode.marshal(marshalRecord, object, session, namespaceResolver, marshaller, ObjectMarshalContext.getInstance(), null) || hasValue; } if (null == nonAttributeChildren) { if (textNode != null) { hasValue = textNode.marshal(marshalRecord, object, session, namespaceResolver, marshaller, ObjectMarshalContext.getInstance(), null) || hasValue; } } else { for (int x = 0, size = marshalContext.getNonAttributeChildrenSize(this); x < size; x++) { XPathNode xPathNode = (XPathNode)marshalContext.getNonAttributeChild(x, this); MarshalContext childMarshalContext = marshalContext.getMarshalContext(x); hasValue = xPathNode.marshal(marshalRecord, object, session, namespaceResolver, marshaller, childMarshalContext, this.xPathFragment) || hasValue; } } if (hasValue) { marshalRecord.endElement(xPathFragment, namespaceResolver); } else { marshalRecord.removeGroupingElement(this); } return hasValue; } else { if(marshalNodeValue.isMappingNodeValue()) { Mapping mapping = ((MappingNodeValue)marshalNodeValue).getMapping(); CoreAttributeGroup currentGroup = marshalRecord.getCurrentAttributeGroup(); if(!(currentGroup.containsAttributeInternal(mapping.getAttributeName()))) { return false; } } return marshalContext.marshal(marshalNodeValue, xPathFragment, marshalRecord, object, session, namespaceResolver, rootFragment); } } public boolean startElement(MarshalRecord marshalRecord, XPathFragment anXPathFragment, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver, ObjectBuilder compositeObjectBuilder, Object compositeObject) { if (null == anXPathFragment) { return false; } marshalRecord.openStartElement(anXPathFragment, namespaceResolver); boolean hasValue = false; marshalRecord.predicateAttribute(anXPathFragment, namespaceResolver); if (null != attributeChildren) { for (int x = 0, size = attributeChildren.size(); x < size; x++) { XPathNode attributeNode = attributeChildren.get(x); hasValue = attributeNode.marshal(marshalRecord, object, session, namespaceResolver, null, ObjectMarshalContext.getInstance(), null) || hasValue; } } if (anyAttributeNode != null) { //marshal the anyAttribute node here before closeStartElement() hasValue = anyAttributeNode.marshal(marshalRecord, object, session, namespaceResolver, null, ObjectMarshalContext.getInstance(), null) || hasValue; } if (null != compositeObjectBuilder) { hasValue = compositeObjectBuilder.marshalAttributes(marshalRecord, compositeObject, session) || hasValue; } marshalRecord.closeStartElement(); return hasValue; } /** * Marshal any 'self' mapped attributes. * */ public boolean marshalSelfAttributes(MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver, Marshaller marshaller) { if (marshalNodeValue == null) { return false; } return marshalNodeValue.marshalSelfAttributes(xPathFragment, marshalRecord, object, session, namespaceResolver, marshaller); } public boolean isWhitespaceAware() { return unmarshalNodeValue.isWhitespaceAware(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy