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

oracle.toplink.essentials.descriptors.ClassDescriptor Maven / Gradle / Ivy

There is a newer version: 2.1-60f
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * // Copyright (c) 1998, 2007, Oracle. All rights reserved.
 * 
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package oracle.toplink.essentials.descriptors;

import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.util.*;
import java.io.*;
import java.lang.reflect.*;

import oracle.toplink.essentials.internal.descriptors.*;
import oracle.toplink.essentials.internal.expressions.SQLSelectStatement;
import oracle.toplink.essentials.internal.expressions.SQLStatement;
import oracle.toplink.essentials.internal.helper.*;
import oracle.toplink.essentials.internal.identitymaps.*;
import oracle.toplink.essentials.mappings.*;
import oracle.toplink.essentials.mappings.foundation.AbstractDirectMapping;
import oracle.toplink.essentials.queryframework.FetchGroup;
import oracle.toplink.essentials.querykeys.*;
import oracle.toplink.essentials.expressions.*;
import oracle.toplink.essentials.internal.databaseaccess.*;
import oracle.toplink.essentials.exceptions.*;
import oracle.toplink.essentials.descriptors.copying.*;
import oracle.toplink.essentials.descriptors.changetracking.*;
import oracle.toplink.essentials.descriptors.invalidation.*;
import oracle.toplink.essentials.descriptors.FetchGroupManager;
import oracle.toplink.essentials.descriptors.InheritancePolicy;
import oracle.toplink.essentials.descriptors.DescriptorEvent;
import oracle.toplink.essentials.descriptors.DescriptorEventManager;
import oracle.toplink.essentials.descriptors.DescriptorQueryManager;
import oracle.toplink.essentials.internal.security.PrivilegedAccessHelper;
import oracle.toplink.essentials.internal.security.PrivilegedClassForName;
import oracle.toplink.essentials.internal.security.PrivilegedMethodInvoker;
import oracle.toplink.essentials.internal.sessions.AbstractRecord;
import oracle.toplink.essentials.internal.sessions.AbstractSession;
import oracle.toplink.essentials.internal.helper.MappingCompare;
import oracle.toplink.essentials.internal.helper.DatabaseTable;
import oracle.toplink.essentials.internal.helper.DatabaseField;

/**
 * 

Purpose: * Abstract descriptor class for defining persistence information on a class. * This class provides the data independent behavior and is subclassed, * for relational, object-relational, EIS, XML, etc. * * @see RelationalDescriptor * @see oracle.toplink.essentials.objectrelational.ObjectRelationalDescriptor * @see oracle.toplink.essentials.eis.EISDescriptor * @see oracle.toplink.essentials.ox.XMLDescriptor */ public class ClassDescriptor implements Cloneable, Serializable { protected Class javaClass; protected String javaClassName; protected Vector tables; protected transient DatabaseTable defaultTable; protected List primaryKeyFields; protected transient Map> additionalTablePrimaryKeyFields; protected transient Vector multipleTableInsertOrder; protected transient Map multipleTableForeignKeys; protected transient Vector fields; protected transient Vector allFields; protected Vector mappings; //used by the lock on clone process. This will contain the foreign reference //mapping without indirection protected List lockableMappings; protected Map queryKeys; // Additional properties. protected Class identityMapClass; protected int identityMapSize; protected String sequenceNumberName; protected DatabaseField sequenceNumberField; protected transient String sessionName; protected boolean shouldAlwaysRefreshCache; protected boolean shouldOnlyRefreshCacheIfNewerVersion; protected boolean shouldDisableCacheHits; protected transient Vector constraintDependencies; protected transient String amendmentMethodName; protected transient Class amendmentClass; protected transient String amendmentClassName; protected String alias; protected boolean shouldBeReadOnly; protected boolean shouldAlwaysConformResultsInUnitOfWork; // this attribute is used to determine what classes should be isolated from the shared cache protected boolean isIsolated; // for bug 2612601 allow ability not to register results in UOW. protected boolean shouldRegisterResultsInUnitOfWork = true; // Delegation objects, these perform most of the behavoir. protected DescriptorEventManager eventManager; protected DescriptorQueryManager queryManager; protected ObjectBuilder objectBuilder; protected CopyPolicy copyPolicy; protected InstantiationPolicy instantiationPolicy; protected InheritancePolicy inheritancePolicy; protected OptimisticLockingPolicy optimisticLockingPolicy; protected Vector cascadeLockingPolicies; protected WrapperPolicy wrapperPolicy; protected ObjectChangePolicy changePolicy; protected CMPPolicy cmpPolicy; //manage fetch group behaviors and operations protected FetchGroupManager fetchGroupManager; /** Additional properties may be added. */ protected Map properties; // Follwing are the states the descriptor passes thru during the initialization. protected static final int UNINITIALIZED = 0; protected static final int PREINITIALIZED = 1; protected static final int INITIALIZED = 2; protected static final int POST_INITIALIZED = 3; protected static final int ERROR = -1; //redefine the descriptor types (exclusively) protected static final int NORMAL = 0; protected static final int AGGREGATE = 2; protected static final int AGGREGATE_COLLECTION = 3; protected transient int initializationStage; protected int descriptorType; protected boolean shouldOrderMappings; protected CacheInvalidationPolicy cacheInvalidationPolicy = null; /** PERF: Used to optimize cache locking to only acquire deferred locks when required (no-indirection). */ protected boolean shouldAcquireCascadedLocks = false; /** PERF: Compute and store if the primary key is simple (direct-mapped) to allow fast extraction. */ protected boolean hasSimplePrimaryKey = false; /** * PUBLIC: * Return a new descriptor. */ public ClassDescriptor() { // Properties this.tables = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(3); this.mappings = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(); this.primaryKeyFields = new ArrayList(2); this.fields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(); this.allFields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(); this.constraintDependencies = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(2); this.multipleTableForeignKeys = new HashMap(5); this.queryKeys = new HashMap(5); this.initializationStage = UNINITIALIZED; this.shouldAlwaysRefreshCache = false; this.shouldOnlyRefreshCacheIfNewerVersion = false; this.shouldDisableCacheHits = false; this.identityMapSize = 100; this.identityMapClass = IdentityMap.getDefaultIdentityMapClass(); this.descriptorType = NORMAL; this.shouldOrderMappings = true; this.shouldBeReadOnly = false; this.shouldAlwaysConformResultsInUnitOfWork = false; this.shouldAcquireCascadedLocks = false; this.hasSimplePrimaryKey = false; this.isIsolated = false; // Policies this.objectBuilder = new ObjectBuilder(this); setCopyPolicy(new InstantiationCopyPolicy()); setInstantiationPolicy(new InstantiationPolicy()); setEventManager(new oracle.toplink.essentials.descriptors.DescriptorEventManager()); setQueryManager(new oracle.toplink.essentials.descriptors.DescriptorQueryManager()); changePolicy = new DeferredChangeDetectionPolicy(); this.cascadeLockingPolicies = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(); } /** * PUBLIC: * This method should only be used for interface descriptors. It * adds an abstract query key to the interface descriptor. Any * implementors of that interface must define the query key * defined by this abstract query key. */ public void addAbstractQueryKey(String queryKeyName) { QueryKey queryKey = new QueryKey(); queryKey.setName(queryKeyName); addQueryKey(queryKey); } /** * ADVANCED: * TopLink automatically orders database access through the foreign key information provided in 1:1 and 1:m mappings. * In some case when 1:1 are not defined it may be required to tell the descriptor about a constraint, * this defines that this descriptor has a foreign key constraint to another class and must be inserted after * instances of the other class. */ public void addConstraintDependencies(Class dependencies) { getConstraintDependencies().addElement(dependencies); } /** * PUBLIC: * Add a direct mapping to the receiver. The new mapping specifies that * an instance variable of the class of objects which the receiver describes maps in * the default manner for its type to the indicated database field. * * @param String instanceVariableName is the name of an instance variable of the * class which the receiver describes. * @param String fieldName is the name of the database column which corresponds * with the designated instance variable. * @return The newly created DatabaseMapping is returned. */ public DatabaseMapping addDirectMapping(String attributeName, String fieldName) { DirectToFieldMapping mapping = new DirectToFieldMapping(); mapping.setAttributeName(attributeName); mapping.setFieldName(fieldName); return addMapping(mapping); } /** * PUBLIC: * Add a direct mapping to the receiver. The new mapping specifies that * a variable accessed by the get and set methods of the class of objects which * the receiver describes maps in the default manner for its type to the indicated * database field. */ public DatabaseMapping addDirectMapping(String attributeName, String getMethodName, String setMethodName, String fieldName) { DirectToFieldMapping mapping = new DirectToFieldMapping(); mapping.setAttributeName(attributeName); mapping.setSetMethodName(setMethodName); mapping.setGetMethodName(getMethodName); mapping.setFieldName(fieldName); return addMapping(mapping); } /** * PUBLIC: * Add a query key to the descriptor. Query keys define Java aliases to database fields. */ public void addDirectQueryKey(String queryKeyName, String fieldName) { DirectQueryKey queryKey = new DirectQueryKey(); DatabaseField field = new DatabaseField(fieldName); queryKey.setName(queryKeyName); queryKey.setField(field); getQueryKeys().put(queryKeyName, queryKey); } /** * PUBLIC: * Add a database mapping to the receiver. Perform any required * initialization of both the mapping and the receiving descriptor * as a result of adding the new mapping. */ public DatabaseMapping addMapping(DatabaseMapping mapping) { // For CR#2646, if the mapping already points to the parent descriptor then leave it. if (mapping.getDescriptor() == null) { mapping.setDescriptor(this); } getMappings().addElement(mapping); return mapping; } protected void validateMappingType(DatabaseMapping mapping) { if (!(mapping.isRelationalMapping())) { throw DescriptorException.invalidMappingType(mapping); } } /** * PUBLIC: * This protocol can be used to associate multiple tables with foreign key * information. The join criteria will be generated based on the fields * provided. By default TopLink associates multiple tables using a primary * key join where the primary keys fields are named the same. */ public void addMultipleTableForeignKeyField(DatabaseField sourceField, DatabaseField targetField) throws DescriptorException { addMultipleTableForeignKeys(sourceField, targetField, true); } /** * PUBLIC: * This protocol can be used to associate multiple tables with foreign key * information. The join criteria will be generated based on the fields * provided. By default TopLink associates multiple tables using a primary * key join where the primary keys fields are named the same. */ public void addMultipleTableForeignKeyFieldName(String sourceFieldName, String targetFieldName) throws DescriptorException { addMultipleTableForeignKeyField(new DatabaseField(sourceFieldName), new DatabaseField(targetFieldName)); } /** * INTERNAL: * Add the multiple fields, if is a foreign key then add the tables to the * foreign keys ordering. */ protected void addMultipleTableForeignKeys(DatabaseField sourceField, DatabaseField targetField, boolean isForeignKey) throws DescriptorException { // Make sure that the table is fully qualified. if ((!sourceField.hasTableName()) || (!targetField.hasTableName())) { throw DescriptorException.multipleTablePrimaryKeyMustBeFullyQualified(this); } DatabaseTable sourceTable = sourceField.getTable(); DatabaseTable targetTable = targetField.getTable(); setAdditionalTablePrimaryKeyFields(targetTable, sourceField, targetField); if (isForeignKey) { getMultipleTableForeignKeys().put(sourceTable, targetTable); } } /** * INTERNAL: * Add the multiple table fields, if is a foreign key then add the tables to the * foreign keys ordering. */ protected void addMultipleTableForeignKeys(String fieldNameInSourceTable, String fieldNameInTargetTable, boolean isForeignKey) throws DescriptorException { addMultipleTableForeignKeys(new DatabaseField(fieldNameInSourceTable), new DatabaseField(fieldNameInTargetTable), isForeignKey); } /** * PUBLIC: * This protocol can be used to map the primary key fields in a multiple * table descriptor. By default TopLink assumes that all of the primary key * fields are named the same. */ public void addMultipleTablePrimaryKeyField(DatabaseField sourceField, DatabaseField targetField) throws DescriptorException { addMultipleTableForeignKeys(sourceField, targetField, false); } /** * PUBLIC: * This protocol can be used to map the primary key field names in a * multiple table descriptor. By default TopLink assumes that all of the * primary key fields are named the same. */ public void addMultipleTablePrimaryKeyFieldName(String sourceFieldName, String targetFieldName) throws DescriptorException { addMultipleTablePrimaryKeyField(new DatabaseField(sourceFieldName), new DatabaseField(targetFieldName)); } /** * PUBLIC: * Specify the primary key field of the descriptors table. * This should be called for each field that makes up the primary key of the table. * If the descriptor has many tables, this must be the primary key in the first table, * if the other tables have the same primary key nothing else is required, otherwise * a primary key/foreign key field mapping must be provided for each of the other tables. * @see #addMultipleTableForeignKeyFieldName(String, String); */ public void addPrimaryKeyFieldName(String fieldName) { getPrimaryKeyFields().add(new DatabaseField(fieldName)); } /** * ADVANCED: * Specify the primary key field of the descriptors table. * This should be called for each field that makes up the primary key of the table. * This can be used for advanced field types, such as XML nodes, or to set the field type. */ public void addPrimaryKeyField(DatabaseField field) { getPrimaryKeyFields().add(field); } /** * PUBLIC: * Add a query key to the descriptor. Query keys define Java aliases to database fields. */ public void addQueryKey(QueryKey queryKey) { getQueryKeys().put(queryKey.getName(), queryKey); } /** * PUBLIC: * Specify the table for the class of objects the receiver describes. * This method is used if there is more than one table. */ public void addTable(DatabaseTable table) { getTables().addElement(table); } /** * PUBLIC: * Specify the table name for the class of objects the receiver describes. * If the table has a qualifier it should be specified using the dot notation, * (i.e. "userid.employee"). This method is used if there is more than one table. */ public void addTableName(String tableName) { addTable(new DatabaseTable(tableName)); } /** * INTERNAL: * Adjust the order of the tables in the multipleTableInsertOrder Vector according to the FK * relationship if one (or more) were previously specified. I.e. target of FK relationship should be inserted * before source. * If the multipleTableInsertOrder has been specified (presumably by the user) then do not change it. */ public void adjustMultipleTableInsertOrder() { // Check if a user defined insert order was given. if ((getMultipleTableInsertOrder() == null) || getMultipleTableInsertOrder().isEmpty()) { setMultipleTableInsertOrder((Vector) getTables().clone()); checkMultipleTableForeignKeys(false); } else { if (getMultipleTableInsertOrder().size() != getTables().size()) { throw DescriptorException.multipleTableInsertOrderMismatch(this); } checkMultipleTableForeignKeys(true); } } /** * PUBLIC: * Used to set the descriptor to always conform in any unit of work query. * */ public void alwaysConformResultsInUnitOfWork() { setShouldAlwaysConformResultsInUnitOfWork(true); } /** * PUBLIC: * This method is the equivalent of calling {@link #setShouldAlwaysRefreshCache} with an argument of true: * it configures a Descriptor to always refresh the cache if data is received from the database by any query.

* * However, if a query hits the cache, data is not refreshed regardless of how this setting is configured. For example, by * default, when a query for a single object based on its primary key is executed, OracleAS TopLink will first look in the * cache for the object. If the object is in the cache, the cached object is returned and data is not refreshed. To avoid * cache hits, use the {@link #disableCacheHits} method.

* * Also note that the {@link oracle.toplink.essentials.sessions.UnitOfWork} will not refresh its registered objects.

* * Use this property with caution because it can lead to poor performance and may refresh on queries when it is not desired. Normally, * if you require fresh data, it is better to configure a query with {@link oracle.toplink.essentials.queryframework.ObjectLevelReadQuery#refreshIdentityMapResult}. * To ensure that refreshes are only done when required, use this method in conjunction with {@link #onlyRefreshCacheIfNewerVersion}. * * @see #dontAlwaysRefreshCache */ public void alwaysRefreshCache() { setShouldAlwaysRefreshCache(true); } /** * ADVANCED: * Call the descriptor amendment method. * This is called while loading or creating a descriptor that has an amendment method defined. */ public void applyAmendmentMethod() { applyAmendmentMethod(null); } /** * INTERNAL: * Call the descriptor amendment method. * This is called while loading or creating a descriptor that has an amendment method defined. */ public void applyAmendmentMethod(DescriptorEvent event) { if ((getAmendmentClass() == null) || (getAmendmentMethodName() == null)) { return; } Method method = null; Class[] argTypes = new Class[1]; // BUG#2669585 // Class argument type must be consistent, descriptor, i.e. instance may be a subclass. argTypes[0] = ClassDescriptor.class; try { method = Helper.getDeclaredMethod(getAmendmentClass(), getAmendmentMethodName(), argTypes); } catch (Exception ignore) { // Return type should now be ClassDescriptor. argTypes[0] = ClassDescriptor.class; try { method = Helper.getDeclaredMethod(getAmendmentClass(), getAmendmentMethodName(), argTypes); } catch (Exception exception) { throw DescriptorException.invalidAmendmentMethod(getAmendmentClass(), getAmendmentMethodName(), exception, this); } } Object[] args = new Object[1]; args[0] = this; try { if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ try { AccessController.doPrivileged(new PrivilegedMethodInvoker(method, null, args)); } catch (PrivilegedActionException exception) { Exception throwableException = exception.getException(); if (throwableException instanceof IllegalAccessException) { throw (IllegalAccessException)throwableException; } else { throw (InvocationTargetException)throwableException; } } } else { PrivilegedAccessHelper.invokeMethod(method, null, args); } } catch (Exception exception) { throw DescriptorException.errorOccuredInAmendmentMethod(getAmendmentClass(), getAmendmentMethodName(), exception, this); } } /** * INTERNAL: * Used to determine if a foreign key references the primary key. */ public boolean arePrimaryKeyFields(Vector fields) { if (!(fields.size() == (getPrimaryKeyFields().size()))) { return false; } for (Enumeration enumFields = fields.elements(); enumFields.hasMoreElements();) { DatabaseField field = (DatabaseField)enumFields.nextElement(); if (!getPrimaryKeyFields().contains(field)) { return false; } } return true; } /** * INTERNAL: * Return a call built from a statement. Subclasses may throw an exception * if the statement is not appropriate. */ public DatabaseCall buildCallFromStatement(SQLStatement statement, AbstractSession session) { return statement.buildCall(session); } /** * INTERNAL: * Extract the direct values from the specified field value. * Return them in a vector. */ public Vector buildDirectValuesFromFieldValue(Object fieldValue) throws DatabaseException { throw DescriptorException.normalDescriptorsDoNotSupportNonRelationalExtensions(this); } /** * INTERNAL: * A DatabaseField is built from the given field name. */ // * added 9/7/00 by Les Davis // * bug fix for null pointer in initialization of mappings in remote session public DatabaseField buildField(String fieldName) { DatabaseField field = new DatabaseField(fieldName); DatabaseTable table; if (field.hasTableName()) { table = getTable(field.getTableName()); } else if (getDefaultTable() != null) { table = getDefaultTable(); } else { table = getTable(getTableName()); } field.setTable(table); return field; } /** * INTERNAL: * The table of the field is ensured to be unique from the descriptor's tables. * If the field has no table the default table is assigned. * This is used only in initialization. */ public void buildField(DatabaseField field) { DatabaseTable table; if (field.hasTableName()) { table = getTable(field.getTableName()); } else { table = getDefaultTable(); } field.setTable(table); } /** * INTERNAL: * Build the appropriate field value for the specified * set of direct values. */ public Object buildFieldValueFromDirectValues(Vector directValues, String elementDataTypeName, AbstractSession session) throws DatabaseException { throw DescriptorException.normalDescriptorsDoNotSupportNonRelationalExtensions(this); } /** * INTERNAL: * Build and return the appropriate field value for the specified * set of foreign keys (i.e. each row has the fields that * make up a foreign key). */ public Object buildFieldValueFromForeignKeys(Vector foreignKeys, String referenceDataTypeName, AbstractSession session) throws DatabaseException { throw DescriptorException.normalDescriptorsDoNotSupportNonRelationalExtensions(this); } /** * INTERNAL: * Build and return the field value from the specified nested database row. */ public Object buildFieldValueFromNestedRow(AbstractRecord nestedRow, AbstractSession session) throws DatabaseException { throw DescriptorException.normalDescriptorsDoNotSupportNonRelationalExtensions(this); } /** * INTERNAL: * Build and return the appropriate field value for the specified * set of nested rows. */ public Object buildFieldValueFromNestedRows(Vector nestedRows, String structureName, AbstractSession session) throws DatabaseException { throw DescriptorException.normalDescriptorsDoNotSupportNonRelationalExtensions(this); } /** * INTERNAL: * Build and return the nested database row from the specified field value. */ public AbstractRecord buildNestedRowFromFieldValue(Object fieldValue) throws DatabaseException { throw DescriptorException.normalDescriptorsDoNotSupportNonRelationalExtensions(this); } /** * INTERNAL: * Build and return the nested rows from the specified field value. */ public Vector buildNestedRowsFromFieldValue(Object fieldValue, AbstractSession session) throws DatabaseException { throw DescriptorException.normalDescriptorsDoNotSupportNonRelationalExtensions(this); } /** * To check that tables and fields are present in database */ protected void checkDatabase(AbstractSession session) { if (session.getIntegrityChecker().shouldCheckDatabase()) { for (Enumeration enumTable = getTables().elements(); enumTable.hasMoreElements();) { DatabaseTable table = (DatabaseTable)enumTable.nextElement(); if (session.getIntegrityChecker().checkTable(table, session)) { // To load the fields of database into a vector Vector databaseFields = new Vector(); Vector result = session.getAccessor().getColumnInfo(null, null, table.getName(), null, session); for (Enumeration resultEnum = result.elements(); resultEnum.hasMoreElements();) { AbstractRecord row = (AbstractRecord)resultEnum.nextElement(); databaseFields.addElement(row.get("COLUMN_NAME")); } // To check that the fields of descriptor are present in the database. for (Enumeration row = getFields().elements(); row.hasMoreElements();) { DatabaseField field = (DatabaseField)row.nextElement(); if (field.getTable().equals(table) && (!databaseFields.contains(field.getName()))) { session.getIntegrityChecker().handleError(DescriptorException.fieldIsNotPresentInDatabase(this, table.getName(), field.getName())); } } } else { session.getIntegrityChecker().handleError(DescriptorException.tableIsNotPresentInDatabase(this)); } } } } /** * INTERNAL: * Verify that an aggregate descriptor's inheritance tree * is full of aggregate descriptors. */ public void checkInheritanceTreeAggregateSettings(AbstractSession session, AggregateMapping mapping) throws DescriptorException { if (!this.hasInheritance()) { return; } if (this.isChildDescriptor()) { Class parentClass = this.getInheritancePolicy().getParentClass(); if (parentClass == this.getJavaClass()) { throw DescriptorException.parentClassIsSelf(this); } // recurse up the inheritance tree to the root descriptor session.getDescriptor(parentClass).checkInheritanceTreeAggregateSettings(session, mapping); } else { // we have a root descriptor, now verify it and all its children, grandchildren, etc. this.checkInheritanceTreeAggregateSettingsForChildren(session, mapping); } } /** * Verify that an aggregate descriptor's inheritance tree * is full of aggregate descriptors, cont. */ private void checkInheritanceTreeAggregateSettingsForChildren(AbstractSession session, AggregateMapping mapping) throws DescriptorException { if (!this.isAggregateDescriptor()) { session.getIntegrityChecker().handleError(DescriptorException.referenceDescriptorIsNotAggregate(this.getJavaClass().getName(), mapping)); } for (Enumeration stream = this.getInheritancePolicy().getChildDescriptors().elements(); stream.hasMoreElements();) { ClassDescriptor childDescriptor = (ClassDescriptor)stream.nextElement(); // recurse down the inheritance tree to its leaves childDescriptor.checkInheritanceTreeAggregateSettingsForChildren(session, mapping); } } /** * INTERNAL: */ protected void checkMultipleTableForeignKeys(boolean userSpecifiedOrder) { // Loop through n times to be sure that the insert order is correct. // Loop n times eliminates our dependence on the order of the foreighKey // relationships specified. We could do this adjustment in one pass but // we would have to put the foreignKeyTables in the same order as the // tables being sorted. Map foreignKeyTableRelationships = getMultipleTableForeignKeys(); for (int i = 0; i < foreignKeyTableRelationships.size(); i++) { for (Iterator sourceTables = foreignKeyTableRelationships.entrySet().iterator(); sourceTables.hasNext();) { Map.Entry entry = (Map.Entry)sourceTables.next(); DatabaseTable sourceTable = (DatabaseTable) entry.getKey(); DatabaseTable targetTable = (DatabaseTable) entry.getValue(); // Verify the source table is a valid. if (getMultipleTableInsertOrder().indexOf(sourceTable) == -1) { throw DescriptorException.illegalTableNameInMultipleTableForeignKeyField(this, sourceTable); } // Verify the target table is a valid. if (getMultipleTableInsertOrder().indexOf(targetTable) == -1) { throw DescriptorException.illegalTableNameInMultipleTableForeignKeyField(this, targetTable); } int sourceTableIndex = getTables().indexOf(sourceTable); int targetTableIndex = getTables().indexOf(targetTable); // The sourceTable must be before the targetTable to avoid // foreign key constraint violations when inserting into the // database. if (targetTableIndex < sourceTableIndex) { if (userSpecifiedOrder) { toggleAdditionalTablePrimaryKeyFields(targetTable, sourceTable); } else { int sti = getMultipleTableInsertOrder().indexOf(sourceTable); int tti = getMultipleTableInsertOrder().indexOf(targetTable); if (tti < sti) { toggleAdditionalTablePrimaryKeyFields(targetTable, sourceTable); getMultipleTableInsertOrder().removeElementAt(tti); getMultipleTableInsertOrder().insertElementAt(targetTable, sti); } } } } } } /** * INTERNAL: * Clones the descriptor */ public Object clone() { ClassDescriptor clonedDescriptor = null; // clones itself try { clonedDescriptor = (ClassDescriptor)super.clone(); } catch (Exception exception) { ; } Vector mappingsVector = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(); // All the mappings for (Enumeration mappingsEnum = getMappings().elements(); mappingsEnum.hasMoreElements();) { DatabaseMapping mapping; mapping = (DatabaseMapping)((DatabaseMapping)mappingsEnum.nextElement()).clone(); mapping.setDescriptor(clonedDescriptor); mappingsVector.addElement(mapping); } clonedDescriptor.setMappings(mappingsVector); Map queryKeyVector = new HashMap(getQueryKeys().size() + 2); // All the query keys for (Iterator queryKeysEnum = getQueryKeys().values().iterator();queryKeysEnum.hasNext();){ QueryKey queryKey = (QueryKey)((QueryKey)queryKeysEnum.next()).clone(); queryKey.setDescriptor(clonedDescriptor); queryKeyVector.put(queryKey.getName(), queryKey); } clonedDescriptor.setQueryKeys(queryKeyVector); // PrimaryKeyFields List primaryKeyVector = new ArrayList(getPrimaryKeyFields().size()); List primaryKeyFields = getPrimaryKeyFields(); for (int index = 0; index < primaryKeyFields.size(); index++) { DatabaseField primaryKey = (DatabaseField)((DatabaseField)primaryKeyFields.get(index)).clone(); primaryKeyVector.add(primaryKey); } clonedDescriptor.setPrimaryKeyFields(primaryKeyVector); // fields. clonedDescriptor.setFields(oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance()); // The inheritance policy if (clonedDescriptor.hasInheritance()) { clonedDescriptor.setInheritancePolicy((InheritancePolicy)getInheritancePolicy().clone()); clonedDescriptor.getInheritancePolicy().setDescriptor(clonedDescriptor); } // The Object builder clonedDescriptor.setObjectBuilder((ObjectBuilder)getObjectBuilder().clone()); clonedDescriptor.getObjectBuilder().setDescriptor(clonedDescriptor); clonedDescriptor.setEventManager((DescriptorEventManager)getEventManager().clone()); clonedDescriptor.getEventManager().setDescriptor(clonedDescriptor); // The Query manager clonedDescriptor.setQueryManager((DescriptorQueryManager)getQueryManager().clone()); clonedDescriptor.getQueryManager().setDescriptor(clonedDescriptor); //fetch group if (hasFetchGroupManager()) { clonedDescriptor.setFetchGroupManager((FetchGroupManager)getFetchGroupManager().clone()); } clonedDescriptor.setIsIsolated(this.isIsolated()); // Bug 3037701 - clone several more elements clonedDescriptor.setInstantiationPolicy((InstantiationPolicy)this.instantiationPolicy.clone()); clonedDescriptor.setCopyPolicy((CopyPolicy)this.copyPolicy.clone()); if (getOptimisticLockingPolicy() != null) { clonedDescriptor.setOptimisticLockingPolicy((OptimisticLockingPolicy)this.getOptimisticLockingPolicy().clone()); } return (Object)clonedDescriptor; } /** * INTERNAL: * Convert all the class-name-based settings in this Descriptor to actual class-based * settings. This method is used when converting a project that has been built * with class names to a project with classes. * @param classLoader */ public void convertClassNamesToClasses(ClassLoader classLoader){ Class descriptorClass = null; Class amendmentClass = null; try{ if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ try { descriptorClass = (Class)AccessController.doPrivileged(new PrivilegedClassForName(getJavaClassName(), true, classLoader)); } catch (PrivilegedActionException exception) { throw ValidationException.classNotFoundWhileConvertingClassNames(getAmendmentClassName(), exception.getException()); } } else { descriptorClass = oracle.toplink.essentials.internal.security.PrivilegedAccessHelper.getClassForName(getJavaClassName(), true, classLoader); } if (getAmendmentClassName() != null){ if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ try { amendmentClass = (Class)AccessController.doPrivileged(new PrivilegedClassForName(getAmendmentClassName(), true, classLoader)); } catch (PrivilegedActionException exception) { throw ValidationException.classNotFoundWhileConvertingClassNames(getAmendmentClassName(), exception.getException()); } } else { amendmentClass = oracle.toplink.essentials.internal.security.PrivilegedAccessHelper.getClassForName(getAmendmentClassName(), true, classLoader); } } } catch (ClassNotFoundException exc){ throw ValidationException.classNotFoundWhileConvertingClassNames(getAmendmentClassName(), exc); } setJavaClass(descriptorClass); if (amendmentClass != null){ setAmendmentClass(amendmentClass); } Iterator mappings = getMappings().iterator(); while (mappings.hasNext()){ ((DatabaseMapping)mappings.next()).convertClassNamesToClasses(classLoader); } if (inheritancePolicy != null){ inheritancePolicy.convertClassNamesToClasses(classLoader); } if (instantiationPolicy != null){ instantiationPolicy.convertClassNamesToClasses(classLoader); } if (hasCMPPolicy()) { getCMPPolicy().convertClassNamesToClasses(classLoader); } queryManager.convertClassNamesToClasses(classLoader); } /** * PUBLIC: * Create a copy policy of the type passed in as a string. */ public void createCopyPolicy(String policyType) { if (policyType.equals("clone")) { useCloneCopyPolicy(); return; } if (policyType.equals("constructor")) { useInstantiationCopyPolicy(); return; } } /** * PUBLIC: * Create a instantiation policy of the type passed in as a string. */ public void createInstantiationPolicy(String policyType) { if (policyType.equals("static method")) { //do nothing for now return; } if (policyType.equals("constructor")) { useDefaultConstructorInstantiationPolicy(); return; } if (policyType.equals("factory")) { //do nothing for now return; } } /** * PUBLIC: * Sets the descriptor to be an aggregate. * An aggregate descriptor is contained within another descriptor's table. * Aggregate descriptors are insert/updated/deleted with their owner and cannot exist without their owner as they share the same row. * Aggregates are not cached (they are cached as part of their owner) and cannot be read/written/deleted/registered. * All aggregate descriptors must call this. */ public void descriptorIsAggregate() { setDescriptorType(AGGREGATE); } /** * PUBLIC: * Sets the descriptor to be part of an aggregate collection. * An aggregate collection descriptor stored in a seperate table but some of the fields (the primary key) comes from its owner. * Aggregate collection descriptors are insert/updated/deleted with their owner and cannot exist without their owner as they share the primary key. * Aggregate collections are not cached (they are cached as part of their owner) and cannot be read/written/deleted/registered. * All aggregate collection descriptors must call this. */ public void descriptorIsAggregateCollection() { setDescriptorType(AGGREGATE_COLLECTION); } /** * PUBLIC: * Sets the descriptor to be normal. * This is the default and means the descriptor is not aggregate or for an interface. */ public void descriptorIsNormal() { setDescriptorType(NORMAL); } /** * PUBLIC: * Allow for cache hits on primary key read object queries to be disabled. * This can be used with {@link #alwaysRefreshCache} or {@link #alwaysRefreshCacheOnRemote} to ensure queries always go to the database. */ public void disableCacheHits() { setShouldDisableCacheHits(true); } /** * PUBLIC: * The descriptor is defined to not conform the results in unit of work in read query. Default. * */ public void dontAlwaysConformResultsInUnitOfWork() { setShouldAlwaysConformResultsInUnitOfWork(false); } /** * PUBLIC: * This method is the equivalent of calling {@link #setShouldAlwaysRefreshCache} with an argument of false: * it ensures that a Descriptor is not configured to always refresh the cache if data is received from the database by any query. * * @see #alwaysRefreshCache */ public void dontAlwaysRefreshCache() { setShouldAlwaysRefreshCache(false); } /** * PUBLIC: * Allow for cache hits on primary key read object queries. * * @see #disableCacheHits() */ public void dontDisableCacheHits() { setShouldDisableCacheHits(false); } /** * PUBLIC: * This method is the equivalent of calling {@link #setShouldOnlyRefreshCacheIfNewerVersion} with an argument of false: * it ensures that a Descriptor is not configured to only refresh the cache if the data received from the database by * a query is newer than the data in the cache (as determined by the optimistic locking field). * * @see #onlyRefreshCacheIfNewerVersion */ public void dontOnlyRefreshCacheIfNewerVersion() { setShouldOnlyRefreshCacheIfNewerVersion(false); } /** * INTERNAL: * The first table in the tables is always treated as default. */ protected DatabaseTable extractDefaultTable() { if (getTables().isEmpty()) { if (isChildDescriptor()) { return getInheritancePolicy().getParentDescriptor().extractDefaultTable(); } else { return null; } } return (DatabaseTable)getTables().firstElement(); } /** * INTERNAL: * This is used to map the primary key field names in a multiple table descriptor. */ public Map> getAdditionalTablePrimaryKeyFields() { if (additionalTablePrimaryKeyFields == null) { additionalTablePrimaryKeyFields = new HashMap(5); } return additionalTablePrimaryKeyFields; } /** * PUBLIC: * Get the alias */ public String getAlias() { /* CR3310: Steven Vo * Default alias to the Java class name if the alias is not set */ if ((alias == null) && (getJavaClassName() != null)) { alias = oracle.toplink.essentials.internal.helper.Helper.getShortClassName(getJavaClassName()); } return alias; } /** * INTERNAL: * Return all the fields which include all child class fields. * By default it is initialized to the fields for the current descriptor. */ public Vector getAllFields() { return allFields; } /** * PUBLIC: * Return the amendment class. * The amendment method will be called on the class before initialization to allow for it to initialize the descriptor. * The method must be a public static method on the class. */ public Class getAmendmentClass() { return amendmentClass; } /** * INTERNAL: * Return amendment class name, used by the MW. */ public String getAmendmentClassName() { if ((amendmentClassName == null) && (amendmentClass != null)) { amendmentClassName = amendmentClass.getName(); } return amendmentClassName; } /** * PUBLIC: * Return the amendment method. * This will be called on the amendment class before initialization to allow for it to initialize the descriptor. * The method must be a public static method on the class. */ public String getAmendmentMethodName() { return amendmentMethodName; } /** * PUBLIC: * Return this objects ObjectChangePolicy. */ public ObjectChangePolicy getObjectChangePolicy() { // part of fix for 4410581: project xml must save change policy // if no change-policy XML element, field is null: lazy-init to default if (changePolicy == null) { changePolicy = new DeferredChangeDetectionPolicy(); } return changePolicy; } /** * PUBLIC: * Return the CacheInvalidationPolicy for this descriptor * For uninitialized cache invalidation policies, this will return a NoExpiryCacheInvalidationPolicy * @return CacheInvalidationPolicy * @see oracle.toplink.essentials.descriptors.invalidation.CacheInvalidationPolicy */ public CacheInvalidationPolicy getCacheInvalidationPolicy() { if (cacheInvalidationPolicy == null) { cacheInvalidationPolicy = new NoExpiryCacheInvalidationPolicy(); } return cacheInvalidationPolicy; } /** * INTERNAL: */ public Vector getCascadeLockingPolicies() { return cascadeLockingPolicies; } /** * ADVANCED: * TopLink automatically orders database access through the foreign key information provided in 1:1 and 1:m mappings. * In some case when 1:1 are not defined it may be required to tell the descriptor about a constraint, * this defines that this descriptor has a foreign key constraint to another class and must be inserted after * instances of the other class. */ public Vector getConstraintDependencies() { return constraintDependencies; } /** * INTERNAL: * Returns the copy policy. */ public CopyPolicy getCopyPolicy() { return copyPolicy; } /** * INTERNAL: * The first table in the tables is always treated as default. */ public DatabaseTable getDefaultTable() { return defaultTable; } /** * ADVANCED: * return the descriptor type (NORMAL by default, others include INTERFACE, AGGREGATE, AGGREGATE COLLECTION) */ public int getDescriptorType() { return descriptorType; } /** * INTERNAL: * This method is explicitly used by the XML reader. */ public String getDescriptorTypeValue() { if (isAggregateCollectionDescriptor()) { return "Aggregate collection"; } else if (isAggregateDescriptor()) { return "Aggregate"; } else { // Default. return "Normal"; } } /** * PUBLIC: * Get the event manager for the descriptor. The event manager is responsible * for managing the pre/post selectors. */ public DescriptorEventManager getDescriptorEventManager() { return getEventManager(); } /** * PUBLIC: * Get the event manager for the descriptor. The event manager is responsible * for managing the pre/post selectors. */ public DescriptorEventManager getEventManager() { return eventManager; } /** * INTERNAL: * Return all the fields */ public Vector getFields() { return fields; } /** * INTERNAL: * Return the class of identity map to be used by this descriptor. * The default is the "SoftCacheWeakIdentityMap". */ public Class getIdentityMapClass() { return identityMapClass; } /** * PUBLIC: * Return the size of the identity map. */ public int getIdentityMapSize() { return identityMapSize; } /** * PUBLIC: * The inheritance policy is used to define how a descriptor takes part in inheritance. * All inheritance properties for both child and parent classes is configured in inheritance policy. * Caution must be used in using this method as it lazy initializes an inheritance policy. * Calling this on a descriptor that does not use inheritance will cause problems, #hasInheritance() must always first be called. */ public InheritancePolicy getDescriptorInheritancePolicy() { return getInheritancePolicy(); } /** * PUBLIC: * The inheritance policy is used to define how a descriptor takes part in inheritance. * All inheritance properties for both child and parent classes is configured in inheritance policy. * Caution must be used in using this method as it lazy initializes an inheritance policy. * Calling this on a descriptor that does not use inheritance will cause problems, #hasInheritance() must always first be called. */ public InheritancePolicy getInheritancePolicy() { if (inheritancePolicy == null) { // Lazy initialize to conserve space in non-inherited classes. setInheritancePolicy(new oracle.toplink.essentials.descriptors.InheritancePolicy(this)); } return inheritancePolicy; } /** * INTERNAL: * Return the inheritance policy. */ public InheritancePolicy getInheritancePolicyOrNull() { return inheritancePolicy; } /** * INTERNAL: * Returns the instantiation policy. */ public InstantiationPolicy getInstantiationPolicy() { return instantiationPolicy; } /** * PUBLIC: * Return the java class. */ public Class getJavaClass() { return javaClass; } /** * Return the class name, used by the MW. */ public String getJavaClassName() { if ((javaClassName == null) && (javaClass != null)) { javaClassName = javaClass.getName(); } return javaClassName; } /** * INTERNAL: * Returns a reference to the mappings that must be traverse when locking */ public List getLockableMappings() { if (this.lockableMappings == null) { this.lockableMappings = new ArrayList(); } return this.lockableMappings; } /** * PUBLIC: * Returns the mapping associated with a given attribute name. * This can be used to find a descriptors mapping in a amendment method before the descriptor has been initialized. */ public DatabaseMapping getMappingForAttributeName(String attributeName) { // ** Don't use this internally, just for amendments, see getMappingForAttributeName on ObjectBuilder. for (Enumeration mappingsNum = mappings.elements(); mappingsNum.hasMoreElements();) { DatabaseMapping mapping = (DatabaseMapping)mappingsNum.nextElement(); if ((mapping.getAttributeName() != null) && mapping.getAttributeName().equals(attributeName)) { return mapping; } } return null; } /** * ADVANCED: * Removes the locally defined mapping associated with a given attribute name. * This can be used in a amendment method before the descriptor has been initialized. */ public DatabaseMapping removeMappingForAttributeName(String attributeName) { DatabaseMapping mapping = getMappingForAttributeName(attributeName); getMappings().remove(mapping); return mapping; } /** * PUBLIC: * Returns mappings */ public Vector getMappings() { return mappings; } /** * INTERNAL: * Returns the foreign key relationships used for multiple tables which were specified by the user. Used * by the Project XML writer to output these associations * * @see #adjustMultipleTableInsertOrder() * @return java.util.Hashtable */ public Vector getMultipleTableForeignKeyAssociations() { Vector associations = new Vector(getAdditionalTablePrimaryKeyFields().size() * 2); Iterator tablesHashtable = getAdditionalTablePrimaryKeyFields().values().iterator(); while (tablesHashtable.hasNext()) { Map tableHash = (Map)tablesHashtable.next(); Iterator fieldEnumeration = tableHash.keySet().iterator(); while (fieldEnumeration.hasNext()) { DatabaseField keyField = (DatabaseField)fieldEnumeration.next(); //PRS#36802(CR#2057) contains() is changed to containsKey() if (getMultipleTableForeignKeys().containsKey(keyField.getTable())) { Association association = new Association(keyField.getQualifiedName(), ((DatabaseField)tableHash.get(keyField)).getQualifiedName()); associations.addElement(association); } } } return associations; } /** * INTERNAL: * Returns the foreign key relationships used for multiple tables which were specified by the user. The key * of the Map is the field in the source table of the foreign key relationship. The value is the field * name of the target table. * * @see #adjustMultipleTableInsertOrder() */ public Map getMultipleTableForeignKeys() { return multipleTableForeignKeys; } /** * INTERNAL: * Returns the Vector of DatabaseTables in the order which INSERTS should take place. This order is * determined by the foreign key fields which are specified by the user. * * @return java.util.Vector */ public Vector getMultipleTableInsertOrder() throws DescriptorException { return multipleTableInsertOrder; } /** * INTERNAL: * Returns the foreign key relationships used for multiple tables which were specified by the user. Used * by the Project XML writer to output these associations * * @see #adjustMultipleTableInsertOrder() */ public Vector getMultipleTablePrimaryKeyAssociations() { Vector associations = new Vector(getAdditionalTablePrimaryKeyFields().size() * 2); Iterator tablesHashtable = getAdditionalTablePrimaryKeyFields().values().iterator(); while (tablesHashtable.hasNext()) { Map tableHash = (Map)tablesHashtable.next(); Iterator fieldEnumeration = tableHash.keySet().iterator(); while (fieldEnumeration.hasNext()) { DatabaseField keyField = (DatabaseField)fieldEnumeration.next(); //PRS#36802(CR#2057) contains() is changed to containsKey() if (!getMultipleTableForeignKeys().containsKey(keyField.getTable())) { Association association = new Association(keyField.getQualifiedName(), ((DatabaseField)tableHash.get(keyField)).getQualifiedName()); associations.addElement(association); } } } return associations; } /** * INTERNAL: * Return the object builder */ public ObjectBuilder getObjectBuilder() { return objectBuilder; } /** * PUBLIC: * Returns the OptimisticLockingPolicy. By default this is an instance of VersionLockingPolicy. */ public OptimisticLockingPolicy getOptimisticLockingPolicy() { return optimisticLockingPolicy; } /** * PUBLIC: * Return the names of all the primary keys. */ public Vector getPrimaryKeyFieldNames() { Vector result = new Vector(getPrimaryKeyFields().size()); List primaryKeyFields = getPrimaryKeyFields(); for (int index = 0; index < primaryKeyFields.size(); index++) { result.addElement(((DatabaseField)primaryKeyFields.get(index)).getQualifiedName()); } return result; } /** * INTERNAL: * Return all the primary key fields */ public List getPrimaryKeyFields() { return primaryKeyFields; } /** * PUBLIC: * Returns the user defined properties. */ public Map getProperties() { if (properties == null) { properties = new HashMap(5); } return properties; } /** * PUBLIC: * Returns the descriptor property associated the given String. */ public Object getProperty(String name) { return getProperties().get(name); } /** * INTERNAL: * Return the query key with the specified name */ public QueryKey getQueryKeyNamed(String queryKeyName) { return this.getQueryKeys().get(queryKeyName); } /** * PUBLIC: * Return the query keys. */ public Map getQueryKeys() { return queryKeys; } /** * PUBLIC: * Return the queryManager. * The query manager can be used to specify customization of the SQL * that TopLink generates for this descriptor. */ public DescriptorQueryManager getDescriptorQueryManager() { return queryManager; } /** * PUBLIC: * Return the queryManager. * The query manager can be used to specify customization of the SQL * that TopLink generates for this descriptor. */ public DescriptorQueryManager getQueryManager() { return queryManager; } /** * INTERNAL: * Get sequence number field */ public DatabaseField getSequenceNumberField() { return sequenceNumberField; } /** * PUBLIC: * Get sequence number field name */ public String getSequenceNumberFieldName() { if (getSequenceNumberField() == null) { return null; } return getSequenceNumberField().getQualifiedName(); } /** * PUBLIC: * Get sequence number name */ public String getSequenceNumberName() { return sequenceNumberName; } /** * INTERNAL: * Return the name of the session local to this descriptor. * This is used by the session broker. */ public String getSessionName() { return sessionName; } /** * INTERNAL: * Checks if table name exists with the current descriptor or not. */ public DatabaseTable getTable(String tableName) throws DescriptorException { if (getTables().isEmpty()) { return null;// Assume aggregate descriptor. } for (Enumeration tables = getTables().elements(); tables.hasMoreElements();) { DatabaseTable table = (DatabaseTable)tables.nextElement(); if (table.getName().equals(tableName)) { return table; } } if (isAggregateDescriptor()) { return getDefaultTable(); } throw DescriptorException.tableNotPresent(tableName, this); } /** * PUBLIC: * Return the name of the descriptor's first table. * This method must only be called on single table descriptors. */ public String getTableName() { if (getTables().isEmpty()) { return null; } else { return ((DatabaseTable)getTables().firstElement()).getName(); } } /** * PUBLIC: * Return the table names. */ public Vector getTableNames() { Vector tableNames = new Vector(getTables().size()); for (Enumeration fieldsEnum = getTables().elements(); fieldsEnum.hasMoreElements();) { tableNames.addElement(((DatabaseTable)fieldsEnum.nextElement()).getQualifiedName()); } return tableNames; } /** * INTERNAL: * Return all the tables. */ public Vector getTables() { return tables; } /** * INTERNAL: * searches first descriptor than its ReturningPolicy for an equal field */ public DatabaseField getTypedField(DatabaseField field) { boolean mayBeMoreThanOne = hasMultipleTables() && !field.hasTableName(); DatabaseField foundField = null; for (int j = 0; j < getFields().size(); j++) { DatabaseField descField = (DatabaseField)getFields().elementAt(j); if (field.equals(descField)) { if (descField.getType() != null) { foundField = descField; if (!mayBeMoreThanOne || descField.getTable().equals(getDefaultTable())) { break; } } } } if (foundField != null) { foundField = (DatabaseField)foundField.clone(); if (!field.hasTableName()) { foundField.setTableName(""); } } return foundField; } /** * ADVANCED: * Return the WrapperPolicy for this descriptor. * This advacned feature can be used to wrap objects with other classes such as CORBA TIE objects or EJBs. */ public WrapperPolicy getWrapperPolicy() { return wrapperPolicy; } /** * INTERNAL: * Checks if the class has any private owned parts or other dependencies, (i.e. M:M join table). */ public boolean hasDependencyOnParts() { for (Enumeration mappings = getMappings().elements(); mappings.hasMoreElements();) { DatabaseMapping mapping = (DatabaseMapping)mappings.nextElement(); if (mapping.hasDependency()) { return true; } } return false; } /** * INTERNAL: * Return if this descriptor is involved in inheritence, (is child or parent). */ public boolean hasInheritance() { return (inheritancePolicy != null); } /** * INTERNAL: * Check if descriptor has multiple tables */ public boolean hasMultipleTables() { return (getTables().size() > 1); } /** * INTERNAL: * Checks if the class has any private owned parts are not */ public boolean hasPrivatelyOwnedParts() { for (Enumeration mappings = getMappings().elements(); mappings.hasMoreElements();) { DatabaseMapping mapping = (DatabaseMapping)mappings.nextElement(); if (mapping.isPrivateOwned()) { return true; } } return false; } /** * INTERNAL: * Checks to see if it has a query key or mapping with the specified name or not. */ public boolean hasQueryKeyOrMapping(String attributeName) { return (getQueryKeys().containsKey(attributeName) || (getObjectBuilder().getMappingForAttributeName(attributeName) != null)); } /** * INTERNAL: * Return if a wrapper policy is used. */ public boolean hasWrapperPolicy() { return getWrapperPolicy() != null; } /** * INTERNAL: * Initialize the mappings as a seperate step. * This is done as a seperate step to ensure that inheritence has been first resolved. */ public void initialize(AbstractSession session) throws DescriptorException { // These cached settings on the project must be set even if descriptor is initialized. // If defined as read-only, add to it's project's default read-only classes collection. if (shouldBeReadOnly() && (!session.getDefaultReadOnlyClasses().contains(getJavaClass()))) { session.getDefaultReadOnlyClasses().add(getJavaClass()); } // Record that there is an isolated class in the project. if (isIsolated()) { session.getProject().setHasIsolatedClasses(true); } // Record that there is a non-CMP1/2 object in the project. if ((! hasCMPPolicy()) || getCMPPolicy().isCMP3Policy()) { session.getProject().setIsPureCMP2Project(false); } // Avoid repetitive initialization (this does not solve loops) if (isInitialized(INITIALIZED) || isInvalid()) { return; } setInitializationStage(INITIALIZED); // make sure that parent mappings are initialized? if (isChildDescriptor()) { getInheritancePolicy().getParentDescriptor().initialize(session); if (getInheritancePolicy().getParentDescriptor().isIsolated()) { //if the parent is isolated then the child must be isolated as well. this.setIsIsolated(true); } } // Mappings must be sorted before field are collected in the order of the mapping for indexes to work. // Sorting the mappings to ensure that all DirectToFields get merged before all other mappings // This prevents null key errors when merging maps if (shouldOrderMappings()) { Vector mappings = getMappings(); Object[] mappingsArray = new Object[mappings.size()]; for (int index = 0; index < mappings.size(); index++) { mappingsArray[index] = mappings.elementAt(index); } TOPSort.quicksort(mappingsArray, new MappingCompare()); mappings = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(mappingsArray.length); for (int index = 0; index < mappingsArray.length; index++) { mappings.addElement(mappingsArray[index]); } setMappings(mappings); } for (Enumeration mappingsEnum = getMappings().elements(); mappingsEnum.hasMoreElements();) { DatabaseMapping mapping = (DatabaseMapping)mappingsEnum.nextElement(); validateMappingType(mapping); mapping.initialize(session); if (mapping.isAggregateObjectMapping() || ((mapping.isForeignReferenceMapping() && (!mapping.isDirectCollectionMapping())) && (!((ForeignReferenceMapping)mapping).usesIndirection()))) { getLockableMappings().add(mapping); } // Add all the fields in the mapping to myself. Helper.addAllUniqueToVector(getFields(), mapping.getFields()); } // PERF: Dont initialize locking until after fields have been computed so // field is in correct position. if (!isAggregateDescriptor()) { if (!isChildDescriptor()) { // Add write lock field to getFields if (usesOptimisticLocking()) { getOptimisticLockingPolicy().initializeProperties(); } } } // All the query keys should be initialized. for (Iterator queryKeys = getQueryKeys().values().iterator(); queryKeys.hasNext();) { QueryKey queryKey = (QueryKey)queryKeys.next(); queryKey.initialize(this); } // If this has inheritence then it needs to be initialized before all fields is set. if (hasInheritance()) { getInheritancePolicy().initialize(session); if (getInheritancePolicy().isChildDescriptor()) { for (Iterator iterator = getInheritancePolicy().getParentDescriptor().getMappings().iterator(); iterator.hasNext();) { DatabaseMapping mapping = (DatabaseMapping)iterator.next(); if (mapping.isAggregateObjectMapping() || ((mapping.isForeignReferenceMapping() && (!mapping.isDirectCollectionMapping())) && (!((ForeignReferenceMapping)mapping).usesIndirection()))) { getLockableMappings().add(mapping);// add those mappings from the parent. } } } } // cr 4097 Ensure that the mappings are ordered after the superclasses mappings have been added. // This ensures that the mappings in the child class are ordered correctly // I am sorting the mappings to ensure that all DirectToFields get merged before all other mappings // This prevents null key errors when merging maps // This resort will change the previous sort order, only do it if has inheritance. if (this.hasInheritance() && shouldOrderMappings()) { Vector mappings = getMappings(); Object[] mappingsArray = new Object[mappings.size()]; for (int index = 0; index < mappings.size(); index++) { mappingsArray[index] = mappings.elementAt(index); } TOPSort.quicksort(mappingsArray, new MappingCompare()); mappings = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(mappingsArray.length); for (int index = 0; index < mappingsArray.length; index++) { mappings.addElement(mappingsArray[index]); } setMappings(mappings); } // Initialize the allFields to its fields, this can be done now because the fields have been computed. setAllFields((Vector)getFields().clone()); getObjectBuilder().initialize(session); if (shouldOrderMappings()) { // PERF: Ensure direct primary key mappings are first. for (int index = getObjectBuilder().getPrimaryKeyMappings().size() - 1; index >= 0; index--) { DatabaseMapping mapping = (DatabaseMapping) getObjectBuilder().getPrimaryKeyMappings().get(index); if ((mapping != null) && mapping.isDirectToFieldMapping()) { getMappings().remove(mapping); getMappings().add(0, mapping); DatabaseField field = ((AbstractDirectMapping) mapping).getField(); getFields().remove(field); getFields().add(0, field); getAllFields().remove(field); getAllFields().add(0, field); } } } if (usesOptimisticLocking() && (!isChildDescriptor())) { getOptimisticLockingPolicy().initialize(session); } if (hasWrapperPolicy()) { getWrapperPolicy().initialize(session); } getQueryManager().initialize(session); getEventManager().initialize(session); getCopyPolicy().initialize(session); getInstantiationPolicy().initialize(session); if (this.getCMPPolicy() != null) { this.getCMPPolicy().initialize(this, session); } //validate the fetch group setting during descriptor initialization if (hasFetchGroupManager() && !(Helper.classImplementsInterface(javaClass, ClassConstants.FetchGroupTracker_class))) { //to use fetch group, the domain class must implement FetchGroupTracker interface session.getIntegrityChecker().handleError(DescriptorException.needToImplementFetchGroupTracker(javaClass, this)); } } /** * INTERNAL: * This initialized method is used exclusively for inheritance. It passes in * true if the child descriptor is isolated. * * This is needed by regular aggregate descriptors (because they are screwed up); * but not by SDK aggregate descriptors. */ public void initializeAggregateInheritancePolicy(AbstractSession session) { ClassDescriptor parentDescriptor = session.getDescriptor(getInheritancePolicy().getParentClass()); parentDescriptor.getInheritancePolicy().addChildDescriptor(this); } /** * INTERNAL: * Rebuild the multiple table primary key map. */ public void initializeMultipleTablePrimaryKeyFields() { int additionalTablesSize = getTables().size() - 1; boolean isChild = hasInheritance() && getInheritancePolicy().isChildDescriptor(); if (isChild) { additionalTablesSize = getTables().size() - getInheritancePolicy().getParentDescriptor().getTables().size(); } if (additionalTablesSize < 1) { return; } ExpressionBuilder builder = new ExpressionBuilder(); Expression joinExpression = getQueryManager().getMultipleTableJoinExpression(); for (int index = getTables().size() - additionalTablesSize; index < getTables().size(); index++) { DatabaseTable table = (DatabaseTable)getTables().elementAt(index); Map oldKeyMapping = (Map)getAdditionalTablePrimaryKeyFields().get(table); if (oldKeyMapping != null) { if (!getQueryManager().hasCustomMultipleTableJoinExpression()) { // Build the multiple table join expression resulting from the fk relationships. for (Iterator enumtr = oldKeyMapping.keySet().iterator(); enumtr.hasNext();) { DatabaseField sourceTableField = (DatabaseField)enumtr.next(); DatabaseField targetTableField = (DatabaseField)oldKeyMapping.get(sourceTableField); DatabaseTable sourceTable = sourceTableField.getTable(); DatabaseTable targetTable = targetTableField.getTable(); // Must add this field to read, so translations work on database row, this could be either. if (!getFields().contains(sourceTableField)) { getFields().addElement(sourceTableField); } if (!getFields().contains(targetTableField)) { getFields().addElement(targetTableField); } Expression keyJoinExpression = builder.getField(targetTableField).equal(builder.getField(sourceTableField)); joinExpression = keyJoinExpression.and(joinExpression); getQueryManager().getTablesJoinExpressions().put(targetTable, keyJoinExpression); if(isChild) { getInheritancePolicy().addChildTableJoinExpressionToAllParents(targetTable, keyJoinExpression); } } } } else { // If the user has specified a custom multiple table join then we do not assume that the secondary tables have identically named pk as the primary table. // No additional fk info was specified so assume the pk field(s) are the named the same in the additional table. Map newKeyMapping = new HashMap(getPrimaryKeyFields().size() + 1); getAdditionalTablePrimaryKeyFields().put(table, newKeyMapping); // For each primary key field in the primary table, add a pk relationship from the primary table's pk field to the assumed identically named secondary pk field. List primaryKeyFields = getPrimaryKeyFields(); for (int pkIndex = 0; pkIndex < primaryKeyFields.size(); pkIndex++) { DatabaseField primaryKeyField = (DatabaseField)primaryKeyFields.get(pkIndex); DatabaseField secondaryKeyField = (DatabaseField)primaryKeyField.clone(); secondaryKeyField.setTable(table); newKeyMapping.put(primaryKeyField, secondaryKeyField); // Must add this field to read, so translations work on database row. getFields().addElement(secondaryKeyField); if (!getQueryManager().hasCustomMultipleTableJoinExpression()) { Expression keyJoinExpression = builder.getField(secondaryKeyField).equal(builder.getField(primaryKeyField)); joinExpression = keyJoinExpression.and(joinExpression); getQueryManager().getTablesJoinExpressions().put(table, keyJoinExpression); if(isChild) { getInheritancePolicy().addChildTableJoinExpressionToAllParents(table, keyJoinExpression); } } } } } if (joinExpression != null) { getQueryManager().setInternalMultipleTableJoinExpression(joinExpression); } if (getQueryManager().hasCustomMultipleTableJoinExpression()) { Map tablesJoinExpressions = SQLSelectStatement.mapTableToExpression(joinExpression, getTables()); getQueryManager().getTablesJoinExpressions().putAll(tablesJoinExpressions); if(isChild) { for (int index = getTables().size() - additionalTablesSize; index < getTables().size(); index++) { DatabaseTable table = (DatabaseTable)getTables().elementAt(index); getInheritancePolicy().addChildTableJoinExpressionToAllParents(table, (Expression)tablesJoinExpressions.get(table)); } } } } /** * INTERNAL: * Initialize the descriptor properties such as write lock and sequecning. */ protected void initializeProperties(AbstractSession session) throws DescriptorException { if (!isAggregateDescriptor()) { if (!isChildDescriptor()) { // Initialize the primary key fields List primaryKeyFields = (List)((ArrayList)getPrimaryKeyFields()).clone(); for (int index = 0; index < primaryKeyFields.size(); index++) { DatabaseField primaryKey = (DatabaseField)primaryKeyFields.get(index); initializePrimaryKey(primaryKey); } } // build sequence number field if (getSequenceNumberField() != null) { buildField(getSequenceNumberField()); } } // Set the local session name for the session broker. setSessionName(session.getName()); } /** * INTERNAL: */ protected void initializePrimaryKey(DatabaseField primaryKey) { buildField(primaryKey); if (!primaryKey.getTable().equals(getDefaultTable())) { getPrimaryKeyFields().remove(primaryKey); } } /** * PUBLIC: * Return true if this descriptor is an aggregate collection descriptor */ public boolean isAggregateCollectionDescriptor() { return (getDescriptorType() == AGGREGATE_COLLECTION); } /** * PUBLIC: * Return true if this descriptor is an aggregate descriptor */ public boolean isAggregateDescriptor() { return (getDescriptorType() == AGGREGATE); } /** * PUBLIC: * Return if the descriptor defines inheritence and is a child. */ public boolean isChildDescriptor() { return hasInheritance() && getInheritancePolicy().isChildDescriptor(); } /** * INTERNAL: * Check if the descriptor is finished initialization. */ public boolean isFullyInitialized() { return this.initializationStage == POST_INITIALIZED; } /** * INTERNAL: * Check if descriptor is already initialized for the level of initialization. * 1 = pre * 2 = mapping * 3 = post */ protected boolean isInitialized(int initializationStage) { return this.initializationStage >= initializationStage; } /** * INTERNAL: * Return if an error occured during initialization which should abort any further initialization. */ public boolean isInvalid() { return this.initializationStage == ERROR; } /** * PUBLIC: * Returns true if the descriptor represents an isolated class */ public boolean isIsolated() { return this.isIsolated; } /** * INTERNAL: * Return if this descriptor has more than one table. */ public boolean isMultipleTableDescriptor() { return getTables().size() > 1; } /** * INTERNAL: * Indicates whether pk or some of its components * set after insert into the database. * Shouldn't be called before Descriptor has been initialized. */ public boolean isPrimaryKeySetAfterInsert(AbstractSession session) { return (usesSequenceNumbers() && session.getSequencing().shouldAcquireValueAfterInsert(getJavaClass())); } /** * PUBLIC: * PUBLIC: * This method is the equivalent of calling {@link #setShouldOnlyRefreshCacheIfNewerVersion} with an argument of true: * it configures a Descriptor to only refresh the cache if the data received from the database by a query is newer than * the data in the cache (as determined by the optimistic locking field) and as long as one of the following is true: * *

    *
  • the Descriptor was configured by calling {@link #alwaysRefreshCache} or {@link #alwaysRefreshCacheOnRemote},
  • *
  • the query was configured by calling {@link oracle.toplink.essentials.queryframework.ObjectLevelReadQuery#refreshIdentityMapResult}, or
  • *
  • the query was a call to {@link oracle.toplink.essentials.sessions.Session#refreshObject}
  • *
*

* * However, if a query hits the cache, data is not refreshed regardless of how this setting is configured. For example, by default, * when a query for a single object based on its primary key is executed, OracleAS TopLink will first look in the cache for the object. * If the object is in the cache, the cached object is returned and data is not refreshed. To avoid cache hits, use * the {@link #disableCacheHits} method.

* * Also note that the {@link oracle.toplink.essentials.sessions.UnitOfWork} will not refresh its registered objects. * * @see #dontOnlyRefreshCacheIfNewerVersion */ public void onlyRefreshCacheIfNewerVersion() { setShouldOnlyRefreshCacheIfNewerVersion(true); } /** * INTERNAL: * Post initializations after mappings are initialized. */ public void postInitialize(AbstractSession session) throws DescriptorException { // Avoid repetitive initialization (this does not solve loops) if (isInitialized(POST_INITIALIZED) || isInvalid()) { return; } setInitializationStage(POST_INITIALIZED); // Make sure that child is post initialized, // this initialize bottom up, unlike the two other phases that to top down. if (hasInheritance()) { for (Enumeration childEnum = getInheritancePolicy().getChildDescriptors().elements(); childEnum.hasMoreElements();) { ((ClassDescriptor)childEnum.nextElement()).postInitialize(session); } } // Allow mapping to perform post initialization. for (Enumeration mappingsEnum = getMappings().elements(); mappingsEnum.hasMoreElements();) { DatabaseMapping mapping = (DatabaseMapping)mappingsEnum.nextElement(); // This causes post init to be called multiple times in inheritence. mapping.postInitialize(session); // PERF: computed if deferred locking is required. if (!shouldAcquireCascadedLocks()) { if ((mapping instanceof ForeignReferenceMapping) && (!((ForeignReferenceMapping)mapping).usesIndirection())) { setShouldAcquireCascadedLocks(true); } if ((mapping instanceof AggregateObjectMapping) && ((AggregateObjectMapping)mapping).getDescriptor().shouldAcquireCascadedLocks()) { setShouldAcquireCascadedLocks(true); } } } if (hasInheritance()) { getInheritancePolicy().postInitialize(session); } //PERF: Ensure that the identical primary key fields are used to avoid equals. for (int index = (getPrimaryKeyFields().size() - 1); index >= 0; index--) { DatabaseField primaryKeyField = (DatabaseField)getPrimaryKeyFields().get(index); int fieldIndex = getFields().indexOf(primaryKeyField); // Aggregate/agg-collections may not have a mapping for pk field. if (fieldIndex != -1) { primaryKeyField = (DatabaseField)getFields().get(fieldIndex); getPrimaryKeyFields().set(index, primaryKeyField); } } // Index and classify fields and primary key. // This is in post because it needs field classification defined in initializeMapping // this can come through a 1:1 so requires all descriptors to be initialized (mappings). // May 02, 2000 - Jon D. for (int index = 0; index < getFields().size(); index++) { DatabaseField field = getFields().elementAt(index); if (field.getType() == null) { DatabaseMapping mapping = getObjectBuilder().getMappingForField(field); if (mapping != null) { field.setType(mapping.getFieldClassification(field)); } } field.setIndex(index); } validateAfterInitialization(session); checkDatabase(session); } /** * INTERNAL: * Allow the descriptor to initialize any dependancies on this session. */ public void preInitialize(AbstractSession session) throws DescriptorException { //3934266 move validation to the policy allowing for this to be done in the sub policies. getObjectChangePolicy().initialize(session, this); // Avoid repetitive initialization (this does not solve loops) if (isInitialized(PREINITIALIZED)) { return; } setInitializationStage(PREINITIALIZED); // Allow mapping pre init, must be done before validate. for (Enumeration mappingsEnum = getMappings().elements(); mappingsEnum.hasMoreElements();) { try { DatabaseMapping mapping = (DatabaseMapping)mappingsEnum.nextElement(); mapping.preInitialize(session); } catch (DescriptorException exception) { session.getIntegrityChecker().handleError(exception); } } validateBeforeInitialization(session); preInitializeInheritancePolicy(session); // Make sure that parent is already preinitialized if (hasInheritance()) { // The default table will be set in this call once the duplicate // tables have been removed. getInheritancePolicy().preInitialize(session); } else { // This must be done now, after validate, before init anything else. setInternalDefaultTable(); } verifyTableQualifiers(session.getDatasourcePlatform()); initializeProperties(session); if (!isAggregateDescriptor()) { // Adjust before you initialize ... adjustMultipleTableInsertOrder(); initializeMultipleTablePrimaryKeyFields(); } getQueryManager().preInitialize(session); } /** * INTERNAL: */ protected void prepareCascadeLockingPolicy(DatabaseMapping mapping) { if (mapping.isPrivateOwned() && mapping.isForeignReferenceMapping()) { if (mapping.isCascadedLockingSupported()) { // Even if the mapping says it is supported in general, there // may be conditions where it is not. Need the following checks. if (((ForeignReferenceMapping) mapping).hasCustomSelectionQuery()) { throw ValidationException.unsupportedCascadeLockingMappingWithCustomQuery(mapping); } else if (isAggregateDescriptor() || isAggregateCollectionDescriptor()) { throw ValidationException.unsupportedCascadeLockingDescriptor(this); } else { mapping.prepareCascadeLockingPolicy(); } } else { throw ValidationException.unsupportedCascadeLockingMapping(mapping); } } } /** * Hook together the inheritance policy tree. */ protected void preInitializeInheritancePolicy(AbstractSession session) throws DescriptorException { if (isChildDescriptor() && (requiresInitialization())) { if (getInheritancePolicy().getParentClass().equals(getJavaClass())) { throw DescriptorException.parentClassIsSelf(this); } ClassDescriptor parentDescriptor = session.getDescriptor(getInheritancePolicy().getParentClass()); parentDescriptor.getInheritancePolicy().addChildDescriptor(this); getInheritancePolicy().setParentDescriptor(parentDescriptor); parentDescriptor.preInitialize(session); } } /** * INTERNAL: * Rehash any hashtables based on fields. * This is used to clone descriptors for aggregates, which hammer field names, * it is probably better not to hammer the field name and this should be refactored. */ public void rehashFieldDependancies(AbstractSession session) { getObjectBuilder().rehashFieldDependancies(session); for (Enumeration enumtr = getMappings().elements(); enumtr.hasMoreElements();) { ((DatabaseMapping)enumtr.nextElement()).rehashFieldDependancies(session); } } /** * INTERNAL: * A user should not be setting which attributes to join or not to join * after descriptor initialization; provided only for backwards compatibility. */ public void reInitializeJoinedAttributes() { if (!isInitialized(POST_INITIALIZED)) { // wait until the descriptor gets initialized first return; } getObjectBuilder().initializeJoinedAttributes(); if (hasInheritance()) { Vector children = getInheritancePolicy().getChildDescriptors(); // use indeces to avoid synchronization. for (int i = 0; i < children.size(); i++) { InheritancePolicy child = (InheritancePolicy)children.elementAt(0); child.getDescriptor().reInitializeJoinedAttributes(); } } } /** * PUBLIC: * Remove the user defined property. */ public void removeProperty(String property) { getProperties().remove(property); } /** * INTERNAL: * Aggregate and Interface descriptors do not require initialization as they are cloned and * initialized by each mapping. */ public boolean requiresInitialization() { return !(isAggregateDescriptor()); } /** * INTERNAL: * Validate that the descriptor was defined correctly. * This allows for checks to be done that require the descriptor initialization to be completed. */ protected void selfValidationAfterInitialization(AbstractSession session) throws DescriptorException { // This has to be done after, because read subclasses must be initialized. if (!(hasInheritance() && (getInheritancePolicy().shouldReadSubclasses() || java.lang.reflect.Modifier.isAbstract(getJavaClass().getModifiers())))) { if (session.getIntegrityChecker().shouldCheckInstantiationPolicy()) { getInstantiationPolicy().buildNewInstance(); } } getObjectBuilder().validate(session); } /** * INTERNAL: * Validate that the descriptor's non-mapping attribute are defined correctly. */ protected void selfValidationBeforeInitialization(AbstractSession session) throws DescriptorException { if (isChildDescriptor()) { ClassDescriptor parentDescriptor = session.getDescriptor(getInheritancePolicy().getParentClass()); if (parentDescriptor == null) { session.getIntegrityChecker().handleError(DescriptorException.parentDescriptorNotSpecified(getInheritancePolicy().getParentClass().getName(), this)); } } else { if (getTables().isEmpty() && (!isAggregateDescriptor())) { session.getIntegrityChecker().handleError(DescriptorException.tableNotSpecified(this)); } } if (!isChildDescriptor() && !isAggregateDescriptor()) { if (getPrimaryKeyFieldNames().isEmpty()) { session.getIntegrityChecker().handleError(DescriptorException.primaryKeyFieldsNotSepcified(this)); } } if ((getIdentityMapClass() == ClassConstants.NoIdentityMap_Class) && (getQueryManager().getDoesExistQuery().shouldCheckCacheForDoesExist())) { session.getIntegrityChecker().handleError(DescriptorException.identityMapNotSpecified(this)); } if (((getSequenceNumberName() != null) && (getSequenceNumberField() == null)) || ((getSequenceNumberName() == null) && (getSequenceNumberField() != null))) { session.getIntegrityChecker().handleError(DescriptorException.sequenceNumberPropertyNotSpecified(this)); } } /** * INTERNAL: * This is used to map the primary key field names in a multiple table * descriptor. */ protected void setAdditionalTablePrimaryKeyFields(DatabaseTable table, DatabaseField field1, DatabaseField field2) { Map tableAdditionalPKFields = (Map)getAdditionalTablePrimaryKeyFields().get(table); if (tableAdditionalPKFields == null) { tableAdditionalPKFields = new HashMap(2); getAdditionalTablePrimaryKeyFields().put(table, tableAdditionalPKFields); } tableAdditionalPKFields.put(field1, field2); } /** * INTERNAL: * This method will be called in the case where the foreign key field is * in the target table which is before the source table. In most cases, * this would be when the fk is on the primary table (that is, true * multiple table foreign key field) */ protected void toggleAdditionalTablePrimaryKeyFields(DatabaseTable targetTable, DatabaseTable sourceTable) { Map targetTableAdditionalPKFields = (Map)getAdditionalTablePrimaryKeyFields().get(targetTable); if (targetTableAdditionalPKFields != null) { Iterator e = targetTableAdditionalPKFields.keySet().iterator(); while (e.hasNext()) { DatabaseField sourceField = (DatabaseField)e.next(); DatabaseField targetField = (DatabaseField) targetTableAdditionalPKFields.get(sourceField); setAdditionalTablePrimaryKeyFields(sourceTable, targetField, sourceField); } targetTableAdditionalPKFields.clear(); } } /** * INTERNAL: * This is used to map the primary key field names in a multiple table * descriptor. */ public void setAdditionalTablePrimaryKeyFields(Map> additionalTablePrimaryKeyFields) { this.additionalTablePrimaryKeyFields = additionalTablePrimaryKeyFields; } /** * PUBLIC: * Set the alias */ public void setAlias(String alias) { this.alias = alias; } /** * INTERNAL: * Set all the fields. */ protected void setAllFields(Vector allFields) { this.allFields = allFields; } /** * PUBLIC: * Set the amendment class. * The amendment method will be called on the class before initialization to allow for it to initialize the descriptor. * The method must be a public static method on the class. */ public void setAmendmentClass(Class amendmentClass) { this.amendmentClass = amendmentClass; } /** * INTERNAL: * Return the amendment class name, used by the MW. */ public void setAmendmentClassName(String amendmentClassName) { this.amendmentClassName = amendmentClassName; } /** * PUBLIC: * Set the amendment method. * This will be called on the amendment class before initialization to allow for it to initialize the descriptor. * The method must be a public static method on the class. */ public void setAmendmentMethodName(String amendmentMethodName) { this.amendmentMethodName = amendmentMethodName; } /** * PUBLIC: * Set the ObjectChangePolicy for this descriptor. */ public void setObjectChangePolicy(ObjectChangePolicy policy) { this.changePolicy = policy; } /** * PUBLIC: * Set the Cache Invalidation Policy for this descriptor * @param CacheInvalidationPolicy * @see oracle.toplink.essentials.descriptors.invalidation.CacheInvalidationPolicy */ public void setCacheInvalidationPolicy(CacheInvalidationPolicy policy) { cacheInvalidationPolicy = policy; } /** * ADVANCED: * TopLink automatically orders database access through the foreign key information provided in 1:1 and 1:m mappings. * In some case when 1:1 are not defined it may be required to tell the descriptor about a constraint, * this defines that this descriptor has a foreign key constraint to another class and must be inserted after * instances of the other class. */ public void setConstraintDependencies(Vector constraintDependencies) { this.constraintDependencies = constraintDependencies; } /** * INTERNAL: * Set the copy policy. * This would be 'protected' but the EJB stuff in another * package needs it to be public */ public void setCopyPolicy(CopyPolicy policy) { copyPolicy = policy; if (policy != null) { policy.setDescriptor(this); } } /** * INTERNAL: * The descriptors default table can be configured if the first table is not desired. */ public void setDefaultTable(DatabaseTable defaultTable) { this.defaultTable = defaultTable; } /** * PUBLIC: * The descriptors default table can be configured if the first table is not desired. */ public void setDefaultTableName(String defaultTableName) { setDefaultTable(new DatabaseTable(defaultTableName)); } /** * ADVANCED: * set the descriptor type (NORMAL by default, others include INTERFACE, AGGREGATE, AGGREGATE COLLECTION) */ public void setDescriptorType(int descriptorType) { this.descriptorType = descriptorType; } /** * INTERNAL: * This method is explicitly used by the XML reader. */ public void setDescriptorTypeValue(String value) { if (value.equals("Aggregate collection")) { descriptorIsAggregateCollection(); } else if (value.equals("Aggregate")) { descriptorIsAggregate(); } else { descriptorIsNormal(); } } /** * INTERNAL: * Set the event manager for the descriptor. The event manager is responsible * for managing the pre/post selectors. */ public void setEventManager(DescriptorEventManager eventManager) { this.eventManager = eventManager; if (eventManager != null) { eventManager.setDescriptor(this); } } /** * INTERNAL: * Set the existence check option from a string constant. */ public void setExistenceChecking(String token) throws DescriptorException { getQueryManager().setExistenceCheck(token); } /** * INTERNAL: * Set the fields used by this descriptor. */ public void setFields(Vector fields) { this.fields = fields; } /** * PUBLIC: * Set the class of identity map to be used by this descriptor. * The default is the "FullIdentityMap". */ public void setIdentityMapClass(Class theIdentityMapClass) { identityMapClass = theIdentityMapClass; } /** * PUBLIC: * Set the size of the identity map to be used by this descriptor. * The default is the 100. */ public void setIdentityMapSize(int identityMapSize) { this.identityMapSize = identityMapSize; } /** * INTERNAL: * Sets the inheritance policy. */ public void setInheritancePolicy(InheritancePolicy inheritancePolicy) { this.inheritancePolicy = inheritancePolicy; if (inheritancePolicy != null) { inheritancePolicy.setDescriptor(this); } } /** * INTERNAL: */ protected void setInitializationStage(int initializationStage) { this.initializationStage = initializationStage; } /** * INTERNAL: * Sets the instantiation policy. */ public void setInstantiationPolicy(InstantiationPolicy instantiationPolicy) { this.instantiationPolicy = instantiationPolicy; if (instantiationPolicy != null) { instantiationPolicy.setDescriptor(this); } } /** * INTERNAL: * Set the default table if one if not already set. This method will * extract the default table. */ public void setInternalDefaultTable() { if (getDefaultTable() == null) { setDefaultTable(extractDefaultTable()); } } /** * INTERNAL: * Set the default table if one if not already set. This method will set * the table that is provided as the default. */ public void setInternalDefaultTable(DatabaseTable defaultTable) { if (getDefaultTable() == null) { setDefaultTable(defaultTable); } } /** * PUBLIC: * Used to set if the class that this descriptor represents should be isolated from the * shared cache. * Note: Calling this method with true will also set the cacheSynchronizationType to DO_NOT_SEND_CHANGES * since isolated objects cannot be sent by TopLink cache synchronization. */ public void setIsIsolated(boolean isIsolated) { this.isIsolated = isIsolated; } /** * PUBLIC: * Set the Java class that this descriptor maps. * Every descriptor maps one and only one class. */ public void setJavaClass(Class theJavaClass) { javaClass = theJavaClass; } /** * INTERNAL: * Return the java class name, used by the MW. */ public void setJavaClassName(String theJavaClassName) { javaClassName = theJavaClassName; } /** * INTERNAL: * Set the list of lockable mappings for this project * This method is provided for CMP use. Normally, the lockable mappings are initialized * at descriptor initialization time. */ public void setLockableMappings(List lockableMappings) { this.lockableMappings = lockableMappings; } /** * INTERNAL: * Set the mappings. */ public void setMappings(Vector mappings) { // This is used from XML reader so must ensure that all mapping's descriptor has been set. for (Enumeration mappingsEnum = mappings.elements(); mappingsEnum.hasMoreElements();) { DatabaseMapping mapping = (DatabaseMapping)mappingsEnum.nextElement(); // For CR#2646, if the mapping already points to the parent descriptor then leave it. if (mapping.getDescriptor() == null) { mapping.setDescriptor(this); } } this.mappings = mappings; } /** * INTERNAL: * This method is used by the TopLink XML Deployment Descriptor to read and write these mappings */ public void setMultipleTableForeignKeyFieldNames(Vector associations) throws DescriptorException { Enumeration foreignKeys = associations.elements(); while (foreignKeys.hasMoreElements()) { Association association = (Association)foreignKeys.nextElement(); addMultipleTableForeignKeys((String)association.getKey(), (String)association.getValue(), true); } } /** * INTERNAL: * * @see #getMultipleTableForeignKeys */ protected void setMultipleTableForeignKeys(Map newValue) { this.multipleTableForeignKeys = newValue; } /** * ADVANCED: * Sets the Vector of DatabaseTables in the order which INSERTS should take place. * This is normally computed correctly by TopLink, however in advanced cases in it may be overridden. */ public void setMultipleTableInsertOrder(Vector newValue) { this.multipleTableInsertOrder = newValue; } /** * INTERNAL: * This method is used by the TopLink XML Deployment Descriptor to read and write these mappings */ public void setMultipleTablePrimaryKeyFieldNames(Vector associations) throws DescriptorException { Enumeration foreignKeys = associations.elements(); while (foreignKeys.hasMoreElements()) { Association association = (Association)foreignKeys.nextElement(); addMultipleTableForeignKeys((String)association.getKey(), (String)association.getValue(), true); } } /** * INTERNAL: * Set the ObjectBuilder. */ protected void setObjectBuilder(ObjectBuilder builder) { objectBuilder = builder; } /** * PUBLIC: * Set the OptimisticLockingPolicy. * This can be one of the provided locking policies or a user defined policy. * @see VersionLockingPolicy * @see TimestampLockingPolicy * @see FieldsLockingPolicy */ public void setOptimisticLockingPolicy(OptimisticLockingPolicy optimisticLockingPolicy) { this.optimisticLockingPolicy = optimisticLockingPolicy; if (optimisticLockingPolicy != null) { optimisticLockingPolicy.setDescriptor(this); } } /** * PUBLIC: * Specify the primary key field of the descriptors table. * This should only be called if it is a singlton primary key field, * otherwise addPrimaryKeyFieldName should be called. * If the descriptor has many tables, this must be the primary key in all of the tables. * * @see #addPrimaryKeyFieldName(String) */ public void setPrimaryKeyFieldName(String fieldName) { addPrimaryKeyFieldName(fieldName); } /** * PUBLIC: * User can specify a vector of all the primary key field names if primary key is composite. * * @see #addPrimaryKeyFieldName(String) */ public void setPrimaryKeyFieldNames(Vector primaryKeyFieldsName) { setPrimaryKeyFields(new ArrayList(primaryKeyFieldsName.size())); for (Enumeration keyEnum = primaryKeyFieldsName.elements(); keyEnum.hasMoreElements();) { addPrimaryKeyFieldName((String)keyEnum.nextElement()); } } /** * INTERNAL: * Set the primary key fields */ public void setPrimaryKeyFields(List thePrimaryKeyFields) { primaryKeyFields = thePrimaryKeyFields; } /** * INTERNAL: * Set the user defined properties. */ public void setProperties(Map properties) { this.properties = properties; } /** * PUBLIC: * Set the user defined property. */ public void setProperty(String name, Object value) { getProperties().put(name, value); } /** * INTERNAL: * Set the query keys. */ public void setQueryKeys(Map queryKeys) { this.queryKeys = queryKeys; } /** * INTERNAL: * Set the query manager. */ public void setQueryManager(DescriptorQueryManager queryManager) { this.queryManager = queryManager; if (queryManager != null) { queryManager.setDescriptor(this); } } /** * INTERNAL: * Set the sequence number field. */ public void setSequenceNumberField(DatabaseField sequenceNumberField) { this.sequenceNumberField = sequenceNumberField; } /** * PUBLIC: * Set the sequence number field name. * This is the field in the descriptors table that needs its value to be generated. * This is normally the primary key field of the descriptor. */ public void setSequenceNumberFieldName(String fieldName) { if (fieldName == null) { setSequenceNumberField(null); } else { setSequenceNumberField(new DatabaseField(fieldName)); } } /** * PUBLIC: * Set the sequence number name. * This is the seq_name part of the row stored in the sequence table for this descriptor. * If using Oracle native sequencing this is the name of the Oracle sequence object. * If using Sybase native sequencing this name has no meaning, but should still be set for compatibility. * The name does not have to be unique among descriptors, as having descriptors share sequences can * improve pre-allocation performance. */ public void setSequenceNumberName(String name) { sequenceNumberName = name; } /** * INTERNAL: * Set the name of the session local to this descriptor. * This is used by the session broker. */ protected void setSessionName(String sessionName) { this.sessionName = sessionName; } /** * PUBLIC: * set if the descriptor is defined to always conform the results in unit of work in read query. * */ public void setShouldAlwaysConformResultsInUnitOfWork(boolean shouldAlwaysConformResultsInUnitOfWork) { this.shouldAlwaysConformResultsInUnitOfWork = shouldAlwaysConformResultsInUnitOfWork; } /** * PUBLIC: * When the shouldAlwaysRefreshCache argument passed into this method is true, * this method configures a Descriptor to always refresh the cache if data is received from * the database by any query.

* * However, if a query hits the cache, data is not refreshed regardless of how this setting is configured. * For example, by default, when a query for a single object based on its primary key is executed, OracleAS TopLink * will first look in the cache for the object. If the object is in the cache, the cached object is returned and * data is not refreshed. To avoid cache hits, use the {@link #disableCacheHits} method.

* * Also note that the {@link oracle.toplink.essentials.sessions.UnitOfWork} will not refresh its registered objects.

* * Use this property with caution because it can lead to poor performance and may refresh on queries when it is not desired. * Normally, if you require fresh data, it is better to configure a query with {@link oracle.toplink.essentials.queryframework.ObjectLevelReadQuery#refreshIdentityMapResult}. * To ensure that refreshes are only done when required, use this method in conjunction with {@link #onlyRefreshCacheIfNewerVersion}.

* * When the shouldAlwaysRefreshCache argument passed into this method is false, this method * ensures that a Descriptor is not configured to always refresh the cache if data is received from the database by any query.

* * @see #alwaysRefreshCache * @see #dontAlwaysRefreshCache */ public void setShouldAlwaysRefreshCache(boolean shouldAlwaysRefreshCache) { this.shouldAlwaysRefreshCache = shouldAlwaysRefreshCache; } /** * PUBLIC: * Define if the descriptor reference class is read-only */ public void setShouldBeReadOnly(boolean shouldBeReadOnly) { this.shouldBeReadOnly = shouldBeReadOnly; } /** * PUBLIC: * Set the descriptor to be read-only. * Declaring a descriptor is read-only means that instances of the reference class will never be modified. * Read-only descriptor is usually used in the unit of work to gain performance as there is no need for * the registration, clone and merge for the read-only classes. */ public void setReadOnly() { setShouldBeReadOnly(true); } /** * PUBLIC: * Set if cache hits on primary key read object queries should be disabled. * * @see #alwaysRefreshCache() */ public void setShouldDisableCacheHits(boolean shouldDisableCacheHits) { this.shouldDisableCacheHits = shouldDisableCacheHits; } /** * PUBLIC: * When the shouldOnlyRefreshCacheIfNewerVersion argument passed into this method is true, * this method configures a Descriptor to only refresh the cache if the data received from the database * by a query is newer than the data in the cache (as determined by the optimistic locking field) and as long as one of the following is true: * *

    *
  • the Descriptor was configured by calling {@link #alwaysRefreshCache} or {@link #alwaysRefreshCacheOnRemote},
  • *
  • the query was configured by calling {@link oracle.toplink.essentials.queryframework.ObjectLevelReadQuery#refreshIdentityMapResult}, or
  • *
  • the query was a call to {@link oracle.toplink.essentials.sessions.Session#refreshObject}
  • *
*

* * However, if a query hits the cache, data is not refreshed regardless of how this setting is configured. For example, by default, * when a query for a single object based on its primary key is executed, OracleAS TopLink will first look in the cache for the object. * If the object is in the cache, the cached object is returned and data is not refreshed. To avoid cache hits, use * the {@link #disableCacheHits} method.

* * Also note that the {@link oracle.toplink.essentials.sessions.UnitOfWork} will not refresh its registered objects.

* * When the shouldOnlyRefreshCacheIfNewerVersion argument passed into this method is false, this method * ensures that a Descriptor is not configured to only refresh the cache if the data received from the database by a * query is newer than the data in the cache (as determined by the optimistic locking field). * * @see #onlyRefreshCacheIfNewerVersion * @see #dontOnlyRefreshCacheIfNewerVersion */ public void setShouldOnlyRefreshCacheIfNewerVersion(boolean shouldOnlyRefreshCacheIfNewerVersion) { this.shouldOnlyRefreshCacheIfNewerVersion = shouldOnlyRefreshCacheIfNewerVersion; } /** * PUBLIC: * This is set to turn off the ordering of mappings. By Default this is set to true. * By ordering the mappings TopLink insures that object are merged in the right order. * If the order of the mappings needs to be specified by the developer then set this to * false and TopLink will use the order that the mappings were added to the descriptor */ public void setShouldOrderMappings(boolean shouldOrderMappings) { this.shouldOrderMappings = shouldOrderMappings; } /** * INTERNAL: * Set to false to have queries conform to a UnitOfWork without registering * any additional objects not already in that UnitOfWork. * @see #shouldRegisterResultsInUnitOfWork * @bug 2612601 */ public void setShouldRegisterResultsInUnitOfWork(boolean shouldRegisterResultsInUnitOfWork) { this.shouldRegisterResultsInUnitOfWork = shouldRegisterResultsInUnitOfWork; } /** * PUBLIC: * Specify the table name for the class of objects the receiver describes. * If the table has a qualifier it should be specified using the dot notation, * (i.e. "userid.employee"). This method is used for single table. */ public void setTableName(String tableName) throws DescriptorException { if (getTables().isEmpty()) { addTableName(tableName); } else { throw DescriptorException.onlyOneTableCanBeAddedWithThisMethod(this); } } /** * PUBLIC: * Specify the all table names for the class of objects the receiver describes. * If the table has a qualifier it should be specified using the dot notation, * (i.e. "userid.employee"). This method is used for multiple tables */ public void setTableNames(Vector tableNames) { setTables(oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(tableNames.size())); for (Enumeration tableEnum = tableNames.elements(); tableEnum.hasMoreElements();) { addTableName((String)tableEnum.nextElement()); } } /** * PUBLIC: Set the table Qualifier for this descriptor. This table creator will be used for * all tables in this descriptor */ public void setTableQualifier(String tableQualifier) { for (Enumeration enumtr = getTables().elements(); enumtr.hasMoreElements();) { DatabaseTable table = (DatabaseTable)enumtr.nextElement(); table.setTableQualifier(tableQualifier); } } /** * INTERNAL: * Sets the tables */ public void setTables(Vector theTables) { tables = theTables; } /** * ADVANCED: * Sets the WrapperPolicy for this descriptor. * This advacned feature can be used to wrap objects with other classes such as CORBA TIE objects or EJBs. */ public void setWrapperPolicy(WrapperPolicy wrapperPolicy) { this.wrapperPolicy = wrapperPolicy; // For bug 2766379 must be able to set the wrapper policy back to default // which is null. if (wrapperPolicy != null) { wrapperPolicy.setDescriptor(this); } } /** * PUBLIC: * Return if the descriptor is defined to always conform the results in unit of work in read query. * */ public boolean shouldAlwaysConformResultsInUnitOfWork() { return shouldAlwaysConformResultsInUnitOfWork; } /** * PUBLIC: * This method returns true if the Descriptor is configured to always refresh * the cache if data is received from the database by any query. Otherwise, it returns false. * * @see #setShouldAlwaysRefreshCache */ public boolean shouldAlwaysRefreshCache() { return shouldAlwaysRefreshCache; } /** * PUBLIC: * Return if the descriptor reference class is defined as read-only * */ public boolean shouldBeReadOnly() { return shouldBeReadOnly; } /** * PUBLIC: * Return if for cache hits on primary key read object queries to be disabled. * * @see #disableCacheHits() */ public boolean shouldDisableCacheHits() { return shouldDisableCacheHits; } /** * PUBLIC: * This method returns true if the Descriptor is configured to only refresh the cache * if the data received from the database by a query is newer than the data in the cache (as determined by the * optimistic locking field). Otherwise, it returns false. * * @see #setShouldOnlyRefreshCacheIfNewerVersion */ public boolean shouldOnlyRefreshCacheIfNewerVersion() { return shouldOnlyRefreshCacheIfNewerVersion; } /** * INTERNAL: * Return if mappings should be ordered or not. By default this is set to true * to prevent attributes from being merged in the wrong order * */ public boolean shouldOrderMappings() { return shouldOrderMappings; } /** * INTERNAL: * PERF: Return if the primary key is simple (direct-mapped) to allow fast extraction. */ public boolean hasSimplePrimaryKey() { return hasSimplePrimaryKey; } /** * INTERNAL: * PERF: Set if the primary key is simple (direct-mapped) to allow fast extraction. */ public void setHasSimplePrimaryKey(boolean hasSimplePrimaryKey) { this.hasSimplePrimaryKey = hasSimplePrimaryKey; } /** * INTERNAL: * PERF: Return if deferred locks should be used. * Used to optimize read locking. * This is determined based on if any relationships do not use indirection. */ public boolean shouldAcquireCascadedLocks() { return shouldAcquireCascadedLocks; } /** * INTERNAL: * PERF: Set if deferred locks should be used. * This is determined based on if any relationships do not use indirection, * but this provides a backdoor hook to force on if require because of events usage etc. */ public void setShouldAcquireCascadedLocks(boolean shouldAcquireCascadedLocks) { this.shouldAcquireCascadedLocks = shouldAcquireCascadedLocks; } /** * PUBLIC: * Return true if this descriptor is using CacheIdentityMap */ public boolean shouldUseCacheIdentityMap() { return (getIdentityMapClass() == ClassConstants.CacheIdentityMap_Class); } /** * PUBLIC: * Return true if this descriptor is using FullIdentityMap */ public boolean shouldUseFullIdentityMap() { return (getIdentityMapClass() == ClassConstants.FullIdentityMap_Class); } /** * PUBLIC: * Return true if this descriptor is using HardCacheWeakIdentityMap. */ public boolean shouldUseHardCacheWeakIdentityMap() { return (getIdentityMapClass() == ClassConstants.HardCacheWeakIdentityMap_Class); } /** * PUBLIC: * Return true if this descriptor is using NoIdentityMap */ public boolean shouldUseNoIdentityMap() { return (getIdentityMapClass() == ClassConstants.NoIdentityMap_Class); } /** * INTERNAL: * Allows one to do conforming in a UnitOfWork without registering. * Queries executed on a UnitOfWork will only return working copies for objects * that have already been registered. *

Extreme care should be taken in using this feature, for a user will * get back a mix of registered and original (unregistered) objects. *

Best used with a WrapperPolicy where invoking on an object will trigger * its registration (CMP). Without a WrapperPolicy {@link oracle.toplink.essentials.sessions.UnitOfWork#registerExistingObject registerExistingObject} * should be called on any object that you intend to change. * @return true by default. * @see #setShouldRegisterResultsInUnitOfWork * @see oracle.toplink.essentials.queryframework.ObjectLevelReadQuery#shouldRegisterResultsInUnitOfWork * @bug 2612601 */ public boolean shouldRegisterResultsInUnitOfWork() { return shouldRegisterResultsInUnitOfWork; } /** * PUBLIC: * Return true if this descriptor is using SoftCacheWeakIdentityMap. */ public boolean shouldUseSoftCacheWeakIdentityMap() { return (getIdentityMapClass() == ClassConstants.SoftCacheWeakIdentityMap_Class); } /** * PUBLIC: * Return true if this descriptor is using WeakIdentityMap */ public boolean shouldUseWeakIdentityMap() { return (getIdentityMapClass() == ClassConstants.WeakIdentityMap_Class); } /** * PUBLIC: * Returns a brief string representation of the receiver. */ public String toString() { return Helper.getShortClassName(getClass()) + "(" + getJavaClassName() + " --> " + getTables() + ")"; } /** * PUBLIC: * Set the class of identity map to be the cache identity map. * This map caches the LRU instances read from the database. * The default in JDK1.1 is "FullIdentityMap", in JDK1.2 it is the "SoftCacheWeakIdentityMap". */ public void useCacheIdentityMap() { setIdentityMapClass(ClassConstants.CacheIdentityMap_Class); } /** * PUBLIC: * Specifies that the creation of clones within a unit of work is done by * sending the #clone() method to the original object. The #clone() method * must return a logical shallow copy of the original object. * This can be used if the default mechanism of creating a new instance * does not handle the object's non-persistent attributes correctly. * * @see #useCloneCopyPolicy(String) */ public void useCloneCopyPolicy() { useCloneCopyPolicy("clone"); } /** * PUBLIC: * Specifies that the creation of clones within a unit of work is done by * sending the cloneMethodName method to the original object. This method * must return a logical shallow copy of the original object. * This can be used if the default mechanism of creating a new instance * does not handle the object's non-persistent attributes correctly. * * @see #useCloneCopyPolicy() */ public void useCloneCopyPolicy(String cloneMethodName) { CloneCopyPolicy policy = new CloneCopyPolicy(); policy.setMethodName(cloneMethodName); setCopyPolicy(policy); } /** * PUBLIC: * Specifies that the creation of clones within a unit of work is done by building * a new instance using the * technique indicated by the descriptor's instantiation policy * (which by default is to use the * the default constructor). This new instance is then populated by using the * descriptor's mappings to copy attributes from the original to the clone. * This is the default. * If another mechanism is desired the copy policy allows for a clone method to be called. * * @see #useCloneCopyPolicy() * @see #useCloneCopyPolicy(String) * @see #useDefaultConstructorInstantiationPolicy() * @see #useMethodInstantiationPolicy(String) * @see #useFactoryInstantiationPolicy(Class, String) * @see #useFactoryInstantiationPolicy(Class, String, String) * @see #useFactoryInstantiationPolicy(Object, String) */ public void useInstantiationCopyPolicy() { setCopyPolicy(new InstantiationCopyPolicy()); } /** * PUBLIC: * Use the default constructor to create new instances of objects built from the database. * This is the default. * The descriptor's class must either define a default constructor or define * no constructors at all. * * @see #useMethodInstantiationPolicy(String) * @see #useFactoryInstantiationPolicy(Class, String) * @see #useFactoryInstantiationPolicy(Class, String, String) * @see #useFactoryInstantiationPolicy(Object, String) */ public void useDefaultConstructorInstantiationPolicy() { getInstantiationPolicy().useDefaultConstructorInstantiationPolicy(); } /** * PUBLIC: * Use an object factory to create new instances of objects built from the database. * The methodName is the name of the * method that will be invoked on the factory. When invoked, it must return a new instance * of the descriptor's class. * The factory will be created by invoking the factoryClass's default constructor. * * @see #useDefaultConstructorInstantiationPolicy() * @see #useMethodInstantiationPolicy(String) * @see #useFactoryInstantiationPolicy(Class, String, String) * @see #useFactoryInstantiationPolicy(Object, String) */ public void useFactoryInstantiationPolicy(Class factoryClass, String methodName) { getInstantiationPolicy().useFactoryInstantiationPolicy(factoryClass, methodName); } /** * INTERNAL: * Set the factory class name, used by the MW. */ public void useFactoryInstantiationPolicy(String factoryClassName, String methodName) { getInstantiationPolicy().useFactoryInstantiationPolicy(factoryClassName, methodName); } /** * PUBLIC: * Use an object factory to create new instances of objects built from the database. * The factoryMethodName is a static method declared by the factoryClass. * When invoked, it must return an instance of the factory. The methodName is the name of the * method that will be invoked on the factory. When invoked, it must return a new instance * of the descriptor's class. * * @see #useDefaultConstructorInstantiationPolicy() * @see #useFactoryInstantiationPolicy(Class, String) * @see #useFactoryInstantiationPolicy(Object, String) * @see #useMethodInstantiationPolicy(String) */ public void useFactoryInstantiationPolicy(Class factoryClass, String methodName, String factoryMethodName) { getInstantiationPolicy().useFactoryInstantiationPolicy(factoryClass, methodName, factoryMethodName); } /** * INTERNAL: * Set the factory class name, used by the MW. */ public void useFactoryInstantiationPolicy(String factoryClassName, String methodName, String factoryMethodName) { getInstantiationPolicy().useFactoryInstantiationPolicy(factoryClassName, methodName, factoryMethodName); } /** * PUBLIC: * Use an object factory to create new instances of objects built from the database. * The methodName is the name of the * method that will be invoked on the factory. When invoked, it must return a new instance * of the descriptor's class. * * @see #useDefaultConstructorInstantiationPolicy() * @see #useMethodInstantiationPolicy(String) * @see #useFactoryInstantiationPolicy(Class, String) * @see #useFactoryInstantiationPolicy(Class, String, String) */ public void useFactoryInstantiationPolicy(Object factory, String methodName) { getInstantiationPolicy().useFactoryInstantiationPolicy(factory, methodName); } /** * PUBLIC: * Set the class of identity map to be the full identity map. * This map caches all instances read and grows to accomodate them. * The default is the "SoftCacheWeakIdentityMap". */ public void useFullIdentityMap() { setIdentityMapClass(ClassConstants.FullIdentityMap_Class); } /** * PUBLIC: * Set the class of identity map to be the hard cache weak identity map. * This map uses weak references to only cache object in-memory. * It also includes a secondary fixed sized soft cache to improve caching performance. * This is provided because some Java VM's do not implement soft references correctly. * The default is the "SoftCacheWeakIdentityMap". */ public void useHardCacheWeakIdentityMap() { setIdentityMapClass(ClassConstants.HardCacheWeakIdentityMap_Class); } /** * PUBLIC: * Use the specified static method to create new instances of objects built from the database. * This method must be statically declared by the descriptor's class, and it must * return a new instance of the descriptor's class. * * @see #useDefaultConstructorInstantiationPolicy() * @see #useFactoryInstantiationPolicy(Class, String) * @see #useFactoryInstantiationPolicy(Class, String, String) * @see #useFactoryInstantiationPolicy(Object, String) */ public void useMethodInstantiationPolicy(String staticMethodName) { getInstantiationPolicy().useMethodInstantiationPolicy(staticMethodName); } /** * PUBLIC: * Set the class of identity map to be the no identity map. * This map does no caching. * The default is the "SoftCacheWeakIdentityMap". */ public void useNoIdentityMap() { setIdentityMapClass(ClassConstants.NoIdentityMap_Class); } /** * PUBLIC: * Set the class of identity map to be the soft cache weak identity map. * The SoftCacheIdentityMap holds a fixed number of objects is memory * (using SoftReferences) to improve caching. * The default is the "SoftCacheWeakIdentityMap". */ public void useSoftCacheWeakIdentityMap() { setIdentityMapClass(ClassConstants.SoftCacheWeakIdentityMap_Class); } /** * PUBLIC: * Return true if the receiver uses write (optimistic) locking. */ public boolean usesOptimisticLocking() { return (optimisticLockingPolicy != null); } /** * PUBLIC: * Return true if the receiver uses version optimistic locking. */ public boolean usesVersionLocking() { return (usesOptimisticLocking() && (getOptimisticLockingPolicy() instanceof VersionLockingPolicy)); } /** * PUBLIC: * Return true if the receiver uses sequence numbers. */ public boolean usesSequenceNumbers() { return ((getSequenceNumberField() != null) && (getSequenceNumberName() != null)); } /** * PUBLIC: * Use the Timestamps locking policy and storing the value in the cache key * #see useVersionLocking(String) */ public void useTimestampLocking(String writeLockFieldName) { useTimestampLocking(writeLockFieldName, true); } /** * PUBLIC: * Set the locking policy to use timestamp version locking. * This updates the timestamp field on all updates, first comparing that the field has not changed to detect locking conflicts. * Note: many database have limited precision of timestamps which can be an issue is highly concurrent systems. * * The parameter 'shouldStoreInCache' configures the version lock value to be stored in the cache or in the object. * Note: if using a stateless model where the object can be passed to a client and then later updated in a different transaction context, * then the version lock value should not be stored in the cache, but in the object to ensure it is the correct value for that object. * @see VersionLockingPolicy */ public void useTimestampLocking(String writeLockFieldName, boolean shouldStoreInCache) { TimestampLockingPolicy policy = new TimestampLockingPolicy(writeLockFieldName); if (shouldStoreInCache) { policy.storeInCache(); } else { policy.storeInObject(); } setOptimisticLockingPolicy(policy); } /** * PUBLIC: * Default to use the version locking policy and storing the value in the cache key * #see useVersionLocking(String) */ public void useVersionLocking(String writeLockFieldName) { useVersionLocking(writeLockFieldName, true); } /** * PUBLIC: * Set the locking policy to use numeric version locking. * This updates the version field on all updates, first comparing that the field has not changed to detect locking conflicts. * * The parameter 'shouldStoreInCache' configures the version lock value to be stored in the cache or in the object. * Note: if using a stateless model where the object can be passed to a client and then later updated in a different transaction context, * then the version lock value should not be stored in the cache, but in the object to ensure it is the correct value for that object. * @see TimestampLockingPolicy */ public void useVersionLocking(String writeLockFieldName, boolean shouldStoreInCache) { VersionLockingPolicy policy = new VersionLockingPolicy(writeLockFieldName); if (shouldStoreInCache) { policy.storeInCache(); } else { policy.storeInObject(); } setOptimisticLockingPolicy(policy); } /** * PUBLIC: * Set the class of identity map to be the weak identity map. * The default is the "SoftCacheWeakIdentityMap". */ public void useWeakIdentityMap() { setIdentityMapClass(ClassConstants.WeakIdentityMap_Class); } /** * INTERNAL: * Validate the entire post-initialization descriptor. */ protected void validateAfterInitialization(AbstractSession session) { selfValidationAfterInitialization(session); for (Enumeration mappings = getMappings().elements(); mappings.hasMoreElements();) { ((DatabaseMapping)mappings.nextElement()).validateAfterInitialization(session); } } /** * INTERNAL: * Validate the entire pre-initialization descriptor. */ protected void validateBeforeInitialization(AbstractSession session) { selfValidationBeforeInitialization(session); for (Enumeration mappings = getMappings().elements(); mappings.hasMoreElements();) { ((DatabaseMapping)mappings.nextElement()).validateBeforeInitialization(session); } } /** * INTERNAL: * Check that the qualifier on the table names are properly set. */ protected void verifyTableQualifiers(Platform platform) { DatabaseTable table; Enumeration tableEnumeration; String tableQualifier = platform.getTableQualifier(); if (tableQualifier.length() == 0) { return; } tableEnumeration = getTables().elements(); while (tableEnumeration.hasMoreElements()) { table = (DatabaseTable)tableEnumeration.nextElement(); if (table.getTableQualifier().length() == 0) { table.setTableQualifier(tableQualifier); } } } /** * ADVANCED: * Return the cmp descriptor that holds EJB CMP specific information. * This will be null unless explicitly set, or after CMP deoloyment. * This can only be specified when using CMP for bean class descriptors. * This must be set explicitly if any setting need to be configured and * before calling getCMPPolicy(). */ public CMPPolicy getCMPPolicy() { return cmpPolicy; } /** * ADVANCED: * Set the cmp descriptor that holds EJB CMP specific information. * This can only be specified when using CMP for bean class descriptors. * This must be set explicitly if any setting need to be configured and * before calling getCMPPolicy(). */ public void setCMPPolicy(CMPPolicy newCMPPolicy) { cmpPolicy = newCMPPolicy; if (cmpPolicy != null){ cmpPolicy.setDescriptor(this); } } /** * PUBLIC: * Get the fetch group manager for the descriptor. The fetch group manager is responsible * for managing the fetch group behaviors and operations. * To use the fetch group, the domain object must implement FetchGroupTracker interface. Otherwise, * a descriptor validation exception would throw during initialization. * NOTE: This is currently only supported in CMP2. * @see oracle.toplink.essentials.queryframework.FetchGroupTracker */ public FetchGroupManager getFetchGroupManager() { return fetchGroupManager; } /** * PUBLIC: * Set the fetch group manager for the descriptor. The fetch group manager is responsible * for managing the fetch group behaviors and operations. */ public void setFetchGroupManager(FetchGroupManager fetchGroupManager) { this.fetchGroupManager = fetchGroupManager; if (fetchGroupManager != null) { //set the back reference fetchGroupManager.setDescriptor(this); } } /** * INTERNAL: * Return true if the descriptor is a CMP entity descriptor */ public boolean isDescriptorForCMP() { return (this.getCMPPolicy() != null); } /** * INTERNAL: * Return if the descriptor has a fecth group manager asociated with. */ public boolean hasFetchGroupManager() { return (fetchGroupManager != null); } /** * INTERNAL: */ public boolean hasCascadeLockingPolicies() { return !cascadeLockingPolicies.isEmpty(); } /** * INTERNAL: * Return if the descriptor has a CMP policy. */ public boolean hasCMPPolicy() { return (cmpPolicy != null); } /** * INTERNAL: * * Return the default fetch group on the descriptor. * All read object and read all queries will use the default fetch group if * no fetch group is explicitly defined for the query. */ public FetchGroup getDefaultFetchGroup() { if (!hasFetchGroupManager()) { //fetch group manager is not set, therefore no default fetch group. return null; } return getFetchGroupManager().getDefaultFetchGroup(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy