| /* |
| * Copyright (c) 1998, 2021 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.oxm.record; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import javax.xml.namespace.QName; |
| |
| import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession; |
| import org.eclipse.persistence.internal.helper.DatabaseField; |
| import org.eclipse.persistence.internal.oxm.ConversionManager; |
| import org.eclipse.persistence.internal.oxm.Namespace; |
| import org.eclipse.persistence.internal.oxm.XPathQName; |
| import org.eclipse.persistence.internal.oxm.mappings.Descriptor; |
| import org.eclipse.persistence.internal.oxm.mappings.Field; |
| import org.eclipse.persistence.internal.oxm.record.AbstractMarshalRecord; |
| import org.eclipse.persistence.internal.oxm.record.AbstractMarshalRecordImpl; |
| import org.eclipse.persistence.internal.oxm.record.AbstractUnmarshalRecord; |
| import org.eclipse.persistence.internal.sessions.AbstractRecord; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.oxm.NamespaceResolver; |
| import org.eclipse.persistence.oxm.XMLConstants; |
| import org.eclipse.persistence.oxm.XMLField; |
| import org.eclipse.persistence.oxm.XMLMarshaller; |
| import org.eclipse.persistence.oxm.XMLUnmarshaller; |
| import org.eclipse.persistence.oxm.documentpreservation.DocumentPreservationPolicy; |
| import org.eclipse.persistence.oxm.schema.XMLSchemaReference; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Node; |
| |
| /** |
| * PUBLIC: |
| * Provides a Record/Map API on an XML DOM element. |
| */ |
| public abstract class XMLRecord extends AbstractRecord implements AbstractMarshalRecord<AbstractSession, DatabaseField, XMLMarshaller, NamespaceResolver>, AbstractUnmarshalRecord<AbstractSession, DatabaseField, XMLUnmarshaller> { |
| protected XMLUnmarshaller unmarshaller; |
| private DocumentPreservationPolicy docPresPolicy; |
| protected Object currentObject; |
| protected AbstractSession session; |
| |
| protected boolean hasCustomNamespaceMapper; |
| protected boolean equalNamespaceResolvers = false; |
| |
| private AbstractMarshalRecord<AbstractSession, DatabaseField, XMLMarshaller, NamespaceResolver> abstractMarshalRecord; |
| |
| /** |
| * INTERNAL: |
| * Nil: This is used to indicate that this field represents xsi:nil="true" |
| */ |
| public static final XMLRecord.Nil NIL = org.eclipse.persistence.internal.oxm.record.XMLRecord.NIL; |
| |
| protected XMLRecord() { |
| super(null, null, 0); |
| abstractMarshalRecord = new AbstractMarshalRecordImpl(this); |
| // Required for subclasses. |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the field-value pair to the row. |
| */ |
| @Override |
| public Object get(String key) { |
| return get(new XMLField(key)); |
| } |
| |
| /** |
| * PUBLIC: |
| * Add the field-value pair to the row. |
| */ |
| @Override |
| public Object put(String key, Object value) { |
| return put(new XMLField(key), value); |
| } |
| |
| |
| /** |
| * Marshal an attribute for the give namespaceURI, localName, preifx and value |
| */ |
| @Override |
| public void attributeWithoutQName(String namespaceURI, String localName, String prefix, String value){ |
| String qualifiedName = localName; |
| if(prefix != null && prefix.length() >0){ |
| qualifiedName = prefix + getNamespaceSeparator() + qualifiedName; |
| } |
| attribute(namespaceURI, localName, qualifiedName, value); |
| } |
| |
| /** |
| * Marshal an attribute for the give namespaceURI, localName, qualifiedName and value |
| */ |
| @Override |
| public void attribute(String namespaceURI, String localName, String qName, String value){ |
| XMLField xmlField = new XMLField(XMLConstants.ATTRIBUTE +qName); |
| xmlField.setNamespaceResolver(getNamespaceResolver()); |
| xmlField.getLastXPathFragment().setNamespaceURI(namespaceURI); |
| add(xmlField, value); |
| } |
| |
| /** |
| * Marshal a namespace declaration for the given prefix and url |
| */ |
| @Override |
| public void namespaceDeclaration(String prefix, String namespaceURI){ |
| |
| String existingPrefix = getNamespaceResolver().resolveNamespaceURI(namespaceURI); |
| if(existingPrefix == null || (existingPrefix != null && !existingPrefix.equals(XMLConstants.EMPTY_STRING) && !existingPrefix.equals(prefix))){ |
| XMLField xmlField = new XMLField("@" + javax.xml.XMLConstants.XMLNS_ATTRIBUTE + XMLConstants.COLON + prefix); |
| xmlField.setNamespaceResolver(getNamespaceResolver()); |
| xmlField.getXPathFragment().setNamespaceURI(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI); |
| add(xmlField, namespaceURI); |
| } |
| } |
| |
| /** |
| * PUBLIC: |
| * Get the local name of the context root element. |
| */ |
| public abstract String getLocalName(); |
| |
| /** |
| * PUBLIC: |
| * Get the namespace URI for the context root element. |
| */ |
| public abstract String getNamespaceURI(); |
| |
| /** |
| * PUBLIC: |
| * Clear the sub-nodes of the DOM. |
| */ |
| @Override |
| public abstract void clear(); |
| |
| /** |
| * PUBLIC: |
| * Return the document. |
| */ |
| public abstract Document getDocument(); |
| |
| /** |
| * PUBLIC: |
| * Check if the value is contained in the row. |
| */ |
| @Override |
| public boolean contains(Object value) { |
| return values().contains(value); |
| } |
| |
| /** |
| * PUBLIC: |
| * Return the DOM. |
| */ |
| @Override |
| public abstract Node getDOM(); |
| |
| /** |
| * Return the XML string representation of the DOM. |
| */ |
| public abstract String transformToXML(); |
| |
| /** |
| * INTERNAL: |
| * Convert a DatabaseField to an XMLField |
| */ |
| protected XMLField convertToXMLField(DatabaseField databaseField) { |
| try { |
| return (XMLField)databaseField; |
| } catch (ClassCastException ex) { |
| return new XMLField(databaseField.getName()); |
| } |
| } |
| |
| protected List<XMLField> convertToXMLField(List<DatabaseField> databaseFields) { |
| ArrayList<XMLField> xmlFields = new ArrayList(databaseFields.size()); |
| for(DatabaseField next:databaseFields) { |
| try { |
| xmlFields.add((XMLField)next); |
| } catch(ClassCastException ex) { |
| xmlFields.add(new XMLField(next.getName())); |
| } |
| } |
| return xmlFields; |
| } |
| |
| /** |
| * INTERNAL: |
| * Retrieve the value for the field. If missing null is returned. |
| */ |
| @Override |
| public Object get(DatabaseField key) { |
| return getIndicatingNoEntry(key); |
| } |
| /** |
| * INTERNAL: |
| * Retrieve the value for the field name. |
| */ |
| @Override |
| public Object getIndicatingNoEntry(String fieldName) { |
| return getIndicatingNoEntry(new XMLField(fieldName)); |
| } |
| |
| @Override |
| public String resolveNamespacePrefix(String prefix) { |
| return abstractMarshalRecord.resolveNamespacePrefix(prefix); |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| @Override |
| public XMLMarshaller getMarshaller() { |
| return abstractMarshalRecord.getMarshaller(); |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| @Override |
| public void setMarshaller(XMLMarshaller marshaller) { |
| abstractMarshalRecord.setMarshaller(marshaller); |
| |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| @Override |
| public XMLUnmarshaller getUnmarshaller() { |
| return unmarshaller; |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| public void setUnmarshaller(XMLUnmarshaller unmarshaller) { |
| this.unmarshaller = unmarshaller; |
| } |
| |
| public void setDocPresPolicy(DocumentPreservationPolicy policy) { |
| this.docPresPolicy = policy; |
| } |
| |
| public DocumentPreservationPolicy getDocPresPolicy() { |
| return docPresPolicy; |
| } |
| /** |
| * INTERNAL: |
| */ |
| @Override |
| public Object getOwningObject() { |
| return abstractMarshalRecord.getOwningObject(); |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| @Override |
| public void setOwningObject(Object owningObject) { |
| abstractMarshalRecord.setOwningObject(owningObject); |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| public Object getCurrentObject() { |
| return currentObject; |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| public void setCurrentObject(Object obj) { |
| this.currentObject = obj; |
| } |
| /** |
| * INTERNAL: |
| */ |
| @Override |
| public XPathQName getLeafElementType() { |
| return abstractMarshalRecord.getLeafElementType(); |
| } |
| /** |
| * INTERNAL: |
| */ |
| @Override |
| public void setLeafElementType(XPathQName leafElementType) { |
| abstractMarshalRecord.setLeafElementType(leafElementType); |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| @Override |
| public void setLeafElementType(QName leafElementType) { |
| abstractMarshalRecord.setLeafElementType(leafElementType); |
| } |
| |
| @Override |
| public void setNamespaceResolver(NamespaceResolver nr) { |
| abstractMarshalRecord.setNamespaceResolver(nr); |
| } |
| |
| @Override |
| public NamespaceResolver getNamespaceResolver() { |
| return abstractMarshalRecord.getNamespaceResolver(); |
| } |
| |
| @Override |
| public AbstractSession getSession() { |
| return session; |
| } |
| |
| @Override |
| public void setSession(AbstractSession session) { |
| this.session = session; |
| } |
| |
| @Override |
| public void setEqualNamespaceResolvers(boolean equalNRs) { |
| this.equalNamespaceResolvers = equalNRs; |
| } |
| |
| @Override |
| public boolean hasEqualNamespaceResolvers() { |
| return equalNamespaceResolvers; |
| } |
| |
| @Override |
| public boolean isXOPPackage() { |
| return abstractMarshalRecord.isXOPPackage(); |
| } |
| |
| @Override |
| public void setXOPPackage(boolean isXOPPackage) { |
| abstractMarshalRecord.setXOPPackage(isXOPPackage); |
| } |
| |
| /** |
| * INTERNAL: |
| * Determine if namespaces will be considered during marshal/unmarshal operations. |
| * @since 2.4 |
| */ |
| @Override |
| public boolean isNamespaceAware() { |
| return abstractMarshalRecord.isNamespaceAware(); |
| } |
| |
| /** |
| * INTERNAL: |
| * The character used to separate the prefix and uri portions when namespaces are present |
| * @since 2.4 |
| */ |
| @Override |
| public char getNamespaceSeparator(){ |
| return XMLConstants.COLON; |
| } |
| |
| @Override |
| public boolean hasCustomNamespaceMapper() { |
| return hasCustomNamespaceMapper; |
| } |
| |
| @Override |
| public void setCustomNamespaceMapper(boolean customNamespaceMapper) { |
| this.hasCustomNamespaceMapper = customNamespaceMapper; |
| } |
| |
| /** |
| * INTERNAL |
| * @since EclipseLink 2.5.0 |
| */ |
| @Override |
| public List<Namespace> addExtraNamespacesToNamespaceResolver(Descriptor descriptor, CoreAbstractSession session, boolean allowOverride, boolean ignoreEqualResolvers) { |
| return abstractMarshalRecord.addExtraNamespacesToNamespaceResolver(descriptor, session, allowOverride, ignoreEqualResolvers); |
| } |
| |
| /** |
| * INTERNAL |
| * @since EclipseLink 2.5.0 |
| */ |
| @Override |
| public boolean addXsiTypeAndClassIndicatorIfRequired(Descriptor descriptor, Descriptor referenceDescriptor, Field xmlField, boolean isRootElement) { |
| return abstractMarshalRecord.addXsiTypeAndClassIndicatorIfRequired(descriptor, referenceDescriptor, xmlField, isRootElement); |
| } |
| |
| /** |
| * INTERNAL |
| * @since EclipseLink 2.5.0 |
| */ |
| @Override |
| public boolean addXsiTypeAndClassIndicatorIfRequired(Descriptor descriptor, Descriptor referenceDescriptor, Field xmlField, |
| Object originalObject, Object obj, boolean wasXMLRoot, boolean isRootElement) { |
| return abstractMarshalRecord.addXsiTypeAndClassIndicatorIfRequired(descriptor, referenceDescriptor, xmlField, originalObject, obj, wasXMLRoot, isRootElement); |
| } |
| |
| /** |
| * INTERNAL |
| * @since EclipseLink 2.5.0 |
| */ |
| @Override |
| public void removeExtraNamespacesFromNamespaceResolver(List<Namespace> extraNamespaces, CoreAbstractSession session) { |
| abstractMarshalRecord.removeExtraNamespacesFromNamespaceResolver(extraNamespaces, session); |
| } |
| |
| /** |
| * INTERNAL |
| * @since EclipseLink 2.5.0 |
| */ |
| @Override |
| public void writeXsiTypeAttribute(Descriptor descriptor, String typeUri, String typeLocal, String typePrefix, boolean addToNamespaceResolver) { |
| abstractMarshalRecord.writeXsiTypeAttribute(descriptor, typeUri, typeLocal, typePrefix, addToNamespaceResolver); |
| } |
| |
| /** |
| * INTERNAL |
| * @since EclipseLink 2.5.0 |
| */ |
| @Override |
| public void writeXsiTypeAttribute(Descriptor xmlDescriptor, XMLSchemaReference xmlRef, boolean addToNamespaceResolver) { |
| abstractMarshalRecord.writeXsiTypeAttribute(xmlDescriptor, xmlRef, addToNamespaceResolver); |
| } |
| |
| /** |
| * INTERNAL |
| * @since EclipseLink 2.6.0 |
| */ |
| @Override |
| public ConversionManager getConversionManager() { |
| if(null == session) { |
| return null; |
| } else { |
| return (ConversionManager) session.getDatasourcePlatform().getConversionManager(); |
| } |
| } |
| |
| } |