blob: 597f876409890f4166d1ee5b4824fc014c2c5725 [file] [log] [blame]
/*******************************************************************************
* 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.Map;
import java.util.Map.Entry;
import org.eclipse.persistence.internal.core.queries.CoreContainerPolicy;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;
import org.eclipse.persistence.internal.oxm.mappings.FragmentCollectionMapping;
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.w3c.dom.Node;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* INTERNAL:
* <p><b>Purpose</b>: This is how the XML Fragment Collection Mapping is handled
* when used with the TreeObjectBuilder.</p>
* @author mmacivor
*/
public class XMLFragmentCollectionMappingNodeValue extends NodeValue implements ContainerValue {
private FragmentCollectionMapping xmlFragmentCollectionMapping;
private int index = -1;
public XMLFragmentCollectionMappingNodeValue(FragmentCollectionMapping xmlFragmentCollectionMapping) {
super();
this.xmlFragmentCollectionMapping = xmlFragmentCollectionMapping;
}
/**
* Override the method in XPathNode such that the marshaller can be set on the
* marshalRecord - this is required for XMLConverter usage.
*/
public boolean marshal(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, CoreAbstractSession session, NamespaceResolver namespaceResolver) {
if (xmlFragmentCollectionMapping.isReadOnly()) {
return false;
}
CoreContainerPolicy cp = xmlFragmentCollectionMapping.getContainerPolicy();
Object collection = xmlFragmentCollectionMapping.getAttributeAccessor().getAttributeValueFromObject(object);
if (null == collection) {
return false;
}
Object iterator = cp.iteratorFor(collection);
if (cp.hasNext(iterator)) {
marshalRecord.openStartGroupingElements(namespaceResolver);
} else {
return false;
}
Object objectValue;
while (cp.hasNext(iterator)) {
objectValue = cp.next(iterator, session);
marshalSingleValue(xPathFragment, marshalRecord, object, objectValue, session, namespaceResolver, ObjectMarshalContext.getInstance());
}
return true;
}
public boolean startElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Attributes atts) {
SAXFragmentBuilder builder = unmarshalRecord.getFragmentBuilder();
builder.setOwningRecord(unmarshalRecord);
try {
String namespaceURI = Constants.EMPTY_STRING;
if(xPathFragment.getNamespaceURI() != null) {
namespaceURI = xPathFragment.getNamespaceURI();
}
String qName = xPathFragment.getLocalName();
if(xPathFragment.getPrefix() != null) {
qName = xPathFragment.getPrefix() + Constants.COLON + qName;
}
if(!(unmarshalRecord.getPrefixesForFragment().isEmpty())) {
for(Entry<String, String> next:((Map<String, String>) unmarshalRecord.getPrefixesForFragment()).entrySet()) {
builder.startPrefixMapping(next.getKey(), next.getValue());
}
}
builder.startElement(namespaceURI, xPathFragment.getLocalName(), qName, atts);
XMLReader xmlReader = unmarshalRecord.getXMLReader();
xmlReader.setContentHandler(builder);
xmlReader.setLexicalHandler(null);
} catch(SAXException ex) {
// Do nothing.
}
return true;
}
public void endElement(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord) {
SAXFragmentBuilder builder = unmarshalRecord.getFragmentBuilder();
Object value = builder.getNodes().remove(builder.getNodes().size() -1);
unmarshalRecord.addAttributeValue(this, value);
}
public Object getContainerInstance() {
return getContainerPolicy().containerInstance();
}
public void setContainerInstance(Object object, Object containerInstance) {
xmlFragmentCollectionMapping.setAttributeValueInObject(object, containerInstance);
}
public CoreContainerPolicy getContainerPolicy() {
return xmlFragmentCollectionMapping.getContainerPolicy();
}
public boolean isContainerValue() {
return true;
}
public boolean marshalSingleValue(XPathFragment xPathFragment, MarshalRecord marshalRecord, Object object, Object value, CoreAbstractSession session, NamespaceResolver namespaceResolver, MarshalContext marshalContext) {
if (value instanceof Node) {
marshalRecord.node((org.w3c.dom.Node)value, namespaceResolver);
}
return true;
}
public FragmentCollectionMapping getMapping() {
return xmlFragmentCollectionMapping;
}
public boolean getReuseContainer() {
return getMapping().getReuseContainer();
}
/**
* INTERNAL:
* Used to track the index of the corresponding containerInstance in the containerInstances Object[] on UnmarshalRecord
*/
public void setIndex(int index){
this.index = index;
}
/**
* INTERNAL:
* Set to track the index of the corresponding containerInstance in the containerInstances Object[] on UnmarshalRecord
* Set during TreeObjectBuilder initialization
*/
public int getIndex(){
return index;
}
/**
* INTERNAL
* Return true if an empty container should be set on the object if there
* is no presence of the collection in the XML document.
* @since EclipseLink 2.3.3
*/
public boolean isDefaultEmptyContainer() {
return getMapping().isDefaultEmptyContainer();
}
@Override
public boolean isWrapperAllowedAsCollectionName() {
return false;
}
}