All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.internal.oxm.QNameInheritancePolicy Maven / Gradle / Ivy

There is a newer version: 5.0.0-B03
Show newest version
/*
 * Copyright (c) 1998, 2021 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 java.util.Iterator;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import javax.xml.namespace.QName;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.InheritancePolicy;
import org.eclipse.persistence.descriptors.MultitenantPolicy;
import org.eclipse.persistence.exceptions.DescriptorException;
import org.eclipse.persistence.internal.core.helper.CoreClassConstants;
import org.eclipse.persistence.internal.core.helper.CoreField;
import org.eclipse.persistence.internal.helper.DatabaseTable;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.oxm.NamespaceResolver;
import org.eclipse.persistence.oxm.XMLDescriptor;
import org.eclipse.persistence.oxm.XMLField;
import org.eclipse.persistence.oxm.record.XMLRecord;

/**
 * INTERNAL:
 * 

Purpose: A Subclass of Inheritance Policy to be used with XML * Descriptors. If the class indicator field is an xsi:type, the value of that * field may be a qualified type name. For example xsi:type="myns:my-type-name". * Since any given XML document can use different prefixes for these namespaces, * we must be able to find the class based on QName instead of just the string * "myns:my-type-name".

* @author mmacivor * @since 10.1.3 */ public class QNameInheritancePolicy extends InheritancePolicy { //used for initialization. Prefixed type names will be changed to QNames. private NamespaceResolver namespaceResolver; private boolean usesXsiType = false; public QNameInheritancePolicy() { super(); } public QNameInheritancePolicy(ClassDescriptor desc) { super(desc); } /** * Override to control order of uniqueTables, child tablenames should be first since * getDefaultRootElement on an XMLDescriptor will return the first table. */ @Override protected void updateTables(){ // Unique is required because the builder can add the same table many times. Vector childTables = getDescriptor().getTables(); Vector parentTables = getParentDescriptor().getTables(); Vector uniqueTables = Helper.concatenateUniqueVectors(childTables, parentTables); getDescriptor().setTables(uniqueTables); if(getDescriptor().isXMLDescriptor() && getParentDescriptor().isXMLDescriptor()){ if(((XMLDescriptor)getDescriptor()).getDefaultRootElementField() == null){ ((XMLDescriptor)getDescriptor()).setDefaultRootElementField(((XMLDescriptor)getParentDescriptor()).getDefaultRootElementField()); } } // After filtering out any duplicate tables, set the default table // if one is not already set. This must be done now before any other // initialization occurs. In a joined strategy case, the default // table will be at an index greater than 0. Which is where // setDefaultTable() assumes it is. Therefore, we need to send the // actual default table instead. if (childTables.isEmpty()) { getDescriptor().setInternalDefaultTable(); } else { getDescriptor().setInternalDefaultTable(uniqueTables.get(uniqueTables.indexOf(childTables.get(0)))); } } /** * INTERNAL: * Allow the inheritance properties of the descriptor to be initialized. * The descriptor's parent must first be initialized. */ @Override public void preInitialize(AbstractSession session) throws DescriptorException { // Override for OXM inheritence to avoid initializing unrequired fields // on the descriptor if (isChildDescriptor()) { updateTables(); // Clone the multitenant policy and set on child descriptor. if (getParentDescriptor().hasMultitenantPolicy()) { MultitenantPolicy clonedMultitenantPolicy = getParentDescriptor().getMultitenantPolicy().clone(getDescriptor()); getDescriptor().setMultitenantPolicy(clonedMultitenantPolicy); } setClassIndicatorMapping(getParentDescriptor().getInheritancePolicy().getClassIndicatorMapping()); setShouldUseClassNameAsIndicator(getParentDescriptor().getInheritancePolicy().shouldUseClassNameAsIndicator()); // Initialize properties. getDescriptor().setPrimaryKeyFields(getParentDescriptor().getPrimaryKeyFields()); getDescriptor().setAdditionalTablePrimaryKeyFields(Helper.concatenateMaps(getParentDescriptor().getAdditionalTablePrimaryKeyFields(), getDescriptor().getAdditionalTablePrimaryKeyFields())); setClassIndicatorField(getParentDescriptor().getInheritancePolicy().getClassIndicatorField()); //if child has sequencing setting, do not bother to call the parent if (!getDescriptor().usesSequenceNumbers()) { getDescriptor().setSequenceNumberField(getParentDescriptor().getSequenceNumberField()); getDescriptor().setSequenceNumberName(getParentDescriptor().getSequenceNumberName()); } } else { // This must be done now before any other initialization occurs. getDescriptor().setInternalDefaultTable(); } initializeClassExtractor(session); if (!isChildDescriptor()) { // build abstract class indicator field. if ((getClassIndicatorField() == null) && (!hasClassExtractor())) { session.getIntegrityChecker().handleError(DescriptorException.classIndicatorFieldNotFound(getDescriptor(), getDescriptor())); } if (getClassIndicatorField() != null) { setClassIndicatorField(getDescriptor().buildField(getClassIndicatorField())); // Determine and set the class indicator classification. if (shouldUseClassNameAsIndicator()) { getClassIndicatorField().setType(CoreClassConstants.STRING); } else if (!getClassIndicatorMapping().isEmpty()) { Class type = null; Iterator fieldValuesEnum = getClassIndicatorMapping().values().iterator(); while (fieldValuesEnum.hasNext() && (type == null)) { Object value = fieldValuesEnum.next(); if (value.getClass() != getClass().getClass()) { type = value.getClass(); } } getClassIndicatorField().setType(type); } getDescriptor().getFields().addElement(getClassIndicatorField()); } } } /** * INTERNAL: * Initialized the inheritance properties of the descriptor once the mappings are initialized. * This is done before formal postInitialize during the end of mapping initialize. */ @Override public void initialize(AbstractSession session) { super.initialize(session); // If we have a namespace resolver, check any of the class-indicator values // for prefixed type names and resolve the namespaces. if (!this.shouldUseClassNameAsIndicator()){ if(classIndicatorField != null){ XPathFragment frag = ((XMLField) classIndicatorField).getXPathFragment(); if (frag.getLocalName().equals(Constants.SCHEMA_TYPE_ATTRIBUTE) && javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(frag.getNamespaceURI())) { usesXsiType = true; } } // Must first clone the map to avoid concurrent modification. Iterator entries = new HashMap(getClassIndicatorMapping()).entrySet().iterator(); while (entries.hasNext()) { Map.Entry entry = entries.next(); Object key = entry.getKey(); if (key instanceof String) { XPathQName qname; String indicatorValue = (String) key; if (!usesXsiType || namespaceResolver == null) { qname = new XPathQName(indicatorValue, true); } else { int index = indicatorValue.indexOf(Constants.COLON); if (index != -1 && namespaceResolver != null) { String prefix = indicatorValue.substring(0, index); String localPart = indicatorValue.substring(index + 1); String uri = namespaceResolver.resolveNamespacePrefix(prefix); qname = new XPathQName(uri, localPart, true); } else { qname = new XPathQName(namespaceResolver.getDefaultNamespaceURI(), indicatorValue, true); } } getClassIndicatorMapping().put(qname, entry.getValue()); } else if (key instanceof QName) { XPathQName xpathQName = new XPathQName((QName) key, true); getClassIndicatorMapping().put(xpathQName, entry.getValue()); } } } //bug 6012173 - changed to initialize namespare uri on indicator field //need to be able to compare uri and local name during marshal to see if field is xsi type field if(getClassIndicatorField() != null){ XMLField classIndicatorXMLField; try { classIndicatorXMLField = (XMLField)getClassIndicatorField(); } catch (ClassCastException ex) { classIndicatorXMLField = new XMLField(getClassIndicatorField().getName()); setClassIndicatorField(classIndicatorXMLField); } XPathFragment frag = classIndicatorXMLField.getLastXPathFragment(); if ((frag != null) && frag.hasNamespace() && frag.getPrefix() !=null && (namespaceResolver != null)) { String uri = namespaceResolver.resolveNamespacePrefix(frag.getPrefix()); classIndicatorXMLField.getLastXPathFragment().setNamespaceURI(uri); } } } /** * INTERNAL: * This method is invoked only for the abstract descriptors. */ @Override public Class classFromRow(AbstractRecord rowFromDatabase, AbstractSession session) throws DescriptorException { ((XMLRecord) rowFromDatabase).setSession(session); if (hasClassExtractor() || shouldUseClassNameAsIndicator()) { return super.classFromRow(rowFromDatabase, session); } Object indicator = rowFromDatabase.get(getClassIndicatorField()); if (indicator == AbstractRecord.noEntry) { return null; } if (indicator == null) { return null; } Class concreteClass; if (indicator instanceof String) { boolean namespaceAware = ((XMLRecord) rowFromDatabase).isNamespaceAware(); String indicatorValue = (String)indicator; int index = -1; if(namespaceAware){ index = indicatorValue.indexOf(((XMLRecord)rowFromDatabase).getNamespaceSeparator()); } if (index == -1) { if (namespaceAware && usesXsiType) { String uri = ((XMLRecord)rowFromDatabase).resolveNamespacePrefix(null); if (uri == null && ((XMLRecord)rowFromDatabase).getNamespaceResolver() != null) { uri = ((XMLRecord)rowFromDatabase).getNamespaceResolver().getDefaultNamespaceURI(); } XPathQName qname = new XPathQName(uri, indicatorValue, namespaceAware); concreteClass = (Class)this.classIndicatorMapping.get(qname); } else { XPathQName qname = new XPathQName(indicatorValue, namespaceAware); concreteClass = (Class)this.classIndicatorMapping.get(qname); } } else { String prefix = indicatorValue.substring(0, index); String localPart = indicatorValue.substring(index + 1); String uri = ((XMLRecord)rowFromDatabase).resolveNamespacePrefix(prefix); if (uri != null) { XPathQName qname = new XPathQName(uri, localPart, namespaceAware); concreteClass = (Class)this.classIndicatorMapping.get(qname); } else { concreteClass = (Class)this.classIndicatorMapping.get(indicatorValue); } } } else { concreteClass = (Class)this.classIndicatorMapping.get(indicator); } if (concreteClass == null) { throw DescriptorException.missingClassForIndicatorFieldValue(indicator, getDescriptor()); } return concreteClass; } public void setNamespaceResolver(NamespaceResolver resolver) { this.namespaceResolver = resolver; } /** * PUBLIC: * To set the class indicator field name. * This is the name of the field in the table that stores what type of object this is. */ @Override public void setClassIndicatorFieldName(String fieldName) { if (fieldName == null) { setClassIndicatorField(null); } else { setClassIndicatorField(new XMLField(fieldName)); } } /** * INTERNAL: * Add abstract class indicator information to the database row. This is * required when building a row for an insert or an update of a concrete child * descriptor. */ @Override public void addClassIndicatorFieldToRow(AbstractRecord databaseRow) { if (hasClassExtractor()) { return; } CoreField field = getClassIndicatorField(); Object value = getClassIndicatorValue(); if(usesXsiType){ boolean namespaceAware = ((XMLRecord)databaseRow).isNamespaceAware() || ((XMLRecord)databaseRow).hasCustomNamespaceMapper(); if(value instanceof String){ if(namespaceAware){ if(((XMLRecord)databaseRow).getNamespaceSeparator() != Constants.COLON){ value= ((String)value).replace(Constants.COLON, ((XMLRecord)databaseRow).getNamespaceSeparator()); } }else{ int colonIndex = ((String)value).indexOf(Constants.COLON); if(colonIndex > -1){ value = ((String)value).substring(colonIndex + 1); } } } } databaseRow.put(field, value); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy