/******************************************************************************* * Copyright (c) 1998, 2015 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.ArrayList; import java.util.HashMap; import java.util.List; import org.eclipse.persistence.core.descriptors.CoreInheritancePolicy; import org.eclipse.persistence.descriptors.ClassDescriptor; import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession; import org.eclipse.persistence.internal.helper.DatabaseField; import org.eclipse.persistence.internal.oxm.mappings.Descriptor; import org.eclipse.persistence.internal.oxm.mappings.Field; import org.eclipse.persistence.internal.oxm.record.AbstractMarshalRecord; import org.eclipse.persistence.internal.oxm.record.MarshalRecord; import org.eclipse.persistence.internal.oxm.record.XMLRecord; import org.eclipse.persistence.internal.sessions.AbstractRecord; import org.eclipse.persistence.internal.sessions.AbstractSession; import org.eclipse.persistence.mappings.DatabaseMapping; import org.eclipse.persistence.mappings.DatabaseMapping.WriteType; import org.eclipse.persistence.oxm.XMLField; import org.eclipse.persistence.oxm.record.NodeRecord; import org.eclipse.persistence.oxm.record.UnmarshalRecord; import org.w3c.dom.Document; import org.w3c.dom.Node; /** * INTERNAL: * <p><b>Purpose</b>: Perform the unmarshal and marshal operations based on the * object-to-XML mapping metadata.</p> * <p><b>Responsibilities</b>:<ul> * <li>Convert mapping metadata to a tree of XPathNodes. This tree is then * traversed during unmarshal and marshal operations.</li> * <li>Create records appropriate to this implementation of ObjectBuilder.</li> * </ul> */ public class TreeObjectBuilder extends XMLObjectBuilder implements ObjectBuilder<AbstractRecord, AbstractSession, ClassDescriptor, XMLMarshaller> { private XPathObjectBuilder xPathObjectBuilder; public TreeObjectBuilder(ClassDescriptor descriptor) { super(descriptor); xPathObjectBuilder = new XPathObjectBuilder(descriptor); } @Override protected void initialize(ClassDescriptor descriptor) { int descriptorMappingsSize = descriptor.getMappings().size(); this.mappingsByField = new HashMap(descriptorMappingsSize); this.fieldsMap = new HashMap(descriptorMappingsSize); this.cloningMappings = new ArrayList(descriptorMappingsSize); } public XPathNode getRootXPathNode() { return xPathObjectBuilder.getRootXPathNode(); } @Override public List<DatabaseMapping> getPrimaryKeyMappings() { if(null == primaryKeyMappings) { primaryKeyMappings = new ArrayList<DatabaseMapping>(1); } return primaryKeyMappings; } public List getTransformationMappings() { return xPathObjectBuilder.getTransformationMappings(); } public List getContainerValues() { return xPathObjectBuilder.getContainerValues(); } public List getNullCapableValues() { return xPathObjectBuilder.getNullCapableValues(); } public List getDefaultEmptyContainerValues() { return xPathObjectBuilder.getDefaultEmptyContainerValues(); } public void initialize(org.eclipse.persistence.internal.sessions.AbstractSession session) { super.initialize(session); Descriptor xmlDescriptor = (Descriptor)getDescriptor(); // INHERITANCE if (xmlDescriptor.hasInheritance()) { CoreInheritancePolicy inheritancePolicy = xmlDescriptor.getInheritancePolicy(); if (!inheritancePolicy.hasClassExtractor()) { Field classIndicatorField = new XMLField(inheritancePolicy.getClassIndicatorFieldName()); classIndicatorField.setNamespaceResolver(xmlDescriptor.getNamespaceResolver()); } } if(!xmlDescriptor.isLazilyInitialized()) { xPathObjectBuilder.lazyInitialize(); } } @Override public AbstractRecord buildRow(AbstractRecord record, Object object, org.eclipse.persistence.internal.sessions.AbstractSession session, WriteType writeType) { return (AbstractRecord) buildRow((XMLRecord) record, object, session, null, null); } public org.eclipse.persistence.internal.oxm.record.XMLRecord buildRow(org.eclipse.persistence.internal.oxm.record.XMLRecord record, Object object, CoreAbstractSession session, XMLMarshaller marshaller, XPathFragment rootFragment) { return xPathObjectBuilder.buildRow(record, object, session, marshaller, rootFragment); } public boolean marshalAttributes(MarshalRecord marshalRecord, Object object, CoreAbstractSession session) { return xPathObjectBuilder.marshalAttributes(marshalRecord, object, session); } /** * Create a new row/record for the object builder. * This allows subclasses to define different record types. */ public AbstractRecord createRecord(AbstractSession session) { xPathObjectBuilder.lazyInitialize(); org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl uRec = new org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl(this); uRec.setSession(session); return new UnmarshalRecord(uRec); } /** * 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) { NodeRecord nRec = new NodeRecord(rootName, getNamespaceResolver()); nRec.setSession(session); return nRec; } /** * 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) { NodeRecord nRec = new NodeRecord(rootName, getNamespaceResolver(), parent); nRec.setSession(session); return nRec; } /** * 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 createRecord(session); } @Override public List addExtraNamespacesToNamespaceResolver(Descriptor desc, AbstractMarshalRecord marshalRecord, CoreAbstractSession session, boolean allowOverride, boolean ignoreEqualResolvers) { return xPathObjectBuilder.addExtraNamespacesToNamespaceResolver(desc, marshalRecord, session, allowOverride, ignoreEqualResolvers); } @Override public boolean addClassIndicatorFieldToRow(AbstractMarshalRecord abstractMarshalRecord) { if (descriptor.hasInheritance() && !xPathObjectBuilder.isXsiTypeIndicatorField()) { InheritanceRecord inheritanceRecord = new InheritanceRecord(abstractMarshalRecord); descriptor.getInheritancePolicy().addClassIndicatorFieldToRow(inheritanceRecord); return true; } return false; } @Override public Class classFromRow(org.eclipse.persistence.internal.oxm.record.UnmarshalRecord unmarshalRecord, AbstractSession session) { UnmarshalRecord inheritanceRecord = new UnmarshalRecord(unmarshalRecord); return descriptor.getInheritancePolicy().classFromRow(inheritanceRecord, session); } private static class InheritanceRecord extends org.eclipse.persistence.oxm.record.XMLRecord { private AbstractMarshalRecord abstractMarshalRecord; public InheritanceRecord(AbstractMarshalRecord abstractMarshalRecord) { this.abstractMarshalRecord = abstractMarshalRecord; } @Override public String getLocalName() { throw new UnsupportedOperationException(); } @Override public String getNamespaceURI() { throw new UnsupportedOperationException(); } @Override public void clear() { throw new UnsupportedOperationException(); } @Override public Document getDocument() { throw new UnsupportedOperationException(); } @Override public Node getDOM() { throw new UnsupportedOperationException(); } @Override public String transformToXML() { throw new UnsupportedOperationException(); } @Override public boolean isNamespaceAware() { return abstractMarshalRecord.isNamespaceAware(); } @Override public boolean hasCustomNamespaceMapper() { return abstractMarshalRecord.hasCustomNamespaceMapper(); } @Override public char getNamespaceSeparator() { return abstractMarshalRecord.getNamespaceSeparator(); } @Override public Object put(DatabaseField key, Object value) { return abstractMarshalRecord.put(key, value); } } }