FileDocCategorySizeDatePackage
ClassDesc.javaAPI DocGlassfish v2 API56760Wed Jul 11 12:57:14 BST 2007com.sun.jdo.spi.persistence.support.sqlstore.model

ClassDesc

public class ClassDesc extends Object implements com.sun.jdo.spi.persistence.support.sqlstore.PersistenceConfig

Fields Summary
private ArrayList
fetchGroups
private int
maxHierarchicalGroupID
private boolean
hasLocalNonDFGField
Used for batched update check. Set to true if this class has at least one local field that does not belong to DFG
public ArrayList
fields
Contains all local and foreign fields.
public ArrayList
hiddenFields
Contains all hidden fields.
public ArrayList
foreignFields
Contains all relationship fields.
private LocalFieldDesc[]
versionFields
Contains the fields used for version consistency validation.
private ArrayList
tables
private Class
pcClass
private Class
oidClass
public int
maxFields
public int
maxVisibleFields
public int
maxHiddenFields
private Concurrency
optimisticConcurrency
private Concurrency
checkDirtyConcurrency
private Concurrency
databaseConcurrency
private Concurrency
explicitConcurrency
private MappingClassElementImpl
mdConfig
private ClassLoader
classLoader
private Constructor
constructor
private com.sun.jdo.api.persistence.model.jdo.PersistenceClassElement
pcElement
private com.sun.jdo.api.persistence.model.jdo.PersistenceFieldElement[]
persistentFields
private Field[]
keyFields
private String[]
keyFieldNames
private LocalFieldDesc[]
keyFieldDescs
private static com.sun.jdo.spi.persistence.utility.logging.Logger
logger
The logger.
private final Map
retrieveDescCache
RetrieveDescriptor cache for navigation and reloading.
private final Map
foreignRetrieveDescCache
RetrieveDescriptor cache for navigation queries. This cache holds foreign RetrieveDescriptors constrained by the relationship key values.
private RetrieveDesc
retrieveDescForVerification
Retrieve descriptor for version consistency verification.
private Object
retrieveDescForVerificationSynchObj
private final Map
updateQueryPlanCache
UpdateQueryPlan cache.
private com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.UpdateQueryPlan
updateQueryPlanForInsert
UpdateQueryPlan for insert.
private Object
updateQueryPlanForInsertSynchObj
private com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.UpdateQueryPlan
updateQueryPlanForDelete
UpdateQueryPlan for delete.
private Object
updateQueryPlanForDeleteSynchObj
private static final ResourceBundle
messages
I18N message handler.
private static final Class[]
sigSM
PC Constructor signature.
Constructors Summary
public ClassDesc(com.sun.jdo.api.persistence.model.mapping.MappingClassElement mdConfig, Class pcClass)


         

        this.mdConfig = (MappingClassElementImpl) mdConfig;
        pcElement = this.mdConfig.getPersistenceElement();
        this.pcClass = pcClass;
        classLoader = pcClass.getClassLoader();

        try {
            constructor = pcClass.getConstructor(sigSM);
        } catch (Exception e) {
            // Persistence capable classes must provide this constructor
            throw new JDOFatalUserException(I18NHelper.getMessage(messages,
                    "jdo.persistencemanagerimpl.assertpersistencecapable.error", // NOI18N
                    pcClass.getName()), e);
        }

        fields = new ArrayList();
        foreignFields = new ArrayList();
        tables = new ArrayList();
        fetchGroups = new ArrayList();
    
Methods Summary
private voidaddFKConstraints(com.sun.jdo.spi.persistence.support.sqlstore.sql.RetrieveDescImpl rd, ForeignFieldDesc foreignField)
Generate the condition on the relationship key in the where clause with InputParamValues for later binding of the actual query parameters.

        for (int i = 0; i < foreignField.foreignFields.size(); i++) {
            LocalFieldDesc fff = (LocalFieldDesc) foreignField.foreignFields.get(i);
            rd.addParameterConstraint(fff, i);
        }
    
private voidaddField(FieldDesc f)

        fields.add(f);
    
private voidaddForeignField(ForeignFieldDesc f)

        foreignFields.add(f);
    
private intaddPKConstraints(com.sun.jdo.spi.persistence.support.sqlstore.sql.RetrieveDescImpl rd)
Generate for each keyField 'keyfield = ?' in the where clause with InputParamValues for later binding of the actual query parameters.

        // PK Constraints are always added first hence startIndex == 0
        rd.addParameterConstraints(keyFieldDescs, 0);

        return keyFieldDescs.length;
    
private voidaddTableDesc(TableDesc t)

        // setConsistencyLevel of this table before adding it to our list
        if (!t.isJoinTable()) {
            // JoinTables represent relationships instead of "real" objects,
            // they should never have a special consistencyLevel.
            t.setConsistencyLevel(mdConfig.getConsistencyLevel());
        }
        tables.add(t);
    
private com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.UpdateQueryPlanbuildQueryPlan(SQLStoreManager store, com.sun.jdo.spi.persistence.support.sqlstore.sql.UpdateObjectDescImpl desc)
Builds and initializes a new query plan based on the information passed with the desc parameter. The returned plan and its related data structures will be readonly.

param
store Store manager
param
desc Update information, including the update action and modified fields as appropriate.
return
A new query plan. The returned plan will be readonly.

        UpdateQueryPlan plan;

        plan = new UpdateQueryPlan(desc, store);
        plan.build(true);

        // Initialize the text for all statements. After this point,
        // the plan and its related data structures will be readonly.
        plan.getStatements();

        return plan;
    
private voidcleanupTrackedFields()
Remove redundant ForeignFieldDescs from each LocalFieldDesc's tracked field list.


        for (int i = 0; i < fields.size(); i++) {
            FieldDesc f = (FieldDesc) fields.get(i);

            if (f instanceof LocalFieldDesc) {
                ((LocalFieldDesc) f).cleanupTrackedFields();
            }
        }
    
private voidcomputeTrackedPrimitiveFields()
Computes all the primitive tracked fields. Primitive fields track each other if they are mapped to same columns. One of them is made the primary tracked field as per precedence rules on the field types. This field is used to bind values to columns while updating the database.

        // Compute the list of primitive fields to track for each primitive field.
        for (int i = 0; i < fields.size(); i++) {
            FieldDesc f = (FieldDesc) fields.get(i);

            if (!f.isRelationshipField()) {
                LocalFieldDesc lf = (LocalFieldDesc) f;

                lf.computeTrackedPrimitiveFields();
                lf.computePrimaryTrackedPrimitiveField();
            }
        }
    
private voidcomputeTrackedRelationshipFields()
Computes the tracked relationship fields. Relationships are tracked in the following way:
  • A relationship field tracks a local field, if it's mappped to the same columns. The relationship will be updated when the local field is set.
  • Relationship fields track each other if they are mapped to the same columns. The first field in the field order is marked as primary tracked field. If the foreign key columns are explicitly mapped, this field also tracks the local foreign key field. The foreign key columns are explicitly mapped in overlapping pk/fk situations. The other relationship fields mapped to the same columns are updated when the primary tracked relationship field is set.

see
FieldDesc#PROP_PRIMARY_TRACKED_FIELD
see
FieldDesc#PROP_SECONDARY_TRACKED_FIELD

        // Compute the list of fields to track for each field.
        for (int i = 0; i < 2; i++) {
            ArrayList theFields = null;

            // We first check all the visible fields and then the hidden fields.
            if (i == 0) {
                theFields = this.fields;
            } else {
                if ((theFields = this.hiddenFields) == null) {
                    continue;
                }
            }

            for (int j = 0; j < theFields.size(); j++) {
                FieldDesc f = (FieldDesc) theFields.get(j);

                f.computeTrackedRelationshipFields();
            }
        }
    
private FieldDesccreateForeignField(com.sun.jdo.api.persistence.model.jdo.RelationshipElement fpcf, MappingRelationshipElementImpl fmdf)


        ForeignFieldDesc ff = new ForeignFieldDesc(this);

        addForeignField(ff);

        ff.cardinalityLWB = fpcf.getLowerBound();
        ff.cardinalityUPB = fpcf.getUpperBound();
        ff.deleteAction = fpcf.getDeleteAction();

        initializeColumnLists(ff, fmdf);

        // This is a workaround to make sure that that cardinalityUPB is not <= 1
        // if the field is of type collection.
        if (Model.RUNTIME.isCollection(fpcf.getCollectionClass()) &&
                (ff.cardinalityUPB <= 1)) {
            ff.cardinalityUPB = Integer.MAX_VALUE;
        }

        if (ff.cardinalityUPB > 1) {
            try {
                ff.setComponentType(Class.forName(fpcf.getElementClass(), true, classLoader));
            } catch (Throwable e) {
              logger.log(Logger.WARNING, "sqlstore.exception.log", e);
            }
        }

        return ff;
    
private LocalFieldDesccreateLocalField(MappingFieldElementImpl mdf)
Creates an instance of LocalFieldDesc.

param
mdf Input MappingFieldElementImpl

        ArrayList columnDesc = mdf.getColumnObjects();

        // Make sure this field is properly mapped.
        if ((columnDesc == null) || (columnDesc.size() == 0)) {
            throw new JDOFatalUserException(I18NHelper.getMessage(messages,
                    "core.configuration.fieldnotmapped", // NOI18N
                    mdf.getName(), pcElement.getName()));
        }
        return new LocalFieldDesc(this, columnDesc);
    
private LocalFieldDesccreateLocalHiddenField(org.netbeans.modules.dbschema.ColumnElement column)
Creates an instance of LocalFieldDesc for column that corresponds to a hidden field. Adds the newly created field to hiddenFields and declaredHiddenFields.

param
column The input column.
return
New instance of LocalFieldDesc

        ArrayList columnDesc = new ArrayList();
        columnDesc.add(column);
        LocalFieldDesc lf = new LocalFieldDesc(this, columnDesc);

        if (hiddenFields == null) {
            hiddenFields = new ArrayList();
        }
        hiddenFields.add(lf);

        // AbsouluteID for hidden fields must be < 0.
        lf.absoluteID = -hiddenFields.size();

        if (logger.isLoggable(Logger.FINEST)) {
            Object[] items = new Object[] {pcClass,lf.getName(),column.getName().getFullName()};
            logger.finest("sqlstore.model.classdesc.getlocalfielddesc", items); // NOI18N
        }

        return lf;
    
private voidcreateSecondaryTableKey(TableDesc table, MappingReferenceKeyElementImpl mappingSecondaryKey)


        ColumnPairElement pairs[] = mappingSecondaryKey.getColumnPairs();
        KeyDesc referencingKey = new KeyDesc();
        KeyDesc referencedKey = new KeyDesc();
        TableDesc secondaryTable = findTableDesc(((MappingTableElementImpl) mappingSecondaryKey.getTable()).getTableObject());

        for (int i = 0; i < pairs.length; i++) {
            ColumnPairElement pair = pairs[i];

            ColumnElement lc = pair.getLocalColumn();
            ColumnElement fc = pair.getReferencedColumn();

            referencingKey.addColumn(lc);

            FieldDesc lf = getLocalFieldDesc(lc);
            referencingKey.addField(lf);

            // We need to force field for the referencing key to be in the DFG
            // so it will always be loaded. This is to facilitate updating
            // secondary tables that requires this field to be loaded
            // for constraint purposes.
            lf.fetchGroup = FieldDesc.GROUP_DEFAULT;

            referencedKey.addColumn(fc);
            referencedKey.addField(getLocalFieldDesc(fc));
        }

        table.addSecondaryTableKey(new ReferenceKeyDesc(secondaryTable, referencingKey, referencedKey));
        secondaryTable.setPrimaryTableKey(new ReferenceKeyDesc(table, referencedKey, referencingKey));
    
private voidcreateTables(java.util.ArrayList mdTables)

        for (int i = 0; i < mdTables.size(); i++) {
            MappingTableElementImpl mdt = (MappingTableElementImpl) mdTables.get(i);
            TableDesc t = new TableDesc(mdt.getTableObject());

            ArrayList keys = mdt.getKeyObjects();
            KeyDesc key = new KeyDesc();
            t.setKey(key);
            key.addColumns(keys);

            for (int j = 0; j < keys.size(); j++) {
                ColumnElement c = (ColumnElement) keys.get(j);

                if (c != null) {
                    key.addField(getLocalFieldDesc(c));
                }
            }

            addTableDesc(t);
        }
    
public TableDescfindTableDesc(org.netbeans.modules.dbschema.TableElement mdTable)

        for (int i = 0; i < tables.size(); i++) {
            TableDesc t = (TableDesc) tables.get(i);

            if (t.getTableElement().equals(mdTable)) {
                return t;
            }
        }

        return null;
    
private voidfixupFieldProperties()


        for (int i = 0; i < foreignFields.size(); i++) {
            ForeignFieldDesc ff = (ForeignFieldDesc) foreignFields.get(i);
            ff.fixupFieldProperties();
        }
    
private voidfixupForeignReferences(ConfigCache cache)
The fixupForeignReferences method finds all the references to foreign classes in this configuration. It then builds the appropriate run-time information (ForeignFieldDesc) for the foreign reference from the meta-data.


        for (int i = 0; i < foreignFields.size(); i++) {
            ForeignFieldDesc ff = (ForeignFieldDesc) foreignFields.get(i);
            Class classType = null;

            if ((classType = ff.getComponentType()) == null) {
                classType = ff.getType();
            }

            ClassDesc foreignConfig = (ClassDesc) cache.getPersistenceConfig(classType);

            if (foreignConfig == null) continue;

            // Look up the inverse relationship field name if there is any.
            String irName = pcElement.getRelationship(ff.getName()).getInverseRelationshipName();
            ForeignFieldDesc inverseField = null;

            if (irName != null) {
                inverseField = (ForeignFieldDesc) foreignConfig.getField(irName);
            }

            ff.fixupForeignReference(foreignConfig, inverseField);
        }
    
private java.lang.StringgenerateRDCacheKey(FieldDesc additionalField)
Generates the key for a RetrieveDescriptor for the cache lookup. The key has one of two forms:
  • Fully qualified classname of the pcclass, if additionalField is null.
  • Fully qualified classname of the pcclass + '/' + additionalFieldName + '/' + additionalFieldID, otherwise.
  • param
    additionalField The field to be retrieved in addition to the DFG fields.
    return
    The generated cache key as a String.

            StringBuffer key = new StringBuffer();
    
            key.append(pcClass.getName());
    
            if (additionalField != null) {
                // using '/' as separator between class and fieldname
                key.append('/");
                key.append(additionalField.getName());
                key.append('/");
                key.append(additionalField.absoluteID);
            }
    
            return key.toString();
        
    public ConcurrencygetConcurrency(boolean optimistic)

            // Following algo is used to determine which concurrency to return:
            // consistency level specified in model(represented by the variable consistencyLevel),
            // takes precedence over
            // concurrency specified by transaction (represented by parameter 'optimistic' to this method)
    
            Concurrency concurrency = null;
            int consistencyLevel = mdConfig.getConsistencyLevel();
    
            if (consistencyLevel == MappingClassElement.NONE_CONSISTENCY) {
                // No consistency level specified in model
                if (optimistic) {
                    concurrency = (Concurrency) optimisticConcurrency.clone();
                } else {
                    concurrency = (Concurrency) databaseConcurrency.clone();
                }
    
            } else {
                // currently, we would not try to interprete consistencyLevel as bitmap
                // When we implment consistencyLevel like 2+, 3+, we would have to interprete
                // consistencyLevel as bitmap and implement some changes in class hierarchy
                // starting  with interface Concurrency
                switch(consistencyLevel) {
    
                    // We would never reach this code because we are in the else part
                    // case MappingClassElement.NONE_CONSISTENCY :
                    //	concurrency = (Concurrency) databaseConcurrency.clone();
                    //	break;
    
                case MappingClassElement.CHECK_MODIFIED_AT_COMMIT_CONSISTENCY :
                    concurrency = (Concurrency) checkDirtyConcurrency.clone();
                    break;
    
                case MappingClassElement.LOCK_WHEN_LOADED_CONSISTENCY :
                    // This consistency level is implemeted inside SelectStatement and
                    // not by any object implementing Concurrency
                    concurrency = (Concurrency) explicitConcurrency.clone();
                    break;
    
                case MappingClassElement.VERSION_CONSISTENCY :
                    // This consistency level is implemented inside ClassDesc and
                    // UpdateQueryPlan and not by any object implementing Concurrency.
                    // Selects are handled in ClassDesc, updates/deletes in
                    // UpdateQueryPlan.
                    concurrency = (Concurrency) databaseConcurrency.clone();
                    break;
    
                // **Note**
                // Plese change text for the exception thrown in default below when
                // we start supporting new consistency levels. The text lists currently supported
                // consistency level
                default :
                    throw new JDOUnsupportedOptionException(I18NHelper.getMessage(messages,
                        "core.configuration.unsupportedconsistencylevel", pcClass));// NOI18N
                }
            }
    
            return concurrency;
        
    public java.lang.reflect.ConstructorgetConstructor()

            return constructor;
        
    public java.util.ArrayListgetFetchGroup(int groupID)
    Returns a list of fields in fetchGroup groupID.

    param
    groupID Fetch group id.
    return
    List of fields in fetchGroup groupID. The list for FieldDesc.GROUP_NONE is empty.
    see
    #initializeFetchGroups

            int index = 0;
    
            if (groupID >= FieldDesc.GROUP_NONE) {
                index = groupID;
            } else if (groupID < FieldDesc.GROUP_NONE) {
                index = -groupID + maxHierarchicalGroupID;
            }
    
            for (int i = fetchGroups.size(); i <= index; i++) {
                fetchGroups.add(null);
            }
    
            ArrayList group = (ArrayList) fetchGroups.get(index);
    
            if (group == null) {
                group = new ArrayList();
                fetchGroups.set(index, group);
            }
    
            return group;
        
    public FieldDescgetField(java.lang.String name)

            for (int i = 0; i < fields.size(); i++) {
                FieldDesc f = (FieldDesc) fields.get(i);
    
                if ((f != null) && (f.getName().compareTo(name) == 0)) {
                    return f;
                }
            }
    
            if (hiddenFields != null) {
                for (int i = 0; i < hiddenFields.size(); i++) {
                    FieldDesc f = (FieldDesc) hiddenFields.get(i);
    
                    if (f.getName().compareTo(name) == 0) {
                        return f;
                    }
                }
            }
    
            return null;
        
    public FieldDescgetField(int index)

            if (index >= 0) {
                return (FieldDesc) fields.get(index);
            } else {
                return (FieldDesc) hiddenFields.get(-(index + 1));
            }
        
    public LocalFieldDesc[]getKeyFieldDescs()
    Returns the descriptors for key fields as array of LocalFieldDesc.

    return
    The descriptors for key fields as array of LocalFieldDesc.

            return keyFieldDescs;
        
    public java.lang.String[]getKeyFieldNames()
    Returns the key field names as array of String.

    return
    The key field names as array of String.

            return keyFieldNames;
        
    public java.lang.reflect.Field[]getKeyFields()
    Return the key fields as array of java.lang.reflect.Field instances.

    return
    The key fields as array of java.lang.reflect.Field instances.

            return keyFields;
        
    LocalFieldDescgetLocalFieldDesc(org.netbeans.modules.dbschema.ColumnElement column)

            LocalFieldDesc result;
    
            for (int i = 0; i < 2; i++) {
                ArrayList theFields = null;
    
                if (i == 0) {
                    theFields = fields;
                } else {
                    theFields = hiddenFields;
                }
    
                if (theFields != null) {
                    for (int j = 0; j < theFields.size(); j++) {
                        FieldDesc f = (FieldDesc) theFields.get(j);
    
                        if (f instanceof LocalFieldDesc) {
                            result = (LocalFieldDesc) f;
    
                            for (int k = 0; k < result.columnDescs.size(); k++) {
                                ColumnElement c = (ColumnElement) result.columnDescs.get(k);
    
                                // if (c.equals(column))
                                if (c.getName().getFullName().compareTo(column.getName().getFullName()) == 0) {
                                    // If f is a tracked field and it is not the primary, we continue
                                    // searching.
                                    if ((f.getTrackedFields() != null) &&
                                            ((f.sqlProperties & FieldDesc.PROP_PRIMARY_TRACKED_FIELD) == 0)) {
                                        continue;
                                    }
    
                                    return result;
                                }
                            }
                        }
                    }
                }
            }
    
            // If we didn't find the field associated with the column, we need to
            // create a hidden field and add it to the hiddenFields list.
            result = createLocalHiddenField(column);
    
            return result;
        
    public LocalFieldDescgetLocalFieldDesc(java.lang.String name)
    Returns the local field descriptor for the field name.

    param
    name Field name.
    return
    Local field descriptor for the field name.
    throws
    JDOFatalInternalException if the field is not defined for this class.

            FieldDesc desc = getField(name);
    
            if (desc == null) {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                            "core.generic.unknownfield", // NOI18N
                            name, getName()));
            }
    
            if (!(desc instanceof LocalFieldDesc)) {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                            "core.generic.notinstanceof", // NOI18N
                            desc.getClass().getName(), "LocalFieldDesc")); // NOI18N
            }
    
            return ((LocalFieldDesc) desc);
        
    public java.lang.StringgetName()

            return pcClass.getName();
        
    public java.lang.ClassgetOidClass()

            return oidClass;
        
    public java.lang.ClassgetPersistenceCapableClass()

            return pcClass;
        
    public TableDescgetPrimaryTable()

            return (TableDesc) tables.get(0);
        
    public RetrieveDescgetRetrieveDescForFKQuery(ForeignFieldDesc foreignField, PersistenceStore store)
    Returns a RetrieveDescriptor which represent a SQL query selecting pc instances by the relationship key. The relationship key is taken from the foreign field foreignField and used as query constraint. Please note that the RDs are cached, so the method first checks the cache. If there is no corresponding RetrieveDescriptor in the cache, it creates a new one and stores it in the cache. FetchGroup fields will be added when the query plan is build, see SelectQueryPlan#processFetchGroups. Note, the reason to introduce the RetrieveDesc cache in ClassDesc and not in the store manager is, that we can have the cache per class, where the store manager could only provide one big cache for all pc classes.

    param
    foreignField The relationship field to be retrieved. Following is true for this field.
    • It is part of an independent fetch group with only one field in the fetch group.

      Or

      Not part of any fetch group.

    • It is not mapped to a join table.
    param
    store The store manager.
    return
    A RetrieveDescriptor selecting pc instance(s) corresponding to the foreign field
    see
    #getRetrieveDescForPKQuery

            RetrieveDescImpl rd = null;
            String cacheKey = generateRDCacheKey(foreignField);
    
            synchronized (foreignRetrieveDescCache) {
                // Cache lookup.
                rd = (RetrieveDescImpl) foreignRetrieveDescCache.get(cacheKey);
                // Generate a new RD if there isn't one be found in the cache.
                if (rd == null) {
                    rd = (RetrieveDescImpl) store.getRetrieveDesc(foreignField.foreignConfig.getPersistenceCapableClass());
    
                    addFKConstraints(rd, foreignField);
                    // Cache fillup.
                    foreignRetrieveDescCache.put(cacheKey, rd);
                }
            }
    
            return rd;
        
    public RetrieveDescgetRetrieveDescForPKQuery(FieldDesc additionalField, PersistenceStore store)
    Returns a RetrieveDescriptor which represent a SQL query selecting a pc instance by pk-fields. Please note that the RDs are cached, so the method first checks the cache. If there is no corresponding RetrieveDescriptor in the cache, it creates a new one and stores it in the cache. If the additionalField is not null, the method retrieves the field indicated by it along with the query. Fetch group fields will be added when the query plan is build. Note, the reason to introduce the RetrieveDesc cache in ClassDesc and not in the store manager is, that we can have the cache per class, where the store manager could only provide one big cache for all pc classes.

    param
    additionalField The field to be retrieved in addition to the DFG fields.
    param
    store The store manager.
    return
    A RetrieveDescriptor selecting a pc instance by pk-fields.
    see
    #getRetrieveDescForFKQuery

            RetrieveDescImpl rd = null;
            String cacheKey = generateRDCacheKey(additionalField);
    
            synchronized (retrieveDescCache) {
                // Cache lookup.
                rd = (RetrieveDescImpl) retrieveDescCache.get(cacheKey);
                // Generate a new RD if there isn't one be found in the cache.
                if (rd == null) {
                    rd = (RetrieveDescImpl) store.getRetrieveDesc(pcClass);
                    if (additionalField != null) {
                        RetrieveDesc frd = null;
                        String name = additionalField.getName();
                        // If the additionalField is not null, we will retrieve
                        // the field indicated by it along with the query.
                        if (additionalField instanceof ForeignFieldDesc) {
                            Class additionalClass = ((ForeignFieldDesc) additionalField).
                                    foreignConfig.getPersistenceCapableClass();
    
                            frd = store.getRetrieveDesc(additionalClass);
                        }
    
                        rd.addPrefetchedField(name, frd);
                    }
    
                    addPKConstraints(rd);
                    // Cache fillup.
                    retrieveDescCache.put(cacheKey, rd);
                }
            }
    
            return rd;
        
    public RetrieveDescgetRetrieveDescForVerificationQuery(PersistenceStore store)
    Gets RetrieveDescriptor(rd) for verifying a VC instance. The returned rd is set up to expect constraints for pk followed by constraints for version fields.

    param
    store
    return
    Instance of retrieve Descriptor for verifying a VC instance.

    
            assert hasVersionConsistency();
    
            synchronized(retrieveDescForVerificationSynchObj) {
                if (retrieveDescForVerification == null) {
                    RetrieveDescImpl rd = (RetrieveDescImpl) store.getRetrieveDesc(pcClass);
    
                    int index = addPKConstraints(rd);
                    rd.addParameterConstraints(versionFields, index);
                    rd.setOption(RetrieveDescImpl.OPT_VERIFY);
    
                    retrieveDescForVerification = rd;
                }
            }
            return retrieveDescForVerification;
        
    private java.lang.StringgetSortedFieldNumbers(java.util.List fields)
    The methods returns the string representation of the sorted field numbers of the FieldDescs. The key is the string representation of the sorted field number list of updated fields.

    param
    fields the list of FieldDescs
    return
    the sorted field number string

            // Use the array of field numbers of the updated fields as the key
            int size = fields.size();
            int [] fieldNos = new int[size];
            for (int i = 0; i < size; i++) {
                FieldDesc f = (FieldDesc)fields.get(i);
                fieldNos[i] = f.absoluteID;
            }
            Arrays.sort(fieldNos);
            return StringHelper.intArrayToSeparatedList(fieldNos, ","); //NOI18N
        
    public intgetTableIndex(TableDesc tableDesc)

            return tables.indexOf(tableDesc);
        
    public java.util.IteratorgetTables()

            return tables.iterator();
        
    public com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.UpdateQueryPlangetUpdateQueryPlan(com.sun.jdo.spi.persistence.support.sqlstore.sql.UpdateObjectDescImpl desc, SQLStoreManager store)
    Retrieves the update query plan for the specified descriptor.

    param
    desc the descriptor
    param
    store the store manager
    return

            switch (desc.getUpdateAction()) {
                case ActionDesc.LOG_CREATE:
                    return getUpdateQueryPlanForInsert(desc, store);
                case ActionDesc.LOG_DESTROY:
                    return getUpdateQueryPlanForDelete(desc, store);
                case ActionDesc.LOG_UPDATE:
                    return getUpdateQueryPlanForUpdate(desc, store);
                default:
                    // TBD: error message + I18N
                    // error unknown action
                    return null;
            }
        
    private com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.UpdateQueryPlangetUpdateQueryPlanForDelete(com.sun.jdo.spi.persistence.support.sqlstore.sql.UpdateObjectDescImpl desc, SQLStoreManager store)

            synchronized(updateQueryPlanForDeleteSynchObj) {
                if (updateQueryPlanForDelete == null) {
                    updateQueryPlanForDelete = buildQueryPlan(store, desc);
                }
            }
            return updateQueryPlanForDelete;
        
    private com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.UpdateQueryPlangetUpdateQueryPlanForInsert(com.sun.jdo.spi.persistence.support.sqlstore.sql.UpdateObjectDescImpl desc, SQLStoreManager store)

            synchronized(updateQueryPlanForInsertSynchObj) {
                if (updateQueryPlanForInsert == null) {
                    updateQueryPlanForInsert = buildQueryPlan(store, desc);
                }
            }
            return updateQueryPlanForInsert;
        
    private com.sun.jdo.spi.persistence.support.sqlstore.sql.generator.UpdateQueryPlangetUpdateQueryPlanForUpdate(com.sun.jdo.spi.persistence.support.sqlstore.sql.UpdateObjectDescImpl desc, SQLStoreManager store)

            String key = getSortedFieldNumbers(desc.getUpdatedFields());
            UpdateQueryPlan plan;
            synchronized(updateQueryPlanCache) {
                plan = (UpdateQueryPlan)updateQueryPlanCache.get(key);
                if (plan == null) {
                    plan = buildQueryPlan(store, desc);
                    updateQueryPlanCache.put(key, plan);
                }
            }
            return plan;
        
    public LocalFieldDesc[]getVersionFields()

            return versionFields;
        
    public booleanhasLocalNonDFGFields()
    Returns true, if this class has got local fields not in the default fetch group. Because UpdateQueryPlans for updates are cached depending on the set of updated fields {@link #getUpdateQueryPlanForUpdate}, we might need to compare the updated fields btw. two instances when batching is enabled.

    return
    True, if this class has got local fields not in the default fetch group.
    see
    SQLStateManager#requiresImmediateFlush

            // All instances with modified DFG fields can be batched with
            // the same statement. If there's a primitive field outside
            // the DFG, we need to compare modified fields to check if the
            // same statement can be used.
            return hasLocalNonDFGField;
        
    public booleanhasModifiedCheckAtCommitConsistency()
    Determines whether this classDesc has the CHECK_MODIFIED_AT_COMMIT_CONSISTENCY level.

    return
    true if this has the CHECK_MODIFIED_AT_COMMIT_CONSISTENCY level; false otherwise.

            return(mdConfig.getConsistencyLevel() ==
                    MappingClassElement.CHECK_MODIFIED_AT_COMMIT_CONSISTENCY);
        
    public booleanhasVersionConsistency()

            return mdConfig.getConsistencyLevel() == MappingClassElement.VERSION_CONSISTENCY;
        
    public voidinitialize(ConfigCache cache)

            boolean debug = logger.isLoggable();
            if (debug) {
                logger.fine("sqlstore.model.classdesc.persistconfiginit", mdConfig); // NOI18N
            }
    
            loadOidClass();
            initializeFields();
            computeTrackedPrimitiveFields();
    
            initializeTables();
            initializeJoinTables();
            initializeVersionFields();
            initializeConcurrency();
    
            initializeKeyFields();
            initializeFetchGroups();
    
            fixupForeignReferences(cache);
            fixupFieldProperties();
            computeTrackedRelationshipFields();
            cleanupTrackedFields();
    
            // All fields should be initialized at this point. Now calculate
            // the total number of hidden fields and fields.
            if (hiddenFields != null) {
                maxHiddenFields = hiddenFields.size();
            }
            maxFields = maxVisibleFields + maxHiddenFields;
    
            if (debug) {
                logger.fine("sqlstore.model.classdesc.persistconfiginit.exit"); // NOI18N
            }
        
    private voidinitializeColumnLists(ForeignFieldDesc ff, MappingRelationshipElementImpl fmdf)

            ArrayList assocPairs = fmdf.getAssociatedColumnObjects();
            ArrayList pairs = fmdf.getColumnObjects();
            ArrayList localColumns = new ArrayList();
            ArrayList foreignColumns = new ArrayList();
    
            // We need to go through each local column and extract the foreign column.
            if ((assocPairs == null) || (assocPairs.size() == 0)) {
                for (int i = 0; i < pairs.size(); i++) {
                    ColumnPairElement fce = (ColumnPairElement) pairs.get(i);
                    localColumns.add(fce.getLocalColumn());
                    foreignColumns.add(fce.getReferencedColumn());
                }
    
                ff.localColumns = localColumns;
                ff.foreignColumns = foreignColumns;
            } else {
                ArrayList assocLocalColumns = new ArrayList();
                ArrayList assocForeignColumns = new ArrayList();
    
                for (int i = 0; i < pairs.size(); i++) {
                    ColumnPairElement alc = (ColumnPairElement) pairs.get(i);
                    localColumns.add(alc.getLocalColumn());
                    assocLocalColumns.add(alc.getReferencedColumn());
                }
    
                for (int i = 0; i < assocPairs.size(); i++) {
                    ColumnPairElement afc = (ColumnPairElement) assocPairs.get(i);
                    assocForeignColumns.add(afc.getLocalColumn());
                    foreignColumns.add(afc.getReferencedColumn());
                }
    
                ff.localColumns = localColumns;
                ff.assocLocalColumns = assocLocalColumns;
                ff.assocForeignColumns = assocForeignColumns;
                ff.foreignColumns = foreignColumns;
            }
        
    private voidinitializeConcurrency()

            optimisticConcurrency = new ConcurrencyOptVerify();
            optimisticConcurrency.configPersistence(this);
            checkDirtyConcurrency = new ConcurrencyCheckDirty();
            checkDirtyConcurrency.configPersistence(this);
            databaseConcurrency = new ConcurrencyDBNative();
            databaseConcurrency.configPersistence(this);
            explicitConcurrency = new ConcurrencyDBExplicit();
            explicitConcurrency.configPersistence(this);
        
    private voidinitializeFetchAndConcurrencyGroup(FieldDesc f, com.sun.jdo.api.persistence.model.jdo.PersistenceFieldElement pcf, MappingFieldElementImpl mdf, java.util.ArrayList concurrencyGroups)

            f.fetchGroup = mdf.getFetchGroup();
    
            // RESOLVE: For now, we can only handle one concurrency group per field
            // MBO:
            // I can call method getConcurrencyGroups w/o exception using the latest mapping files.
            // Please note the mapping files do not include any concurrency group info,
            // thus getConcurrencyGroups returns an empty array.
            ConcurrencyGroupElement cgroups[] = pcf.getConcurrencyGroups();
            //ConcurrencyGroupElement cgroups[] = null;
    
            if ((cgroups == null) || (cgroups.length == 0)) {
                if (f.fetchGroup == FieldDesc.GROUP_DEFAULT) {
                    f.concurrencyGroup = f.fetchGroup;
                }
            } else {
                ConcurrencyGroupElement cge = cgroups[0];
                int index = 0;
    
                if ((index = concurrencyGroups.indexOf(cge)) == -1) {
                    index = concurrencyGroups.size();
                    concurrencyGroups.add(cge);
                }
    
                f.concurrencyGroup = index;
            }
        
    private voidinitializeFetchGroups()
    Compute the fetch group lists for the declared fields. A fetch group lists the fields sharing the same value for FieldDesc.fetchGroup. Note: Fields that aren't in any fetch group must not be added to fetchGroups[FieldDesc.GROUP_NONE].

    see
    #getFetchGroup

    
            for (int i = 0; i < 2; i++) {
                ArrayList theFields = null;
    
                if (i == 0) {
                    theFields = fields;
                } else {
                    // It is possible to have hidden fields in the DFG.
                    if ((theFields = hiddenFields) == null)
                        continue;
                }
    
                for (int j = 0; j < theFields.size(); j++) {
                    FieldDesc f = (FieldDesc) theFields.get(j);
    
                    // Do not add the field to the fetch group for GROUP_NONE.
                    if (f.fetchGroup > FieldDesc.GROUP_NONE) {
                        getFetchGroup(f.fetchGroup).add(f);
                    }
    
                    // Check declared visible fields only.
                    if (i == 0 && !f.isRelationshipField()
                            && f.fetchGroup != FieldDesc.GROUP_DEFAULT) {
                        hasLocalNonDFGField = true;
                    }
                }
            }
    
            this.maxHierarchicalGroupID = fetchGroups.size() - 1;
    
            for (int i = 0; i < fields.size(); i++) {
                FieldDesc f = (FieldDesc) fields.get(i);
    
                // Do not add the field to the fetch group for GROUP_NONE.
                if (f.fetchGroup < FieldDesc.GROUP_NONE) {
                    getFetchGroup(f.fetchGroup).add(f);
                }
            }
        
    private voidinitializeFields()
    This method maps all the visible fields. It has the side-effect of computing the value for maxVisibleFields.

            ArrayList concurrencyGroups = new ArrayList();
            persistentFields = pcElement.getFields();
    
            for (int i = 0; i < persistentFields.length; i++) {
                PersistenceFieldElement pcf = persistentFields[i];
                MappingFieldElementImpl mdf = (MappingFieldElementImpl) mdConfig.getField(pcf.getName());
    
                if (mdf == null) {
                    throw new JDOFatalUserException(I18NHelper.getMessage(messages,
                            "core.configuration.fieldnotmapped", // NOI18N
                            pcf.getName(), pcElement.getName()));
                }
    
                FieldDesc f;
    
                if (!(mdf instanceof MappingRelationshipElement)) {
                    f = createLocalField(mdf);
                } else {
                    f = createForeignField((RelationshipElement) pcf, (MappingRelationshipElementImpl) mdf);
                }
    
                initializeFetchAndConcurrencyGroup(f, pcf, mdf, concurrencyGroups);
    
                if (mdf.isReadOnly()) {
                    f.sqlProperties |= FieldDesc.PROP_READ_ONLY;
                }
    
                try {
                    f.setupDesc(pcClass, pcf.getName());
                } catch (JDOException e) {
                    throw e;
                } catch (Exception e) {
                    throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.configuration.loadfailed.field", // NOI18N
                    pcf.getName(), pcElement.getName()), e);
                }
    
                f.absoluteID = pcf.getFieldNumber();
    
                addField(f);
    
                if (logger.isLoggable(Logger.FINEST)) {
                    Object[] items = new Object[] {f.getName(),new Integer(f.absoluteID)};
                    logger.finest("sqlstore.model.classdesc.fieldinfo", items); // NOI18N
                }
            }
    
            this.maxVisibleFields = fields.size();
        
    private voidinitializeJoinTables()

            Iterator iter = foreignFields.iterator();
    
            while (iter.hasNext()) {
                ForeignFieldDesc ff = (ForeignFieldDesc) iter.next();
    
                if (ff.useJoinTable()) {
                    TableElement joinTable = ((ColumnElement) ff.assocLocalColumns.get(0)).getDeclaringTable();
                    TableDesc joinTableDesc = findTableDesc(joinTable);
    
                    if (joinTableDesc == null) {
                        joinTableDesc = new TableDesc(joinTable);
    
                        // Mark this table as a join table
                        joinTableDesc.setJoinTable(true);
                        addTableDesc(joinTableDesc);
                    }
                  }
            }
        
    private voidinitializeKeyFields()

            boolean debug = logger.isLoggable(Logger.FINEST);
            if (oidClass == null)
                return;
    
            keyFields = oidClass.getFields();
            keyFieldNames = new String[keyFields.length];
            keyFieldDescs = new LocalFieldDesc[keyFields.length];
    
            if (debug) {
                logger.finest("sqlstore.model.classdesc.createsqldesc", oidClass); // NOI18N
            }
    
            for (int i = 0; i < keyFields.length; i++) {
                Field kf = keyFields[i];
                String name = kf.getName();
                keyFieldNames[i] = name;
    
                if (name.equals("serialVersionUID")) { // NOI18N
                    continue;
                }
    
                LocalFieldDesc f = getLocalFieldDesc(name);
    
                if (f != null) {
                    if (debug) {
                        logger.finest("sqlstore.model.classdesc.pkfield", f.getName()); // NOI18N
                    }
    
                    // The fetch group for pk fields should always be DFG.
                    f.fetchGroup = FieldDesc.GROUP_DEFAULT;
                    f.sqlProperties &= ~(FieldDesc.PROP_REF_INTEGRITY_UPDATES);
                    f.sqlProperties &= ~(FieldDesc.PROP_IN_CONCURRENCY_CHECK);
                    f.sqlProperties |= FieldDesc.PROP_PRIMARY_KEY_FIELD;
    
                    keyFieldDescs[i] = f;
                } else {
                    throw new JDOFatalUserException(I18NHelper.getMessage(messages,
                            "core.configuration.noneexistentpkfield", // NOI18N
                            name, oidClass.getName(), pcClass.getName()));
                }
            }
        
    private voidinitializeTables()
    This method maps all the tables.

            ArrayList mdTables = mdConfig.getTables();
    
            createTables(mdTables);
            processSecondaryTables(mdTables);
        
    private voidinitializeVersionFields()
    Initialize the list of field descriptors of version consistency fields. The names of the version fields are obtained from {@link MappingClassElement#getVersionFields}.

            int size = mdConfig.getVersionFields().size();
            Iterator versionFieldIterator = mdConfig.getVersionFields().iterator();
            versionFields = new LocalFieldDesc[size];
    
            for (int i = 0; i < size; i++) {
                MappingFieldElement mdField = (MappingFieldElement) versionFieldIterator.next();
                LocalFieldDesc f = (LocalFieldDesc) getField(mdField.getName());
    
                if (f != null) {
                    if (logger.isLoggable()) {
                        logger.finest("sqlstore.model.classdesc.vcfield", f.getName()); // NOI18N
                    }
    
                    versionFields[i] = f;
                    registerVersionFieldWithTable(f);
    
                    // The fetch group for version fields should always be DFG.
                    f.fetchGroup = FieldDesc.GROUP_DEFAULT;
                    f.sqlProperties &= ~(FieldDesc.PROP_REF_INTEGRITY_UPDATES);
                    f.sqlProperties |= FieldDesc.PROP_VERSION_FIELD;
                } else {
                    throw new JDOFatalUserException(I18NHelper.getMessage(messages,
                            "core.configuration.noneexistentvcfield", // NOI18N
                            mdField.getName(), pcClass.getName()));
                }
            }
        
    public booleanisNavigable()

            return mdConfig.isNavigable();
        
    public booleanisPKField(int index)

            return persistentFields[index].isKey();
        
    private voidloadOidClass()

    
            if (oidClass != null) return;
    
            String keyClassName = pcElement.getKeyClass();
            String suffix = keyClassName.substring(keyClassName.length() - 4);
    
            // First check whether the key class name ends with ".oid".
            // If so, we need to convert it '.' to '$' because is it
            // an inner class.
            if (suffix.compareToIgnoreCase(".oid") == 0) { // NOI18N
                StringBuffer buf = new StringBuffer(keyClassName);
    
                buf.setCharAt(buf.length() - 4, '$");
                keyClassName = buf.toString();
            }
    
            try {
                oidClass = Class.forName(keyClassName, true, classLoader);
            } catch (Throwable e) {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                        "core.configuration.cantloadclass", keyClassName)); // NOI18N
            }
    
            if (logger.isLoggable()) {
                logger.fine("sqlstore.model.classdesc.loadedclass", oidClass); // NOI18N
            }
        
    static com.sun.jdo.spi.persistence.support.sqlstore.model.ClassDescnewInstance(java.lang.Class pcClass)
    Creates a new instance of ClassDesc for the given pcClass.

    param
    pcClass The persistence capable class.
    return
    A new instance of ClassDesc.

            Model model = Model.RUNTIME;
            String className = pcClass.getName();
            ClassLoader classLoader = pcClass.getClassLoader();
            ClassDesc rc = null;
    
            try {
                MappingClassElement mdConfig =
                   model.getMappingClass(className, classLoader);
    
                // Validate the model information for this class.
                validateModel(model, className, classLoader);
    
                rc = new ClassDesc(mdConfig, pcClass);
    
            } catch (JDOException e) {
                throw e;
            } catch (IllegalArgumentException e) {
                throw new JDOFatalUserException(I18NHelper.getMessage(messages,
                    "core.configuration.loadfailed.class", className), e); // NOI18N
            } catch (Exception e) {
                throw new JDOFatalInternalException(I18NHelper.getMessage(messages,
                    "core.configuration.loadfailed.class", className), e); // NOI18N
            }
    
            return rc;
        
    public SQLStateManagernewStateManagerInstance(PersistenceStore store)
    Returns a new SQLStateManager instance, initialized with passed store manager and this instance of the runtime class model.

    param
    store Store manager, an instance of SQLStoreManager.
    return
    A new SQLStateManager instance.

            return new SQLStateManager(store, this);
        
    private voidprocessSecondaryTables(java.util.ArrayList mdTables)
    Validity checks on secondary tables: 1) Ensure that every secondary table has a TableDesc 2) Every referencing key is the same length as the table's key Build the referencing keys. NOTE: This method assumes that the entries of mdTables and tables are sorted in the same order.

    
            for (int i = 0; i < tables.size(); i++) {
                MappingTableElementImpl mdt = (MappingTableElementImpl) mdTables.get(i);
                TableDesc t = (TableDesc) tables.get(i);
                ArrayList secondaryKeys = mdt.getReferencingKeys();
    
                for (int j = 0; j < secondaryKeys.size(); j++) {
                    MappingReferenceKeyElementImpl mappingSecondaryKey = (MappingReferenceKeyElementImpl) secondaryKeys.get(j);
                    createSecondaryTableKey(t, mappingSecondaryKey);
                }
            }
        
    private voidregisterVersionFieldWithTable(LocalFieldDesc versionField)
    Registers the version field versionField with the corresponding table.

    param
    versionField Field used in version consistency check.

            // Version field must be mapped to exactly one column.
            ColumnElement ce =  (ColumnElement) versionField.getColumnElements().next();
            Iterator iter = tables.iterator();
    
            while (iter.hasNext()) {
                TableDesc table = (TableDesc) iter.next();
    
                if (!table.isJoinTable()) {
                    if (ce.getDeclaringTable() == table.getTableElement()) {
                        table.setVersionField(versionField);
                        break;
                    }
                }
            }
        
    public java.lang.StringtoString()

            return getName();
        
    private static voidvalidateModel(com.sun.jdo.api.persistence.model.Model model, java.lang.String className, java.lang.ClassLoader classLoader)
    Validate the mapping for the given class. If the result collection returned by validate() is not empty, it means it failed the test. After logging all the exceptions, throw a JDOUserException and inform the user to go back to the mapping tool to fix up the mapping file. The JDOUserException contains the validation messages aswell.

    param
    model Runtime model.
    param
    className Persistence capable class' name.
    param
    classLoader Persistence capable class' loader.

            Collection c = null;
    
            if (!(c = model.validate(className, classLoader, null)).isEmpty()) {
                Iterator iter = c.iterator();
                StringBuffer validationMsgs = new StringBuffer();
    
                while (iter.hasNext()) {
                    Exception ex = (Exception) iter.next();
                    String validationMsg = ex.getLocalizedMessage();
    
                    logger.fine(I18NHelper.getMessage(messages,
                        "core.configuration.validationproblem", // NOI18N
                        className, validationMsg));
                    validationMsgs.append(validationMsg).append('\n"); // NOI18N
                }
                throw new JDOFatalUserException(I18NHelper.getMessage(messages,
                    "core.configuration.validationfailed", // NOI18N
                    className, validationMsgs.toString()));
            }