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

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

/*******************************************************************************
 * Copyright (c) 1998, 2012 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.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.helper.ClassConstants;
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.XMLConstants;
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. */ 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); // 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 = (MultitenantPolicy) 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(ClassConstants.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. */ 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()){ // 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(); XPathFragment frag = ((XMLField) getClassIndicatorField()).getXPathFragment(); if (frag.getLocalName().equals(XMLConstants.SCHEMA_TYPE_ATTRIBUTE) && frag.getNamespaceURI() != null && frag.getNamespaceURI().equals(XMLConstants.SCHEMA_INSTANCE_URL)) { usesXsiType = true; } if (key instanceof String) { QName qname; String indicatorValue = (String) key; if (!usesXsiType || namespaceResolver == null) { qname = new QName(indicatorValue); } else { int index = indicatorValue.indexOf(XMLConstants.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 QName(uri, localPart); } else { qname = new QName(namespaceResolver.getDefaultNamespaceURI(), indicatorValue); } } getClassIndicatorMapping().put(qname, entry.getValue()); } else if (key instanceof QName) { getClassIndicatorMapping().put(key, 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. */ 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) { String indicatorValue = (String)indicator; int index = indicatorValue.indexOf(XMLConstants.COLON); if (index == -1) { if (usesXsiType) { String uri = ((XMLRecord)rowFromDatabase).resolveNamespacePrefix(null); if (uri == null && ((XMLRecord)rowFromDatabase).getNamespaceResolver() != null) { uri = ((XMLRecord)rowFromDatabase).getNamespaceResolver().getDefaultNamespaceURI(); } QName qname = new QName(uri, indicatorValue); concreteClass = (Class)this.classIndicatorMapping.get(qname); } else { QName qname = new QName(indicatorValue); 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) { QName qname = new QName(uri, localPart); 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. */ public void setClassIndicatorFieldName(String fieldName) { if (fieldName == null) { setClassIndicatorField(null); } else { setClassIndicatorField(new XMLField(fieldName)); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy