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

org.eclipse.persistence.internal.oxm.record.DOMReader Maven / Gradle / Ivy

There is a newer version: 4.0.2
Show newest version
/*
 * Copyright (c) 1998, 2018 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.record;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;
import org.eclipse.persistence.internal.oxm.Constants;
import org.eclipse.persistence.internal.oxm.NamespaceResolver;
import org.eclipse.persistence.internal.oxm.Unmarshaller;
import org.eclipse.persistence.internal.oxm.mappings.Login;
import org.eclipse.persistence.internal.oxm.mappings.Mapping;
import org.eclipse.persistence.internal.oxm.record.namespaces.StackUnmarshalNamespaceResolver;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.oxm.documentpreservation.DocumentPreservationPolicy;

import org.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.ext.Locator2;

/**
 *  INTERNAL:
 *  

Purpose: An implementation of XMLReader for parsing DOM Nodes into SAX events. *

Responsibilities:

    *
  • Walk the DOM tree and report sax events to the provided content handler
  • *
  • Report lexical events to the lexical handler if it's provided
  • *
  • Listen for callbacks from the Mapping-Level framework to handle caching nodes for document preservation
  • *
* */ public class DOMReader extends XMLReaderAdapter { private Node currentNode; private DocumentPreservationPolicy docPresPolicy; public DOMReader() { super(); } public DOMReader(Unmarshaller xmlUnmarshaller) { super(xmlUnmarshaller); } @Override public void parse(InputSource input) throws SAXException { if(input instanceof DOMInputSource) { Node node = ((DOMInputSource) input).getNode(); if(contentHandler != null && contentHandler.getClass() == SAXUnmarshallerHandler.class){ ((SAXUnmarshallerHandler)contentHandler).setUnmarshalNamespaceResolver(new StackUnmarshalNamespaceResolver()); } parse(node); } } public void parse (Node node, String newURI, String newName) throws SAXException { if(null == contentHandler) { return; } Element rootNode = null; if(node.getNodeType() == Node.DOCUMENT_NODE) { rootNode = ((Document)node).getDocumentElement(); } else { rootNode = (Element)node; } if(rootNode == null) { return; } processParentNamespaces(rootNode); startDocument(); setupLocator(rootNode.getOwnerDocument()); reportElementEvents(rootNode, newURI, newName); endDocument(); } public void parse (Node node) throws SAXException { parse(node, null, null); } /** * Process namespace declarations on parent elements if not the root. * For each parent node from current to root push each onto a stack, * then pop each off, calling startPrefixMapping for each XMLNS * attribute. Using a stack ensures that the parent nodes are * processed top down. * * @param element */ protected void processParentNamespaces(Element element) throws SAXException { Node parent = element.getParentNode(); // If we're already at the root, do nothing if (parent != null && parent.getNodeType() == Node.DOCUMENT_NODE) { return; } // Add each parent node up to root to the stack List parentElements = new ArrayList(); while (parent != null && parent.getNodeType() != Node.DOCUMENT_NODE) { parentElements.add(parent); parent = parent.getParentNode(); } // Pop off each node and call startPrefixMapping for each XMLNS attribute for (Iterator stackIt = parentElements.iterator(); stackIt.hasNext(); ) { NamedNodeMap attrs = parentElements.remove(parentElements.size() - 1).getAttributes(); if (attrs != null) { for (int i=0, length = attrs.getLength(); i < length; i++) { Attr next = (Attr)attrs.item(i); String attrPrefix = next.getPrefix(); if (attrPrefix != null && attrPrefix.equals(javax.xml.XMLConstants.XMLNS_ATTRIBUTE)) { contentHandler.startPrefixMapping(next.getLocalName(), next.getValue()); } } } } } protected void reportElementEvents(Element elem) throws SAXException { reportElementEvents(elem, null, null); } protected void reportElementEvents(Element elem, String newUri, String newName) throws SAXException { this.currentNode = elem; IndexedAttributeList attributes = buildAttributeList(elem); String namespaceUri = null; String qname = null; String lname = null; if(newName == null){ // Handle null local name lname = elem.getLocalName(); if (lname == null) { // If local name is null, use the node name lname = elem.getNodeName(); qname = lname; handlePrefixedAttribute(elem); } else { qname = getQName(elem); } namespaceUri = elem.getNamespaceURI(); if(namespaceUri == null) { namespaceUri = ""; } } else { namespaceUri = newUri; lname = newName; qname = newName; if(namespaceUri != null && isNamespaceAware()){ NamespaceResolver tmpNR = new NamespaceResolver(); tmpNR.setDOM(elem); String prefix = tmpNR.resolveNamespaceURI(namespaceUri); if(prefix == null || prefix.length() == 0){ String defaultNamespace = elem.getAttributeNS(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI, javax.xml.XMLConstants.XMLNS_ATTRIBUTE); if(defaultNamespace == null){ prefix = tmpNR.generatePrefix(); contentHandler.startPrefixMapping(prefix, namespaceUri); }else if(defaultNamespace != namespaceUri){ prefix = tmpNR.generatePrefix(); contentHandler.startPrefixMapping(prefix, namespaceUri); }else{ prefix = Constants.EMPTY_STRING; } } if(prefix != null && prefix.length() >0){ qname = prefix + Constants.COLON + qname; } } } contentHandler.startElement(namespaceUri, lname, qname, attributes); handleChildNodes(elem.getChildNodes()); contentHandler.endElement(namespaceUri, lname, qname); endPrefixMappings(elem); } protected IndexedAttributeList buildAttributeList(Element elem) throws SAXException { IndexedAttributeList attributes = new IndexedAttributeList(); NamedNodeMap attrs = elem.getAttributes(); for (int i = 0, length = attrs.getLength(); i < length; i++) { Attr next = (Attr)attrs.item(i); String attrPrefix = next.getPrefix(); if(attrPrefix != null && attrPrefix.equals(javax.xml.XMLConstants.XMLNS_ATTRIBUTE)) { contentHandler.startPrefixMapping(next.getLocalName(), next.getValue()); // Handle XMLNS prefixed attributes handleNewNamespaceDeclaration(elem, next.getLocalName(), next.getValue()); } else if(attrPrefix == null) { String name = next.getLocalName(); if(name == null) { name = next.getNodeName(); } if(name != null && name.equals(javax.xml.XMLConstants.XMLNS_ATTRIBUTE)) { contentHandler.startPrefixMapping(Constants.EMPTY_STRING, next.getValue()); handleNewNamespaceDeclaration(elem, Constants.EMPTY_STRING, next.getValue()); } } if(next.getNamespaceURI() != null && next.getNamespaceURI().equals(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI) && next.getLocalName().equals("type")) { handleXsiTypeAttribute(next); } attributes.addAttribute(next); } return attributes; } protected void endPrefixMappings(Element elem) throws SAXException { NamedNodeMap attrs = elem.getAttributes(); for(int i = 0, numOfAtts = attrs.getLength(); i < numOfAtts; i++) { Attr next = (Attr)attrs.item(i); String attrPrefix = next.getPrefix(); if (attrPrefix != null && attrPrefix.equals(javax.xml.XMLConstants.XMLNS_ATTRIBUTE)) { contentHandler.endPrefixMapping(next.getLocalName()); } else if(attrPrefix == null) { String name = next.getLocalName(); if(name == null) { name = next.getNodeName(); } if(javax.xml.XMLConstants.XMLNS_ATTRIBUTE.equals(name)) { contentHandler.endPrefixMapping(Constants.EMPTY_STRING); } } } } protected String getQName(Element elem) throws SAXException { handlePrefixedAttribute(elem); String prefix = elem.getPrefix(); if (prefix != null && prefix.length() > 0) { String qname = prefix + Constants.COLON + elem.getLocalName(); return qname; } else { return elem.getLocalName(); } } protected void handleNewNamespaceDeclaration(Element elem, String emptyString, String value) { // DO NOTHING } protected void handleXsiTypeAttribute(Attr attr) throws SAXException { } /** * Handle prefixed attribute - may need to declare the namespace * URI locally. * */ protected void handlePrefixedAttribute(Element elem) throws SAXException { // DO NOTHING } protected void handleChildNodes(NodeList children) throws SAXException { Node nextChild = null; if(children.getLength() > 0) { nextChild = children.item(0); } while(nextChild != null) { if(nextChild.getNodeType() == Node.TEXT_NODE) { char[] value = ((Text)nextChild).getNodeValue().toCharArray(); contentHandler.characters(value, 0, value.length); } else if(nextChild.getNodeType() == Node.COMMENT_NODE) { char[] value = ((Comment)nextChild).getNodeValue().toCharArray(); if (lexicalHandler != null) { lexicalHandler.comment(value, 0, value.length); } } else if(nextChild.getNodeType() == Node.ELEMENT_NODE) { Element childElement = (Element)nextChild; reportElementEvents(childElement); } else if(nextChild.getNodeType() == Node.CDATA_SECTION_NODE) { if(lexicalHandler != null) { lexicalHandler.startCDATA(); } char[] value = ((CDATASection)nextChild).getData().toCharArray(); contentHandler.characters(value, 0, value.length); if(lexicalHandler != null) { lexicalHandler.endCDATA(); } } nextChild = nextChild.getNextSibling(); } } /** * Trigger an endDocument event on the contenthandler. */ protected void endDocument() throws SAXException { contentHandler.endDocument(); } /** * Trigger a startDocument event on the contenthandler. */ protected void startDocument() throws SAXException { contentHandler.startDocument(); } /** * An EclipseLink specific callback into the Reader. This allows Objects to be * associated with the XML Nodes they came from. */ @Override public void newObjectEvent(Object object, Object parent, Mapping selfRecordMapping) { docPresPolicy.addObjectToCache(object, currentNode, selfRecordMapping); } @Override public Object getCurrentObject(CoreAbstractSession session, Mapping selfRecordMapping) { //if session == null then this is a marshal of a non-root //if docPres policy is null, then we never unmarshalled anything, and can //safely return null; if(session == null && docPresPolicy == null) { return null; } if(docPresPolicy == null) { Login login = (Login)session.getDatasourceLogin(); docPresPolicy = login.getDocumentPreservationPolicy(); } return docPresPolicy.getObjectForNode(currentNode, selfRecordMapping); } public DocumentPreservationPolicy getDocPresPolicy() { return docPresPolicy; } public void setDocPresPolicy(DocumentPreservationPolicy policy) { docPresPolicy = policy; } protected void setupLocator(Document doc) { LocatorImpl locator = new LocatorImpl(); try { locator.setEncoding(doc.getXmlEncoding()); locator.setXMLVersion(doc.getXmlVersion()); } catch(Exception ex) { //if unable to invoke these methods, just return and don't invoke return; } this.contentHandler.setDocumentLocator(locator); } // Made static final for performance reasons. /** * Implementation of Attributes - used to pass along a given node's attributes * to the startElement method of the reader's content handler. */ protected static final class IndexedAttributeList implements org.xml.sax.Attributes { private List attrs; public IndexedAttributeList() { attrs = new ArrayList(); } public void addAttribute(Attr attribute) { attrs.add(attribute); } public String getQName(int index) { try { Attr item = attrs.get(index); if (item.getName() != null) { return item.getName(); } return Constants.EMPTY_STRING; } catch (IndexOutOfBoundsException iobe) { return null; } } public String getType(String namespaceUri, String localName) { return Constants.CDATA; } public String getType(int index) { return Constants.CDATA; } public String getType(String qname) { return Constants.CDATA; } public int getIndex(String qname) { for (int i=0, size = attrs.size(); i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy