org.eclipse.persistence.internal.oxm.XMLBinaryDataMappingNodeValue Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* 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.internal.oxm;
import jakarta.activation.DataHandler;
import javax.xml.namespace.QName;
import org.eclipse.persistence.core.sessions.CoreSession;
import org.eclipse.persistence.exceptions.XMLMarshalException;
import org.eclipse.persistence.internal.core.helper.CoreClassConstants;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;
import org.eclipse.persistence.internal.oxm.mappings.BinaryDataMapping;
import org.eclipse.persistence.internal.oxm.mappings.Field;
import org.eclipse.persistence.internal.oxm.record.BinaryDataUnmarshalRecord;
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 org.eclipse.persistence.internal.oxm.record.UnmarshalRecord;
import org.eclipse.persistence.internal.oxm.record.XMLReader;
import org.eclipse.persistence.internal.oxm.record.deferred.BinaryMappingContentHandler;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* INTERNAL:
* Purpose: This is how the XML Binary Data Mapping is handled when
* used with the TreeObjectBuilder.
* @author mmacivor
*/
public class XMLBinaryDataMappingNodeValue extends NodeValue implements NullCapableValue {
private BinaryDataMapping xmlBinaryDataMapping;
protected String getValueToWrite(QName schemaType, Object value, CoreAbstractSession session) {
return ((ConversionManager) session.getDatasourcePlatform().getConversionManager()).convertObject(value, CoreClassConstants.STRING, schemaType);
}
@Override
public boolean isOwningNode(XPathFragment xPathFragment) {
return (xPathFragment.getNextFragment() == null) || xPathFragment.isAttribute();
}
public XMLBinaryDataMappingNodeValue(BinaryDataMapping mapping) {
this.xmlBinaryDataMapping = mapping;
}
@Override
public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver) {
return marshal(xPathFragment, marshalRecord, object, session, namespaceResolver, ObjectMarshalContext.getInstance(), null);
}
@Override
public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext, XPathFragment rootFragment) {
if (xmlBinaryDataMapping.isReadOnly()) {
return false;
}
Object objectValue = marshalContext.getAttributeValue(object, xmlBinaryDataMapping);
return this.marshalSingleValue(xPathFragment, marshalRecord, object, objectValue, session, namespaceResolver, marshalContext, rootFragment);
}
@Override
public boolean marshalSingleValue(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, Object objectValue, CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext) {
return marshalSingleValue(xPathFragment, marshalRecord, object, objectValue, session, namespaceResolver, marshalContext, null);
}
@Override
public boolean marshalSingleValue(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, Object objectValue,CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext, XPathFragment rootFragment) {
XPathFragment xmlRootFrag = null;
if (objectValue instanceof Root) {
Root xmlRoot = (Root) objectValue;
xmlRootFrag = new XPathFragment();
if (xmlRoot.getNamespaceURI() != null && !xmlRoot.getNamespaceURI().equals(namespaceResolver.getDefaultNamespaceURI())) {
String prefix = namespaceResolver.resolveNamespaceURI(xmlRoot.getNamespaceURI());
xmlRootFrag.setXPath(prefix + Constants.COLON + xmlRoot.getLocalName());
xmlRootFrag.setNamespaceURI(xmlRoot.getNamespaceURI());
}else{
xmlRootFrag.setXPath(xmlRoot.getLocalName());
if(xmlRoot.getNamespaceURI() != null && xmlRoot.getNamespaceURI().length() > 0) {
xmlRootFrag.setNamespaceURI(xmlRoot.getNamespaceURI());
}
}
}
Marshaller marshaller = marshalRecord.getMarshaller();
objectValue = xmlBinaryDataMapping.convertObjectValueToDataValue(objectValue, session, marshaller);
XPathFragment groupingFragment = marshalRecord.openStartGroupingElements(namespaceResolver);
if(xPathFragment.isAttribute()){
if (objectValue == null) {
marshalRecord.closeStartGroupingElements(groupingFragment);
return true;
}
}else {
marshalRecord.closeStartGroupingElements(groupingFragment);
XPathFragment elementFragment = xPathFragment;
if(xmlRootFrag != null) {
elementFragment = xmlRootFrag;
}
if (objectValue == null) {
XPathNode holderXPathNode = new XPathNode();
holderXPathNode.setXPathFragment(elementFragment);
marshalRecord.addGroupingElement(holderXPathNode);
boolean returnVal = xmlBinaryDataMapping.getNullPolicy().directMarshal(xPathFragment, marshalRecord, object, session, namespaceResolver);
if(returnVal){
marshalRecord.endElement(elementFragment, namespaceResolver);
}
marshalRecord.removeGroupingElement(holderXPathNode);
return returnVal;
}else if(!xPathFragment.isSelfFragment){
marshalRecord.openStartElement(elementFragment, namespaceResolver);
marshalRecord.closeStartElement();
}
}
// figure out CID or bytes
String c_id = null;
byte[] bytes = null;
String mimeType = this.xmlBinaryDataMapping.getMimeType(object);
String attachmentType = mimeType;
if(mimeType == null) {
mimeType = "";
attachmentType = "application/octet-stream";
}
if (xmlBinaryDataMapping.isSwaRef() && (marshaller.getAttachmentMarshaller() != null)) {
//object value should be a DataHandler
if (xmlBinaryDataMapping.getAttributeClassification() == XMLBinaryDataHelper.getXMLBinaryDataHelper().DATA_HANDLER) {
c_id = marshaller.getAttachmentMarshaller().addSwaRefAttachment((DataHandler) objectValue);
} else {
XMLBinaryDataHelper.EncodedData data = XMLBinaryDataHelper.getXMLBinaryDataHelper().getBytesForBinaryValue(//
objectValue, marshaller, xmlBinaryDataMapping.getMimeType(object));
bytes = data.getData();
c_id = marshaller.getAttachmentMarshaller().addSwaRefAttachment(bytes, 0, bytes.length);
}
} else if (marshalRecord.isXOPPackage() && !xmlBinaryDataMapping.shouldInlineBinaryData()) {
XPathFragment lastFrag = ((Field) xmlBinaryDataMapping.getField()).getLastXPathFragment();
if(xmlRootFrag != null) {
lastFrag = xmlRootFrag;
}
String localName = null;
String namespaceUri = null;
if(rootFragment != null) {
localName = rootFragment.getLocalName();
namespaceUri = rootFragment.getNamespaceURI();
}
if(!lastFrag.isSelfFragment) {
localName = lastFrag.getLocalName();
namespaceUri = lastFrag.getNamespaceURI();
}
if (objectValue.getClass() == CoreClassConstants.APBYTE) {
bytes = (byte[]) objectValue;
c_id = marshaller.getAttachmentMarshaller().addMtomAttachment(bytes, 0, bytes.length, attachmentType, localName, namespaceUri);
} else if (xmlBinaryDataMapping.getAttributeClassification() == XMLBinaryDataHelper.getXMLBinaryDataHelper().DATA_HANDLER) {
c_id = marshaller.getAttachmentMarshaller().addMtomAttachment((DataHandler) objectValue, localName, namespaceUri);
} else {
XMLBinaryDataHelper.EncodedData data = XMLBinaryDataHelper.getXMLBinaryDataHelper().getBytesForBinaryValue(//
objectValue, marshaller, xmlBinaryDataMapping.getMimeType(object));
bytes = data.getData();
c_id = marshaller.getAttachmentMarshaller().addMtomAttachment(bytes, 0, bytes.length, data.getMimeType(), localName, namespaceUri);
}
}
// handle attributes
if (xPathFragment.isAttribute()) {
// if the CID is null there's nothing to write out
if (c_id != null) {
marshalRecord.attribute(xPathFragment, namespaceResolver, c_id);
}else {
String value = getValueToWrite(((Field) xmlBinaryDataMapping.getField()).getSchemaType(), objectValue, session);
marshalRecord.attribute(xPathFragment, namespaceResolver, value);
}
marshalRecord.closeStartGroupingElements(groupingFragment);
return true;
}
if (xmlBinaryDataMapping.isSwaRef() && (marshaller.getAttachmentMarshaller() != null)) {
if(c_id != null) {
marshalRecord.characters(c_id);
} else {
marshalRecord.characters(((Field) xmlBinaryDataMapping.getField()).getSchemaType(), objectValue, mimeType, false);
}
} else {
if (marshalRecord.isXOPPackage() && !xmlBinaryDataMapping.shouldInlineBinaryData()) {
if(c_id == null) {
marshalRecord.characters(((Field) xmlBinaryDataMapping.getField()).getSchemaType(), objectValue, mimeType, false);
} else {
String xopPrefix = null;
// If the field's resolver is non-null and has an entry for XOP,
// use it - otherwise, create a new resolver, set the XOP entry,
// on it, and use it instead.
// We do this to avoid setting the XOP namespace declaration on
// a given field or descriptor's resolver, as it is only required
// on the current element
// 20061023: handle NPE on null NSR
if (namespaceResolver != null) {
xopPrefix = namespaceResolver.resolveNamespaceURI(Constants.XOP_URL);
}
boolean addDeclaration = false;
if (xopPrefix == null || namespaceResolver == null) {
addDeclaration = true;
xopPrefix = Constants.XOP_PREFIX;
}
XPathFragment xopInclude = new XPathFragment();
xopInclude.setLocalName("Include");
xopInclude.setPrefix(xopPrefix);
xopInclude.setNamespaceURI(Constants.XOP_URL);
marshalRecord.openStartElement(xopInclude, namespaceResolver);
marshalRecord.attribute(Constants.EMPTY_STRING, "href", "href", c_id);
if (addDeclaration) {
marshalRecord.namespaceDeclaration(xopPrefix, Constants.XOP_URL);
}
marshalRecord.closeStartElement();
marshalRecord.endElement(xopInclude, namespaceResolver);
//marshal as an attachment
}
} else {
marshalRecord.characters(((Field)xmlBinaryDataMapping.getField()).getSchemaType(), objectValue, mimeType, false);
}
}
if(!xPathFragment.isSelfFragment()){
marshalRecord.endElement(xPathFragment, namespaceResolver);
}
return true;
}
@Override
public boolean startElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Attributes atts) {
try {
unmarshalRecord.removeNullCapableValue(this);
Field xmlField = (Field) xmlBinaryDataMapping.getField();
BinaryMappingContentHandler handler = new BinaryMappingContentHandler(unmarshalRecord, this, this.xmlBinaryDataMapping);
String qnameString = xPathFragment.getLocalName();
if (xPathFragment.getPrefix() != null) {
qnameString = xPathFragment.getPrefix() + Constants.COLON + qnameString;
}
handler.startElement(xPathFragment.getNamespaceURI(), xPathFragment.getLocalName(), qnameString, atts);
XMLReader xmlReader = unmarshalRecord.getXMLReader();
xmlReader.setContentHandler(handler);
xmlReader.setLexicalHandler(handler);
return true;
} catch(SAXException ex) {
throw XMLMarshalException.unmarshalException(ex);
}
}
@Override
public void endElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord) {
unmarshalRecord.resetStringBuffer();
}
/**
* Handle swaRef and inline attribute cases.
*/
@Override
public void attribute(UnmarshalRecord unmarshalRecord, String URI, String localName, String value) {
unmarshalRecord.removeNullCapableValue(this);
Object fieldValue = null;
if (xmlBinaryDataMapping.isSwaRef()) {
if (unmarshalRecord.getUnmarshaller().getAttachmentUnmarshaller() != null) {
if (xmlBinaryDataMapping.getAttributeClassification() == XMLBinaryDataHelper.getXMLBinaryDataHelper().DATA_HANDLER) {
fieldValue = unmarshalRecord.getUnmarshaller().getAttachmentUnmarshaller().getAttachmentAsDataHandler(value);
} else {
fieldValue = unmarshalRecord.getUnmarshaller().getAttachmentUnmarshaller().getAttachmentAsByteArray(value);
}
xmlBinaryDataMapping.setAttributeValueInObject(unmarshalRecord.getCurrentObject(), XMLBinaryDataHelper.getXMLBinaryDataHelper().convertObject(fieldValue, xmlBinaryDataMapping.getAttributeClassification(), unmarshalRecord.getSession(), null));
}
} else {
// value should be base64 binary string
fieldValue = ((ConversionManager) unmarshalRecord.getSession().getDatasourcePlatform().getConversionManager()).convertSchemaBase64ToByteArray(value);
xmlBinaryDataMapping.setAttributeValueInObject(unmarshalRecord.getCurrentObject(), XMLBinaryDataHelper.getXMLBinaryDataHelper().convertObject(fieldValue, xmlBinaryDataMapping.getAttributeClassification(), unmarshalRecord.getSession(), null));
}
}
@Override
public void setNullValue(Object object, CoreSession session) {
Object value = xmlBinaryDataMapping.getObjectValue(null, session);
xmlBinaryDataMapping.setAttributeValueInObject(object, value);
}
@Override
public boolean isNullCapableValue() {
return xmlBinaryDataMapping.getNullPolicy().getIsSetPerformedForAbsentNode();
}
public DataHandler getDataHandlerForObjectValue(Object obj, Class> classification) {
if (classification == DataHandler.class) {
return (DataHandler) obj;
}
return null;
}
public BinaryDataMapping getMapping() {
return this.xmlBinaryDataMapping;
}
@Override
public UnmarshalRecord buildSelfRecord(UnmarshalRecord unmarshalRecord, Attributes atts) {
unmarshalRecord.removeNullCapableValue(this);
BinaryDataUnmarshalRecord newRecord = new BinaryDataUnmarshalRecord(null, unmarshalRecord, this, xmlBinaryDataMapping);
return newRecord;
}
@Override
public void endSelfNodeValue(UnmarshalRecord unmarshalRecord, UnmarshalRecord selfRecord, Attributes attributes) {
unmarshalRecord.resetStringBuffer();
}
}