KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > essentials > descriptors > ClassDescriptor


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21 // Copyright (c) 1998, 2006, Oracle. All rights reserved.
22
package oracle.toplink.essentials.descriptors;
23
24 import com.sun.jndi.ldap.EntryChangeResponseControl;
25
26 import java.security.AccessController JavaDoc;
27 import java.security.PrivilegedActionException JavaDoc;
28 import java.util.*;
29 import java.io.*;
30 import java.lang.reflect.*;
31
32 import oracle.toplink.essentials.internal.descriptors.*;
33 import oracle.toplink.essentials.internal.expressions.SQLSelectStatement;
34 import oracle.toplink.essentials.internal.expressions.SQLStatement;
35 import oracle.toplink.essentials.internal.helper.*;
36 import oracle.toplink.essentials.internal.identitymaps.*;
37 import oracle.toplink.essentials.mappings.*;
38 import oracle.toplink.essentials.mappings.foundation.AbstractDirectMapping;
39 import oracle.toplink.essentials.queryframework.FetchGroup;
40 import oracle.toplink.essentials.querykeys.*;
41 import oracle.toplink.essentials.expressions.*;
42 import oracle.toplink.essentials.internal.databaseaccess.*;
43 import oracle.toplink.essentials.exceptions.*;
44 import oracle.toplink.essentials.descriptors.copying.*;
45 import oracle.toplink.essentials.descriptors.changetracking.*;
46 import oracle.toplink.essentials.descriptors.invalidation.*;
47 import oracle.toplink.essentials.descriptors.FetchGroupManager;
48 import oracle.toplink.essentials.descriptors.InheritancePolicy;
49 import oracle.toplink.essentials.descriptors.DescriptorEvent;
50 import oracle.toplink.essentials.descriptors.DescriptorEventManager;
51 import oracle.toplink.essentials.descriptors.DescriptorQueryManager;
52 import oracle.toplink.essentials.internal.security.PrivilegedAccessHelper;
53 import oracle.toplink.essentials.internal.security.PrivilegedClassForName;
54 import oracle.toplink.essentials.internal.security.PrivilegedMethodInvoker;
55 import oracle.toplink.essentials.internal.sessions.AbstractRecord;
56 import oracle.toplink.essentials.internal.sessions.AbstractSession;
57 import oracle.toplink.essentials.internal.helper.MappingCompare;
58 import oracle.toplink.essentials.internal.helper.DatabaseTable;
59 import oracle.toplink.essentials.internal.helper.DatabaseField;
60
61 /**
62  * <p><b>Purpose</b>:
63  * Abstract descriptor class for defining persistence information on a class.
64  * This class provides the data independent behavior and is subclassed,
65  * for relational, object-relational, EIS, XML, etc.
66  *
67  * @see RelationalDescriptor
68  * @see oracle.toplink.essentials.objectrelational.ObjectRelationalDescriptor
69  * @see oracle.toplink.essentials.eis.EISDescriptor
70  * @see oracle.toplink.essentials.ox.XMLDescriptor
71  */

72 public class ClassDescriptor implements Cloneable JavaDoc, Serializable {
73     protected Class JavaDoc javaClass;
74     protected String JavaDoc javaClassName;
75     protected Vector tables;
76     protected transient DatabaseTable defaultTable;
77     protected List primaryKeyFields;
78     protected transient Map additionalTablePrimaryKeyFields;
79     protected transient Vector multipleTableInsertOrder;
80     protected transient Map multipleTableForeignKeys;
81     protected transient Vector fields;
82     protected transient Vector allFields;
83     protected Vector mappings;
84
85     //used by the lock on clone process. This will contain the foreign reference
86
//mapping without indirection
87
protected List lockableMappings;
88     protected Map queryKeys;
89
90     // Additional properties.
91
protected Class JavaDoc identityMapClass;
92     protected int identityMapSize;
93     protected String JavaDoc sequenceNumberName;
94     protected DatabaseField sequenceNumberField;
95     protected transient String JavaDoc sessionName;
96     protected boolean shouldAlwaysRefreshCache;
97     protected boolean shouldOnlyRefreshCacheIfNewerVersion;
98     protected boolean shouldDisableCacheHits;
99     protected transient Vector constraintDependencies;
100     protected transient String JavaDoc amendmentMethodName;
101     protected transient Class JavaDoc amendmentClass;
102     protected transient String JavaDoc amendmentClassName;
103     protected String JavaDoc alias;
104     protected boolean shouldBeReadOnly;
105     protected boolean shouldAlwaysConformResultsInUnitOfWork;
106
107     // this attribute is used to determine what classes should be isolated from the shared cache
108
protected boolean isIsolated;
109
110     // for bug 2612601 allow ability not to register results in UOW.
111
protected boolean shouldRegisterResultsInUnitOfWork = true;
112
113     // Delegation objects, these perform most of the behavoir.
114
protected DescriptorEventManager eventManager;
115     protected DescriptorQueryManager queryManager;
116     protected ObjectBuilder objectBuilder;
117     protected CopyPolicy copyPolicy;
118     protected InstantiationPolicy instantiationPolicy;
119     protected InheritancePolicy inheritancePolicy;
120     protected OptimisticLockingPolicy optimisticLockingPolicy;
121     protected Vector cascadeLockingPolicies;
122     protected WrapperPolicy wrapperPolicy;
123     protected ObjectChangePolicy changePolicy;
124     protected CMPPolicy cmpPolicy;
125
126     //manage fetch group behaviors and operations
127
protected FetchGroupManager fetchGroupManager;
128
129     /** Additional properties may be added. */
130     protected Map properties;
131
132     // Follwing are the states the descriptor passes thru during the initialization.
133
protected static final int UNINITIALIZED = 0;
134     protected static final int PREINITIALIZED = 1;
135     protected static final int INITIALIZED = 2;
136     protected static final int POST_INITIALIZED = 3;
137     protected static final int ERROR = -1;
138
139     //redefine the descriptor types (exclusively)
140
protected static final int NORMAL = 0;
141     protected static final int AGGREGATE = 2;
142     protected static final int AGGREGATE_COLLECTION = 3;
143     protected transient int initializationStage;
144     protected int descriptorType;
145     protected boolean shouldOrderMappings;
146     protected CacheInvalidationPolicy cacheInvalidationPolicy = null;
147
148     /** PERF: Used to optimize cache locking to only acquire deferred locks when required (no-indirection). */
149     protected boolean shouldAcquireCascadedLocks = false;
150
151     /** PERF: Compute and store if the primary key is simple (direct-mapped) to allow fast extraction. */
152     protected boolean hasSimplePrimaryKey = false;
153
154     /**
155      * PUBLIC:
156      * Return a new descriptor.
157      */

158     public ClassDescriptor() {
159         // Properties
160
this.tables = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(3);
161         this.mappings = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance();
162         this.primaryKeyFields = new ArrayList(2);
163         this.fields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance();
164         this.allFields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance();
165         this.constraintDependencies = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(2);
166         this.multipleTableForeignKeys = new HashMap(5);
167         this.queryKeys = new HashMap(5);
168         this.initializationStage = UNINITIALIZED;
169         this.shouldAlwaysRefreshCache = false;
170         this.shouldOnlyRefreshCacheIfNewerVersion = false;
171         this.shouldDisableCacheHits = false;
172         this.identityMapSize = 100;
173         this.identityMapClass = IdentityMap.getDefaultIdentityMapClass();
174         this.descriptorType = NORMAL;
175         this.shouldOrderMappings = true;
176         this.shouldBeReadOnly = false;
177         this.shouldAlwaysConformResultsInUnitOfWork = false;
178         this.shouldAcquireCascadedLocks = false;
179         this.hasSimplePrimaryKey = false;
180         this.isIsolated = false;
181
182         // Policies
183
this.objectBuilder = new ObjectBuilder(this);
184         setCopyPolicy(new InstantiationCopyPolicy());
185         setInstantiationPolicy(new InstantiationPolicy());
186         setEventManager(new oracle.toplink.essentials.descriptors.DescriptorEventManager());
187         setQueryManager(new oracle.toplink.essentials.descriptors.DescriptorQueryManager());
188
189         changePolicy = new DeferredChangeDetectionPolicy();
190         this.cascadeLockingPolicies = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance();
191     }
192
193     /**
194      * PUBLIC:
195      * This method should only be used for interface descriptors. It
196      * adds an abstract query key to the interface descriptor. Any
197      * implementors of that interface must define the query key
198      * defined by this abstract query key.
199      */

200     public void addAbstractQueryKey(String JavaDoc queryKeyName) {
201         QueryKey queryKey = new QueryKey();
202         queryKey.setName(queryKeyName);
203         addQueryKey(queryKey);
204     }
205      
206     /**
207      * ADVANCED:
208      * TopLink automatically orders database access through the foreign key information provided in 1:1 and 1:m mappings.
209      * In some case when 1:1 are not defined it may be required to tell the descriptor about a constraint,
210      * this defines that this descriptor has a foreign key constraint to another class and must be inserted after
211      * instances of the other class.
212      */

213     public void addConstraintDependencies(Class JavaDoc dependencies) {
214         getConstraintDependencies().addElement(dependencies);
215     }
216
217     /**
218      * PUBLIC:
219      * Add a direct mapping to the receiver. The new mapping specifies that
220      * an instance variable of the class of objects which the receiver describes maps in
221      * the default manner for its type to the indicated database field.
222      *
223      * @param String instanceVariableName is the name of an instance variable of the
224      * class which the receiver describes.
225      * @param String fieldName is the name of the database column which corresponds
226      * with the designated instance variable.
227      * @return The newly created DatabaseMapping is returned.
228      */

229     public DatabaseMapping addDirectMapping(String JavaDoc attributeName, String JavaDoc fieldName) {
230         DirectToFieldMapping mapping = new DirectToFieldMapping();
231
232         mapping.setAttributeName(attributeName);
233         mapping.setFieldName(fieldName);
234
235         return addMapping(mapping);
236     }
237
238     /**
239      * PUBLIC:
240      * Add a direct mapping to the receiver. The new mapping specifies that
241      * a variable accessed by the get and set methods of the class of objects which
242      * the receiver describes maps in the default manner for its type to the indicated
243      * database field.
244      */

245     public DatabaseMapping addDirectMapping(String JavaDoc attributeName, String JavaDoc getMethodName, String JavaDoc setMethodName, String JavaDoc fieldName) {
246         DirectToFieldMapping mapping = new DirectToFieldMapping();
247
248         mapping.setAttributeName(attributeName);
249         mapping.setSetMethodName(setMethodName);
250         mapping.setGetMethodName(getMethodName);
251         mapping.setFieldName(fieldName);
252
253         return addMapping(mapping);
254     }
255
256     /**
257      * PUBLIC:
258      * Add a query key to the descriptor. Query keys define Java aliases to database fields.
259      */

260     public void addDirectQueryKey(String JavaDoc queryKeyName, String JavaDoc fieldName) {
261         DirectQueryKey queryKey = new DirectQueryKey();
262         DatabaseField field = new DatabaseField(fieldName);
263
264         queryKey.setName(queryKeyName);
265         queryKey.setField(field);
266         getQueryKeys().put(queryKeyName, queryKey);
267     }
268
269     /**
270      * PUBLIC:
271      * Add a database mapping to the receiver. Perform any required
272      * initialization of both the mapping and the receiving descriptor
273      * as a result of adding the new mapping.
274      */

275     public DatabaseMapping addMapping(DatabaseMapping mapping) {
276         // For CR#2646, if the mapping already points to the parent descriptor then leave it.
277
if (mapping.getDescriptor() == null) {
278             mapping.setDescriptor(this);
279         }
280         getMappings().addElement(mapping);
281         return mapping;
282     }
283
284     protected void validateMappingType(DatabaseMapping mapping) {
285         if (!(mapping.isRelationalMapping())) {
286             throw DescriptorException.invalidMappingType(mapping);
287         }
288     }
289
290     /**
291      * PUBLIC:
292      * This protocol can be used to associate multiple tables with foreign key
293      * information. The join criteria will be generated based on the fields
294      * provided. By default TopLink associates multiple tables using a primary
295      * key join where the primary keys fields are named the same.
296      */

297     public void addMultipleTableForeignKeyField(DatabaseField sourceField, DatabaseField targetField) throws DescriptorException {
298         addMultipleTableForeignKeys(sourceField, targetField, true);
299     }
300     
301     /**
302      * PUBLIC:
303      * This protocol can be used to associate multiple tables with foreign key
304      * information. The join criteria will be generated based on the fields
305      * provided. By default TopLink associates multiple tables using a primary
306      * key join where the primary keys fields are named the same.
307      */

308     public void addMultipleTableForeignKeyFieldName(String JavaDoc sourceFieldName, String JavaDoc targetFieldName) throws DescriptorException {
309         addMultipleTableForeignKeyField(new DatabaseField(sourceFieldName), new DatabaseField(targetFieldName));
310     }
311     
312     /**
313      * INTERNAL:
314      * Add the multiple fields, if is a foreign key then add the tables to the
315      * foreign keys ordering.
316      */

317     protected void addMultipleTableForeignKeys(DatabaseField sourceField, DatabaseField targetField, boolean isForeignKey) throws DescriptorException {
318         // Make sure that the table is fully qualified.
319
if ((!sourceField.hasTableName()) || (!targetField.hasTableName())) {
320             throw DescriptorException.multipleTablePrimaryKeyMustBeFullyQualified(this);
321         }
322         
323         DatabaseTable sourceTable = sourceField.getTable();
324         DatabaseTable targetTable = targetField.getTable();
325         setAdditionalTablePrimaryKeyFields(targetTable, sourceField, targetField);
326         
327         if (isForeignKey) {
328             getMultipleTableForeignKeys().put(sourceTable, targetTable);
329         }
330     }
331     
332     /**
333      * INTERNAL:
334      * Add the multiple table fields, if is a foreign key then add the tables to the
335      * foreign keys ordering.
336      */

337     protected void addMultipleTableForeignKeys(String JavaDoc fieldNameInSourceTable, String JavaDoc fieldNameInTargetTable, boolean isForeignKey) throws DescriptorException {
338         addMultipleTableForeignKeys(new DatabaseField(fieldNameInSourceTable), new DatabaseField(fieldNameInTargetTable), isForeignKey);
339     }
340
341     /**
342      * PUBLIC:
343      * This protocol can be used to map the primary key fields in a multiple
344      * table descriptor. By default TopLink assumes that all of the primary key
345      * fields are named the same.
346      */

347     public void addMultipleTablePrimaryKeyField(DatabaseField sourceField, DatabaseField targetField) throws DescriptorException {
348         addMultipleTableForeignKeys(sourceField, targetField, false);
349     }
350     
351     /**
352      * PUBLIC:
353      * This protocol can be used to map the primary key field names in a
354      * multiple table descriptor. By default TopLink assumes that all of the
355      * primary key fields are named the same.
356      */

357     public void addMultipleTablePrimaryKeyFieldName(String JavaDoc sourceFieldName, String JavaDoc targetFieldName) throws DescriptorException {
358         addMultipleTablePrimaryKeyField(new DatabaseField(sourceFieldName), new DatabaseField(targetFieldName));
359     }
360
361     /**
362      * PUBLIC:
363      * Specify the primary key field of the descriptors table.
364      * This should be called for each field that makes up the primary key of the table.
365      * If the descriptor has many tables, this must be the primary key in the first table,
366      * if the other tables have the same primary key nothing else is required, otherwise
367      * a primary key/foreign key field mapping must be provided for each of the other tables.
368      * @see #addMultipleTableForeignKeyFieldName(String, String);
369      */

370     public void addPrimaryKeyFieldName(String JavaDoc fieldName) {
371         getPrimaryKeyFields().add(new DatabaseField(fieldName));
372     }
373
374     /**
375      * ADVANCED:
376      * Specify the primary key field of the descriptors table.
377      * This should be called for each field that makes up the primary key of the table.
378      * This can be used for advanced field types, such as XML nodes, or to set the field type.
379      */

380     public void addPrimaryKeyField(DatabaseField field) {
381         getPrimaryKeyFields().add(field);
382     }
383
384     /**
385      * PUBLIC:
386      * Add a query key to the descriptor. Query keys define Java aliases to database fields.
387      */

388     public void addQueryKey(QueryKey queryKey) {
389         getQueryKeys().put(queryKey.getName(), queryKey);
390     }
391
392     /**
393      * PUBLIC:
394      * Specify the table for the class of objects the receiver describes.
395      * This method is used if there is more than one table.
396      */

397     public void addTable(DatabaseTable table) {
398         getTables().addElement(table);
399     }
400     
401     /**
402      * PUBLIC:
403      * Specify the table name for the class of objects the receiver describes.
404      * If the table has a qualifier it should be specified using the dot notation,
405      * (i.e. "userid.employee"). This method is used if there is more than one table.
406      */

407     public void addTableName(String JavaDoc tableName) {
408         addTable(new DatabaseTable(tableName));
409     }
410
411     /**
412      * INTERNAL:
413      * Adjust the order of the tables in the multipleTableInsertOrder Vector according to the FK
414      * relationship if one (or more) were previously specified. I.e. target of FK relationship should be inserted
415      * before source.
416      * If the multipleTableInsertOrder has been specified (presumably by the user) then do not change it.
417      */

418     public void adjustMultipleTableInsertOrder() {
419         // Check if a user defined insert order was given.
420
if ((getMultipleTableInsertOrder() == null) || getMultipleTableInsertOrder().isEmpty()) {
421             setMultipleTableInsertOrder((Vector) getTables().clone());
422             
423             checkMultipleTableForeignKeys(false);
424         } else {
425             if (getMultipleTableInsertOrder().size() != getTables().size()) {
426                 throw DescriptorException.multipleTableInsertOrderMismatch(this);
427             }
428         
429             checkMultipleTableForeignKeys(true);
430         }
431     }
432     
433     /**
434      * PUBLIC:
435      * Used to set the descriptor to always conform in any unit of work query.
436      *
437      */

438     public void alwaysConformResultsInUnitOfWork() {
439         setShouldAlwaysConformResultsInUnitOfWork(true);
440     }
441
442     /**
443      * PUBLIC:
444      * This method is the equivalent of calling {@link #setShouldAlwaysRefreshCache} with an argument of <CODE>true</CODE>:
445      * it configures a <CODE>Descriptor</CODE> to always refresh the cache if data is received from the database by any query.<P>
446      *
447      * However, if a query hits the cache, data is not refreshed regardless of how this setting is configured. For example, by
448      * default, when a query for a single object based on its primary key is executed, OracleAS TopLink will first look in the
449      * cache for the object. If the object is in the cache, the cached object is returned and data is not refreshed. To avoid
450      * cache hits, use the {@link #disableCacheHits} method.<P>
451      *
452      * Also note that the {@link oracle.toplink.essentials.sessions.UnitOfWork} will not refresh its registered objects.<P>
453      *
454      * Use this property with caution because it can lead to poor performance and may refresh on queries when it is not desired. Normally,
455      * if you require fresh data, it is better to configure a query with {@link oracle.toplink.essentials.queryframework.ObjectLevelReadQuery#refreshIdentityMapResult}.
456      * To ensure that refreshes are only done when required, use this method in conjunction with {@link #onlyRefreshCacheIfNewerVersion}.
457      *
458      * @see #dontAlwaysRefreshCache
459      */

460     public void alwaysRefreshCache() {
461         setShouldAlwaysRefreshCache(true);
462     }
463
464     /**
465      * ADVANCED:
466      * Call the descriptor amendment method.
467      * This is called while loading or creating a descriptor that has an amendment method defined.
468      */

469     public void applyAmendmentMethod() {
470         applyAmendmentMethod(null);
471     }
472
473     /**
474      * INTERNAL:
475      * Call the descriptor amendment method.
476      * This is called while loading or creating a descriptor that has an amendment method defined.
477      */

478     public void applyAmendmentMethod(DescriptorEvent event) {
479         if ((getAmendmentClass() == null) || (getAmendmentMethodName() == null)) {
480             return;
481         }
482
483         Method method = null;
484         Class JavaDoc[] argTypes = new Class JavaDoc[1];
485
486         // BUG#2669585
487
// Class argument type must be consistent, descriptor, i.e. instance may be a subclass.
488
argTypes[0] = ClassDescriptor.class;
489         try {
490             method = Helper.getDeclaredMethod(getAmendmentClass(), getAmendmentMethodName(), argTypes);
491         } catch (Exception JavaDoc ignore) {
492             // Return type should now be ClassDescriptor.
493
argTypes[0] = ClassDescriptor.class;
494             try {
495                 method = Helper.getDeclaredMethod(getAmendmentClass(), getAmendmentMethodName(), argTypes);
496             } catch (Exception JavaDoc exception) {
497                 throw DescriptorException.invalidAmendmentMethod(getAmendmentClass(), getAmendmentMethodName(), exception, this);
498             }
499         }
500
501         Object JavaDoc[] args = new Object JavaDoc[1];
502         args[0] = this;
503
504         try {
505             if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
506                 try {
507                     AccessController.doPrivileged(new PrivilegedMethodInvoker(method, null, args));
508                 } catch (PrivilegedActionException JavaDoc exception) {
509                     Exception JavaDoc throwableException = exception.getException();
510                     if (throwableException instanceof IllegalAccessException JavaDoc) {
511                         throw (IllegalAccessException JavaDoc)throwableException;
512                     } else {
513                         throw (InvocationTargetException)throwableException;
514                     }
515                 }
516             } else {
517                 PrivilegedAccessHelper.invokeMethod(method, null, args);
518             }
519         } catch (Exception JavaDoc exception) {
520             throw DescriptorException.errorOccuredInAmendmentMethod(getAmendmentClass(), getAmendmentMethodName(), exception, this);
521         }
522     }
523
524     /**
525      * INTERNAL:
526      * Used to determine if a foreign key references the primary key.
527      */

528     public boolean arePrimaryKeyFields(Vector fields) {
529         if (!(fields.size() == (getPrimaryKeyFields().size()))) {
530             return false;
531         }
532
533         for (Enumeration enumFields = fields.elements(); enumFields.hasMoreElements();) {
534             DatabaseField field = (DatabaseField)enumFields.nextElement();
535
536             if (!getPrimaryKeyFields().contains(field)) {
537                 return false;
538             }
539         }
540
541         return true;
542     }
543
544     /**
545      * INTERNAL:
546      * Return a call built from a statement. Subclasses may throw an exception
547      * if the statement is not appropriate.
548      */

549     public DatabaseCall buildCallFromStatement(SQLStatement statement, AbstractSession session) {
550         return statement.buildCall(session);
551     }
552
553     /**
554      * INTERNAL:
555      * Extract the direct values from the specified field value.
556      * Return them in a vector.
557      */

558     public Vector buildDirectValuesFromFieldValue(Object JavaDoc fieldValue) throws DatabaseException {
559         throw DescriptorException.normalDescriptorsDoNotSupportNonRelationalExtensions(this);
560     }
561
562     /**
563      * INTERNAL:
564      * A DatabaseField is built from the given field name.
565      */

566
567     // * added 9/7/00 by Les Davis
568
// * bug fix for null pointer in initialization of mappings in remote session
569
public DatabaseField buildField(String JavaDoc fieldName) {
570         DatabaseField field = new DatabaseField(fieldName);
571         DatabaseTable table;
572
573         if (field.hasTableName()) {
574             table = getTable(field.getTableName());
575         } else if (getDefaultTable() != null) {
576             table = getDefaultTable();
577         } else {
578             table = getTable(getTableName());
579         }
580
581         field.setTable(table);
582         return field;
583     }
584
585     /**
586      * INTERNAL:
587      * The table of the field is ensured to be unique from the descriptor's tables.
588      * If the field has no table the default table is assigned.
589      * This is used only in initialization.
590      */

591     public void buildField(DatabaseField field) {
592         DatabaseTable table;
593         if (field.hasTableName()) {
594             table = getTable(field.getTableName());
595         } else {
596             table = getDefaultTable();
597         }
598
599         field.setTable(table);
600     }
601
602     /**
603      * INTERNAL:
604      * Build the appropriate field value for the specified
605      * set of direct values.
606      */

607     public Object JavaDoc buildFieldValueFromDirectValues(Vector directValues, String JavaDoc elementDataTypeName, AbstractSession session) throws DatabaseException {
608         throw DescriptorException.normalDescriptorsDoNotSupportNonRelationalExtensions(this);
609     }
610
611     /**
612      * INTERNAL:
613      * Build and return the appropriate field value for the specified
614      * set of foreign keys (i.e. each row has the fields that
615      * make up a foreign key).
616      */

617     public Object JavaDoc buildFieldValueFromForeignKeys(Vector foreignKeys, String JavaDoc referenceDataTypeName, AbstractSession session) throws DatabaseException {
618         throw DescriptorException.normalDescriptorsDoNotSupportNonRelationalExtensions(this);
619     }
620
621     /**
622      * INTERNAL:
623      * Build and return the field value from the specified nested database row.
624      */

625     public Object JavaDoc buildFieldValueFromNestedRow(AbstractRecord nestedRow, AbstractSession session) throws DatabaseException {
626         throw DescriptorException.normalDescriptorsDoNotSupportNonRelationalExtensions(this);
627     }
628
629     /**
630      * INTERNAL:
631      * Build and return the appropriate field value for the specified
632      * set of nested rows.
633      */

634     public Object JavaDoc buildFieldValueFromNestedRows(Vector nestedRows, String JavaDoc structureName, AbstractSession session) throws DatabaseException {
635         throw DescriptorException.normalDescriptorsDoNotSupportNonRelationalExtensions(this);
636     }
637
638     /**
639      * INTERNAL:
640      * Build and return the nested database row from the specified field value.
641      */

642     public AbstractRecord buildNestedRowFromFieldValue(Object JavaDoc fieldValue) throws DatabaseException {
643         throw DescriptorException.normalDescriptorsDoNotSupportNonRelationalExtensions(this);
644     }
645
646     /**
647      * INTERNAL:
648      * Build and return the nested rows from the specified field value.
649      */

650     public Vector buildNestedRowsFromFieldValue(Object JavaDoc fieldValue, AbstractSession session) throws DatabaseException {
651         throw DescriptorException.normalDescriptorsDoNotSupportNonRelationalExtensions(this);
652     }
653
654     /**
655      * To check that tables and fields are present in database
656      */

657     protected void checkDatabase(AbstractSession session) {
658         if (session.getIntegrityChecker().shouldCheckDatabase()) {
659             for (Enumeration enumTable = getTables().elements(); enumTable.hasMoreElements();) {
660                 DatabaseTable table = (DatabaseTable)enumTable.nextElement();
661                 if (session.getIntegrityChecker().checkTable(table, session)) {
662                     // To load the fields of database into a vector
663
Vector databaseFields = new Vector();
664                     Vector result = session.getAccessor().getColumnInfo(null, null, table.getName(), null, session);
665                     for (Enumeration resultEnum = result.elements(); resultEnum.hasMoreElements();) {
666                         AbstractRecord row = (AbstractRecord)resultEnum.nextElement();
667                         databaseFields.addElement(row.get("COLUMN_NAME"));
668                     }
669
670                     // To check that the fields of descriptor are present in the database.
671
for (Enumeration row = getFields().elements(); row.hasMoreElements();) {
672                         DatabaseField field = (DatabaseField)row.nextElement();
673                         if (field.getTable().equals(table) && (!databaseFields.contains(field.getName()))) {
674                             session.getIntegrityChecker().handleError(DescriptorException.fieldIsNotPresentInDatabase(this, table.getName(), field.getName()));
675                         }
676                     }
677                 } else {
678                     session.getIntegrityChecker().handleError(DescriptorException.tableIsNotPresentInDatabase(this));
679                 }
680             }
681         }
682     }
683
684     /**
685      * INTERNAL:
686      * Verify that an aggregate descriptor's inheritance tree
687      * is full of aggregate descriptors.
688      */

689     public void checkInheritanceTreeAggregateSettings(AbstractSession session, AggregateMapping mapping) throws DescriptorException {
690         if (!this.hasInheritance()) {
691             return;
692         }
693
694         if (this.isChildDescriptor()) {
695             Class JavaDoc parentClass = this.getInheritancePolicy().getParentClass();
696             if (parentClass == this.getJavaClass()) {
697                 throw DescriptorException.parentClassIsSelf(this);
698             }
699
700             // recurse up the inheritance tree to the root descriptor
701
session.getDescriptor(parentClass).checkInheritanceTreeAggregateSettings(session, mapping);
702         } else {
703             // we have a root descriptor, now verify it and all its children, grandchildren, etc.
704
this.checkInheritanceTreeAggregateSettingsForChildren(session, mapping);
705         }
706     }
707
708     /**
709      * Verify that an aggregate descriptor's inheritance tree
710      * is full of aggregate descriptors, cont.
711      */

712     private void checkInheritanceTreeAggregateSettingsForChildren(AbstractSession session, AggregateMapping mapping) throws DescriptorException {
713         if (!this.isAggregateDescriptor()) {
714             session.getIntegrityChecker().handleError(DescriptorException.referenceDescriptorIsNotAggregate(this.getJavaClass().getName(), mapping));
715         }
716         for (Enumeration stream = this.getInheritancePolicy().getChildDescriptors().elements();
717                  stream.hasMoreElements();) {
718             ClassDescriptor childDescriptor = (ClassDescriptor)stream.nextElement();
719
720             // recurse down the inheritance tree to its leaves
721
childDescriptor.checkInheritanceTreeAggregateSettingsForChildren(session, mapping);
722         }
723     }
724     
725     /**
726      * INTERNAL:
727      */

728     protected void checkMultipleTableForeignKeys(boolean userSpecifiedOrder) {
729         // Loop through n times to be sure that the insert order is correct.
730
// Loop n times eliminates our dependence on the order of the foreighKey
731
// relationships specified. We could do this adjustment in one pass but
732
// we would have to put the foreignKeyTables in the same order as the
733
// tables being sorted.
734
Map foreignKeyTableRelationships = getMultipleTableForeignKeys();
735         
736         for (int i = 0; i < foreignKeyTableRelationships.size(); i++) {
737             for (Iterator sourceTables = foreignKeyTableRelationships.entrySet().iterator(); sourceTables.hasNext();) {
738                 Map.Entry entry = (Map.Entry)sourceTables.next();
739                 DatabaseTable sourceTable = (DatabaseTable) entry.getKey();
740                 DatabaseTable targetTable = (DatabaseTable) entry.getValue();
741                 
742                 // Verify the source table is a valid.
743
if (getMultipleTableInsertOrder().indexOf(sourceTable) == -1) {
744                     throw DescriptorException.illegalTableNameInMultipleTableForeignKeyField(this, sourceTable);
745                 }
746                 
747                 // Verify the target table is a valid.
748
if (getMultipleTableInsertOrder().indexOf(targetTable) == -1) {
749                     throw DescriptorException.illegalTableNameInMultipleTableForeignKeyField(this, targetTable);
750                 }
751                 
752                 int sourceTableIndex = getTables().indexOf(sourceTable);
753                 int targetTableIndex = getTables().indexOf(targetTable);
754                 
755                 // The sourceTable must be before the targetTable to avoid
756
// foreign key constraint violations when inserting into the
757
// database.
758
if (targetTableIndex < sourceTableIndex) {
759                     if (userSpecifiedOrder) {
760                         toggleAdditionalTablePrimaryKeyFields(targetTable, sourceTable);
761                     } else {
762                         int sti = getMultipleTableInsertOrder().indexOf(sourceTable);
763                         int tti = getMultipleTableInsertOrder().indexOf(targetTable);
764                         
765                         if (tti < sti) {
766                             toggleAdditionalTablePrimaryKeyFields(targetTable, sourceTable);
767                             getMultipleTableInsertOrder().removeElementAt(tti);
768                             getMultipleTableInsertOrder().insertElementAt(targetTable, sti);
769                         }
770                     }
771                 }
772             }
773         }
774     }
775
776     /**
777      * INTERNAL:
778      * Clones the descriptor
779      */

780     public Object JavaDoc clone() {
781         ClassDescriptor clonedDescriptor = null;
782
783         // clones itself
784
try {
785             clonedDescriptor = (ClassDescriptor)super.clone();
786         } catch (Exception JavaDoc exception) {
787             ;
788         }
789
790         Vector mappingsVector = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance();
791
792         // All the mappings
793
for (Enumeration mappingsEnum = getMappings().elements(); mappingsEnum.hasMoreElements();) {
794             DatabaseMapping mapping;
795
796             mapping = (DatabaseMapping)((DatabaseMapping)mappingsEnum.nextElement()).clone();
797             mapping.setDescriptor(clonedDescriptor);
798             mappingsVector.addElement(mapping);
799         }
800         clonedDescriptor.setMappings(mappingsVector);
801
802         Map queryKeyVector = new HashMap(getQueryKeys().size() + 2);
803
804         // All the query keys
805
for (Iterator queryKeysEnum = getQueryKeys().values().iterator();queryKeysEnum.hasNext();){
806             QueryKey queryKey = (QueryKey)((QueryKey)queryKeysEnum.next()).clone();
807             queryKey.setDescriptor(clonedDescriptor);
808             queryKeyVector.put(queryKey.getName(), queryKey);
809         }
810         clonedDescriptor.setQueryKeys(queryKeyVector);
811
812         // PrimaryKeyFields
813
List primaryKeyVector = new ArrayList(getPrimaryKeyFields().size());
814         List primaryKeyFields = getPrimaryKeyFields();
815         for (int index = 0; index < primaryKeyFields.size(); index++) {
816             DatabaseField primaryKey = (DatabaseField)((DatabaseField)primaryKeyFields.get(index)).clone();
817             primaryKeyVector.add(primaryKey);
818         }
819         clonedDescriptor.setPrimaryKeyFields(primaryKeyVector);
820
821         // fields.
822
clonedDescriptor.setFields(oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance());
823
824         // The inheritance policy
825
if (clonedDescriptor.hasInheritance()) {
826             clonedDescriptor.setInheritancePolicy((InheritancePolicy)getInheritancePolicy().clone());
827             clonedDescriptor.getInheritancePolicy().setDescriptor(clonedDescriptor);
828         }
829
830         // The Object builder
831
clonedDescriptor.setObjectBuilder((ObjectBuilder)getObjectBuilder().clone());
832         clonedDescriptor.getObjectBuilder().setDescriptor(clonedDescriptor);
833
834         clonedDescriptor.setEventManager((DescriptorEventManager)getEventManager().clone());
835         clonedDescriptor.getEventManager().setDescriptor(clonedDescriptor);
836
837         // The Query manager
838
clonedDescriptor.setQueryManager((DescriptorQueryManager)getQueryManager().clone());
839         clonedDescriptor.getQueryManager().setDescriptor(clonedDescriptor);
840
841         //fetch group
842
if (hasFetchGroupManager()) {
843             clonedDescriptor.setFetchGroupManager((FetchGroupManager)getFetchGroupManager().clone());
844         }
845
846         clonedDescriptor.setIsIsolated(this.isIsolated());
847
848         // Bug 3037701 - clone several more elements
849
clonedDescriptor.setInstantiationPolicy((InstantiationPolicy)this.instantiationPolicy.clone());
850         clonedDescriptor.setCopyPolicy((CopyPolicy)this.copyPolicy.clone());
851         if (getOptimisticLockingPolicy() != null) {
852             clonedDescriptor.setOptimisticLockingPolicy((OptimisticLockingPolicy)this.getOptimisticLockingPolicy().clone());
853         }
854
855         return (Object JavaDoc)clonedDescriptor;
856     }
857
858     /**
859      * INTERNAL:
860      * Convert all the class-name-based settings in this Descriptor to actual class-based
861      * settings. This method is used when converting a project that has been built
862      * with class names to a project with classes.
863      * @param classLoader
864      */

865     public void convertClassNamesToClasses(ClassLoader JavaDoc classLoader){
866         Class JavaDoc descriptorClass = null;
867         Class JavaDoc amendmentClass = null;
868         try{
869             if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
870                 try {
871                     descriptorClass = (Class JavaDoc)AccessController.doPrivileged(new PrivilegedClassForName(getJavaClassName(), true, classLoader));
872                 } catch (PrivilegedActionException JavaDoc exception) {
873                     throw ValidationException.classNotFoundWhileConvertingClassNames(getAmendmentClassName(), exception.getException());
874                 }
875             } else {
876                 descriptorClass = oracle.toplink.essentials.internal.security.PrivilegedAccessHelper.getClassForName(getJavaClassName(), true, classLoader);
877             }
878             if (getAmendmentClassName() != null){
879                 if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
880                     try {
881                         amendmentClass = (Class JavaDoc)AccessController.doPrivileged(new PrivilegedClassForName(getAmendmentClassName(), true, classLoader));
882                     } catch (PrivilegedActionException JavaDoc exception) {
883                         throw ValidationException.classNotFoundWhileConvertingClassNames(getAmendmentClassName(), exception.getException());
884                    }
885                 } else {
886                     amendmentClass = oracle.toplink.essentials.internal.security.PrivilegedAccessHelper.getClassForName(getAmendmentClassName(), true, classLoader);
887                 }
888             }
889         } catch (ClassNotFoundException JavaDoc exc){
890             throw ValidationException.classNotFoundWhileConvertingClassNames(getAmendmentClassName(), exc);
891         }
892         setJavaClass(descriptorClass);
893         if (amendmentClass != null){
894             setAmendmentClass(amendmentClass);
895         }
896         Iterator mappings = getMappings().iterator();
897         while (mappings.hasNext()){
898             ((DatabaseMapping)mappings.next()).convertClassNamesToClasses(classLoader);
899         }
900         if (inheritancePolicy != null){
901             inheritancePolicy.convertClassNamesToClasses(classLoader);
902         }
903         if (instantiationPolicy != null){
904             instantiationPolicy.convertClassNamesToClasses(classLoader);
905         }
906         if (hasCMPPolicy()) {
907             getCMPPolicy().convertClassNamesToClasses(classLoader);
908         }
909         queryManager.convertClassNamesToClasses(classLoader);
910     }
911
912     /**
913      * PUBLIC:
914      * Create a copy policy of the type passed in as a string.
915      */

916     public void createCopyPolicy(String JavaDoc policyType) {
917         if (policyType.equals("clone")) {
918             useCloneCopyPolicy();
919             return;
920         }
921         if (policyType.equals("constructor")) {
922             useInstantiationCopyPolicy();
923             return;
924         }
925     }
926
927     /**
928      * PUBLIC:
929      * Create a instantiation policy of the type passed in as a string.
930      */

931     public void createInstantiationPolicy(String JavaDoc policyType) {
932         if (policyType.equals("static method")) {
933             //do nothing for now
934
return;
935         }
936         if (policyType.equals("constructor")) {
937             useDefaultConstructorInstantiationPolicy();
938             return;
939         }
940         if (policyType.equals("factory")) {
941             //do nothing for now
942
return;
943         }
944     }
945
946     /**
947      * PUBLIC:
948      * Sets the descriptor to be an aggregate.
949      * An aggregate descriptor is contained within another descriptor's table.
950      * Aggregate descriptors are insert/updated/deleted with their owner and cannot exist without their owner as they share the same row.
951      * Aggregates are not cached (they are cached as part of their owner) and cannot be read/written/deleted/registered.
952      * All aggregate descriptors must call this.
953      */

954     public void descriptorIsAggregate() {
955         setDescriptorType(AGGREGATE);
956     }
957
958     /**
959      * PUBLIC:
960      * Sets the descriptor to be part of an aggregate collection.
961      * An aggregate collection descriptor stored in a seperate table but some of the fields (the primary key) comes from its owner.
962      * Aggregate collection descriptors are insert/updated/deleted with their owner and cannot exist without their owner as they share the primary key.
963      * Aggregate collections are not cached (they are cached as part of their owner) and cannot be read/written/deleted/registered.
964      * All aggregate collection descriptors must call this.
965      */

966     public void descriptorIsAggregateCollection() {
967         setDescriptorType(AGGREGATE_COLLECTION);
968     }
969
970     /**
971      * PUBLIC:
972      * Sets the descriptor to be normal.
973      * This is the default and means the descriptor is not aggregate or for an interface.
974      */

975     public void descriptorIsNormal() {
976         setDescriptorType(NORMAL);
977     }
978
979     /**
980      * PUBLIC:
981      * Allow for cache hits on primary key read object queries to be disabled.
982      * This can be used with {@link #alwaysRefreshCache} or {@link #alwaysRefreshCacheOnRemote} to ensure queries always go to the database.
983      */

984     public void disableCacheHits() {
985         setShouldDisableCacheHits(true);
986     }
987
988     /**
989      * PUBLIC:
990      * The descriptor is defined to not conform the results in unit of work in read query. Default.
991      *
992      */

993     public void dontAlwaysConformResultsInUnitOfWork() {
994         setShouldAlwaysConformResultsInUnitOfWork(false);
995     }
996
997     /**
998      * PUBLIC:
999      * This method is the equivalent of calling {@link #setShouldAlwaysRefreshCache} with an argument of <CODE>false</CODE>:
1000     * it ensures that a <CODE>Descriptor</CODE> is not configured to always refresh the cache if data is received from the database by any query.
1001     *
1002     * @see #alwaysRefreshCache
1003     */

1004    public void dontAlwaysRefreshCache() {
1005        setShouldAlwaysRefreshCache(false);
1006    }
1007
1008    /**
1009     * PUBLIC:
1010     * Allow for cache hits on primary key read object queries.
1011     *
1012     * @see #disableCacheHits()
1013     */

1014    public void dontDisableCacheHits() {
1015        setShouldDisableCacheHits(false);
1016    }
1017
1018    /**
1019     * PUBLIC:
1020     * This method is the equivalent of calling {@link #setShouldOnlyRefreshCacheIfNewerVersion} with an argument of <CODE>false</CODE>:
1021     * it ensures that a <CODE>Descriptor</CODE> is not configured to only refresh the cache if the data received from the database by
1022     * a query is newer than the data in the cache (as determined by the optimistic locking field).
1023     *
1024     * @see #onlyRefreshCacheIfNewerVersion
1025     */

1026    public void dontOnlyRefreshCacheIfNewerVersion() {
1027        setShouldOnlyRefreshCacheIfNewerVersion(false);
1028    }
1029
1030    /**
1031     * INTERNAL:
1032     * The first table in the tables is always treated as default.
1033     */

1034    protected DatabaseTable extractDefaultTable() {
1035        if (getTables().isEmpty()) {
1036            return getInheritancePolicy().getParentDescriptor().extractDefaultTable();
1037        }
1038
1039        return (DatabaseTable)getTables().firstElement();
1040    }
1041
1042    /**
1043     * INTERNAL:
1044     * This is used to map the primary key field names in a multiple table descriptor.
1045     */

1046    public Map getAdditionalTablePrimaryKeyFields() {
1047        if (additionalTablePrimaryKeyFields == null) {
1048            additionalTablePrimaryKeyFields = new HashMap(5);
1049        }
1050        return additionalTablePrimaryKeyFields;
1051    }
1052
1053    /**
1054     * PUBLIC:
1055     * Get the alias
1056     */

1057    public String JavaDoc getAlias() {
1058
1059        /* CR3310: Steven Vo
1060         * Default alias to the Java class name if the alias is not set
1061         */

1062        if ((alias == null) && (getJavaClassName() != null)) {
1063            alias = oracle.toplink.essentials.internal.helper.Helper.getShortClassName(getJavaClassName());
1064        }
1065        return alias;
1066    }
1067
1068    /**
1069     * INTERNAL:
1070     * Return all the fields. By default it is initialized to the fields for the current
1071     * descriptor.
1072     */

1073    public Vector getAllFields() {
1074        return allFields;
1075    }
1076
1077    /**
1078     * PUBLIC:
1079     * Return the amendment class.
1080     * The amendment method will be called on the class before initialization to allow for it to initialize the descriptor.
1081     * The method must be a public static method on the class.
1082     */

1083    public Class JavaDoc getAmendmentClass() {
1084        return amendmentClass;
1085    }
1086
1087    /**
1088     * INTERNAL:
1089     * Return amendment class name, used by the MW.
1090     */

1091    public String JavaDoc getAmendmentClassName() {
1092        if ((amendmentClassName == null) && (amendmentClass != null)) {
1093            amendmentClassName = amendmentClass.getName();
1094        }
1095        return amendmentClassName;
1096    }
1097
1098    /**
1099     * PUBLIC:
1100     * Return the amendment method.
1101     * This will be called on the amendment class before initialization to allow for it to initialize the descriptor.
1102     * The method must be a public static method on the class.
1103     */

1104    public String JavaDoc getAmendmentMethodName() {
1105        return amendmentMethodName;
1106    }
1107
1108    /**
1109     * PUBLIC:
1110     * Return this objects ObjectChangePolicy.
1111     */

1112    public ObjectChangePolicy getObjectChangePolicy() {
1113        // part of fix for 4410581: project xml must save change policy
1114
// if no change-policy XML element, field is null: lazy-init to default
1115
if (changePolicy == null) {
1116            changePolicy = new DeferredChangeDetectionPolicy();
1117        }
1118        return changePolicy;
1119    }
1120
1121    /**
1122     * PUBLIC:
1123     * Return the CacheInvalidationPolicy for this descriptor
1124     * For uninitialized cache invalidation policies, this will return a NoExpiryCacheInvalidationPolicy
1125     * @return CacheInvalidationPolicy
1126     * @see oracle.toplink.essentials.descriptors.invalidation.CacheInvalidationPolicy
1127     */

1128    public CacheInvalidationPolicy getCacheInvalidationPolicy() {
1129        if (cacheInvalidationPolicy == null) {
1130            cacheInvalidationPolicy = new NoExpiryCacheInvalidationPolicy();
1131        }
1132        return cacheInvalidationPolicy;
1133    }
1134    
1135    /**
1136     * INTERNAL:
1137     */

1138     public Vector getCascadeLockingPolicies() {
1139        return cascadeLockingPolicies;
1140     }
1141
1142    /**
1143     * ADVANCED:
1144     * TopLink automatically orders database access through the foreign key information provided in 1:1 and 1:m mappings.
1145     * In some case when 1:1 are not defined it may be required to tell the descriptor about a constraint,
1146     * this defines that this descriptor has a foreign key constraint to another class and must be inserted after
1147     * instances of the other class.
1148     */

1149    public Vector getConstraintDependencies() {
1150        return constraintDependencies;
1151    }
1152
1153    /**
1154     * INTERNAL:
1155     * Returns the copy policy.
1156     */

1157    public CopyPolicy getCopyPolicy() {
1158        return copyPolicy;
1159    }
1160
1161    /**
1162     * INTERNAL:
1163     * The first table in the tables is always treated as default.
1164     */

1165    public DatabaseTable getDefaultTable() {
1166        return defaultTable;
1167    }
1168
1169    /**
1170     * ADVANCED:
1171     * return the descriptor type (NORMAL by default, others include INTERFACE, AGGREGATE, AGGREGATE COLLECTION)
1172     */

1173    public int getDescriptorType() {
1174        return descriptorType;
1175    }
1176
1177    /**
1178     * INTERNAL:
1179     * This method is explicitly used by the XML reader.
1180     */

1181    public String JavaDoc getDescriptorTypeValue() {
1182        if (isAggregateCollectionDescriptor()) {
1183            return "Aggregate collection";
1184        } else if (isAggregateDescriptor()) {
1185            return "Aggregate";
1186        } else {
1187            // Default.
1188
return "Normal";
1189        }
1190    }
1191
1192    /**
1193     * PUBLIC:
1194     * Get the event manager for the descriptor. The event manager is responsible
1195     * for managing the pre/post selectors.
1196     */

1197    public DescriptorEventManager getDescriptorEventManager() {
1198        return getEventManager();
1199    }
1200
1201    /**
1202     * PUBLIC:
1203     * Get the event manager for the descriptor. The event manager is responsible
1204     * for managing the pre/post selectors.
1205     */

1206    public DescriptorEventManager getEventManager() {
1207        return eventManager;
1208    }
1209
1210    /**
1211     * INTERNAL:
1212     * Return all the fields
1213     */

1214    public Vector getFields() {
1215        return fields;
1216    }
1217
1218    /**
1219     * INTERNAL:
1220     * Return the class of identity map to be used by this descriptor.
1221     * The default is the "SoftCacheWeakIdentityMap".
1222     */

1223    public Class JavaDoc getIdentityMapClass() {
1224        return identityMapClass;
1225    }
1226
1227    /**
1228     * PUBLIC:
1229     * Return the size of the identity map.
1230     */

1231    public int getIdentityMapSize() {
1232        return identityMapSize;
1233    }
1234
1235    /**
1236     * PUBLIC:
1237     * The inheritance policy is used to define how a descriptor takes part in inheritance.
1238     * All inheritance properties for both child and parent classes is configured in inheritance policy.
1239     * Caution must be used in using this method as it lazy initializes an inheritance policy.
1240     * Calling this on a descriptor that does not use inheritance will cause problems, #hasInheritance() must always first be called.
1241     */

1242    public InheritancePolicy getDescriptorInheritancePolicy() {
1243        return getInheritancePolicy();
1244    }
1245
1246    /**
1247     * PUBLIC:
1248     * The inheritance policy is used to define how a descriptor takes part in inheritance.
1249     * All inheritance properties for both child and parent classes is configured in inheritance policy.
1250     * Caution must be used in using this method as it lazy initializes an inheritance policy.
1251     * Calling this on a descriptor that does not use inheritance will cause problems, #hasInheritance() must always first be called.
1252     */

1253    public InheritancePolicy getInheritancePolicy() {
1254        if (inheritancePolicy == null) {
1255            // Lazy initialize to conserve space in non-inherited classes.
1256
setInheritancePolicy(new oracle.toplink.essentials.descriptors.InheritancePolicy(this));
1257        }
1258        return inheritancePolicy;
1259    }
1260
1261    /**
1262     * INTERNAL:
1263     * Return the inheritance policy.
1264     */

1265    public InheritancePolicy getInheritancePolicyOrNull() {
1266        return inheritancePolicy;
1267    }
1268
1269    /**
1270     * INTERNAL:
1271     * Returns the instantiation policy.
1272     */

1273    public InstantiationPolicy getInstantiationPolicy() {
1274        return instantiationPolicy;
1275    }
1276
1277    /**
1278     * PUBLIC:
1279     * Return the java class.
1280     */

1281    public Class JavaDoc getJavaClass() {
1282        return javaClass;
1283    }
1284
1285    /**
1286     * Return the class name, used by the MW.
1287     */

1288    public String JavaDoc getJavaClassName() {
1289        if ((javaClassName == null) && (javaClass != null)) {
1290            javaClassName = javaClass.getName();
1291        }
1292        return javaClassName;
1293    }
1294
1295    /**
1296     * INTERNAL:
1297     * Returns a reference to the mappings that must be traverse when locking
1298     */

1299    public List getLockableMappings() {
1300        if (this.lockableMappings == null) {
1301            this.lockableMappings = new ArrayList();
1302        }
1303        return this.lockableMappings;
1304    }
1305    
1306    /**
1307     * PUBLIC:
1308     * Returns the mapping associated with a given attribute name.
1309     * This can be used to find a descriptors mapping in a amendment method before the descriptor has been initialized.
1310     */

1311    public DatabaseMapping getMappingForAttributeName(String JavaDoc attributeName) {
1312        // ** Don't use this internally, just for amendments, see getMappingForAttributeName on ObjectBuilder.
1313
for (Enumeration mappingsNum = mappings.elements(); mappingsNum.hasMoreElements();) {
1314            DatabaseMapping mapping = (DatabaseMapping)mappingsNum.nextElement();
1315            if ((mapping.getAttributeName() != null) && mapping.getAttributeName().equals(attributeName)) {
1316                return mapping;
1317            }
1318        }
1319        return null;
1320    }
1321    
1322    /**
1323     * ADVANCED:
1324     * Removes the locally defined mapping associated with a given attribute name.
1325     * This can be used in a amendment method before the descriptor has been initialized.
1326     */

1327    public DatabaseMapping removeMappingForAttributeName(String JavaDoc attributeName) {
1328        DatabaseMapping mapping = getMappingForAttributeName(attributeName);
1329        getMappings().remove(mapping);
1330        return mapping;
1331    }
1332
1333    /**
1334     * PUBLIC:
1335     * Returns mappings
1336     */

1337    public Vector getMappings() {
1338        return mappings;
1339    }
1340
1341    /**
1342     * INTERNAL:
1343     * Returns the foreign key relationships used for multiple tables which were specified by the user. Used
1344     * by the Project XML writer to output these associations
1345     *
1346     * @see #adjustMultipleTableInsertOrder()
1347     * @return java.util.Hashtable
1348     */

1349    public Vector getMultipleTableForeignKeyAssociations() {
1350        Vector associations = new Vector(getAdditionalTablePrimaryKeyFields().size() * 2);
1351        Iterator tablesHashtable = getAdditionalTablePrimaryKeyFields().values().iterator();
1352        while (tablesHashtable.hasNext()) {
1353            Map tableHash = (Map)tablesHashtable.next();
1354            Iterator fieldEnumeration = tableHash.keySet().iterator();
1355            while (fieldEnumeration.hasNext()) {
1356                DatabaseField keyField = (DatabaseField)fieldEnumeration.next();
1357
1358                //PRS#36802(CR#2057) contains() is changed to containsKey()
1359
if (getMultipleTableForeignKeys().containsKey(keyField.getTable())) {
1360                    Association association = new Association(keyField.getQualifiedName(), ((DatabaseField)tableHash.get(keyField)).getQualifiedName());
1361                    associations.addElement(association);
1362                }
1363            }
1364        }
1365        return associations;
1366    }
1367
1368    /**
1369     * INTERNAL:
1370     * Returns the foreign key relationships used for multiple tables which were specified by the user. The key
1371     * of the Map is the field in the source table of the foreign key relationship. The value is the field
1372     * name of the target table.
1373     *
1374     * @see #adjustMultipleTableInsertOrder()
1375     */

1376    public Map getMultipleTableForeignKeys() {
1377        return multipleTableForeignKeys;
1378    }
1379
1380    /**
1381     * INTERNAL:
1382     * Returns the Vector of DatabaseTables in the order which INSERTS should take place. This order is
1383     * determined by the foreign key fields which are specified by the user.
1384     *
1385     * @return java.util.Vector
1386     */

1387    public Vector getMultipleTableInsertOrder() throws DescriptorException {
1388        return multipleTableInsertOrder;
1389    }
1390
1391    /**
1392     * INTERNAL:
1393     * Returns the foreign key relationships used for multiple tables which were specified by the user. Used
1394     * by the Project XML writer to output these associations
1395     *
1396     * @see #adjustMultipleTableInsertOrder()
1397     */

1398    public Vector getMultipleTablePrimaryKeyAssociations() {
1399        Vector associations = new Vector(getAdditionalTablePrimaryKeyFields().size() * 2);
1400        Iterator tablesHashtable = getAdditionalTablePrimaryKeyFields().values().iterator();
1401        while (tablesHashtable.hasNext()) {
1402            Map tableHash = (Map)tablesHashtable.next();
1403            Iterator fieldEnumeration = tableHash.keySet().iterator();
1404            while (fieldEnumeration.hasNext()) {
1405                DatabaseField keyField = (DatabaseField)fieldEnumeration.next();
1406
1407                //PRS#36802(CR#2057) contains() is changed to containsKey()
1408
if (!getMultipleTableForeignKeys().containsKey(keyField.getTable())) {
1409                    Association association = new Association(keyField.getQualifiedName(), ((DatabaseField)tableHash.get(keyField)).getQualifiedName());
1410                    associations.addElement(association);
1411                }
1412            }
1413        }
1414        return associations;
1415    }
1416
1417    /**
1418     * INTERNAL:
1419     * Return the object builder
1420     */

1421    public ObjectBuilder getObjectBuilder() {
1422        return objectBuilder;
1423    }
1424
1425    /**
1426     * PUBLIC:
1427     * Returns the OptimisticLockingPolicy. By default this is an instance of VersionLockingPolicy.
1428     */

1429    public OptimisticLockingPolicy getOptimisticLockingPolicy() {
1430        return optimisticLockingPolicy;
1431    }
1432
1433    /**
1434     * PUBLIC:
1435     * Return the names of all the primary keys.
1436     */

1437    public Vector getPrimaryKeyFieldNames() {
1438        Vector result = new Vector(getPrimaryKeyFields().size());
1439        List primaryKeyFields = getPrimaryKeyFields();
1440        for (int index = 0; index < primaryKeyFields.size(); index++) {
1441            result.addElement(((DatabaseField)primaryKeyFields.get(index)).getQualifiedName());
1442        }
1443
1444        return result;
1445    }
1446
1447    /**
1448     * INTERNAL:
1449     * Return all the primary key fields
1450     */

1451    public List getPrimaryKeyFields() {
1452        return primaryKeyFields;
1453    }
1454
1455    /**
1456     * PUBLIC:
1457     * Returns the user defined properties.
1458     */

1459    public Map getProperties() {
1460        if (properties == null) {
1461            properties = new HashMap(5);
1462        }
1463        return properties;
1464    }
1465
1466    /**
1467     * PUBLIC:
1468     * Returns the descriptor property associated the given String.
1469     */

1470    public Object JavaDoc getProperty(String JavaDoc name) {
1471        return getProperties().get(name);
1472    }
1473
1474    /**
1475     * INTERNAL:
1476     * Return the query key with the specified name
1477     */

1478    public QueryKey getQueryKeyNamed(String JavaDoc queryKeyName) {
1479        return (QueryKey)this.getQueryKeys().get(queryKeyName);
1480    }
1481
1482    /**
1483     * PUBLIC:
1484     * Return the query keys.
1485     */

1486    public Map getQueryKeys() {
1487        return queryKeys;
1488    }
1489
1490    /**
1491     * PUBLIC:
1492     * Return the queryManager.
1493     * The query manager can be used to specify customization of the SQL
1494     * that TopLink generates for this descriptor.
1495     */

1496    public DescriptorQueryManager getDescriptorQueryManager() {
1497        return queryManager;
1498    }
1499
1500    /**
1501     * PUBLIC:
1502     * Return the queryManager.
1503     * The query manager can be used to specify customization of the SQL
1504     * that TopLink generates for this descriptor.
1505     */

1506    public DescriptorQueryManager getQueryManager() {
1507        return queryManager;
1508    }
1509
1510    /**
1511     * INTERNAL:
1512     * Get sequence number field
1513     */

1514    public DatabaseField getSequenceNumberField() {
1515        return sequenceNumberField;
1516    }
1517
1518    /**
1519     * PUBLIC:
1520     * Get sequence number field name
1521     */

1522    public String JavaDoc getSequenceNumberFieldName() {
1523        if (getSequenceNumberField() == null) {
1524            return null;
1525        }
1526        return getSequenceNumberField().getQualifiedName();
1527    }
1528
1529    /**
1530     * PUBLIC:
1531     * Get sequence number name
1532     */

1533    public String JavaDoc getSequenceNumberName() {
1534        return sequenceNumberName;
1535    }
1536
1537    /**
1538     * INTERNAL:
1539     * Return the name of the session local to this descriptor.
1540     * This is used by the session broker.
1541     */

1542    public String JavaDoc getSessionName() {
1543        return sessionName;
1544    }
1545
1546    /**
1547     * INTERNAL:
1548     * Checks if table name exists with the current descriptor or not.
1549     */

1550    public DatabaseTable getTable(String JavaDoc tableName) throws DescriptorException {
1551        if (getTables().isEmpty()) {
1552            return null;// Assume aggregate descriptor.
1553
}
1554
1555        for (Enumeration tables = getTables().elements(); tables.hasMoreElements();) {
1556            DatabaseTable table = (DatabaseTable)tables.nextElement();
1557
1558            if (table.getName().equals(tableName)) {
1559                return table;
1560            }
1561        }
1562
1563        if (isAggregateDescriptor()) {
1564            return getDefaultTable();
1565        }
1566        throw DescriptorException.tableNotPresent(tableName, this);
1567    }
1568
1569    /**
1570     * PUBLIC:
1571     * Return the name of the descriptor's first table.
1572     * This method must only be called on single table descriptors.
1573     */

1574    public String JavaDoc getTableName() {
1575        if (getTables().isEmpty()) {
1576            return null;
1577        } else {
1578            return ((DatabaseTable)getTables().firstElement()).getName();
1579        }
1580    }
1581
1582    /**
1583     * PUBLIC:
1584     * Return the table names.
1585     */

1586    public Vector getTableNames() {
1587        Vector tableNames = new Vector(getTables().size());
1588        for (Enumeration fieldsEnum = getTables().elements(); fieldsEnum.hasMoreElements();) {
1589            tableNames.addElement(((DatabaseTable)fieldsEnum.nextElement()).getQualifiedName());
1590        }
1591
1592        return tableNames;
1593    }
1594
1595    /**
1596     * INTERNAL:
1597     * Return all the tables.
1598     */

1599    public Vector getTables() {
1600        return tables;
1601    }
1602
1603    /**
1604     * INTERNAL:
1605     * searches first descriptor than its ReturningPolicy for an equal field
1606     */

1607    public DatabaseField getTypedField(DatabaseField field) {
1608        boolean mayBeMoreThanOne = hasMultipleTables() && !field.hasTableName();
1609        DatabaseField foundField = null;
1610        for (int j = 0; j < getFields().size(); j++) {
1611            DatabaseField descField = (DatabaseField)getFields().elementAt(j);
1612            if (field.equals(descField)) {
1613                if (descField.getType() != null) {
1614                    foundField = descField;
1615                    if (!mayBeMoreThanOne || descField.getTable().equals(getDefaultTable())) {
1616                        break;
1617                    }
1618                }
1619            }
1620        }
1621        if (foundField != null) {
1622            foundField = (DatabaseField)foundField.clone();
1623            if (!field.hasTableName()) {
1624                foundField.setTableName("");
1625            }
1626        }
1627
1628        return foundField;
1629    }
1630
1631    /**
1632     * ADVANCED:
1633     * Return the WrapperPolicy for this descriptor.
1634     * This advacned feature can be used to wrap objects with other classes such as CORBA TIE objects or EJBs.
1635     */

1636    public WrapperPolicy getWrapperPolicy() {
1637        return wrapperPolicy;
1638    }
1639
1640    /**
1641     * INTERNAL:
1642     * Checks if the class has any private owned parts or other dependencies, (i.e. M:M join table).
1643     */

1644    public boolean hasDependencyOnParts() {
1645        for (Enumeration mappings = getMappings().elements(); mappings.hasMoreElements();) {
1646            DatabaseMapping mapping = (DatabaseMapping)mappings.nextElement();
1647            if (mapping.hasDependency()) {
1648                return true;
1649            }
1650        }
1651
1652        return false;
1653    }
1654
1655    /**
1656     * INTERNAL:
1657     * Return if this descriptor is involved in inheritence, (is child or parent).
1658     */

1659    public boolean hasInheritance() {
1660        return (inheritancePolicy != null);
1661    }
1662
1663    /**
1664     * INTERNAL:
1665     * Check if descriptor has multiple tables
1666     */

1667    public boolean hasMultipleTables() {
1668        return (getTables().size() > 1);
1669    }
1670
1671    /**
1672     * INTERNAL:
1673     * Checks if the class has any private owned parts are not
1674     */

1675    public boolean hasPrivatelyOwnedParts() {
1676        for (Enumeration mappings = getMappings().elements(); mappings.hasMoreElements();) {
1677            DatabaseMapping mapping = (DatabaseMapping)mappings.nextElement();
1678            if (mapping.isPrivateOwned()) {
1679                return true;
1680            }
1681        }
1682
1683        return false;
1684    }
1685
1686    /**
1687     * INTERNAL:
1688     * Checks to see if it has a query key or mapping with the specified name or not.
1689     */

1690    public boolean hasQueryKeyOrMapping(String JavaDoc attributeName) {
1691        return (getQueryKeys().containsKey(attributeName) || (getObjectBuilder().getMappingForAttributeName(attributeName) != null));
1692    }
1693
1694    /**
1695     * INTERNAL:
1696     * Return if a wrapper policy is used.
1697     */

1698    public boolean hasWrapperPolicy() {
1699        return getWrapperPolicy() != null;
1700    }
1701
1702    /**
1703     * INTERNAL:
1704     * Initialize the mappings as a seperate step.
1705     * This is done as a seperate step to ensure that inheritence has been first resolved.
1706     */

1707    public void initialize(AbstractSession session) throws DescriptorException {
1708        // These cached settings on the project must be set even if descriptor is initialized.
1709
// If defined as read-only, add to it's project's default read-only classes collection.
1710
if (shouldBeReadOnly() && (!session.getDefaultReadOnlyClasses().contains(getJavaClass()))) {
1711            session.getDefaultReadOnlyClasses().add(getJavaClass());
1712        }
1713        // Record that there is an isolated class in the project.
1714
if (isIsolated()) {
1715            session.getProject().setHasIsolatedClasses(true);
1716        }
1717        // Record that there is a non-CMP1/2 object in the project.
1718
if ((! hasCMPPolicy()) || getCMPPolicy().isCMP3Policy()) {
1719            session.getProject().setIsPureCMP2Project(false);
1720        }
1721        
1722        // Avoid repetitive initialization (this does not solve loops)
1723
if (isInitialized(INITIALIZED) || isInvalid()) {
1724            return;
1725        }
1726
1727        setInitializationStage(INITIALIZED);
1728
1729        // make sure that parent mappings are initialized?
1730
if (isChildDescriptor()) {
1731            getInheritancePolicy().getParentDescriptor().initialize(session);
1732            if (getInheritancePolicy().getParentDescriptor().isIsolated()) {
1733                //if the parent is isolated then the child must be isolated as well.
1734
this.setIsIsolated(true);
1735            }
1736        }
1737
1738        // Mappings must be sorted before field are collected in the order of the mapping for indexes to work.
1739
// Sorting the mappings to ensure that all DirectToFields get merged before all other mappings
1740
// This prevents null key errors when merging maps
1741
if (shouldOrderMappings()) {
1742            Vector mappings = getMappings();
1743            Object JavaDoc[] mappingsArray = new Object JavaDoc[mappings.size()];
1744            for (int index = 0; index < mappings.size(); index++) {
1745                mappingsArray[index] = mappings.elementAt(index);
1746            }
1747            TOPSort.quicksort(mappingsArray, new MappingCompare());
1748            mappings = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(mappingsArray.length);
1749            for (int index = 0; index < mappingsArray.length; index++) {
1750                mappings.addElement(mappingsArray[index]);
1751            }
1752            setMappings(mappings);
1753        }
1754        
1755        for (Enumeration mappingsEnum = getMappings().elements(); mappingsEnum.hasMoreElements();) {
1756            DatabaseMapping mapping = (DatabaseMapping)mappingsEnum.nextElement();
1757            validateMappingType(mapping);
1758            mapping.initialize(session);
1759            if (mapping.isAggregateObjectMapping() || ((mapping.isForeignReferenceMapping() && (!mapping.isDirectCollectionMapping())) && (!((ForeignReferenceMapping)mapping).usesIndirection()))) {
1760                getLockableMappings().add(mapping);
1761            }
1762            
1763            // Add all the fields in the mapping to myself.
1764
Helper.addAllUniqueToVector(getFields(), mapping.getFields());
1765        }
1766        
1767        // PERF: Dont initialize locking until after fields have been computed so
1768
// field is in correct position.
1769
if (!isAggregateDescriptor()) {
1770            if (!isChildDescriptor()) {
1771                // Add write lock field to getFields
1772
if (usesOptimisticLocking()) {
1773                    getOptimisticLockingPolicy().initializeProperties();
1774                }
1775            }
1776        }
1777
1778        // All the query keys should be initialized.
1779
for (Iterator queryKeys = getQueryKeys().values().iterator(); queryKeys.hasNext();) {
1780            QueryKey queryKey = (QueryKey)queryKeys.next();
1781            queryKey.initialize(this);
1782        }
1783
1784        // If this has inheritence then it needs to be initialized before all fields is set.
1785
if (hasInheritance()) {
1786            getInheritancePolicy().initialize(session);
1787            if (getInheritancePolicy().isChildDescriptor()) {
1788                for (Iterator iterator = getInheritancePolicy().getParentDescriptor().getMappings().iterator();
1789                         iterator.hasNext();) {
1790                    DatabaseMapping mapping = (DatabaseMapping)iterator.next();
1791                    if (mapping.isAggregateObjectMapping() || ((mapping.isForeignReferenceMapping() && (!mapping.isDirectCollectionMapping())) && (!((ForeignReferenceMapping)mapping).usesIndirection()))) {
1792                        getLockableMappings().add(mapping);// add those mappings from the parent.
1793
}
1794                }
1795            }
1796        }
1797
1798        // cr 4097 Ensure that the mappings are ordered after the superclasses mappings have been added.
1799
// This ensures that the mappings in the child class are ordered correctly
1800
// I am sorting the mappings to ensure that all DirectToFields get merged before all other mappings
1801
// This prevents null key errors when merging maps
1802
// This resort will change the previous sort order, only do it if has inheritance.
1803
if (this.hasInheritance() && shouldOrderMappings()) {
1804            Vector mappings = getMappings();
1805            Object JavaDoc[] mappingsArray = new Object JavaDoc[mappings.size()];
1806            for (int index = 0; index < mappings.size(); index++) {
1807                mappingsArray[index] = mappings.elementAt(index);
1808            }
1809            TOPSort.quicksort(mappingsArray, new MappingCompare());
1810            mappings = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(mappingsArray.length);
1811            for (int index = 0; index < mappingsArray.length; index++) {
1812                mappings.addElement(mappingsArray[index]);
1813            }
1814            setMappings(mappings);
1815        }
1816
1817        // Initialize the allFields to its fields, this can be done now because the fields have been computed.
1818
setAllFields((Vector)getFields().clone());
1819
1820        getObjectBuilder().initialize(session);
1821        
1822        if (shouldOrderMappings()) {
1823            // PERF: Ensure direct primary key mappings are first.
1824
for (int index = getObjectBuilder().getPrimaryKeyMappings().size() - 1; index >= 0; index--) {
1825                DatabaseMapping mapping = (DatabaseMapping) getObjectBuilder().getPrimaryKeyMappings().get(index);
1826                if ((mapping != null) && mapping.isDirectToFieldMapping()) {
1827                    getMappings().remove(mapping);
1828                    getMappings().add(0, mapping);
1829                    DatabaseField field = ((AbstractDirectMapping) mapping).getField();
1830                    getFields().remove(field);
1831                    getFields().add(0, field);
1832                    getAllFields().remove(field);
1833                    getAllFields().add(0, field);
1834                }
1835            }
1836        }
1837
1838        if (usesOptimisticLocking() && (!isChildDescriptor())) {
1839            getOptimisticLockingPolicy().initialize(session);
1840        }
1841        if (hasWrapperPolicy()) {
1842            getWrapperPolicy().initialize(session);
1843        }
1844        getQueryManager().initialize(session);
1845        getEventManager().initialize(session);
1846        getCopyPolicy().initialize(session);
1847        getInstantiationPolicy().initialize(session);
1848
1849        if (this.getCMPPolicy() != null) {
1850            this.getCMPPolicy().initialize(this, session);
1851        }
1852
1853        //validate the fetch group setting during descriptor initialization
1854
if (hasFetchGroupManager() && !(Helper.classImplementsInterface(javaClass, ClassConstants.FetchGroupTracker_class))) {
1855            //to use fetch group, the domain class must implement FetchGroupTracker interface
1856
session.getIntegrityChecker().handleError(DescriptorException.needToImplementFetchGroupTracker(javaClass, this));
1857        }
1858    }
1859
1860    /**
1861     * INTERNAL:
1862     * This initialized method is used exclusively for inheritance. It passes in
1863     * true if the child descriptor is isolated.
1864     *
1865     * This is needed by regular aggregate descriptors (because they are screwed up);
1866     * but not by SDK aggregate descriptors.
1867     */

1868    public void initializeAggregateInheritancePolicy(AbstractSession session) {
1869        ClassDescriptor parentDescriptor = session.getDescriptor(getInheritancePolicy().getParentClass());
1870        parentDescriptor.getInheritancePolicy().addChildDescriptor(this);
1871    }
1872
1873    /**
1874     * INTERNAL:
1875     * Rebuild the multiple table primary key map.
1876     */

1877    public void initializeMultipleTablePrimaryKeyFields() {
1878        int additionalTablesSize = getTables().size() - 1;
1879        boolean isChild = hasInheritance() && getInheritancePolicy().isChildDescriptor();
1880        if (isChild) {
1881            additionalTablesSize = getTables().size() - getInheritancePolicy().getParentDescriptor().getTables().size();
1882        }
1883        if (additionalTablesSize < 1) {
1884            return;
1885        }
1886        ExpressionBuilder builder = new ExpressionBuilder();
1887        Expression joinExpression = getQueryManager().getMultipleTableJoinExpression();
1888        for (int index = getTables().size() - additionalTablesSize; index < getTables().size();
1889                 index++) {
1890            DatabaseTable table = (DatabaseTable)getTables().elementAt(index);
1891            Map oldKeyMapping = (Map)getAdditionalTablePrimaryKeyFields().get(table);
1892            if (oldKeyMapping != null) {
1893                if (!getQueryManager().hasCustomMultipleTableJoinExpression()) {
1894                    // Build the multiple table join expression resulting from the fk relationships.
1895
for (Iterator enumtr = oldKeyMapping.keySet().iterator(); enumtr.hasNext();) {
1896                        DatabaseField sourceTableField = (DatabaseField)enumtr.next();
1897                        DatabaseField targetTableField = (DatabaseField)oldKeyMapping.get(sourceTableField);
1898                        DatabaseTable sourceTable = sourceTableField.getTable();
1899                        DatabaseTable targetTable = targetTableField.getTable();
1900
1901                        // Must add this field to read, so translations work on database row, this could be either.
1902
if (!getFields().contains(sourceTableField)) {
1903                            getFields().addElement(sourceTableField);
1904                        }
1905                        if (!getFields().contains(targetTableField)) {
1906                            getFields().addElement(targetTableField);
1907                        }
1908
1909                        Expression keyJoinExpression = builder.getField(targetTableField).equal(builder.getField(sourceTableField));
1910                        joinExpression = keyJoinExpression.and(joinExpression);
1911                        
1912                        getQueryManager().getTablesJoinExpressions().put(targetTable, keyJoinExpression);
1913                        if(isChild) {
1914                            getInheritancePolicy().addChildTableJoinExpressionToAllParents(targetTable, keyJoinExpression);
1915                        }
1916                    }
1917                }
1918            } else {
1919                // 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.
1920
// No additional fk info was specified so assume the pk field(s) are the named the same in the additional table.
1921
Map newKeyMapping = new HashMap(getPrimaryKeyFields().size() + 1);
1922                getAdditionalTablePrimaryKeyFields().put(table, newKeyMapping);
1923
1924                // 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.
1925
List primaryKeyFields = getPrimaryKeyFields();
1926                for (int pkIndex = 0; pkIndex < primaryKeyFields.size(); pkIndex++) {
1927                    DatabaseField primaryKeyField = (DatabaseField)primaryKeyFields.get(pkIndex);
1928                    DatabaseField secondaryKeyField = (DatabaseField)primaryKeyField.clone();
1929                    secondaryKeyField.setTable(table);
1930                    newKeyMapping.put(primaryKeyField, secondaryKeyField);
1931                    // Must add this field to read, so translations work on database row.
1932
getFields().addElement(secondaryKeyField);
1933
1934                    if (!getQueryManager().hasCustomMultipleTableJoinExpression()) {
1935                        Expression keyJoinExpression = builder.getField(secondaryKeyField).equal(builder.getField(primaryKeyField));
1936                        joinExpression = keyJoinExpression.and(joinExpression);
1937
1938                        getQueryManager().getTablesJoinExpressions().put(table, keyJoinExpression);
1939                        if(isChild) {
1940                            getInheritancePolicy().addChildTableJoinExpressionToAllParents(table, keyJoinExpression);
1941                        }
1942                    }
1943                }
1944            }
1945        }
1946        if (joinExpression != null) {
1947            getQueryManager().setInternalMultipleTableJoinExpression(joinExpression);
1948        }
1949        if (getQueryManager().hasCustomMultipleTableJoinExpression()) {
1950            Map tablesJoinExpressions = SQLSelectStatement.mapTableToExpression(joinExpression, getTables());
1951            getQueryManager().getTablesJoinExpressions().putAll(tablesJoinExpressions);
1952            if(isChild) {
1953                for (int index = getTables().size() - additionalTablesSize; index < getTables().size();
1954                         index++) {
1955                    DatabaseTable table = (DatabaseTable)getTables().elementAt(index);
1956                    getInheritancePolicy().addChildTableJoinExpressionToAllParents(table, (Expression)tablesJoinExpressions.get(table));
1957                }
1958            }
1959        }
1960    }
1961
1962    /**
1963     * INTERNAL:
1964     * Initialize the descriptor properties such as write lock and sequecning.
1965     */

1966    protected void initializeProperties(AbstractSession session) throws DescriptorException {
1967        if (!isAggregateDescriptor()) {
1968            if (!isChildDescriptor()) {
1969                // Initialize the primary key fields
1970
List primaryKeyFields = (List)((ArrayList)getPrimaryKeyFields()).clone();
1971                for (int index = 0; index < primaryKeyFields.size(); index++) {
1972                    DatabaseField primaryKey = (DatabaseField)primaryKeyFields.get(index);
1973                    initializePrimaryKey(primaryKey);
1974                }
1975            }
1976
1977            // build sequence number field
1978
if (getSequenceNumberField() != null) {
1979                buildField(getSequenceNumberField());
1980            }
1981        }
1982
1983        // Set the local session name for the session broker.
1984
setSessionName(session.getName());
1985    }
1986
1987    /**
1988     * INTERNAL:
1989     */

1990    protected void initializePrimaryKey(DatabaseField primaryKey) {
1991        buildField(primaryKey);
1992        if (!primaryKey.getTable().equals(getDefaultTable())) {
1993            getPrimaryKeyFields().remove(primaryKey);
1994        }
1995    }
1996
1997    /**
1998     * PUBLIC:
1999     * Return true if this descriptor is an aggregate collection descriptor
2000     */

2001    public boolean isAggregateCollectionDescriptor() {
2002        return (getDescriptorType() == AGGREGATE_COLLECTION);
2003    }
2004
2005    /**
2006     * PUBLIC:
2007     * Return true if this descriptor is an aggregate descriptor
2008     */

2009    public boolean isAggregateDescriptor() {
2010        return (getDescriptorType() == AGGREGATE);
2011    }
2012
2013    /**
2014     * PUBLIC:
2015     * Return if the descriptor defines inheritence and is a child.
2016     */

2017    public boolean isChildDescriptor() {
2018        return hasInheritance() && getInheritancePolicy().isChildDescriptor();
2019    }
2020
2021    /**
2022     * INTERNAL:
2023     * Check if the descriptor is finished initialization.
2024     */

2025    public boolean isFullyInitialized() {
2026        return this.initializationStage == POST_INITIALIZED;
2027    }
2028
2029    /**
2030     * INTERNAL:
2031     * Check if descriptor is already initialized for the level of initialization.
2032     * 1 = pre
2033     * 2 = mapping
2034     * 3 = post
2035     */

2036    protected boolean isInitialized(int initializationStage) {
2037        return this.initializationStage >= initializationStage;
2038    }
2039
2040    /**
2041     * INTERNAL:
2042     * Return if an error occured during initialization which should abort any further initialization.
2043     */

2044    public boolean isInvalid() {
2045        return this.initializationStage == ERROR;
2046    }
2047
2048    /**
2049     * PUBLIC:
2050     * Returns true if the descriptor represents an isolated class
2051     */

2052    public boolean isIsolated() {
2053        return this.isIsolated;
2054    }
2055
2056    /**
2057     * INTERNAL:
2058     * Return if this descriptor has more than one table.
2059     */

2060    public boolean isMultipleTableDescriptor() {
2061        return getTables().size() > 1;
2062    }
2063
2064    /**
2065     * INTERNAL:
2066     * Indicates whether pk or some of its components
2067     * set after insert into the database.
2068     * Shouldn't be called before Descriptor has been initialized.
2069     */

2070    public boolean isPrimaryKeySetAfterInsert(AbstractSession session) {
2071        return (usesSequenceNumbers() && session.getSequencing().shouldAcquireValueAfterInsert(getJavaClass()));
2072    }
2073
2074    /**
2075     * PUBLIC:
2076     * PUBLIC:
2077     * This method is the equivalent of calling {@link #setShouldOnlyRefreshCacheIfNewerVersion} with an argument of <CODE>true</CODE>:
2078     * it configures a <CODE>Descriptor</CODE> to only refresh the cache if the data received from the database by a query is newer than
2079     * the data in the cache (as determined by the optimistic locking field) and as long as one of the following is true:
2080     *
2081     * <UL>
2082     * <LI>the <CODE>Descriptor</CODE> was configured by calling {@link #alwaysRefreshCache} or {@link #alwaysRefreshCacheOnRemote},</LI>
2083     * <LI>the query was configured by calling {@link oracle.toplink.essentials.queryframework.ObjectLevelReadQuery#refreshIdentityMapResult}, or</LI>
2084     * <LI>the query was a call to {@link oracle.toplink.essentials.sessions.Session#refreshObject}</LI>
2085     * </UL>
2086     * <P>
2087     *
2088     * However, if a query hits the cache, data is not refreshed regardless of how this setting is configured. For example, by default,
2089     * 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.
2090     * If the object is in the cache, the cached object is returned and data is not refreshed. To avoid cache hits, use
2091     * the {@link #disableCacheHits} method.<P>
2092     *
2093     * Also note that the {@link oracle.toplink.essentials.sessions.UnitOfWork} will not refresh its registered objects.
2094     *
2095     * @see #dontOnlyRefreshCacheIfNewerVersion
2096     */

2097    public void onlyRefreshCacheIfNewerVersion() {
2098        setShouldOnlyRefreshCacheIfNewerVersion(true);
2099    }
2100
2101    /**
2102     * INTERNAL:
2103     * Post initializations after mappings are initialized.
2104     */

2105    public void postInitialize(AbstractSession session) throws DescriptorException {
2106        // Avoid repetitive initialization (this does not solve loops)
2107
if (isInitialized(POST_INITIALIZED) || isInvalid()) {
2108            return;
2109        }
2110
2111        setInitializationStage(POST_INITIALIZED);
2112
2113        // Make sure that child is post initialized,
2114
// this initialize bottom up, unlike the two other phases that to top down.
2115
if (hasInheritance()) {
2116            for (Enumeration childEnum = getInheritancePolicy().getChildDescriptors().elements();
2117                     childEnum.hasMoreElements();) {
2118                ((ClassDescriptor)childEnum.nextElement()).postInitialize(session);
2119            }
2120        }
2121
2122        // Allow mapping to perform post initialization.
2123
for (Enumeration mappingsEnum = getMappings().elements(); mappingsEnum.hasMoreElements();) {
2124            DatabaseMapping mapping = (DatabaseMapping)mappingsEnum.nextElement();
2125
2126            // This causes post init to be called multiple times in inheritence.
2127
mapping.postInitialize(session);
2128            // PERF: computed if deferred locking is required.
2129
if (!shouldAcquireCascadedLocks()) {
2130                if ((mapping instanceof ForeignReferenceMapping) && (!((ForeignReferenceMapping)mapping).usesIndirection())) {
2131                    setShouldAcquireCascadedLocks(true);
2132                }
2133                if ((mapping instanceof AggregateObjectMapping) && ((AggregateObjectMapping)mapping).getDescriptor().shouldAcquireCascadedLocks()) {
2134                    setShouldAcquireCascadedLocks(true);
2135                }
2136            }
2137        }
2138
2139        if (hasInheritance()) {
2140            getInheritancePolicy().postInitialize(session);
2141        }
2142
2143        //PERF: Ensure that the identical primary key fields are used to avoid equals.
2144
for (int index = (getPrimaryKeyFields().size() - 1); index >= 0; index--) {
2145            DatabaseField primaryKeyField = (DatabaseField)getPrimaryKeyFields().get(index);
2146            int fieldIndex = getFields().indexOf(primaryKeyField);
2147
2148            // Aggregate/agg-collections may not have a mapping for pk field.
2149
if (fieldIndex != -1) {
2150                primaryKeyField = (DatabaseField)getFields().get(fieldIndex);
2151                getPrimaryKeyFields().set(index, primaryKeyField);
2152            }
2153        }
2154
2155        // Index and classify fields and primary key.
2156
// This is in post because it needs field classification defined in initializeMapping
2157
// this can come through a 1:1 so requires all descriptors to be initialized (mappings).
2158
// May 02, 2000 - Jon D.
2159
// Added mapping.isAggregateMapping() check for fix to pr 381
2160
for (int index = 0; index < getFields().size(); index++) {
2161            DatabaseField field = (DatabaseField)getFields().elementAt(index);
2162            DatabaseMapping mapping = getObjectBuilder().getMappingForField(field);
2163            if ((mapping != null) && (!(mapping.isAggregateMapping()))) {
2164                field.setType(mapping.getFieldClassification(field));
2165            }
2166            field.setIndex(index);
2167        }
2168
2169        validateAfterInitialization(session);
2170
2171        checkDatabase(session);
2172    }
2173
2174    /**
2175     * INTERNAL:
2176     * Allow the descriptor to initialize any dependancies on this session.
2177     */

2178    public void preInitialize(AbstractSession session) throws DescriptorException {
2179        //3934266 move validation to the policy allowing for this to be done in the sub policies.
2180
getObjectChangePolicy().initialize(session, this);
2181
2182        // Avoid repetitive initialization (this does not solve loops)
2183
if (isInitialized(PREINITIALIZED)) {
2184            return;
2185        }
2186
2187        setInitializationStage(PREINITIALIZED);
2188
2189        // Allow mapping pre init, must be done before validate.
2190
for (Enumeration mappingsEnum = getMappings().elements(); mappingsEnum.hasMoreElements();) {
2191            try {
2192                DatabaseMapping mapping = (DatabaseMapping)mappingsEnum.nextElement();
2193                mapping.preInitialize(session);
2194            } catch (DescriptorException exception) {
2195                session.getIntegrityChecker().handleError(exception);
2196            }
2197        }
2198
2199        validateBeforeInitialization(session);
2200
2201        preInitializeInheritancePolicy(session);
2202
2203        // This must be done now, after validate, before init anything else.
2204
if (getDefaultTable() == null) {// May already be set if first is not desired.
2205
setDefaultTable(extractDefaultTable());
2206        }
2207
2208        // Make sure that parent is already preinitialized
2209
if (hasInheritance()) {
2210            getInheritancePolicy().preInitialize(session);
2211        }
2212
2213        verifyTableQualifiers(session.getDatasourcePlatform());
2214        initializeProperties(session);
2215        if (!isAggregateDescriptor()) {
2216            // Adjust before you initialize ...
2217
adjustMultipleTableInsertOrder();
2218            initializeMultipleTablePrimaryKeyFields();
2219        }
2220
2221        getQueryManager().preInitialize(session);
2222
2223    }
2224
2225    /**
2226     * INTERNAL:
2227     */

2228    protected void prepareCascadeLockingPolicy(DatabaseMapping mapping) {
2229        if (mapping.isPrivateOwned() && mapping.isForeignReferenceMapping()) {
2230            if (mapping.isCascadedLockingSupported()) {
2231                // Even if the mapping says it is supported in general, there
2232
// may be conditions where it is not. Need the following checks.
2233
if (((ForeignReferenceMapping) mapping).hasCustomSelectionQuery()) {
2234                    throw ValidationException.unsupportedCascadeLockingMappingWithCustomQuery(mapping);
2235                } else if (isAggregateDescriptor() || isAggregateCollectionDescriptor()) {
2236                    throw ValidationException.unsupportedCascadeLockingDescriptor(this);
2237                } else {
2238                    mapping.prepareCascadeLockingPolicy();
2239                }
2240            } else {
2241                throw ValidationException.unsupportedCascadeLockingMapping(mapping);
2242            }
2243        }
2244    }
2245    
2246    /**
2247     * Hook together the inheritance policy tree.
2248     */

2249    protected void preInitializeInheritancePolicy(AbstractSession session) throws DescriptorException {
2250        if (isChildDescriptor() && (requiresInitialization())) {
2251            if (getInheritancePolicy().getParentClass().equals(getJavaClass())) {
2252                throw DescriptorException.parentClassIsSelf(this);
2253            }
2254            ClassDescriptor parentDescriptor = session.getDescriptor(getInheritancePolicy().getParentClass());
2255            parentDescriptor.getInheritancePolicy().addChildDescriptor(this);
2256            getInheritancePolicy().setParentDescriptor(parentDescriptor);
2257            parentDescriptor.preInitialize(session);
2258        }
2259    }
2260
2261    /**
2262     * INTERNAL:
2263     * Rehash any hashtables based on fields.
2264     * This is used to clone descriptors for aggregates, which hammer field names,
2265     * it is probably better not to hammer the field name and this should be refactored.
2266     */

2267    public void rehashFieldDependancies(AbstractSession session) {
2268        getObjectBuilder().rehashFieldDependancies(session);
2269
2270        for (Enumeration enumtr = getMappings().elements(); enumtr.hasMoreElements();) {
2271            ((DatabaseMapping)enumtr.nextElement()).rehashFieldDependancies(session);
2272        }
2273    }
2274
2275    /**
2276     * INTERNAL:
2277     * A user should not be setting which attributes to join or not to join
2278     * after descriptor initialization; provided only for backwards compatibility.
2279     */

2280    public void reInitializeJoinedAttributes() {
2281        if (!isInitialized(POST_INITIALIZED)) {
2282            // wait until the descriptor gets initialized first
2283
return;
2284        }
2285        getObjectBuilder().initializeJoinedAttributes();
2286        if (hasInheritance()) {
2287            Vector children = getInheritancePolicy().getChildDescriptors();
2288
2289            // use indeces to avoid synchronization.
2290
for (int i = 0; i < children.size(); i++) {
2291                InheritancePolicy child = (InheritancePolicy)children.elementAt(0);
2292                child.getDescriptor().reInitializeJoinedAttributes();
2293            }
2294        }
2295    }
2296
2297    /**
2298     * PUBLIC:
2299     * Remove the user defined property.
2300     */

2301    public void removeProperty(String JavaDoc property) {
2302        getProperties().remove(property);
2303    }
2304
2305    /**
2306     * INTERNAL:
2307     * Aggregate and Interface descriptors do not require initialization as they are cloned and
2308     * initialized by each mapping.
2309     */

2310    public boolean requiresInitialization() {
2311        return !(isAggregateDescriptor());
2312    }
2313
2314    /**
2315     * INTERNAL:
2316     * Validate that the descriptor was defined correctly.
2317     * This allows for checks to be done that require the descriptor initialization to be completed.
2318     */

2319    protected void selfValidationAfterInitialization(AbstractSession session) throws DescriptorException {
2320        // This has to be done after, because read subclasses must be initialized.
2321
if (!(hasInheritance() && (getInheritancePolicy().shouldReadSubclasses() || java.lang.reflect.Modifier.isAbstract(getJavaClass().getModifiers())))) {
2322            if (session.getIntegrityChecker().shouldCheckInstantiationPolicy()) {
2323                getInstantiationPolicy().buildNewInstance();
2324            }
2325        }
2326        getObjectBuilder().validate(session);
2327    }
2328
2329    /**
2330     * INTERNAL:
2331     * Validate that the descriptor's non-mapping attribute are defined correctly.
2332     */

2333    protected void selfValidationBeforeInitialization(AbstractSession session) throws DescriptorException {
2334        if (isChildDescriptor()) {
2335            ClassDescriptor parentDescriptor = session.getDescriptor(getInheritancePolicy().getParentClass());
2336
2337            if (parentDescriptor == null) {
2338                session.getIntegrityChecker().handleError(DescriptorException.parentDescriptorNotSpecified(getInheritancePolicy().getParentClass().getName(), this));
2339            }
2340        } else {
2341            if (getTables().isEmpty() && (!isAggregateDescriptor())) {
2342                session.getIntegrityChecker().handleError(DescriptorException.tableNotSpecified(this));
2343            }
2344        }
2345
2346        if (!isChildDescriptor() && !isAggregateDescriptor()) {
2347            if (getPrimaryKeyFieldNames().isEmpty()) {
2348                session.getIntegrityChecker().handleError(DescriptorException.primaryKeyFieldsNotSepcified(this));
2349            }
2350        }
2351
2352        if ((getIdentityMapClass() == ClassConstants.NoIdentityMap_Class) && (getQueryManager().getDoesExistQuery().shouldCheckCacheForDoesExist())) {
2353            session.getIntegrityChecker().handleError(DescriptorException.identityMapNotSpecified(this));
2354        }
2355
2356        if (((getSequenceNumberName() != null) && (getSequenceNumberField() == null)) || ((getSequenceNumberName() == null) && (getSequenceNumberField() != null))) {
2357            session.getIntegrityChecker().handleError(DescriptorException.sequenceNumberPropertyNotSpecified(this));
2358        }
2359    }
2360
2361    /**
2362     * INTERNAL:
2363     * This is used to map the primary key field names in a multiple table
2364     * descriptor.
2365     */

2366    protected void setAdditionalTablePrimaryKeyFields(DatabaseTable table, DatabaseField field1, DatabaseField field2) {
2367        Map tableAdditionalPKFields = (Map)getAdditionalTablePrimaryKeyFields().get(table);
2368            
2369        if (tableAdditionalPKFields == null) {
2370            tableAdditionalPKFields = new HashMap(2);
2371            getAdditionalTablePrimaryKeyFields().put(table, tableAdditionalPKFields);
2372        }
2373            
2374        tableAdditionalPKFields.put(field1, field2);
2375    }
2376    
2377    /**
2378     * INTERNAL:
2379     * This method will be called in the case where the foreign key field is
2380     * in the target table which is before the source table. In most cases,
2381     * this would be when the fk is on the primary table (that is, true
2382     * multiple table foreign key field)
2383     */

2384    protected void toggleAdditionalTablePrimaryKeyFields(DatabaseTable targetTable, DatabaseTable sourceTable) {
2385        Map targetTableAdditionalPKFields = (Map)getAdditionalTablePrimaryKeyFields().get(targetTable);
2386            
2387        if (targetTableAdditionalPKFields != null) {
2388            Iterator e = targetTableAdditionalPKFields.keySet().iterator();
2389        
2390            while (e.hasNext()) {
2391                DatabaseField sourceField = (DatabaseField)e.next();
2392                DatabaseField targetField = (DatabaseField) targetTableAdditionalPKFields.get(sourceField);
2393            
2394                setAdditionalTablePrimaryKeyFields(sourceTable, targetField, sourceField);
2395            }
2396            
2397            targetTableAdditionalPKFields.clear();
2398        }
2399    }
2400    
2401    /**
2402     * INTERNAL:
2403     * This is used to map the primary key field names in a multiple table
2404     * descriptor.
2405     */

2406    public void setAdditionalTablePrimaryKeyFields(Map additionalTablePrimaryKeyFields) {
2407        this.additionalTablePrimaryKeyFields = additionalTablePrimaryKeyFields;
2408    }
2409
2410    /**
2411     * PUBLIC:
2412     * Set the alias
2413     */

2414    public void setAlias(String JavaDoc alias) {
2415        this.alias = alias;
2416    }
2417
2418    /**
2419     * INTERNAL:
2420     * Set all the fields.
2421     */

2422    protected void setAllFields(Vector allFields) {
2423        this.allFields = allFields;
2424    }
2425
2426    /**
2427     * PUBLIC:
2428     * Set the amendment class.
2429     * The amendment method will be called on the class before initialization to allow for it to initialize the descriptor.
2430     * The method must be a public static method on the class.
2431     */

2432    public void setAmendmentClass(Class JavaDoc amendmentClass) {
2433        this.amendmentClass = amendmentClass;
2434    }
2435
2436    /**
2437     * INTERNAL:
2438     * Return the amendment class name, used by the MW.
2439     */

2440    public void setAmendmentClassName(String JavaDoc amendmentClassName) {
2441        this.amendmentClassName = amendmentClassName;
2442    }
2443
2444    /**
2445     * PUBLIC:
2446     * Set the amendment method.
2447     * This will be called on the amendment class before initialization to allow for it to initialize the descriptor.
2448     * The method must be a public static method on the class.
2449     */

2450    public void setAmendmentMethodName(String JavaDoc amendmentMethodName) {
2451        this.amendmentMethodName = amendmentMethodName;
2452    }
2453
2454    /**
2455     * PUBLIC:
2456     * Set the ObjectChangePolicy for this descriptor.
2457     */

2458    public void setObjectChangePolicy(ObjectChangePolicy policy) {
2459        this.changePolicy = policy;
2460    }
2461
2462    /**
2463     * PUBLIC:
2464     * Set the Cache Invalidation Policy for this descriptor
2465     * @param CacheInvalidationPolicy
2466     * @see oracle.toplink.essentials.descriptors.invalidation.CacheInvalidationPolicy
2467     */

2468    public void setCacheInvalidationPolicy(CacheInvalidationPolicy policy) {
2469        cacheInvalidationPolicy = policy;
2470    }
2471
2472    /**
2473     * ADVANCED:
2474     * TopLink automatically orders database access through the foreign key information provided in 1:1 and 1:m mappings.
2475     * In some case when 1:1 are not defined it may be required to tell the descriptor about a constraint,
2476     * this defines that this descriptor has a foreign key constraint to another class and must be inserted after
2477     * instances of the other class.
2478     */

2479    public void setConstraintDependencies(Vector constraintDependencies) {
2480        this.constraintDependencies = constraintDependencies;
2481    }
2482
2483    /**
2484     * INTERNAL:
2485     * Set the copy policy.
2486     * This would be 'protected' but the EJB stuff in another
2487     * package needs it to be public
2488     */

2489    public void setCopyPolicy(CopyPolicy policy) {
2490        copyPolicy = policy;
2491        if (policy != null) {
2492            policy.setDescriptor(this);
2493        }
2494    }
2495
2496    /**
2497     * INTERNAL:
2498     * The descriptors default table can be configured if the first table is not desired.
2499     */

2500    public void setDefaultTable(DatabaseTable defaultTable) {
2501        this.defaultTable = defaultTable;
2502    }
2503
2504    /**
2505     * PUBLIC:
2506     * The descriptors default table can be configured if the first table is not desired.
2507     */

2508    public void setDefaultTableName(String JavaDoc defaultTableName) {
2509        setDefaultTable(new DatabaseTable(defaultTableName));
2510    }
2511
2512    /**
2513     * ADVANCED:
2514     * set the descriptor type (NORMAL by default, others include INTERFACE, AGGREGATE, AGGREGATE COLLECTION)
2515     */

2516    public void setDescriptorType(int descriptorType) {
2517        this.descriptorType = descriptorType;
2518    }
2519
2520    /**
2521     * INTERNAL:
2522     * This method is explicitly used by the XML reader.
2523     */

2524    public void setDescriptorTypeValue(String JavaDoc value) {
2525        if (value.equals("Aggregate collection")) {
2526            descriptorIsAggregateCollection();
2527        } else if (value.equals("Aggregate")) {
2528            descriptorIsAggregate();
2529        } else {
2530            descriptorIsNormal();
2531        }
2532    }
2533
2534    /**
2535     * INTERNAL:
2536     * Set the event manager for the descriptor. The event manager is responsible
2537     * for managing the pre/post selectors.
2538     */

2539    public void setEventManager(DescriptorEventManager eventManager) {
2540        this.eventManager = eventManager;
2541        if (eventManager != null) {
2542            eventManager.setDescriptor(this);
2543        }
2544    }
2545
2546    /**
2547     * INTERNAL:
2548     * Set the existence check option from a string constant.
2549     */

2550    public void setExistenceChecking(String JavaDoc token) throws DescriptorException {
2551        getQueryManager().setExistenceCheck(token);
2552    }
2553
2554    /**
2555     * INTERNAL:
2556     * Set the fields used by this descriptor.
2557     */

2558    public void setFields(Vector fields) {
2559        this.fields = fields;
2560    }
2561
2562    /**
2563     * PUBLIC:
2564     * Set the class of identity map to be used by this descriptor.
2565     * The default is the "FullIdentityMap".
2566     */

2567    public void setIdentityMapClass(Class JavaDoc theIdentityMapClass) {
2568        identityMapClass = theIdentityMapClass;
2569    }
2570
2571    /**
2572     * PUBLIC:
2573     * Set the size of the identity map to be used by this descriptor.
2574     * The default is the 100.
2575     */

2576    public void setIdentityMapSize(int identityMapSize) {
2577        this.identityMapSize = identityMapSize;
2578    }
2579
2580    /**
2581     * INTERNAL:
2582     * Sets the inheritance policy.
2583     */

2584    public void setInheritancePolicy(InheritancePolicy inheritancePolicy) {
2585        this.inheritancePolicy = inheritancePolicy;
2586        if (inheritancePolicy != null) {
2587            inheritancePolicy.setDescriptor(this);
2588        }
2589    }
2590
2591    /**
2592     * INTERNAL:
2593     */

2594    protected void setInitializationStage(int initializationStage) {
2595        this.initializationStage = initializationStage;
2596    }
2597
2598    /**
2599     * INTERNAL:
2600     * Sets the instantiation policy.
2601     */

2602    public void setInstantiationPolicy(InstantiationPolicy instantiationPolicy) {
2603        this.instantiationPolicy = instantiationPolicy;
2604        if (instantiationPolicy != null) {
2605            instantiationPolicy.setDescriptor(this);
2606        }
2607    }
2608
2609    /**
2610     * PUBLIC:
2611     * Used to set if the class that this descriptor represents should be isolated from the
2612     * shared cache.
2613     * Note: Calling this method with true will also set the cacheSynchronizationType to DO_NOT_SEND_CHANGES
2614     * since isolated objects cannot be sent by TopLink cache synchronization.
2615     */

2616    public void setIsIsolated(boolean isIsolated) {
2617        this.isIsolated = isIsolated;
2618    }
2619
2620    /**
2621    * PUBLIC:
2622    * Set the Java class that this descriptor maps.
2623    * Every descriptor maps one and only one class.
2624    */

2625    public void setJavaClass(Class JavaDoc theJavaClass) {
2626        javaClass = theJavaClass;
2627    }
2628
2629    /**
2630     * INTERNAL:
2631     * Return the java class name, used by the MW.
2632     */

2633    public void setJavaClassName(String JavaDoc theJavaClassName) {
2634        javaClassName = theJavaClassName;
2635    }
2636
2637    /**
2638     * INTERNAL:
2639     * Set the list of lockable mappings for this project
2640     * This method is provided for CMP use. Normally, the lockable mappings are initialized
2641     * at descriptor initialization time.
2642     */

2643    public void setLockableMappings(ArrayList lockableMappings) {
2644        this.lockableMappings = lockableMappings;
2645    }
2646
2647    /**
2648     * INTERNAL:
2649     * Set the mappings.
2650     */

2651    public void setMappings(Vector mappings) {
2652        // This is used from XML reader so must ensure that all mapping's descriptor has been set.
2653
for (Enumeration mappingsEnum = mappings.elements(); mappingsEnum.hasMoreElements();) {
2654            DatabaseMapping mapping = (DatabaseMapping)mappingsEnum.nextElement();
2655
2656            // For CR#2646, if the mapping already points to the parent descriptor then leave it.
2657
if (mapping.getDescriptor() == null) {
2658                mapping.setDescriptor(this);
2659            }
2660        }
2661        this.mappings = mappings;
2662    }
2663
2664    /**
2665     * INTERNAL:
2666     * This method is used by the TopLink XML Deployment Descriptor to read and write these mappings
2667     */

2668    public void setMultipleTableForeignKeyFieldNames(Vector associations) throws DescriptorException {
2669        Enumeration foreignKeys = associations.elements();
2670        while (foreignKeys.hasMoreElements()) {
2671            Association association = (Association)foreignKeys.nextElement();
2672            addMultipleTableForeignKeys((String JavaDoc)association.getKey(), (String JavaDoc)association.getValue(), true);
2673        }
2674    }
2675
2676    /**
2677     * INTERNAL:
2678     *
2679     * @see #getMultipleTableForeignKeys
2680     */

2681    protected void setMultipleTableForeignKeys(Map newValue) {
2682        this.multipleTableForeignKeys = newValue;
2683    }
2684
2685    /**
2686     * ADVANCED:
2687     * Sets the Vector of DatabaseTables in the order which INSERTS should take place.
2688     * This is normally computed correctly by TopLink, however in advanced cases in it may be overridden.
2689     */

2690    public void setMultipleTableInsertOrder(Vector newValue) {
2691        this.multipleTableInsertOrder = newValue;
2692    }
2693
2694    /**
2695     * INTERNAL:
2696     * This method is used by the TopLink XML Deployment Descriptor to read and write these mappings
2697     */

2698    public void setMultipleTablePrimaryKeyFieldNames(Vector associations) throws DescriptorException {
2699        Enumeration foreignKeys = associations.elements();
2700        while (foreignKeys.hasMoreElements()) {
2701            Association association = (Association)foreignKeys.nextElement();
2702            addMultipleTableForeignKeys((String JavaDoc)association.getKey(), (String JavaDoc)association.getValue(), true);
2703        }
2704    }
2705
2706    /**
2707     * INTERNAL:
2708     * Set the ObjectBuilder.
2709     */

2710    protected void setObjectBuilder(ObjectBuilder builder) {
2711        objectBuilder = builder;
2712    }
2713
2714    /**
2715     * PUBLIC:
2716     * Set the OptimisticLockingPolicy.
2717     * This can be one of the provided locking policies or a user defined policy.
2718     * @see VersionLockingPolicy
2719     * @see TimestampLockingPolicy
2720     * @see FieldsLockingPolicy
2721     */

2722    public void setOptimisticLockingPolicy(OptimisticLockingPolicy optimisticLockingPolicy) {
2723        this.optimisticLockingPolicy = optimisticLockingPolicy;
2724        if (optimisticLockingPolicy != null) {
2725            optimisticLockingPolicy.setDescriptor(this);
2726        }
2727    }
2728
2729    /**
2730     * PUBLIC:
2731     * Specify the primary key field of the descriptors table.
2732     * This should only be called if it is a singlton primary key field,
2733     * otherwise addPrimaryKeyFieldName should be called.
2734     * If the descriptor has many tables, this must be the primary key in all of the tables.
2735     *
2736     * @see #addPrimaryKeyFieldName(String)
2737     */

2738    public void setPrimaryKeyFieldName(String JavaDoc fieldName) {
2739        addPrimaryKeyFieldName(fieldName);
2740    }
2741
2742    /**
2743     * PUBLIC:
2744     * User can specify a vector of all the primary key field names if primary key is composite.
2745     *
2746     * @see #addPrimaryKeyFieldName(String)
2747     */

2748    public void setPrimaryKeyFieldNames(Vector primaryKeyFieldsName) {
2749        setPrimaryKeyFields(new ArrayList(primaryKeyFieldsName.size()));
2750        for (Enumeration keyEnum = primaryKeyFieldsName.elements(); keyEnum.hasMoreElements();) {
2751            addPrimaryKeyFieldName((String JavaDoc)keyEnum.nextElement());
2752        }
2753    }
2754
2755    /**
2756     * INTERNAL:
2757     * Set the primary key fields
2758     */

2759    public void setPrimaryKeyFields(List thePrimaryKeyFields) {
2760        primaryKeyFields = thePrimaryKeyFields;
2761    }
2762
2763    /**
2764     * INTERNAL:
2765     * Set the user defined properties.
2766     */

2767    public void setProperties(Map properties) {
2768        this.properties = properties;
2769    }
2770
2771    /**
2772     * PUBLIC:
2773     * Set the user defined property.
2774     */

2775    public void setProperty(String JavaDoc name, Object JavaDoc value) {
2776        getProperties().put(name, value);
2777    }
2778
2779    /**
2780     * INTERNAL:
2781     * Set the query keys.
2782     */

2783    public void setQueryKeys(Map queryKeys) {
2784        this.queryKeys = queryKeys;
2785    }
2786
2787    /**
2788     * INTERNAL:
2789     * Set the query manager.
2790     */

2791    public void setQueryManager(DescriptorQueryManager queryManager) {
2792        this.queryManager = queryManager;
2793        if (queryManager != null) {
2794            queryManager.setDescriptor(this);
2795        }
2796    }
2797
2798    /**
2799     * INTERNAL:
2800     * Set the sequence number field.
2801     */

2802    public void setSequenceNumberField(DatabaseField sequenceNumberField) {
2803        this.sequenceNumberField = sequenceNumberField;
2804    }
2805
2806    /**
2807     * PUBLIC:
2808     * Set the sequence number field name.
2809     * This is the field in the descriptors table that needs its value to be generated.
2810     * This is normally the primary key field of the descriptor.
2811     */

2812    public void setSequenceNumberFieldName(String JavaDoc fieldName) {
2813        if (fieldName == null) {
2814            setSequenceNumberField(null);
2815        } else {
2816            setSequenceNumberField(new DatabaseField(fieldName));
2817        }
2818    }
2819
2820    /**
2821     * PUBLIC:
2822     * Set the sequence number name.
2823     * This is the seq_name part of the row stored in the sequence table for this descriptor.
2824     * If using Oracle native sequencing this is the name of the Oracle sequence object.
2825     * If using Sybase native sequencing this name has no meaning, but should still be set for compatibility.
2826     * The name does not have to be unique among descriptors, as having descriptors share sequences can
2827     * improve pre-allocation performance.
2828     */

2829    public void setSequenceNumberName(String JavaDoc name) {
2830        sequenceNumberName = name;
2831    }
2832
2833    /**
2834     * INTERNAL:
2835     * Set the name of the session local to this descriptor.
2836     * This is used by the session broker.
2837     */

2838    protected void setSessionName(String JavaDoc sessionName) {
2839        this.sessionName = sessionName;
2840    }
2841
2842    /**
2843     * PUBLIC:
2844     * set if the descriptor is defined to always conform the results in unit of work in read query.
2845     *
2846     */

2847    public void setShouldAlwaysConformResultsInUnitOfWork(boolean shouldAlwaysConformResultsInUnitOfWork) {
2848        this.shouldAlwaysConformResultsInUnitOfWork = shouldAlwaysConformResultsInUnitOfWork;
2849    }
2850
2851    /**
2852     * PUBLIC:
2853     * When the <CODE>shouldAlwaysRefreshCache</CODE> argument passed into this method is <CODE>true</CODE>,
2854     * this method configures a <CODE>Descriptor</CODE> to always refresh the cache if data is received from
2855     * the database by any query.<P>
2856     *
2857     * However, if a query hits the cache, data is not refreshed regardless of how this setting is configured.
2858     * For example, by default, when a query for a single object based on its primary key is executed, OracleAS TopLink
2859     * will first look in the cache for the object. If the object is in the cache, the cached object is returned and
2860     * data is not refreshed. To avoid cache hits, use the {@link #disableCacheHits} method.<P>
2861     *
2862     * Also note that the {@link oracle.toplink.essentials.sessions.UnitOfWork} will not refresh its registered objects.<P>
2863     *
2864     * Use this property with caution because it can lead to poor performance and may refresh on queries when it is not desired.
2865     * Normally, if you require fresh data, it is better to configure a query with {@link oracle.toplink.essentials.queryframework.ObjectLevelReadQuery#refreshIdentityMapResult}.
2866     * To ensure that refreshes are only done when required, use this method in conjunction with {@link #onlyRefreshCacheIfNewerVersion}.<P>
2867     *
2868     * When the <CODE>shouldAlwaysRefreshCache</CODE> argument passed into this method is <CODE>false</CODE>, this method
2869     * ensures that a <CODE>Descriptor</CODE> is not configured to always refresh the cache if data is received from the database by any query.<P>
2870     *
2871     * @see #alwaysRefreshCache
2872     * @see #dontAlwaysRefreshCache
2873     */

2874    public void setShouldAlwaysRefreshCache(boolean shouldAlwaysRefreshCache) {
2875        this.shouldAlwaysRefreshCache = shouldAlwaysRefreshCache;
2876    }
2877
2878    /**
2879     * PUBLIC:
2880     * Define if the descriptor reference class is read-only
2881     */

2882    public void setShouldBeReadOnly(boolean shouldBeReadOnly) {
2883        this.shouldBeReadOnly = shouldBeReadOnly;
2884    }
2885
2886    /**
2887     * PUBLIC:
2888     * Set the descriptor to be read-only.
2889     * Declaring a descriptor is read-only means that instances of the reference class will never be modified.
2890     * Read-only descriptor is usually used in the unit of work to gain performance as there is no need for
2891     * the registration, clone and merge for the read-only classes.
2892     */

2893    public void setReadOnly() {
2894        setShouldBeReadOnly(true);
2895    }
2896
2897    /**
2898     * PUBLIC:
2899     * Set if cache hits on primary key read object queries should be disabled.
2900     *
2901     * @see #alwaysRefreshCache()
2902     */

2903    public void setShouldDisableCacheHits(boolean shouldDisableCacheHits) {
2904        this.shouldDisableCacheHits = shouldDisableCacheHits;
2905    }
2906
2907    /**
2908     * PUBLIC:
2909     * When the <CODE>shouldOnlyRefreshCacheIfNewerVersion</CODE> argument passed into this method is <CODE>true</CODE>,
2910     * this method configures a <CODE>Descriptor</CODE> to only refresh the cache if the data received from the database
2911     * 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:
2912     *
2913     * <UL>
2914     * <LI>the <CODE>Descriptor</CODE> was configured by calling {@link #alwaysRefreshCache} or {@link #alwaysRefreshCacheOnRemote},</LI>
2915     * <LI>the query was configured by calling {@link oracle.toplink.essentials.queryframework.ObjectLevelReadQuery#refreshIdentityMapResult}, or</LI>
2916     * <LI>the query was a call to {@link oracle.toplink.essentials.sessions.Session#refreshObject}</LI>
2917     * </UL>
2918     * <P>
2919     *
2920     * However, if a query hits the cache, data is not refreshed regardless of how this setting is configured. For example, by default,
2921     * 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.
2922     * If the object is in the cache, the cached object is returned and data is not refreshed. To avoid cache hits, use
2923     * the {@link #disableCacheHits} method.<P>
2924     *
2925     * Also note that the {@link oracle.toplink.essentials.sessions.UnitOfWork} will not refresh its registered objects.<P>
2926     *
2927     * When the <CODE>shouldOnlyRefreshCacheIfNewerVersion</CODE> argument passed into this method is <CODE>false</CODE>, this method
2928     * ensures that a <CODE>Descriptor</CODE> is not configured to only refresh the cache if the data received from the database by a
2929     * query is newer than the data in the cache (as determined by the optimistic locking field).
2930     *
2931     * @see #onlyRefreshCacheIfNewerVersion
2932     * @see #dontOnlyRefreshCacheIfNewerVersion
2933     */

2934    public void setShouldOnlyRefreshCacheIfNewerVersion(boolean shouldOnlyRefreshCacheIfNewerVersion) {
2935        this.shouldOnlyRefreshCacheIfNewerVersion = shouldOnlyRefreshCacheIfNewerVersion;
2936    }
2937
2938    /**
2939     * PUBLIC:
2940     * This is set to turn off the ordering of mappings. By Default this is set to true.
2941     * By ordering the mappings TopLink insures that object are merged in the right order.
2942     * If the order of the mappings needs to be specified by the developer then set this to
2943     * false and TopLink will use the order that the mappings were added to the descriptor
2944     */

2945    public void setShouldOrderMappings(boolean shouldOrderMappings) {
2946        this.shouldOrderMappings = shouldOrderMappings;
2947    }
2948
2949    /**
2950     * INTERNAL:
2951     * Set to false to have queries conform to a UnitOfWork without registering
2952     * any additional objects not already in that UnitOfWork.
2953     * @see #shouldRegisterResultsInUnitOfWork
2954     * @bug 2612601
2955     */

2956    public void setShouldRegisterResultsInUnitOfWork(boolean shouldRegisterResultsInUnitOfWork) {
2957        this.shouldRegisterResultsInUnitOfWork = shouldRegisterResultsInUnitOfWork;
2958    }
2959
2960    /**
2961     * PUBLIC:
2962     * Specify the table name for the class of objects the receiver describes.
2963     * If the table has a qualifier it should be specified using the dot notation,
2964     * (i.e. "userid.employee"). This method is used for single table.
2965     */

2966    public void setTableName(String JavaDoc tableName) throws DescriptorException {
2967        if (getTables().isEmpty()) {
2968            addTableName(tableName);
2969        } else {
2970            throw DescriptorException.onlyOneTableCanBeAddedWithThisMethod(this);
2971        }
2972    }
2973
2974    /**
2975     * PUBLIC:
2976     * Specify the all table names for the class of objects the receiver describes.
2977     * If the table has a qualifier it should be specified using the dot notation,
2978     * (i.e. "userid.employee"). This method is used for multiple tables
2979     */

2980    public void setTableNames(Vector tableNames) {
2981        setTables(oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(tableNames.size()));
2982        for (Enumeration tableEnum = tableNames.elements(); tableEnum.hasMoreElements();) {
2983            addTableName((String JavaDoc)tableEnum.nextElement());
2984        }
2985    }
2986
2987    /**
2988     * PUBLIC: Set the table Qualifier for this descriptor. This table creator will be used for
2989     * all tables in this descriptor
2990     */

2991    public void setTableQualifier(String JavaDoc tableQualifier) {
2992        for (Enumeration enumtr = getTables().elements(); enumtr.hasMoreElements();) {
2993            DatabaseTable table = (DatabaseTable)enumtr.nextElement();
2994            table.setTableQualifier(tableQualifier);
2995        }
2996    }
2997
2998    /**
2999     * INTERNAL:
3000     * Sets the tables
3001     */

3002    public void setTables(Vector theTables) {
3003        tables = theTables;
3004    }
3005
3006    /**
3007     * ADVANCED:
3008     * Sets the WrapperPolicy for this descriptor.
3009     * This advacned feature can be used to wrap objects with other classes such as CORBA TIE objects or EJBs.
3010     */

3011    public void setWrapperPolicy(WrapperPolicy wrapperPolicy) {
3012        this.wrapperPolicy = wrapperPolicy;
3013
3014        // For bug 2766379 must be able to set the wrapper policy back to default
3015
// which is null.
3016
if (wrapperPolicy != null) {
3017            wrapperPolicy.setDescriptor(this);
3018        }
3019    }
3020
3021    /**
3022     * PUBLIC:
3023     * Return if the descriptor is defined to always conform the results in unit of work in read query.
3024     *
3025     */

3026    public boolean shouldAlwaysConformResultsInUnitOfWork() {
3027        return shouldAlwaysConformResultsInUnitOfWork;
3028    }
3029
3030    /**
3031     * PUBLIC:
3032     * This method returns <CODE>true</CODE> if the <CODE>Descriptor</CODE> is configured to always refresh
3033     * the cache if data is received from the database by any query. Otherwise, it returns <CODE>false</CODE>.
3034     *
3035     * @see #setShouldAlwaysRefreshCache
3036     */

3037    public boolean shouldAlwaysRefreshCache() {
3038        return shouldAlwaysRefreshCache;
3039    }
3040
3041    /**
3042     * PUBLIC:
3043     * Return if the descriptor reference class is defined as read-only
3044     *
3045     */

3046    public boolean shouldBeReadOnly() {
3047        return shouldBeReadOnly;
3048    }
3049
3050    /**
3051     * PUBLIC:
3052     * Return if for cache hits on primary key read object queries to be disabled.
3053     *
3054     * @see #disableCacheHits()
3055     */

3056    public boolean shouldDisableCacheHits() {
3057        return shouldDisableCacheHits;
3058    }
3059
3060    /**
3061     * PUBLIC:
3062     * This method returns <CODE>true</CODE> if the <CODE>Descriptor</CODE> is configured to only refresh the cache
3063     * if the data received from the database by a query is newer than the data in the cache (as determined by the
3064     * optimistic locking field). Otherwise, it returns <CODE>false</CODE>.
3065     *
3066     * @see #setShouldOnlyRefreshCacheIfNewerVersion
3067     */

3068    public boolean shouldOnlyRefreshCacheIfNewerVersion() {
3069        return shouldOnlyRefreshCacheIfNewerVersion;
3070    }
3071
3072    /**
3073     * INTERNAL:
3074     * Return if mappings should be ordered or not. By default this is set to true
3075     * to prevent attributes from being merged in the wrong order
3076     *
3077     */

3078    public boolean shouldOrderMappings() {
3079        return shouldOrderMappings;
3080    }
3081
3082    /**
3083     * INTERNAL:
3084     * PERF: Return if the primary key is simple (direct-mapped) to allow fast extraction.
3085     */

3086    public boolean hasSimplePrimaryKey() {
3087        return hasSimplePrimaryKey;
3088    }
3089
3090    /**
3091     * INTERNAL:
3092     * PERF: Set if the primary key is simple (direct-mapped) to allow fast extraction.
3093     */

3094    public void setHasSimplePrimaryKey(boolean hasSimplePrimaryKey) {
3095        this.hasSimplePrimaryKey = hasSimplePrimaryKey;
3096    }
3097
3098    /**
3099     * INTERNAL:
3100     * PERF: Return if deferred locks should be used.
3101     * Used to optimize read locking.
3102     * This is determined based on if any relationships do not use indirection.
3103     */

3104    public boolean shouldAcquireCascadedLocks() {
3105        return shouldAcquireCascadedLocks;
3106    }
3107
3108    /**
3109     * INTERNAL:
3110     * PERF: Set if deferred locks should be used.
3111     * This is determined based on if any relationships do not use indirection,
3112     * but this provides a backdoor hook to force on if require because of events usage etc.
3113     */

3114    public void setShouldAcquireCascadedLocks(boolean shouldAcquireCascadedLocks) {
3115        this.shouldAcquireCascadedLocks = shouldAcquireCascadedLocks;
3116    }
3117
3118    /**
3119     * PUBLIC:
3120     * Return true if this descriptor is using CacheIdentityMap
3121     */

3122    public boolean shouldUseCacheIdentityMap() {
3123        return (getIdentityMapClass() == ClassConstants.CacheIdentityMap_Class);
3124    }
3125
3126    /**
3127     * PUBLIC:
3128     * Return true if this descriptor is using FullIdentityMap
3129     */

3130    public boolean shouldUseFullIdentityMap() {
3131        return (getIdentityMapClass() == ClassConstants.FullIdentityMap_Class);
3132    }
3133
3134    /**
3135     * PUBLIC:
3136     * Return true if this descriptor is using HardCacheWeakIdentityMap.
3137     */

3138    public boolean shouldUseHardCacheWeakIdentityMap() {
3139        return (getIdentityMapClass() == ClassConstants.HardCacheWeakIdentityMap_Class);
3140    }
3141
3142    /**
3143     * PUBLIC:
3144     * Return true if this descriptor is using NoIdentityMap
3145     */

3146    public boolean shouldUseNoIdentityMap() {
3147        return (getIdentityMapClass() == ClassConstants.NoIdentityMap_Class);
3148    }
3149
3150    /**
3151     * INTERNAL:
3152     * Allows one to do conforming in a UnitOfWork without registering.
3153     * Queries executed on a UnitOfWork will only return working copies for objects
3154     * that have already been registered.
3155     * <p>Extreme care should be taken in using this feature, for a user will
3156     * get back a mix of registered and original (unregistered) objects.
3157     * <p>Best used with a WrapperPolicy where invoking on an object will trigger
3158     * its registration (CMP). Without a WrapperPolicy {@link oracle.toplink.essentials.sessions.UnitOfWork#registerExistingObject registerExistingObject}
3159     * should be called on any object that you intend to change.
3160     * @return true by default.
3161     * @see #setShouldRegisterResultsInUnitOfWork
3162     * @see oracle.toplink.essentials.queryframework.ObjectLevelReadQuery#shouldRegisterResultsInUnitOfWork
3163     * @bug 2612601
3164     */

3165    public boolean shouldRegisterResultsInUnitOfWork() {
3166        return shouldRegisterResultsInUnitOfWork;
3167    }
3168
3169    /**
3170     * PUBLIC:
3171     * Return true if this descriptor is using SoftCacheWeakIdentityMap.
3172     */

3173    public boolean shouldUseSoftCacheWeakIdentityMap() {
3174        return (getIdentityMapClass() == ClassConstants.SoftCacheWeakIdentityMap_Class);
3175    }
3176
3177    /**
3178     * PUBLIC:
3179     * Return true if this descriptor is using WeakIdentityMap
3180     */

3181    public boolean shouldUseWeakIdentityMap() {
3182        return (getIdentityMapClass() == ClassConstants.WeakIdentityMap_Class);
3183    }
3184
3185    /**
3186     * PUBLIC:
3187     * Returns a brief string representation of the receiver.
3188     */

3189    public String JavaDoc toString() {
3190        return Helper.getShortClassName(getClass()) + "(" + getJavaClassName() + " --> " + getTables() + ")";
3191    }
3192
3193    /**
3194     * PUBLIC:
3195     * Set the class of identity map to be the cache identity map.
3196     * This map caches the LRU instances read from the database.
3197     * The default in JDK1.1 is "FullIdentityMap", in JDK1.2 it is the "SoftCacheWeakIdentityMap".
3198     */

3199    public void useCacheIdentityMap() {
3200        setIdentityMapClass(ClassConstants.CacheIdentityMap_Class);
3201    }
3202
3203    /**
3204     * PUBLIC:
3205     * Specifies that the creation of clones within a unit of work is done by
3206     * sending the #clone() method to the original object. The #clone() method
3207     * must return a logical shallow copy of the original object.
3208     * This can be used if the default mechanism of creating a new instance
3209     * does not handle the object's non-persistent attributes correctly.
3210     *
3211     * @see #useCloneCopyPolicy(String)
3212     */

3213    public void useCloneCopyPolicy() {
3214        useCloneCopyPolicy("clone");
3215    }
3216
3217    /**
3218     * PUBLIC:
3219     * Specifies that the creation of clones within a unit of work is done by
3220     * sending the cloneMethodName method to the original object. This method
3221     * must return a logical shallow copy of the original object.
3222     * This can be used if the default mechanism of creating a new instance
3223     * does not handle the object's non-persistent attributes correctly.
3224     *
3225     * @see #useCloneCopyPolicy()
3226     */

3227    public void useCloneCopyPolicy(String JavaDoc cloneMethodName) {
3228        CloneCopyPolicy policy = new CloneCopyPolicy();
3229        policy.setMethodName(cloneMethodName);
3230        setCopyPolicy(policy);
3231    }
3232
3233    /**
3234     * PUBLIC:
3235     * Specifies that the creation of clones within a unit of work is done by building
3236     * a new instance using the
3237     * technique indicated by the descriptor's instantiation policy
3238     * (which by default is to use the
3239     * the default constructor). This new instance is then populated by using the
3240     * descriptor's mappings to copy attributes from the original to the clone.
3241     * This is the default.
3242     * If another mechanism is desired the copy policy allows for a clone method to be called.
3243     *
3244     * @see #useCloneCopyPolicy()
3245     * @see #useCloneCopyPolicy(String)
3246     * @see #useDefaultConstructorInstantiationPolicy()
3247     * @see #useMethodInstantiationPolicy(String)
3248     * @see #useFactoryInstantiationPolicy(Class, String)
3249     * @see #useFactoryInstantiationPolicy(Class, String, String)
3250     * @see #useFactoryInstantiationPolicy(Object, String)
3251     */

3252    public void useInstantiationCopyPolicy() {
3253        setCopyPolicy(new InstantiationCopyPolicy());
3254    }
3255
3256    /**
3257     * PUBLIC:
3258     * Use the default constructor to create new instances of objects built from the database.
3259     * This is the default.
3260     * The descriptor's class must either define a default constructor or define
3261     * no constructors at all.
3262     *
3263     * @see #useMethodInstantiationPolicy(String)
3264     * @see #useFactoryInstantiationPolicy(Class, String)
3265     * @see #useFactoryInstantiationPolicy(Class, String, String)
3266     * @see #useFactoryInstantiationPolicy(Object, String)
3267     */

3268    public void useDefaultConstructorInstantiationPolicy() {
3269        getInstantiationPolicy().useDefaultConstructorInstantiationPolicy();
3270    }
3271
3272    /**
3273     * PUBLIC:
3274     * Use an object factory to create new instances of objects built from the database.
3275     * The methodName is the name of the
3276     * method that will be invoked on the factory. When invoked, it must return a new instance
3277     * of the descriptor's class.
3278     * The factory will be created by invoking the factoryClass's default constructor.
3279     *
3280     * @see #useDefaultConstructorInstantiationPolicy()
3281     * @see #useMethodInstantiationPolicy(String)
3282     * @see #useFactoryInstantiationPolicy(Class, String, String)
3283     * @see #useFactoryInstantiationPolicy(Object, String)
3284     */

3285    public void useFactoryInstantiationPolicy(Class JavaDoc factoryClass, String JavaDoc methodName) {
3286        getInstantiationPolicy().useFactoryInstantiationPolicy(factoryClass, methodName);
3287    }
3288
3289    /**
3290     * INTERNAL:
3291     * Set the factory class name, used by the MW.
3292     */

3293    public void useFactoryInstantiationPolicy(String JavaDoc factoryClassName, String JavaDoc methodName) {
3294        getInstantiationPolicy().useFactoryInstantiationPolicy(factoryClassName, methodName);
3295    }
3296
3297    /**
3298     * PUBLIC:
3299     * Use an object factory to create new instances of objects built from the database.
3300     * The factoryMethodName is a static method declared by the factoryClass.
3301     * When invoked, it must return an instance of the factory. The methodName is the name of the
3302     * method that will be invoked on the factory. When invoked, it must return a new instance
3303     * of the descriptor's class.
3304     *
3305     * @see #useDefaultConstructorInstantiationPolicy()
3306     * @see #useFactoryInstantiationPolicy(Class, String)
3307     * @see #useFactoryInstantiationPolicy(Object, String)
3308     * @see #useMethodInstantiationPolicy(String)
3309     */

3310    public void useFactoryInstantiationPolicy(Class JavaDoc factoryClass, String JavaDoc methodName, String JavaDoc factoryMethodName) {
3311        getInstantiationPolicy().useFactoryInstantiationPolicy(factoryClass, methodName, factoryMethodName);
3312    }
3313
3314    /**
3315     * INTERNAL:
3316     * Set the factory class name, used by the MW.
3317     */

3318    public void useFactoryInstantiationPolicy(String JavaDoc factoryClassName, String JavaDoc methodName, String JavaDoc factoryMethodName) {
3319        getInstantiationPolicy().useFactoryInstantiationPolicy(factoryClassName, methodName, factoryMethodName);
3320    }
3321
3322    /**
3323     * PUBLIC:
3324     * Use an object factory to create new instances of objects built from the database.
3325     * The methodName is the name of the
3326     * method that will be invoked on the factory. When invoked, it must return a new instance
3327     * of the descriptor's class.
3328     *
3329     * @see #useDefaultConstructorInstantiationPolicy()
3330     * @see #useMethodInstantiationPolicy(String)
3331     * @see #useFactoryInstantiationPolicy(Class, String)
3332     * @see #useFactoryInstantiationPolicy(Class, String, String)
3333     */

3334    public void useFactoryInstantiationPolicy(Object JavaDoc factory, String JavaDoc methodName) {
3335        getInstantiationPolicy().useFactoryInstantiationPolicy(factory, methodName);
3336    }
3337
3338    /**
3339     * PUBLIC:
3340     * Set the class of identity map to be the full identity map.
3341     * This map caches all instances read and grows to accomodate them.
3342     * The default is the "SoftCacheWeakIdentityMap".
3343     */

3344    public void useFullIdentityMap() {
3345        setIdentityMapClass(ClassConstants.FullIdentityMap_Class);
3346    }
3347
3348    /**
3349     * PUBLIC:
3350     * Set the class of identity map to be the hard cache weak identity map.
3351     * This map uses weak references to only cache object in-memory.
3352     * It also includes a secondary fixed sized soft cache to improve caching performance.
3353     * This is provided because some Java VM's do not implement soft references correctly.
3354     * The default is the "SoftCacheWeakIdentityMap".
3355     */

3356    public void useHardCacheWeakIdentityMap() {
3357        setIdentityMapClass(ClassConstants.HardCacheWeakIdentityMap_Class);
3358    }
3359
3360    /**
3361     * PUBLIC:
3362     * Use the specified static method to create new instances of objects built from the database.
3363     * This method must be statically declared by the descriptor's class, and it must
3364     * return a new instance of the descriptor's class.
3365     *
3366     * @see #useDefaultConstructorInstantiationPolicy()
3367     * @see #useFactoryInstantiationPolicy(Class, String)
3368     * @see #useFactoryInstantiationPolicy(Class, String, String)
3369     * @see #useFactoryInstantiationPolicy(Object, String)
3370     */

3371    public void useMethodInstantiationPolicy(String JavaDoc staticMethodName) {
3372        getInstantiationPolicy().useMethodInstantiationPolicy(staticMethodName);
3373    }
3374
3375    /**
3376     * PUBLIC:
3377     * Set the class of identity map to be the no identity map.
3378     * This map does no caching.
3379     * The default is the "SoftCacheWeakIdentityMap".
3380     */

3381    public void useNoIdentityMap() {
3382        setIdentityMapClass(ClassConstants.NoIdentityMap_Class);
3383    }
3384
3385    /**
3386     * PUBLIC:
3387     * Set the class of identity map to be the soft cache weak identity map.
3388     * The SoftCacheIdentityMap holds a fixed number of objects is memory
3389     * (using SoftReferences) to improve caching.
3390     * The default is the "SoftCacheWeakIdentityMap".
3391     */

3392    public void useSoftCacheWeakIdentityMap() {
3393        setIdentityMapClass(ClassConstants.SoftCacheWeakIdentityMap_Class);
3394    }
3395
3396    /**
3397     * PUBLIC:
3398     * Return true if the receiver uses write (optimistic) locking.
3399     */

3400    public boolean usesOptimisticLocking() {
3401        return (optimisticLockingPolicy != null);
3402    }
3403    
3404    /**
3405     * PUBLIC:
3406     * Return true if the receiver uses version optimistic locking.
3407     */

3408    public boolean usesVersionLocking() {
3409        return (usesOptimisticLocking() && (getOptimisticLockingPolicy() instanceof VersionLockingPolicy));
3410    }
3411
3412    /**
3413     * PUBLIC:
3414     * Return true if the receiver uses sequence numbers.
3415     */

3416    public boolean usesSequenceNumbers() {
3417        return ((getSequenceNumberField() != null) && (getSequenceNumberName() != null));
3418    }
3419
3420    /**
3421     * PUBLIC:
3422     * Use the Timestamps locking policy and storing the value in the cache key
3423     * #see useVersionLocking(String)
3424     */

3425    public void useTimestampLocking(String JavaDoc writeLockFieldName) {
3426        useTimestampLocking(writeLockFieldName, true);
3427    }
3428
3429    /**
3430     * PUBLIC:
3431     * Set the locking policy to use timestamp version locking.
3432     * This updates the timestamp field on all updates, first comparing that the field has not changed to detect locking conflicts.
3433     * Note: many database have limited precision of timestamps which can be an issue is highly concurrent systems.
3434     *
3435     * The parameter 'shouldStoreInCache' configures the version lock value to be stored in the cache or in the object.
3436     * Note: if using a stateless model where the object can be passed to a client and then later updated in a different transaction context,
3437     * 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.
3438     * @see VersionLockingPolicy
3439     */

3440    public void useTimestampLocking(String JavaDoc writeLockFieldName, boolean shouldStoreInCache) {
3441        TimestampLockingPolicy policy = new TimestampLockingPolicy(writeLockFieldName);
3442        if (shouldStoreInCache) {
3443            policy.storeInCache();
3444        } else {
3445            policy.storeInObject();
3446        }
3447        setOptimisticLockingPolicy(policy);
3448    }
3449
3450    /**
3451     * PUBLIC:
3452     * Default to use the version locking policy and storing the value in the cache key
3453     * #see useVersionLocking(String)
3454     */

3455    public void useVersionLocking(String JavaDoc writeLockFieldName) {
3456        useVersionLocking(writeLockFieldName, true);
3457    }
3458
3459    /**
3460     * PUBLIC:
3461     * Set the locking policy to use numeric version locking.
3462     * This updates the version field on all updates, first comparing that the field has not changed to detect locking conflicts.
3463     *
3464     * The parameter 'shouldStoreInCache' configures the version lock value to be stored in the cache or in the object.
3465     * Note: if using a stateless model where the object can be passed to a client and then later updated in a different transaction context,
3466     * 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.
3467     * @see TimestampLockingPolicy
3468     */

3469    public void useVersionLocking(String JavaDoc writeLockFieldName, boolean shouldStoreInCache) {
3470        VersionLockingPolicy policy = new VersionLockingPolicy(writeLockFieldName);
3471        if (shouldStoreInCache) {
3472            policy.storeInCache();
3473        } else {
3474            policy.storeInObject();
3475        }
3476        setOptimisticLockingPolicy(policy);
3477    }
3478
3479    /**
3480     * PUBLIC:
3481     * Set the class of identity map to be the weak identity map.
3482     * The default is the "SoftCacheWeakIdentityMap".
3483     */

3484    public void useWeakIdentityMap() {
3485        setIdentityMapClass(ClassConstants.WeakIdentityMap_Class);
3486    }
3487
3488    /**
3489     * INTERNAL:
3490     * Validate the entire post-initialization descriptor.
3491     */

3492    protected void validateAfterInitialization(AbstractSession session) {
3493        selfValidationAfterInitialization(session);
3494        for (Enumeration mappings = getMappings().elements(); mappings.hasMoreElements();) {
3495            ((DatabaseMapping)mappings.nextElement()).validateAfterInitialization(session);
3496        }
3497    }
3498
3499    /**
3500     * INTERNAL:
3501     * Validate the entire pre-initialization descriptor.
3502     */

3503    protected void validateBeforeInitialization(AbstractSession session) {
3504        selfValidationBeforeInitialization(session);
3505        for (Enumeration mappings = getMappings().elements(); mappings.hasMoreElements();) {
3506            ((DatabaseMapping)mappings.nextElement()).validateBeforeInitialization(session);
3507        }
3508    }
3509
3510    /**
3511     * INTERNAL:
3512     * Check that the qualifier on the table names are properly set.
3513     */

3514    protected void verifyTableQualifiers(Platform platform) {
3515        DatabaseTable table;
3516        Enumeration tableEnumeration;
3517        String JavaDoc tableQualifier = platform.getTableQualifier();
3518
3519        if (tableQualifier.length() == 0) {
3520            return;
3521        }
3522
3523        tableEnumeration = getTables().elements();
3524        while (tableEnumeration.hasMoreElements()) {
3525            table = (DatabaseTable)tableEnumeration.nextElement();
3526            if (table.getTableQualifier().length() == 0) {
3527                table.setTableQualifier(tableQualifier);
3528            }
3529        }
3530    }
3531
3532    /**
3533     * ADVANCED:
3534     * Return the cmp descriptor that holds EJB CMP specific information.
3535     * This will be null unless explicitly set, or after CMP deoloyment.
3536     * This can only be specified when using CMP for bean class descriptors.
3537     * This must be set explicitly if any setting need to be configured and
3538     * before calling getCMPPolicy().
3539     */

3540    public CMPPolicy getCMPPolicy() {
3541        return cmpPolicy;
3542    }
3543
3544    /**
3545     * ADVANCED:
3546     * Set the cmp descriptor that holds EJB CMP specific information.
3547     * This can only be specified when using CMP for bean class descriptors.
3548     * This must be set explicitly if any setting need to be configured and
3549     * before calling getCMPPolicy().
3550     */

3551    public void setCMPPolicy(CMPPolicy newCMPPolicy) {
3552        cmpPolicy = newCMPPolicy;
3553        if (cmpPolicy != null){
3554            cmpPolicy.setDescriptor(this);
3555        }
3556    }
3557
3558    /**
3559     * PUBLIC:
3560     * Get the fetch group manager for the descriptor. The fetch group manager is responsible
3561     * for managing the fetch group behaviors and operations.
3562     * To use the fetch group, the domain object must implement FetchGroupTracker interface. Otherwise,
3563     * a descriptor validation exception would throw during initialization.
3564     * NOTE: This is currently only supported in CMP2.
3565     * @see oracle.toplink.essentials.queryframework.FetchGroupTracker
3566     */

3567    public FetchGroupManager getFetchGroupManager() {
3568        return fetchGroupManager;
3569    }
3570
3571    /**
3572     * PUBLIC:
3573     * Set the fetch group manager for the descriptor. The fetch group manager is responsible
3574     * for managing the fetch group behaviors and operations.
3575     */

3576    public void setFetchGroupManager(FetchGroupManager fetchGroupManager) {
3577        this.fetchGroupManager = fetchGroupManager;
3578        if (fetchGroupManager != null) {
3579            //set the back reference
3580
fetchGroupManager.setDescriptor(this);
3581        }
3582    }
3583
3584    /**
3585     * INTERNAL:
3586     * Return true if the descriptor is a CMP entity descriptor
3587     */

3588    public boolean isDescriptorForCMP() {
3589        return (this.getCMPPolicy() != null);
3590    }
3591
3592    /**
3593     * INTERNAL:
3594     * Return if the descriptor has a fecth group manager asociated with.
3595     */

3596    public boolean hasFetchGroupManager() {
3597        return (fetchGroupManager != null);
3598    }
3599    
3600    /**
3601     * INTERNAL:
3602     */

3603     public boolean hasCascadeLockingPolicies() {
3604        return !cascadeLockingPolicies.isEmpty();
3605     }
3606     
3607    /**
3608     * INTERNAL:
3609     * Return if the descriptor has a CMP policy.
3610     */

3611    public boolean hasCMPPolicy() {
3612        return (cmpPolicy != null);
3613    }
3614
3615    /**
3616     * INTERNAL:
3617     *
3618     * Return the default fetch group on the descriptor.
3619     * All read object and read all queries will use the default fetch group if
3620     * no fetch group is explicitly defined for the query.
3621     */

3622    public FetchGroup getDefaultFetchGroup() {
3623        if (!hasFetchGroupManager()) {
3624            //fetch group manager is not set, therefore no default fetch group.
3625
return null;
3626        }
3627        return getFetchGroupManager().getDefaultFetchGroup();
3628    }
3629}
3630
Popular Tags