/******************************************************************************* | |
* 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.lang.reflect.Modifier; | |
import java.util.ArrayList; | |
import java.util.Enumeration; | |
import java.util.List; | |
import javax.xml.namespace.QName; | |
import org.eclipse.persistence.descriptors.ClassDescriptor; | |
import org.eclipse.persistence.descriptors.InheritancePolicy; | |
import org.eclipse.persistence.exceptions.DatabaseException; | |
import org.eclipse.persistence.exceptions.DescriptorException; | |
import org.eclipse.persistence.exceptions.QueryException; | |
import org.eclipse.persistence.expressions.Expression; | |
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession; | |
import org.eclipse.persistence.internal.descriptors.ObjectBuilder; | |
import org.eclipse.persistence.internal.helper.DatabaseField; | |
import org.eclipse.persistence.internal.identitymaps.CacheId; | |
import org.eclipse.persistence.internal.identitymaps.CacheKey; | |
import org.eclipse.persistence.internal.oxm.WeakObjectWrapper; | |
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.record.AbstractMarshalRecord; | |
import org.eclipse.persistence.internal.queries.JoinedAttributeManager; | |
import org.eclipse.persistence.internal.sessions.AbstractRecord; | |
import org.eclipse.persistence.internal.sessions.AbstractSession; | |
import org.eclipse.persistence.mappings.AggregateObjectMapping; | |
import org.eclipse.persistence.mappings.DatabaseMapping; | |
import org.eclipse.persistence.mappings.ForeignReferenceMapping; | |
import org.eclipse.persistence.mappings.DatabaseMapping.WriteType; | |
import org.eclipse.persistence.mappings.foundation.AbstractDirectMapping; | |
import org.eclipse.persistence.oxm.NamespaceResolver; | |
import org.eclipse.persistence.oxm.XMLDescriptor; | |
import org.eclipse.persistence.oxm.XMLMarshaller; | |
import org.eclipse.persistence.oxm.XMLUnmarshaller; | |
import org.eclipse.persistence.oxm.record.DOMRecord; | |
import org.eclipse.persistence.oxm.record.XMLRecord; | |
import org.eclipse.persistence.oxm.documentpreservation.DocumentPreservationPolicy; | |
import org.eclipse.persistence.queries.FetchGroup; | |
import org.eclipse.persistence.queries.ObjectBuildingQuery; | |
import org.eclipse.persistence.sessions.SessionProfiler; | |
import org.w3c.dom.Document; | |
import org.w3c.dom.Element; | |
import org.w3c.dom.Node; | |
/** | |
* INTERNAL: | |
* <p><b>Purpose</b>: Object-to-XML specific ObjectBuilder.</p> | |
* @author Rick Barkhouse - rick.barkhouse@oracle.com | |
* @since TopLink 10<i>i</i>, 03/31/2003 16:29:40 | |
*/ | |
public class XMLObjectBuilder extends ObjectBuilder { | |
private Boolean isXMLDescriptor; | |
private boolean xsiTypeIndicatorField; | |
/** | |
* Create an XML object builder for the descriptor. | |
*/ | |
public XMLObjectBuilder(ClassDescriptor descriptor) { | |
super(descriptor); | |
} | |
/** | |
* Build the nested row into the parent dom. | |
*/ | |
public AbstractRecord buildRow(Object object, AbstractSession session, DatabaseField xmlField, XMLRecord parentRecord) { | |
if (isXmlDescriptor() && ((Descriptor)getDescriptor()).shouldPreserveDocument()) { | |
Object pk = extractPrimaryKeyFromObject(object, session); | |
if ((pk == null) || (pk instanceof CacheId) && (((CacheId)pk).getPrimaryKey().length == 0)) { | |
pk = new CacheId(new Object[]{ new WeakObjectWrapper(object) }); | |
} | |
CacheKey cacheKey = session.getIdentityMapAccessorInstance().getCacheKeyForObject(pk, getDescriptor().getJavaClass(), getDescriptor(), false); | |
if ((cacheKey != null) && (cacheKey.getRecord() != null)) { | |
XMLRecord nestedRecord = (XMLRecord)cacheKey.getRecord(); | |
nestedRecord.setMarshaller(parentRecord.getMarshaller()); | |
nestedRecord.setLeafElementType(parentRecord.getLeafElementType()); | |
parentRecord.setLeafElementType((XPathQName)null); | |
return buildIntoNestedRow(nestedRecord, object, session); | |
} | |
} | |
Element newNode = XPathEngine.getInstance().createUnownedElement(parentRecord.getDOM(), (Field)xmlField); | |
XMLRecord nestedRecord = new DOMRecord(newNode); | |
nestedRecord.setNamespaceResolver(parentRecord.getNamespaceResolver()); | |
nestedRecord.setMarshaller(parentRecord.getMarshaller()); | |
nestedRecord.setLeafElementType(parentRecord.getLeafElementType()); | |
parentRecord.setLeafElementType((XPathQName)null); | |
return buildIntoNestedRow(nestedRecord, object, session); | |
} | |
/** | |
* Create a new row/record for the object builder. | |
* This allows subclasses to define different record types. | |
*/ | |
public AbstractRecord createRecord(AbstractSession session) { | |
return (AbstractRecord) createRecord(getDescriptor().getTableName(), session); | |
} | |
/** | |
* Create a new row/record for the object builder. | |
* This allows subclasses to define different record types. | |
*/ | |
public AbstractRecord createRecord(int size, AbstractSession session) { | |
return (AbstractRecord) createRecord(getDescriptor().getTableName(), session); | |
} | |
/** | |
* Create a new row/record for the object builder with the given name. This | |
* allows subclasses to define different record types. | |
*/ | |
public AbstractMarshalRecord createRecord(String rootName, AbstractSession session) { | |
NamespaceResolver namespaceResolver = getNamespaceResolver(); | |
XMLRecord xmlRec = new DOMRecord(rootName, namespaceResolver); | |
xmlRec.setSession(session); | |
return xmlRec; | |
} | |
/** | |
* Create a new row/record for the object builder with the given name and | |
* namespace resolver instead of the namespace resolver from the descriptor. | |
* This allows subclasses to define different record types. | |
*/ | |
public AbstractRecord createRecord(String rootName, String rootUri, AbstractSession session) { | |
XMLRecord xmlRec = new DOMRecord(rootName, rootUri); | |
xmlRec.setSession(session); | |
return xmlRec; | |
} | |
/** | |
* Create a new row/record for the object builder with the given name. This | |
* allows subclasses to define different record types. | |
*/ | |
public AbstractMarshalRecord createRecord(String rootName, Node parent, AbstractSession session) { | |
NamespaceResolver namespaceResolver = getNamespaceResolver(); | |
XMLRecord xmlRec = new DOMRecord(rootName, namespaceResolver, parent); | |
xmlRec.setSession(session); | |
return xmlRec; | |
} | |
public AbstractRecord createRecordFor(Object attributeValue, Field xmlField, XMLRecord parentRecord, Mapping mapping) { | |
DocumentPreservationPolicy policy = parentRecord.getDocPresPolicy(); | |
Element newNode = null; | |
if(policy != null) { | |
newNode = (Element)policy.getNodeForObject(attributeValue); | |
} | |
if(newNode == null) { | |
newNode = XPathEngine.getInstance().createUnownedElement(parentRecord.getDOM(), xmlField); | |
if(policy !=null ){ | |
if(xmlField.isSelfField()) { | |
policy.addObjectToCache(attributeValue, newNode, mapping); | |
} else { | |
policy.addObjectToCache(attributeValue, newNode); | |
} | |
} | |
} | |
DOMRecord nestedRecord = new DOMRecord(newNode); | |
nestedRecord.setMarshaller(parentRecord.getMarshaller()); | |
nestedRecord.setLeafElementType(parentRecord.getLeafElementType()); | |
parentRecord.setLeafElementType((XPathQName)null); | |
nestedRecord.setDocPresPolicy(policy); | |
nestedRecord.setXOPPackage(parentRecord.isXOPPackage()); | |
nestedRecord.setReferenceResolver(((DOMRecord) parentRecord).getReferenceResolver()); | |
return nestedRecord; | |
} | |
public AbstractRecord createRecordFor(Object object, DocumentPreservationPolicy docPresPolicy) { | |
Element cachedNode = null; | |
XMLRecord record = null; | |
if(docPresPolicy != null) { | |
cachedNode = (Element)docPresPolicy.getNodeForObject(object); | |
} | |
if(cachedNode == null) { | |
record = new DOMRecord(getDescriptor().getTableName(), getNamespaceResolver()); | |
docPresPolicy.addObjectToCache(object, record.getDOM()); | |
} else { | |
record = new DOMRecord(cachedNode); | |
} | |
record.setDocPresPolicy(docPresPolicy); | |
return record; | |
} | |
public AbstractRecord createRecordFor(Object object, DocumentPreservationPolicy docPresPolicy, String rootName, String rootUri) { | |
Element cachedNode = null; | |
XMLRecord record = null; | |
if(docPresPolicy != null) { | |
cachedNode = (Element)docPresPolicy.getNodeForObject(object); | |
} | |
if(cachedNode == null) { | |
record = new DOMRecord(rootName, rootUri); | |
docPresPolicy.addObjectToCache(object, record.getDOM()); | |
} else { | |
record = new DOMRecord(cachedNode); | |
} | |
record.setDocPresPolicy(docPresPolicy); | |
return record; | |
} | |
/** | |
* Create a new row/record for the object builder. This allows subclasses to | |
* define different record types. This will typically be called when a | |
* record will be used for temporarily holding on to primary key fields. | |
*/ | |
protected AbstractRecord createRecordForPKExtraction(int size, AbstractSession session) { | |
NamespaceResolver namespaceResolver = getNamespaceResolver(); | |
XMLRecord xmlRec = new DOMRecord(getDescriptor().getTableName(), namespaceResolver); | |
xmlRec.setSession(session); | |
return xmlRec; | |
} | |
/** | |
* INTERNAL: Override the parent's buildObject to allow for the caching of | |
* aggregate objects in OX. By caching aggregates along with XML Nodes that | |
* they were created from, we are able to preserve the structure and | |
* unmapped content of the document that was used to create these objects. | |
*/ | |
@Override | |
public Object buildObject(ObjectBuildingQuery query, AbstractRecord databaseRow, JoinedAttributeManager joinManager) throws DatabaseException, QueryException { | |
XMLRecord row = (XMLRecord) databaseRow; | |
row.setSession(query.getSession()); | |
XMLUnmarshaller unmarshaller = row.getUnmarshaller(); | |
Object parent = row.getOwningObject(); | |
if (!(isXmlDescriptor() || getDescriptor().isDescriptorTypeAggregate())) { | |
return super.buildObject(query, databaseRow, joinManager); | |
} | |
query.getSession().startOperationProfile(SessionProfiler.ObjectBuilding, query, SessionProfiler.ALL); | |
ClassDescriptor concreteDescriptor = getDescriptor(); | |
Object domainObject = null; | |
// only need to check in the root case since the nested case is handled | |
// in the mapping | |
if (concreteDescriptor.hasInheritance() && (parent == null)) { | |
// look for an xsi:type attribute in the xml document | |
InheritancePolicy inheritancePolicy = concreteDescriptor.getInheritancePolicy(); | |
Class classValue = inheritancePolicy.classFromRow(databaseRow, query.getSession()); | |
if ((classValue == null) && isXmlDescriptor()) { | |
// no xsi:type attribute - look for type indicator on the | |
// default root element | |
QName leafElementType = ((Descriptor) concreteDescriptor).getDefaultRootElementType(); | |
// if we have a user-set type, try to get the class from the | |
// inheritance policy | |
if (leafElementType != null) { | |
XPathQName xpathQName = new XPathQName(leafElementType, row.isNamespaceAware()); | |
Object indicator = inheritancePolicy.getClassIndicatorMapping().get(xpathQName); | |
if (indicator != null) { | |
classValue = (Class) indicator; | |
} | |
} | |
} | |
// if we found the class, use it - otherwise, use the descriptor | |
// class, if non-abstract | |
if (classValue != null) { | |
concreteDescriptor = query.getSession().getDescriptor(classValue); | |
if ((concreteDescriptor == null) && query.hasPartialAttributeExpressions()) { | |
concreteDescriptor = getDescriptor(); | |
} | |
if (concreteDescriptor == null) { | |
throw QueryException.noDescriptorForClassFromInheritancePolicy(query, classValue); | |
} | |
} else { | |
// make sure the class is non-abstract | |
if (Modifier.isAbstract(concreteDescriptor.getJavaClass().getModifiers())) { | |
// throw an exception | |
throw DescriptorException.missingClassIndicatorField(databaseRow, inheritancePolicy.getDescriptor()); | |
} | |
} | |
} | |
domainObject = concreteDescriptor.getObjectBuilder().buildNewInstance(); | |
row.setCurrentObject(domainObject); | |
if ((unmarshaller != null) && (unmarshaller.getUnmarshalListener() != null)) { | |
unmarshaller.getUnmarshalListener().beforeUnmarshal(domainObject, parent); | |
} | |
concreteDescriptor.getObjectBuilder().buildAttributesIntoObject(domainObject, null, databaseRow, query, joinManager, null, false, query.getSession()); | |
if (isXmlDescriptor() && ((Descriptor) concreteDescriptor).getPrimaryKeyFieldNames().size() > 0) { | |
Object pk = extractPrimaryKeyFromRow(databaseRow, query.getSession()); | |
if ((pk != null) && (((CacheId) pk).getPrimaryKey().length > 0)) { | |
DOMRecord domRecord = (DOMRecord) databaseRow; | |
domRecord.getReferenceResolver().putValue(concreteDescriptor.getJavaClass(), pk, domainObject); | |
} | |
} | |
DocumentPreservationPolicy docPresPolicy = ((DOMRecord) row).getDocPresPolicy(); | |
if (docPresPolicy != null) { | |
// EIS XML Cases won't have a doc pres policy set | |
((DOMRecord) row).getDocPresPolicy().addObjectToCache(domainObject, ((DOMRecord) row).getDOM()); | |
} | |
query.getSession().endOperationProfile(SessionProfiler.ObjectBuilding, query, SessionProfiler.ALL); | |
if ((unmarshaller != null) && (unmarshaller.getUnmarshalListener() != null)) { | |
unmarshaller.getUnmarshalListener().afterUnmarshal(domainObject, parent); | |
} | |
return domainObject; | |
} | |
public AbstractRecord buildRow(AbstractRecord databaseRow, Object object, AbstractSession session) { | |
return buildRow(databaseRow, object, session, false); | |
} | |
public AbstractRecord buildRow(AbstractRecord databaseRow, Object object, AbstractSession session, boolean wasXMLRoot) { | |
XMLRecord row = (XMLRecord)databaseRow; | |
row.setSession(session); | |
XMLMarshaller marshaller = row.getMarshaller(); | |
if ((marshaller != null) && (marshaller.getMarshalListener() != null)) { | |
marshaller.getMarshalListener().beforeMarshal(object); | |
} | |
addNamespaceDeclarations((row).getDocument()); | |
writeOutMappings(row, object, session); | |
// If this descriptor has multiple tables then we need to append the | |
// primary keys for | |
// the non default tables. | |
if (!getDescriptor().isAggregateDescriptor()) { | |
addPrimaryKeyForNonDefaultTable(row); | |
} | |
if ((marshaller != null) && (marshaller.getMarshalListener() != null)) { | |
marshaller.getMarshalListener().afterMarshal(object); | |
} | |
return row; | |
} | |
public void writeOutMappings(XMLRecord row, Object object, AbstractSession session) { | |
List<DatabaseMapping> mappings = getDescriptor().getMappings(); | |
for (int index = 0; index < mappings.size(); index++) { | |
DatabaseMapping mapping = mappings.get(index); | |
mapping.writeFromObjectIntoRow(object, row, session, WriteType.UNDEFINED); | |
} | |
} | |
public void addNamespaceDeclarations(Document document) { | |
NamespaceResolver namespaceResolver = getNamespaceResolver(); | |
if (namespaceResolver == null) { | |
return; | |
} | |
Element docElement = document.getDocumentElement(); | |
if(namespaceResolver.getDefaultNamespaceURI() != null) { | |
docElement.setAttributeNS(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI, javax.xml.XMLConstants.XMLNS_ATTRIBUTE, namespaceResolver.getDefaultNamespaceURI()); | |
} | |
Enumeration prefixes = namespaceResolver.getPrefixes(); | |
String prefix; | |
String namespace; | |
while (prefixes.hasMoreElements()) { | |
prefix = (String)prefixes.nextElement(); | |
namespace = namespaceResolver.resolveNamespacePrefix(prefix); | |
docElement.setAttributeNS(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI, javax.xml.XMLConstants.XMLNS_ATTRIBUTE + Constants.COLON + prefix, namespace); | |
} | |
} | |
/** | |
* Override method in superclass in order to set the session on the record. | |
* Each mapping is recursed to assign values from the Record to the attributes in the domain object. | |
*/ | |
@Override | |
public void buildAttributesIntoObject(Object domainObject, CacheKey cacheKey, AbstractRecord databaseRow, ObjectBuildingQuery query, JoinedAttributeManager joinManager, FetchGroup executionFetchGroup, boolean forRefresh, AbstractSession targetSession) throws DatabaseException { | |
((XMLRecord)databaseRow).setSession(query.getSession().getExecutionSession(query)); | |
super.buildAttributesIntoObject(domainObject, cacheKey, databaseRow, query, joinManager, executionFetchGroup, forRefresh, targetSession); | |
} | |
/** | |
* Override method in superclass in order to set the session on the record. | |
* Return the row with primary keys and their values from the given expression. | |
*/ | |
public AbstractRecord extractPrimaryKeyRowFromExpression(Expression expression, AbstractRecord translationRow, AbstractSession session) { | |
AbstractRecord primaryKeyRow = createRecord(getPrimaryKeyMappings().size(), session); | |
expression.getBuilder().setSession(session.getRootSession(null)); | |
// Get all the field & values from expression | |
boolean isValid = expression.extractPrimaryKeyValues(true, getDescriptor(), primaryKeyRow, translationRow); | |
if (!isValid) { | |
return null; | |
} | |
// Check that the sizes match up | |
if (primaryKeyRow.size() != getDescriptor().getPrimaryKeyFields().size()) { | |
return null; | |
} | |
return primaryKeyRow; | |
} | |
/** | |
* Override method in superclass in order to set the session on the record. | |
* Return the row with primary keys and their values from the given expression. | |
*/ | |
@Override | |
public Object extractPrimaryKeyFromExpression(boolean requiresExactMatch, Expression expression, AbstractRecord translationRow, AbstractSession session) { | |
AbstractRecord primaryKeyRow = createRecord(getPrimaryKeyMappings().size(), session); | |
expression.getBuilder().setSession(session.getRootSession(null)); | |
// Get all the field & values from expression. | |
boolean isValid = expression.extractPrimaryKeyValues(requiresExactMatch, getDescriptor(), primaryKeyRow, translationRow); | |
if (requiresExactMatch && (!isValid)) { | |
return null; | |
} | |
// Check that the sizes match. | |
if (primaryKeyRow.size() != getDescriptor().getPrimaryKeyFields().size()) { | |
return null; | |
} | |
return extractPrimaryKeyFromRow(primaryKeyRow, session); | |
} | |
@Override | |
public Object extractPrimaryKeyFromObject(Object domainObject, AbstractSession session) { | |
if (getDescriptor().hasInheritance() && (domainObject.getClass() != getDescriptor().getJavaClass()) && (!domainObject.getClass().getSuperclass().equals(getDescriptor().getJavaClass()))) { | |
return session.getDescriptor(domainObject.getClass()).getObjectBuilder().extractPrimaryKeyFromObject(domainObject, session); | |
} | |
List<DatabaseField> descriptorPrimaryKeyFields = getDescriptor().getPrimaryKeyFields(); | |
if (null == descriptorPrimaryKeyFields || descriptorPrimaryKeyFields.size() == 0) { | |
return null; | |
} | |
return super.extractPrimaryKeyFromObject(domainObject, session); | |
} | |
public AbstractRecord buildIntoNestedRow(AbstractRecord row, Object object, AbstractSession session) { | |
return buildIntoNestedRow(row, null, object, session, null, null, false); | |
} | |
public AbstractRecord buildIntoNestedRow(AbstractRecord row, Object object, AbstractSession session, Descriptor refDesc, Field xmlField) { | |
return buildIntoNestedRow(row, null, object, session, refDesc, xmlField, false); | |
} | |
public AbstractRecord buildIntoNestedRow(AbstractRecord row, Object originalObject, Object object, AbstractSession session, Descriptor refDesc, Field xmlField, boolean wasXMLRoot) { | |
// PERF: Avoid synchronized enumerator as is concurrency bottleneck. | |
XMLRecord record = (XMLRecord)row; | |
record.setSession(session); | |
XMLMarshaller marshaller = record.getMarshaller(); | |
if ((marshaller != null) && (marshaller.getMarshalListener() != null)) { | |
marshaller.getMarshalListener().beforeMarshal(object); | |
} | |
List extraNamespaces = null; | |
if (isXmlDescriptor()) { | |
Descriptor xmlDescriptor = (Descriptor)getDescriptor(); | |
extraNamespaces = addExtraNamespacesToNamespaceResolver(xmlDescriptor, record, session, false, false); | |
writeExtraNamespaces(extraNamespaces, record); | |
record.addXsiTypeAndClassIndicatorIfRequired(xmlDescriptor, refDesc, xmlField, originalObject, object, wasXMLRoot, false); | |
} | |
writeOutMappings(record, object, session); | |
// If this descriptor is involved in inheritance add the class type. | |
if (isXmlDescriptor()) { | |
record.removeExtraNamespacesFromNamespaceResolver(extraNamespaces, session); | |
} | |
// If this descriptor has multiple tables then we need to append the | |
// primary keys for | |
// the non default tables. | |
if (!getDescriptor().isAggregateDescriptor()) { | |
addPrimaryKeyForNonDefaultTable(row); | |
} | |
if ((marshaller != null) && (marshaller.getMarshalListener() != null)) { | |
marshaller.getMarshalListener().afterMarshal(object); | |
} | |
return row; | |
} | |
public NamespaceResolver getNamespaceResolver() { | |
NamespaceResolver namespaceResolver = null; | |
if (isXmlDescriptor()) { | |
namespaceResolver = ((XMLDescriptor)getDescriptor()).getNamespaceResolver(); | |
} else if (getDescriptor() instanceof org.eclipse.persistence.eis.EISDescriptor) { | |
namespaceResolver = ((org.eclipse.persistence.eis.EISDescriptor)getDescriptor()).getNamespaceResolver(); | |
} | |
return namespaceResolver; | |
} | |
/** | |
* Indicates if the object builder's descriptor is an XMLDescriptor. | |
* The value is lazily initialized. | |
* | |
* @return | |
*/ | |
protected boolean isXmlDescriptor() { | |
if (isXMLDescriptor == null) { | |
isXMLDescriptor = getDescriptor() instanceof Descriptor; | |
} | |
return isXMLDescriptor.booleanValue(); | |
} | |
/** | |
* Set the descriptor. This method is overridden so the | |
* isXMLDescriptor Boolean can be reset. | |
*/ | |
public void setDescriptor(ClassDescriptor aDescriptor) { | |
super.setDescriptor(aDescriptor); | |
isXMLDescriptor = null; | |
} | |
protected List<Namespace> addExtraNamespacesToNamespaceResolver(Descriptor desc, AbstractMarshalRecord marshalRecord, CoreAbstractSession session, boolean allowOverride, boolean ignoreEqualResolvers) { | |
return marshalRecord.addExtraNamespacesToNamespaceResolver(desc, session, allowOverride, ignoreEqualResolvers); | |
} | |
public void writeExtraNamespaces(List extraNamespaces, XMLRecord xmlRecord) { | |
if(extraNamespaces == null){ | |
return; | |
} | |
if(xmlRecord.getDOM().getNodeType() != Node.ELEMENT_NODE) { | |
return; | |
} | |
for (int i = 0; i < extraNamespaces.size(); i++) { | |
Namespace next = (Namespace)extraNamespaces.get(i); | |
((Element)xmlRecord.getDOM()).setAttributeNS(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI, javax.xml.XMLConstants.XMLNS_ATTRIBUTE + Constants.COLON + next.getPrefix(), next.getNamespaceURI()); | |
} | |
} | |
public void initialize(AbstractSession session) throws DescriptorException { | |
mappingsByField.clear(); | |
if(null != readOnlyMappingsByField) { | |
readOnlyMappingsByField.clear(); | |
} | |
if(null != mappingsByAttribute) { | |
mappingsByAttribute.clear(); | |
} | |
cloningMappings.clear(); | |
if(null != eagerMappings) { | |
eagerMappings.clear(); | |
} | |
if(null != relationshipMappings) { | |
relationshipMappings.clear(); | |
} | |
for (Enumeration mappings = this.descriptor.getMappings().elements(); | |
mappings.hasMoreElements();) { | |
DatabaseMapping mapping = (DatabaseMapping)mappings.nextElement(); | |
// Add attribute to mapping association | |
if (!mapping.isWriteOnly()) { | |
if(mappingsByAttribute != null) { | |
getMappingsByAttribute().put(mapping.getAttributeName(), mapping); | |
} | |
} | |
// Cache mappings that require cloning. | |
if (mapping.isCloningRequired()) { | |
getCloningMappings().add(mapping); | |
} | |
// Cache eager mappings. | |
if (mapping.isForeignReferenceMapping() && ((ForeignReferenceMapping)mapping).usesIndirection() && (!mapping.isLazy())) { | |
getEagerMappings().add(mapping); | |
} | |
// Cache relationship mappings. | |
if (!mapping.isDirectToFieldMapping()) { | |
if(null != relationshipMappings) { | |
relationshipMappings.add(mapping); | |
} | |
} | |
// Add field to mapping association | |
for (DatabaseField field : mapping.getFields()) { | |
if (mapping.isReadOnly()) { | |
if(null != readOnlyMappingsByField) { | |
List readOnlyMappings = getReadOnlyMappingsByField().get(field); | |
if (readOnlyMappings == null) { | |
readOnlyMappings = new ArrayList(); | |
getReadOnlyMappingsByField().put(field, readOnlyMappings); | |
} | |
readOnlyMappings.add(mapping); | |
} | |
} else { | |
if (mapping.isAggregateObjectMapping()) { | |
// For Embeddable class, we need to test read-only | |
// status of individual fields in the embeddable. | |
ObjectBuilder aggregateObjectBuilder = ((AggregateObjectMapping)mapping).getReferenceDescriptor().getObjectBuilder(); | |
// Look in the non-read-only fields mapping | |
DatabaseMapping aggregatedFieldMapping = aggregateObjectBuilder.getMappingForField(field); | |
if (aggregatedFieldMapping == null) { // mapping must be read-only | |
List readOnlyMappings = getReadOnlyMappingsByField().get(field); | |
if (readOnlyMappings == null) { | |
readOnlyMappings = new ArrayList(); | |
getReadOnlyMappingsByField().put(field, readOnlyMappings); | |
} | |
readOnlyMappings.add(mapping); | |
} else { | |
getMappingsByField().put(field, mapping); | |
} | |
} else { // Not an embeddable mapping | |
if (!getMappingsByField().containsKey(field)) { | |
getMappingsByField().put(field, mapping); | |
} | |
} | |
} | |
} | |
} | |
this.isSimple = null == relationshipMappings || relationshipMappings.isEmpty(); | |
initializePrimaryKey(session); | |
initializeJoinedAttributes(); | |
if (this.descriptor.usesSequenceNumbers()) { | |
DatabaseMapping sequenceMapping = getMappingForField(this.descriptor.getSequenceNumberField()); | |
if ((sequenceMapping != null) && sequenceMapping.isDirectToFieldMapping()) { | |
setSequenceMapping((AbstractDirectMapping)sequenceMapping); | |
} | |
} | |
if (descriptor.hasInheritance() ) { | |
Field indicatorField = (Field) descriptor.getInheritancePolicy().getClassIndicatorField(); | |
if(indicatorField != null){ | |
if (indicatorField.getLastXPathFragment().getNamespaceURI() != null && indicatorField.getLastXPathFragment().getNamespaceURI().equals(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI) | |
&& indicatorField.getLastXPathFragment().getLocalName().equals(Constants.SCHEMA_TYPE_ATTRIBUTE)){ | |
xsiTypeIndicatorField = true; | |
} | |
} | |
} | |
} | |
public boolean isXMLObjectBuilder() { | |
return true; | |
} | |
public boolean isXsiTypeIndicatorField() { | |
return xsiTypeIndicatorField; | |
} | |
} |