/******************************************************************************* | |
* Copyright (c) 1998, 2013 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 v1.0 and Eclipse Distribution License v. 1.0 | |
* which accompanies this distribution. | |
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html | |
* and the Eclipse Distribution License is available at | |
* http://www.eclipse.org/org/documents/edl-v10.php. | |
* | |
* Contributors: | |
* Oracle - initial API and implementation from Oracle TopLink | |
******************************************************************************/ | |
package org.eclipse.persistence.internal.oxm; | |
import java.util.List; | |
import javax.xml.namespace.QName; | |
import org.eclipse.persistence.core.sessions.CoreSession; | |
import org.eclipse.persistence.exceptions.XMLMarshalException; | |
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession; | |
import org.eclipse.persistence.internal.helper.Helper; | |
import org.eclipse.persistence.internal.oxm.mappings.AnyObjectMapping; | |
import org.eclipse.persistence.internal.oxm.mappings.Descriptor; | |
import org.eclipse.persistence.internal.oxm.mappings.Field; | |
import org.eclipse.persistence.internal.oxm.mappings.Mapping; | |
import org.eclipse.persistence.internal.oxm.mappings.UnmarshalKeepAsElementPolicy; | |
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.AnyMappingContentHandler; | |
import org.eclipse.persistence.logging.AbstractSessionLog; | |
import org.eclipse.persistence.logging.SessionLog; | |
import org.xml.sax.Attributes; | |
import org.xml.sax.SAXException; | |
/** | |
* INTERNAL: | |
* <p><b>Purpose</b>: This is how the XML Any Object Mapping is handled when | |
* used with the TreeObjectBuilder.</p> | |
*/ | |
public class XMLAnyObjectMappingNodeValue extends XMLRelationshipMappingNodeValue { | |
private AnyObjectMapping xmlAnyObjectMapping; | |
public XMLAnyObjectMappingNodeValue(AnyObjectMapping xmlAnyObjectMapping) { | |
super(); | |
this.xmlAnyObjectMapping = xmlAnyObjectMapping; | |
} | |
public boolean isOwningNode(XPathFragment xPathFragment) { | |
return null == xPathFragment; | |
} | |
public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver) { | |
return marshal(xPathFragment, marshalRecord, object, session, namespaceResolver, ObjectMarshalContext.getInstance()); | |
} | |
public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext) { | |
if (xmlAnyObjectMapping.isReadOnly()) { | |
return false; | |
} | |
Object objectValue = marshalContext.getAttributeValue(object, xmlAnyObjectMapping); | |
return this.marshalSingleValue(xPathFragment, marshalRecord, object, objectValue, session, namespaceResolver, marshalContext); | |
} | |
public boolean marshalSingleValue(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, Object objectValue, CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext) { | |
XPathFragment rootFragment = null; | |
Marshaller marshaller = marshalRecord.getMarshaller(); | |
objectValue = xmlAnyObjectMapping.convertObjectValueToDataValue(objectValue, session, marshalRecord.getMarshaller()); | |
if (null == objectValue) { | |
return false; | |
} | |
XPathFragment groupingFragment = marshalRecord.openStartGroupingElements(namespaceResolver); | |
marshalRecord.closeStartGroupingElements(groupingFragment); | |
boolean wasXMLRoot = false; | |
XPathFragment xmlRootFragment = null; | |
Object originalValue = objectValue; | |
if (xmlAnyObjectMapping.usesXMLRoot() && (objectValue instanceof Root)) { | |
xmlRootFragment = new XPathFragment(); | |
xmlRootFragment.setNamespaceAware(marshalRecord.isNamespaceAware()); | |
wasXMLRoot = true; | |
objectValue = ((Root) objectValue).getObject(); | |
if(objectValue == null){ | |
setupFragment(((Root) originalValue), xmlRootFragment, marshalRecord); | |
marshalRecord.nilComplex(xmlRootFragment, namespaceResolver); | |
return true; | |
} | |
} | |
if (objectValue instanceof String) { | |
marshalSimpleValue(xmlRootFragment, marshalRecord, originalValue, object, objectValue, session, namespaceResolver); | |
} else { | |
CoreSession childSession = null; | |
try { | |
childSession = marshaller.getContext().getSession(objectValue); | |
} catch (XMLMarshalException e) { | |
marshalSimpleValue(xmlRootFragment, marshalRecord, originalValue, object, objectValue, session, namespaceResolver); | |
return true; | |
} | |
Descriptor descriptor = (Descriptor) childSession.getDescriptor(objectValue); | |
ObjectBuilder objectBuilder = (ObjectBuilder) descriptor.getObjectBuilder(); | |
List extraNamespaces = objectBuilder.addExtraNamespacesToNamespaceResolver(descriptor, marshalRecord, session, true, true); | |
if(wasXMLRoot){ | |
setupFragment(((Root) originalValue), xmlRootFragment, marshalRecord); | |
} | |
/* | |
* B5112171: 25 Apr 2006 | |
* During marshalling - XML AnyObject and AnyCollection | |
* mappings throw a NullPointerException when the | |
* "document root element" on child object descriptors are not | |
* all defined. These nodes will be ignored with a warning. | |
*/ | |
String defaultRootElementString = descriptor.getDefaultRootElement(); | |
if (!wasXMLRoot && (defaultRootElementString == null)) { | |
AbstractSessionLog.getLog().log(SessionLog.WARNING, "marshal_warning_null_document_root_element", new Object[] { Helper.getShortClassName(this.getClass()), descriptor }); | |
} else { | |
marshalRecord.beforeContainmentMarshal(objectValue); | |
if (xmlRootFragment != null) { | |
rootFragment = xmlRootFragment; | |
} else { | |
rootFragment = new XPathFragment(defaultRootElementString); | |
//resolve URI | |
if (rootFragment.getNamespaceURI() == null) { | |
if(rootFragment.getPrefix() != null) { | |
String uri = descriptor.getNonNullNamespaceResolver().resolveNamespacePrefix(rootFragment.getPrefix()); | |
rootFragment.setNamespaceURI(uri); | |
} else { | |
rootFragment.setNamespaceURI(descriptor.getNonNullNamespaceResolver().getDefaultNamespaceURI()); | |
} | |
} | |
} | |
if (!wasXMLRoot) { | |
marshalRecord.setLeafElementType(descriptor.getDefaultRootElementType()); | |
} | |
getXPathNode().startElement(marshalRecord, rootFragment, object, session, descriptor.getNonNullNamespaceResolver(), objectBuilder, objectValue); | |
writeExtraNamespaces(extraNamespaces, marshalRecord, session); | |
marshalRecord.addXsiTypeAndClassIndicatorIfRequired(descriptor, descriptor, (Field)xmlAnyObjectMapping.getField(), originalValue, objectValue, wasXMLRoot, false); | |
objectBuilder.buildRow(marshalRecord, objectValue, (org.eclipse.persistence.internal.sessions.AbstractSession) childSession, marshaller, null); | |
marshalRecord.afterContainmentMarshal(object, objectValue); | |
marshalRecord.endElement(rootFragment, namespaceResolver); | |
marshalRecord.removeExtraNamespacesFromNamespaceResolver(extraNamespaces, session); | |
} | |
} | |
return true; | |
} | |
public boolean startElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Attributes atts) { | |
try { | |
Descriptor workingDescriptor = findReferenceDescriptor(xPathFragment, unmarshalRecord, atts, xmlAnyObjectMapping, xmlAnyObjectMapping.getKeepAsElementPolicy()); | |
UnmarshalKeepAsElementPolicy policy = xmlAnyObjectMapping.getKeepAsElementPolicy(); | |
if (null != policy && ((workingDescriptor == null && policy.isKeepUnknownAsElement()) || policy.isKeepAllAsElement())) { | |
setupHandlerForKeepAsElementPolicy(unmarshalRecord, xPathFragment, atts); | |
}else if (workingDescriptor != null) { | |
processChild(xPathFragment, unmarshalRecord, atts, workingDescriptor, xmlAnyObjectMapping); | |
}else{ | |
AnyMappingContentHandler handler = new AnyMappingContentHandler(unmarshalRecord, xmlAnyObjectMapping.usesXMLRoot()); | |
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 e) { | |
throw XMLMarshalException.unmarshalException(e); | |
} | |
return true; | |
} | |
public void endElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord) { | |
UnmarshalRecord childRecord = unmarshalRecord.getChildRecord(); | |
if (null != childRecord) { | |
Object childObject = childRecord.getCurrentObject(); | |
// OBJECT VALUE | |
if (xmlAnyObjectMapping.usesXMLRoot()) { | |
Descriptor workingDescriptor = childRecord.getDescriptor(); | |
if (workingDescriptor != null) { | |
String prefix = xPathFragment.getPrefix(); | |
if ((prefix == null) && (xPathFragment.getNamespaceURI() != null)) { | |
prefix = unmarshalRecord.resolveNamespaceUri(xPathFragment.getNamespaceURI()); | |
} | |
childObject = workingDescriptor.wrapObjectInXMLRoot(childObject, xPathFragment.getNamespaceURI(), xPathFragment.getLocalName(), prefix, false, unmarshalRecord.isNamespaceAware(), unmarshalRecord.getUnmarshaller()); | |
workingDescriptor = null; | |
} | |
} | |
childObject = xmlAnyObjectMapping.convertDataValueToObjectValue(childObject, unmarshalRecord.getSession(), unmarshalRecord.getUnmarshaller()); | |
unmarshalRecord.setAttributeValue(childObject, xmlAnyObjectMapping); | |
} else { | |
SAXFragmentBuilder builder = unmarshalRecord.getFragmentBuilder(); | |
UnmarshalKeepAsElementPolicy keepAsElementPolicy = xmlAnyObjectMapping.getKeepAsElementPolicy(); | |
if (null != keepAsElementPolicy && (keepAsElementPolicy.isKeepUnknownAsElement() || keepAsElementPolicy.isKeepAllAsElement()) && builder.getNodes().size() > 1) { | |
setOrAddAttributeValueForKeepAsElement(builder, xmlAnyObjectMapping, xmlAnyObjectMapping, unmarshalRecord, false, null); | |
} else { | |
// TEXT VALUE | |
if(xmlAnyObjectMapping.isMixedContent()) { | |
endElementProcessText(unmarshalRecord, xmlAnyObjectMapping, xPathFragment, null); | |
} else { | |
unmarshalRecord.resetStringBuffer(); | |
} | |
} | |
} | |
} | |
protected void setOrAddAttributeValue(UnmarshalRecord unmarshalRecord, Object value, XPathFragment xPathFragment, Object collection){ | |
if (!xmlAnyObjectMapping.usesXMLRoot()) { | |
unmarshalRecord.setAttributeValue(value, xmlAnyObjectMapping); | |
} else { | |
Root xmlRoot = unmarshalRecord.createRoot(); | |
xmlRoot.setNamespaceURI(xPathFragment.getNamespaceURI()); | |
xmlRoot.setSchemaType(unmarshalRecord.getTypeQName()); | |
xmlRoot.setLocalName(xPathFragment.getLocalName()); | |
xmlRoot.setObject(value); | |
// xmlRoot.setDeclaredType(type); | |
unmarshalRecord.setAttributeValue(xmlRoot, xmlAnyObjectMapping); | |
} | |
} | |
private Namespace setupFragment(Root originalValue, XPathFragment xmlRootFragment, MarshalRecord marshalRecord) { | |
Namespace generatedNamespace = null; | |
String xpath = originalValue.getLocalName(); | |
if (originalValue.getNamespaceURI() != null) { | |
xmlRootFragment.setNamespaceURI((originalValue).getNamespaceURI()); | |
String prefix = marshalRecord.getNamespaceResolver().resolveNamespaceURI((originalValue).getNamespaceURI()); | |
if (prefix == null || prefix.length() == 0) { | |
prefix = marshalRecord.getNamespaceResolver().generatePrefix("ns0"); | |
generatedNamespace = new Namespace(prefix, xmlRootFragment.getNamespaceURI()); | |
xmlRootFragment.setGeneratedPrefix(true); | |
} | |
xpath = prefix + Constants.COLON + xpath; | |
} | |
xmlRootFragment.setXPath(xpath); | |
return generatedNamespace; | |
} | |
private void marshalSimpleValue(XPathFragment xmlRootFragment, MarshalRecord marshalRecord, Object originalValue, Object object, Object value, CoreAbstractSession session, NamespaceResolver namespaceResolver) { | |
QName qname = null; | |
if (xmlRootFragment != null) { | |
qname = ((Root) originalValue).getSchemaType(); | |
setupFragment(((Root) originalValue), xmlRootFragment, marshalRecord); | |
getXPathNode().startElement(marshalRecord, xmlRootFragment, object, session, namespaceResolver, null, null); | |
updateNamespaces(qname, marshalRecord, null); | |
} | |
if (value instanceof org.w3c.dom.Node) { | |
marshalRecord.node((org.w3c.dom.Node) value, marshalRecord.getNamespaceResolver()); | |
} else { | |
marshalRecord.characters(qname, value, null, false); | |
} | |
if (xmlRootFragment != null) { | |
marshalRecord.endElement(xmlRootFragment, namespaceResolver); | |
} | |
} | |
public AnyObjectMapping getMapping() { | |
return xmlAnyObjectMapping; | |
} | |
public boolean isWhitespaceAware() { | |
return false; | |
} | |
public boolean isAnyMappingNodeValue() { | |
return true; | |
} | |
@Override | |
public boolean isMixedContentNodeValue() { | |
return this.xmlAnyObjectMapping.isMixedContent(); | |
} | |
@Override | |
protected Descriptor findReferenceDescriptor(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Attributes atts, Mapping mapping, UnmarshalKeepAsElementPolicy policy) { | |
Descriptor referenceDescriptor = super.findReferenceDescriptor(xPathFragment, unmarshalRecord, atts, mapping, policy); | |
if (referenceDescriptor == null) { | |
Context xmlContext = unmarshalRecord.getUnmarshaller().getContext(); | |
XPathQName xpathQName = new XPathQName(xPathFragment.getNamespaceURI(), xPathFragment.getLocalName(), unmarshalRecord.isNamespaceAware()); | |
referenceDescriptor = (Descriptor) xmlContext.getDescriptor(xpathQName); | |
// Check if descriptor is for a wrapper, if it is null it out and let continue | |
if (referenceDescriptor != null && referenceDescriptor.isWrapper()) { | |
referenceDescriptor = null; | |
} | |
} | |
return referenceDescriptor; | |
} | |
} |