blob: 4f281a6362f158cda3524ac3037a39c112ada43a [file] [log] [blame]
/*
* 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();
}
}
}