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

org.datanucleus.store.rdbms.mapping.java.EmbeddedMapping Maven / Gradle / Ivy

There is a newer version: 6.0.7
Show newest version
/**********************************************************************
Copyright (c) 2005 Andy Jefferson and others. All rights reserved. 
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. 
 

Contributors:
    ...
**********************************************************************/
package org.datanucleus.store.rdbms.mapping.java;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.ExecutionContext;
import org.datanucleus.api.ApiAdapter;
import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.exceptions.NucleusUserException;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.metadata.ColumnMetaData;
import org.datanucleus.metadata.DiscriminatorMetaData;
import org.datanucleus.metadata.DiscriminatorStrategy;
import org.datanucleus.metadata.EmbeddedMetaData;
import org.datanucleus.metadata.FieldPersistenceModifier;
import org.datanucleus.metadata.FieldRole;
import org.datanucleus.metadata.InheritanceMetaData;
import org.datanucleus.metadata.MetaDataManager;
import org.datanucleus.metadata.RelationType;
import org.datanucleus.state.ObjectProvider;
import org.datanucleus.store.rdbms.mapping.MappingManager;
import org.datanucleus.store.rdbms.mapping.datastore.DatastoreMapping;
import org.datanucleus.store.rdbms.table.Column;
import org.datanucleus.store.rdbms.table.Table;
import org.datanucleus.util.Localiser;
import org.datanucleus.util.NucleusLogger;

/**
 * Mapping for an embedded PC object. 
 * The PC object can be embedded directly (1-1 relation) or be the element of a collection/array, or be the key/value of a map.
 * 

* Note that the mmd can be for the override of an embedded member rather than for the basic member itself. This can be the source of problems when nested. * Refer to

getRealMemberMetaData
for the (base) metadata of the member that is embedded. */ public abstract class EmbeddedMapping extends SingleFieldMapping { protected DiscriminatorMetaData discrimMetaData; /** Mapping for a discriminator (when supporting inherited embedded objects. */ protected DiscriminatorMapping discrimMapping; /** Mappings of the fields of the embedded PC. */ protected List javaTypeMappings; /** ClassLoader resolver */ protected ClassLoaderResolver clr; /** EmbeddedMetaData for the object being embedded. */ protected EmbeddedMetaData emd; /** Type name for the object being embedded. */ protected String typeName; /** Type of PC object. Corresponds to the values in StateManagerImpl. */ protected short objectType = -1; /** MetaData for the embedded class. */ protected AbstractClassMetaData embCmd = null; /** * Initialize this JavaTypeMapping with the given DatastoreAdapter for the given FieldMetaData. * @param table The datastore container storing this mapping (if any) * @param clr the ClassLoaderResolver * @param mmd FieldMetaData for the field to be mapped (if any) * @throws NucleusException if an error occurs */ public void initialize(AbstractMemberMetaData mmd, Table table, ClassLoaderResolver clr) { throw new NucleusException("subclass must override this method").setFatal(); } /** * Initialize for the specified member. * @param mmd metadata for the embedded member * @param table Table for persisting this field * @param clr The ClassLoaderResolver * @param emd Embedded MetaData for the object being embedded * @param typeName type of the embedded PC object being stored * @param objectType Object type of the PC object being embedded (see StateManagerImpl object types) */ public void initialize(AbstractMemberMetaData mmd, Table table, ClassLoaderResolver clr, EmbeddedMetaData emd, String typeName, int objectType) { super.initialize(mmd, table, clr); this.clr = clr; this.emd = emd; this.typeName = typeName; this.objectType = (short) objectType; // Find the MetaData for the embedded PC class MetaDataManager mmgr = table.getStoreManager().getMetaDataManager(); AbstractClassMetaData rootEmbCmd = mmgr.getMetaDataForClass(typeName, clr); if (rootEmbCmd == null) { // Not found so must be an interface // Try using the fieldTypes on the field/property - we support it if only 1 implementation String[] fieldTypes = mmd.getFieldTypes(); if (fieldTypes != null && fieldTypes.length == 1) { rootEmbCmd = mmgr.getMetaDataForClass(fieldTypes[0], clr); } else if (fieldTypes != null && fieldTypes.length > 1) { // TODO Cater for multiple implementations throw new NucleusUserException("Field " + mmd.getFullFieldName() + " is a reference field that is embedded with multiple possible implementations. " + "DataNucleus doesnt support embedded reference fields that have more than 1 implementation"); } if (rootEmbCmd == null) { // Try a persistent interface rootEmbCmd = mmgr.getMetaDataForInterface(clr.classForName(typeName), clr); if (rootEmbCmd == null && mmd.getFieldTypes() != null && mmd.getFieldTypes().length == 1) { // No MetaData for the type so try "fieldType" specified on the field rootEmbCmd = mmgr.getMetaDataForInterface(clr.classForName(mmd.getFieldTypes()[0]), clr); } } } if (rootEmbCmd == null) { throw new NucleusUserException("Unable to find root class embedded metadata for field=" + mmd.getFullFieldName()); } embCmd = rootEmbCmd; AbstractMemberMetaData[] embFmds = null; if (emd == null && rootEmbCmd.isEmbeddedOnly()) { // No block yet the class is defined as embedded-only so just use its own definition of fields embFmds = rootEmbCmd.getManagedMembers(); } else if (emd != null) { // block so use those field definitions embFmds = emd.getMemberMetaData(); } String[] subclasses = mmgr.getSubclassesForClass(rootEmbCmd.getFullClassName(), true); if (subclasses != null && subclasses.length > 0) { if (rootEmbCmd.hasDiscriminatorStrategy()) { // Fabricate a DiscriminatorMetaData to use for the embedded object discrimMetaData = new DiscriminatorMetaData(); InheritanceMetaData embInhMd = new InheritanceMetaData(); embInhMd.setParent(rootEmbCmd); discrimMetaData.setParent(embInhMd); // Set strategy based on the inheritance of the embedded object, otherwise class name. DiscriminatorMetaData dismd = rootEmbCmd.getDiscriminatorMetaDataRoot(); if (dismd.getStrategy() != null && dismd.getStrategy() != DiscriminatorStrategy.NONE) { discrimMetaData.setStrategy(dismd.getStrategy()); } else { discrimMetaData.setStrategy(DiscriminatorStrategy.CLASS_NAME); // Fallback to class name } // Set column for discriminator ColumnMetaData disColmd = new ColumnMetaData(); disColmd.setAllowsNull(Boolean.TRUE); DiscriminatorMetaData embDismd = (emd != null) ? emd.getDiscriminatorMetaData() : null; if (embDismd != null && embDismd.getColumnMetaData() != null) { disColmd.setName(embDismd.getColumnMetaData().getName()); } else { ColumnMetaData colmd = dismd.getColumnMetaData(); if (colmd != null && colmd.getName() != null) { disColmd.setName(colmd.getName()); } } discrimMetaData.setColumnMetaData(disColmd); discrimMapping = DiscriminatorMapping.createDiscriminatorMapping(table, discrimMetaData); addDatastoreMapping(discrimMapping.getDatastoreMapping(0)); } else { NucleusLogger.PERSISTENCE.info("Member " + mmd.getFullFieldName() + " is embedded and the type " + "(" + rootEmbCmd.getFullClassName() + ") has potential subclasses." + " Impossible to detect which is stored embedded. Add a discriminator to the embedded type"); } } // Add all fields of the embedded class (that are persistent) int[] pcFieldNumbers = rootEmbCmd.getAllMemberPositions(); for (int i=0;i 0) { for (int i=0;i 0 && mapping.getMemberMetaData().getColumnMetaData()[0].getName().equals(nullColumn)) { // Try to cater for user having an integer based column and value if (mapping instanceof IntegerMapping || mapping instanceof BigIntegerMapping || mapping instanceof LongMapping || mapping instanceof ShortMapping) { Object convertedValue = null; try { if (mapping instanceof IntegerMapping || mapping instanceof ShortMapping) { convertedValue = Integer.valueOf(nullValue); } else if (mapping instanceof LongMapping || mapping instanceof BigIntegerMapping) { convertedValue = Long.valueOf(nullValue); } } catch (Exception e) { } mapping.setObject(ec, ps, posMapping, convertedValue); } else { mapping.setObject(ec, ps, posMapping, nullValue); } } else { if (mapping.getNumberOfDatastoreMappings() > 0) { mapping.setObject(ec, ps, posMapping, null); } } } } else { ApiAdapter api = ec.getApiAdapter(); if (!api.isPersistable(value)) { throw new NucleusException(Localiser.msg("041016", value.getClass(), value)).setFatal(); } AbstractClassMetaData embCmd = ec.getMetaDataManager().getMetaDataForClass(value.getClass(), ec.getClassLoaderResolver()); ObjectProvider embOP = ec.findObjectProvider(value); if (embOP == null || api.getExecutionContext(value) == null) { // Assign a StateManager to manage our embedded object embOP = ec.getNucleusContext().getObjectProviderFactory().newForEmbedded(ec, value, false, ownerOP, ownerFieldNumber); embOP.setPcObjectType(objectType); } int n = 0; if (discrimMapping != null) { if (discrimMetaData.getStrategy() != DiscriminatorStrategy.NONE) { discrimMapping.setObject(ec, ps, new int[]{param[n]}, embCmd.getDiscriminatorValue()); } n++; } for (int i=0; i= 0) { // Member is present in this embedded type Object fieldValue = embOP.provideField(embAbsFieldNum); if (mapping instanceof EmbeddedPCMapping) { mapping.setObject(ec, ps, posMapping, fieldValue, embOP, embAbsFieldNum); } else { if (mapping.getNumberOfDatastoreMappings() > 0) { mapping.setObject(ec, ps, posMapping, fieldValue); } } } else { mapping.setObject(ec, ps, posMapping, null); } } } } /** * Accessor for the embedded object from the result set * @param ec ExecutionContext * @param rs The ResultSet * @param param Array of param numbers in the ResultSet for the fields of this object * @return The embedded object */ public Object getObject(ExecutionContext ec, ResultSet rs, int[] param) { return getObject(ec, rs, param, null, -1); } /** * Accessor for the embedded object from the result set * @param ec ExecutionContext * @param rs The ResultSet * @param param Array of param numbers in the ResultSet for the fields of this object * @param ownerOP ObjectProvider of the owning object containing this embedded object * @param ownerFieldNumber Field number in the owning object where this is stored * @return The embedded object */ public Object getObject(ExecutionContext ec, ResultSet rs, int[] param, ObjectProvider ownerOP, int ownerFieldNumber) { Object value = null; int n = 0; // Determine the type of the embedded object AbstractClassMetaData embCmd = this.embCmd; if (discrimMapping != null) { Object discrimValue = discrimMapping.getObject(ec, rs, new int[]{param[n]}); String className = ec.getMetaDataManager().getClassNameFromDiscriminatorValue((String)discrimValue, discrimMetaData); embCmd = storeMgr.getMetaDataManager().getMetaDataForClass(className, clr); n++; } // Create a persistable to put the values into Class embeddedType = clr.classForName(embCmd.getFullClassName()); if (mmd.getFieldTypes() != null && mmd.getFieldTypes().length > 0) { // Embedded type has field-type defined so use that as our embedded type embeddedType = ec.getClassLoaderResolver().classForName(mmd.getFieldTypes()[0]); } ObjectProvider embOP = ec.getNucleusContext().getObjectProviderFactory().newForHollow(ec, embeddedType, null); embOP.setPcObjectType(objectType); value = embOP.getObject(); String nullColumn = null; String nullValue = null; if (emd != null) { nullColumn = emd.getNullIndicatorColumn(); nullValue = emd.getNullIndicatorValue(); } // Populate the field values for (int i=0; i= 0) { // Mapping for field that is present in this embedded type, so set the field if (mapping instanceof EmbeddedPCMapping) { // We have a nested embedded int numSubParams = mapping.getNumberOfDatastoreMappings(); int[] subParam = new int[numSubParams]; int k = 0; for (int j=n;j 0) { // Extract the value(s) for this field and update the PC if it is not null int[] posMapping = new int[mapping.getNumberOfDatastoreMappings()]; for (int j=0; j= 0) { embOP.replaceField(ownerFieldNumberInElement, ownerOP != null ? ownerOP.getObject() : null); } } } // Register the owner-embedded ObjectProvider relation now we have values set if (value != null && ownerOP != null) { ec.registerEmbeddedRelation(ownerOP, ownerFieldNumber, embOP); } return value; } /** * Accessor for the Java type being represented here. * @return The Java type */ public Class getJavaType() { return clr.classForName(typeName); } public AbstractMemberMetaData getRealMemberMetaData() { if (mmd.getParent() instanceof EmbeddedMetaData) { // Get the real owner classMetaData (when embedded the cmd is often the embedded) AbstractClassMetaData cmd = storeMgr.getMetaDataManager().getMetaDataForClass(mmd.getClassName(), clr); return cmd.getMetaDataForMember(mmd.getName()); } return mmd; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy