| /* |
| * Copyright (c) 1998, 2020 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: |
| * <p><b>Purpose</b>: This is how the XML Binary Data Mapping is handled when |
| * used with the TreeObjectBuilder.</p> |
| * @author mmacivor |
| */ |
| |
| public class XMLBinaryDataMappingNodeValue extends NodeValue implements NullCapableValue { |
| private BinaryDataMapping xmlBinaryDataMapping; |
| |
| protected String getValueToWrite(QName schemaType, Object value, CoreAbstractSession session) { |
| return (String) ((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(); |
| } |
| |
| } |