KickJava   Java API By Example, From Geeks To Geeks.

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


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 java.io.*;
25 import java.lang.reflect.*;
26 import java.security.AccessController JavaDoc;
27 import java.security.PrivilegedActionException JavaDoc;
28 import java.util.*;
29 import oracle.toplink.essentials.exceptions.*;
30 import oracle.toplink.essentials.expressions.*;
31 import oracle.toplink.essentials.internal.descriptors.OptimisticLockingPolicy;
32 import oracle.toplink.essentials.internal.expressions.*;
33 import oracle.toplink.essentials.internal.helper.*;
34 import oracle.toplink.essentials.internal.queryframework.*;
35 import oracle.toplink.essentials.mappings.*;
36 import oracle.toplink.essentials.queryframework.*;
37 import oracle.toplink.essentials.internal.sessions.AbstractRecord;
38 import oracle.toplink.essentials.internal.sessions.AbstractSession;
39 import oracle.toplink.essentials.internal.security.PrivilegedAccessHelper;
40 import oracle.toplink.essentials.internal.security.PrivilegedClassForName;
41
42 /**
43  * <p><b>Purpose</b>: Allows customization of an object's inheritance.
44  * The primary supported inheritance model uses a class type indicator
45  * column in the table that stores the object's class type.
46  * The class-to-type mapping is specified on this policy.
47  * The full class name can also be used for the indicator instead of the mapping.
48  * <p>Each subclass can either share their parents table, or in addition add their
49  * own table(s).
50  * <p>For legacy models a customized inheritance class-extractor can be provided.
51  * This allows Java code to be used to compute the class type to use for a row.
52  * When this customized inheritance model is used an only-instances and with-all-subclasses
53  * filter expression may be required for concrete and branch querying.
54  */

55 public class InheritancePolicy implements Serializable, Cloneable JavaDoc {
56     protected Class JavaDoc parentClass;
57     protected String JavaDoc parentClassName;
58     protected ClassDescriptor parentDescriptor;
59     protected Vector childDescriptors;
60     protected transient DatabaseField classIndicatorField;
61      protected transient Map classIndicatorMapping;
62      protected transient Map classNameIndicatorMapping;
63     protected transient boolean shouldUseClassNameAsIndicator;
64     protected transient Boolean JavaDoc shouldReadSubclasses;
65     protected transient DatabaseTable readAllSubclassesView;
66     protected transient Vector allChildClassIndicators;
67     protected transient Expression onlyInstancesExpression;
68     protected transient Expression withAllSubclassesExpression;
69     // null if there are no childrenTables, otherwise all tables for reference class plus childrenTables
70
protected transient Vector allTables;
71     // all tables for all subclasses (subclasses of subclasses included), should be in sync with childrenTablesJoinExpressions.
72
protected transient List childrenTables;
73     // join expression for each child table, keyed by the table, should be in sync with childrenTables.
74
protected transient Map childrenTablesJoinExpressions;
75     // all expressions from childrenTablesJoinExpressions ANDed together
76
protected transient Expression childrenJoinExpression;
77
78     /** Allow for class extraction method to be specified. */
79     protected transient ClassExtractor classExtractor;
80     protected ClassDescriptor descriptor;
81     protected boolean shouldAlwaysUseOuterJoin;
82
83     //CR 4005
84
protected boolean useDescriptorsToValidateInheritedObjects;
85
86     // used by the entity-mappings XML writer to determine inheritance strategy
87
protected boolean isJoinedStrategy;
88
89     /**
90      * INTERNAL:
91      * Create a new policy.
92      * Only descriptors involved in inheritence should have a policy.
93      */

94     public InheritancePolicy() {
95          this.classIndicatorMapping = new HashMap(10);
96          this.classNameIndicatorMapping = new HashMap(10);
97         this.shouldUseClassNameAsIndicator = false;
98          this.allChildClassIndicators = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance();
99          this.childDescriptors = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(5);
100         this.setJoinedStrategy();
101     }
102
103     /**
104      * INTERNAL:
105      * Create a new policy.
106      * Only descriptors involved in inheritence should have a policy.
107      */

108     public InheritancePolicy(ClassDescriptor descriptor) {
109         this();
110         this.descriptor = descriptor;
111     }
112
113     /**
114      * INTERNAL:
115      * Add child descriptor to the parent descriptor.
116      */

117     public void addChildDescriptor(ClassDescriptor childDescriptor) {
118         getChildDescriptors().addElement(childDescriptor);
119     }
120
121     /**
122      * INTERNAL:
123      * childrenTablesJoinExpressions, childrenTables, allTables and childrenJoinExpression
124      * are created simultaneously and kept in sync.
125      */

126     protected void addChildTableJoinExpression(DatabaseTable table, Expression expression) {
127         if(childrenTablesJoinExpressions == null) {
128            childrenTablesJoinExpressions = new HashMap();
129            // childrenTables should've been null, too
130
childrenTables = new ArrayList();
131            // allTables should've been null, too
132
allTables = new Vector(getDescriptor().getTables());
133         }
134         childrenTables.add(table);
135         allTables.add(table);
136         childrenTablesJoinExpressions.put(table, expression);
137         childrenJoinExpression = expression.and(childrenJoinExpression);
138     }
139
140     /**
141      * INTERNAL:
142      * call addChildTableJoinExpression on all parents
143      */

144     public void addChildTableJoinExpressionToAllParents(DatabaseTable table, Expression expression) {
145         ClassDescriptor parentDescriptor = getParentDescriptor();
146         while(parentDescriptor != null) {
147             InheritancePolicy parentPolicy = parentDescriptor.getInheritancePolicy();
148             parentPolicy.addChildTableJoinExpression(table, expression);
149             parentDescriptor = parentPolicy.getParentDescriptor();
150         }
151     }
152
153     /**
154      * PUBLIC:
155      * Add a class indicator for the root classes subclass.
156      * The indicator is used to determine the class to use for a row read from the database,
157      * and to query only instances of a class from the database.
158      * Every concrete persistent subclass must have a single unique indicator defined for it.
159      * If the root class is concrete then it must also define an indicator.
160      * Only the root class's descriptor of the entire inheritance hierarchy can define the class indicator mapping.
161      */

162     public void addClassIndicator(Class JavaDoc childClass, Object JavaDoc typeValue) {
163         // Note we should think about supporting null values.
164
// Store as key and value for bi-diractional lookup.
165
getClassIndicatorMapping().put(typeValue, childClass);
166         getClassIndicatorMapping().put(childClass, typeValue);
167     }
168
169     /**
170      * INTERNAL:
171      * Add the class name reference by class name, used by the MW.
172      */

173     public void addClassNameIndicator(String JavaDoc childClassName, Object JavaDoc typeValue) {
174         getClassNameIndicatorMapping().put(childClassName, typeValue);
175     }
176
177     /**
178      * INTERNAL:
179      * Add abstract class indicator information to the database row. This is
180      * required when building a row for an insert or an update of a concrete child
181      * descriptor.
182      * This is only used to build a template row.
183      */

184     public void addClassIndicatorFieldToInsertRow(AbstractRecord databaseRow) {
185         if (hasClassExtractor()) {
186             return;
187         }
188
189         DatabaseField field = getClassIndicatorField();
190         databaseRow.put(field, null);
191     }
192
193     /**
194      * INTERNAL:
195      * Add abstract class indicator information to the database row. This is
196      * required when building a row for an insert or an update of a concrete child
197      * descriptor.
198      */

199     public void addClassIndicatorFieldToRow(AbstractRecord databaseRow) {
200         if (hasClassExtractor()) {
201             return;
202         }
203
204         DatabaseField field = getClassIndicatorField();
205         Object JavaDoc value = getClassIndicatorValue();
206
207         databaseRow.put(field, value);
208     }
209
210     /**
211      * INTERNAL:
212      * Post initialize the child descriptors
213      */

214     protected void addClassIndicatorTypeToParent(Object JavaDoc indicator) {
215         ClassDescriptor parentDescriptor = getDescriptor().getInheritancePolicy().getParentDescriptor();
216
217         if (parentDescriptor.getInheritancePolicy().isChildDescriptor()) {
218             if (parentDescriptor.getInheritancePolicy().shouldReadSubclasses()) {
219                 parentDescriptor.getInheritancePolicy().getAllChildClassIndicators().addElement(indicator);
220             }
221             parentDescriptor.getInheritancePolicy().addClassIndicatorTypeToParent(indicator);
222         }
223     }
224
225     /**
226      * INTERNAL:
227      * Recursively adds fields to all the parents
228      */

229     protected void addFieldsToParent(Vector fields) {
230         if (isChildDescriptor()) {
231             if (getParentDescriptor().isInvalid()) {
232                 return;
233             }
234             ClassDescriptor parentDescriptor = getParentDescriptor();
235             if (parentDescriptor.getInheritancePolicy().shouldReadSubclasses()) {
236                 Helper.addAllUniqueToVector(parentDescriptor.getAllFields(), fields);
237             }
238             parentDescriptor.getInheritancePolicy().addFieldsToParent(fields);
239         }
240     }
241
242     /**
243      * INTERNAL:
244      * Return a select statement that will be used to query the class indicators required to query.
245      * This is used in the abstract-multiple read.
246      */

247     public SQLSelectStatement buildClassIndicatorSelectStatement(ObjectLevelReadQuery query) {
248         SQLSelectStatement selectStatement;
249         selectStatement = new SQLSelectStatement();
250         selectStatement.useDistinct();
251         selectStatement.addTable(classIndicatorField.getTable());
252         selectStatement.addField(getClassIndicatorField());
253         // 2612538 - the default size of IdentityHashtable (32) is appropriate
254
IdentityHashtable clonedExpressions = new IdentityHashtable();
255         selectStatement.setWhereClause(((ExpressionQueryMechanism)query.getQueryMechanism()).buildBaseSelectionCriteria(false, clonedExpressions));
256         appendWithAllSubclassesExpression(selectStatement);
257         selectStatement.setTranslationRow(query.getTranslationRow());
258         selectStatement.normalize(query.getSession(), getDescriptor(), clonedExpressions);
259         ExpressionQueryMechanism m = (ExpressionQueryMechanism)query.getQueryMechanism();
260
261         return selectStatement;
262     }
263
264     /**
265      * INTERNAL:
266      * Append the branch with all subclasses expression to the statement.
267      */

268     public void appendWithAllSubclassesExpression(SQLSelectStatement selectStatement) {
269         if (getWithAllSubclassesExpression() != null) {
270             // For Flashback: Must always rebuild with simple expression on right.
271
if (selectStatement.getWhereClause() == null) {
272                 selectStatement.setWhereClause((Expression)getWithAllSubclassesExpression().clone());
273             } else {
274                 selectStatement.setWhereClause(selectStatement.getWhereClause().and(getWithAllSubclassesExpression()));
275             }
276         }
277     }
278
279     /**
280      * INTERNAL:
281      * Build a select statement for all subclasses on the view using the same
282      * selection criteria as the query.
283      */

284     public SQLSelectStatement buildViewSelectStatement(ObjectLevelReadQuery query) {
285         // 2612538 - the default size of IdentityHashtable (32) is appropriate
286
IdentityHashtable clonedExpressions = new IdentityHashtable();
287         ExpressionQueryMechanism mechanism = (ExpressionQueryMechanism)query.getQueryMechanism();
288
289         // CR#3166555 - Have the mechanism build the statement to avoid duplicating code and ensure that lock-mode, hints, hierarchical, etc. are set.
290
SQLSelectStatement selectStatement = mechanism.buildBaseSelectStatement(false, clonedExpressions);
291          selectStatement.setTables(oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(1));
292         selectStatement.addTable(getReadAllSubclassesView());
293
294         // Case, normal read for branch inheritence class that reads subclasses all in its own table(s).
295
if (getWithAllSubclassesExpression() != null) {
296             Expression branchIndicator = (Expression)getWithAllSubclassesExpression().clone();
297             if (branchIndicator != null) {
298                 selectStatement.setWhereClause(branchIndicator.and(selectStatement.getWhereClause()));
299             }
300         }
301
302         selectStatement.setFields(mechanism.getSelectionFields(selectStatement, true));
303         selectStatement.normalizeForView(query.getSession(), getDescriptor(), clonedExpressions);
304         // Allow for joining indexes to be computed to ensure distinct rows
305
((ObjectLevelReadQuery)query).getJoinedAttributeManager().computeJoiningMappingIndexes(false, query.getSession(), 0);
306
307         return selectStatement;
308     }
309
310     /**
311      * INTERNAL:
312      * This method is invoked only for the abstract descriptors.
313      */

314     public Class JavaDoc classFromRow(AbstractRecord rowFromDatabase, AbstractSession session) throws DescriptorException {
315         if (hasClassExtractor()) {
316             return getClassExtractor().extractClassFromRow(rowFromDatabase, session);
317         }
318
319         Object JavaDoc classFieldValue = session.getDatasourcePlatform().getConversionManager().convertObject(rowFromDatabase.get(getClassIndicatorField()), getClassIndicatorField().getType());
320
321         if (classFieldValue == null) {
322             throw DescriptorException.missingClassIndicatorField(rowFromDatabase, getDescriptor());
323         }
324
325         Class JavaDoc concreteClass;
326         if (!shouldUseClassNameAsIndicator()) {
327             concreteClass = (Class JavaDoc)getClassIndicatorMapping().get(classFieldValue);
328             if (concreteClass == null) {
329                 throw DescriptorException.missingClassForIndicatorFieldValue(classFieldValue, getDescriptor());
330             }
331         } else {
332             try {
333                 String JavaDoc className = (String JavaDoc)classFieldValue;
334                 //PWK 2.5.1.7 can not use class for name, must go through conversion manager.
335
//Should use the root Descriptor's classloader to avoid loading from a loader other
336
//than the one that loaded the project
337
concreteClass = getDescriptor().getJavaClass().getClassLoader().loadClass(className);
338                 if (concreteClass == null) {
339                     throw DescriptorException.missingClassForIndicatorFieldValue(classFieldValue, getDescriptor());
340                 }
341             } catch (ClassNotFoundException JavaDoc e) {
342                 throw DescriptorException.missingClassForIndicatorFieldValue(classFieldValue, getDescriptor());
343             } catch (ClassCastException JavaDoc e) {
344                 throw DescriptorException.missingClassForIndicatorFieldValue(classFieldValue, getDescriptor());
345             }
346         }
347
348         return concreteClass;
349     }
350
351     /**
352      * INTERNAL:
353      * Clone the policy
354      */

355     public Object JavaDoc clone() {
356         InheritancePolicy clone = null;
357
358         try {
359             clone = (InheritancePolicy)super.clone();
360             if (hasClassIndicator()) {
361                 clone.setClassIndicatorField((DatabaseField)clone.getClassIndicatorField().clone());
362             }
363         } catch (Exception JavaDoc exception) {
364             throw new InternalError JavaDoc("clone failed");
365         }
366
367         return clone;
368     }
369
370     /**
371      * INTERNAL:
372      * Convert all the class-name-based settings in this InheritancePolicy to actual class-based
373      * settings. This method is used when converting a project that has been built
374      * with class names to a project with classes.
375      * @param classLoader
376      */

377     public void convertClassNamesToClasses(ClassLoader JavaDoc classLoader){
378         if (parentClassName == null){
379             return;
380         }
381         Class JavaDoc parentClass = null;
382         try{
383             if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
384                 try {
385                     parentClass = (Class JavaDoc)AccessController.doPrivileged(new PrivilegedClassForName(parentClassName, true, classLoader));
386                 } catch (PrivilegedActionException JavaDoc exception) {
387                     throw ValidationException.classNotFoundWhileConvertingClassNames(parentClassName, exception.getException());
388                 }
389             } else {
390                 parentClass = oracle.toplink.essentials.internal.security.PrivilegedAccessHelper.getClassForName(parentClassName, true, classLoader);
391             }
392         } catch (ClassNotFoundException JavaDoc exc){
393             throw ValidationException.classNotFoundWhileConvertingClassNames(parentClassName, exc);
394         }
395         setParentClass(parentClass);
396     }
397
398     /**
399      * PUBLIC:
400      * Set the descriptor to only read instance of itself when queried.
401      * This is used with inheritance to configure the result of queries.
402      * By default this is true for root inheritance descriptors, and false for all others.
403      */

404     public void dontReadSubclassesOnQueries() {
405         setShouldReadSubclasses(false);
406     }
407
408     /**
409      * PUBLIC:
410      * Set the descriptor not to use the class' full name as the indicator.
411      * The class indicator is used with inheritance to determine the class from a row.
412      * By default a class indicator mapping is required, this can be set to true if usage of the class name is desired.
413      * The field must be of a large enough size to store the fully qualified class name.
414      */

415     public void dontUseClassNameAsIndicator() {
416         setShouldUseClassNameAsIndicator(false);
417     }
418
419     /**
420      * INTERNAL:
421      * Stores class indicators for all child and children's children.
422      * Used for queries on branch classes only.
423      */

424     protected Vector getAllChildClassIndicators() {
425         return allChildClassIndicators;
426     }
427
428     /**
429      * INTERNAL:
430      * Returns all the child descriptors, even descriptors for subclasses of
431      * subclasses.
432      * Required for bug 3019934.
433      */

434     public Vector getAllChildDescriptors() {
435         // Guess the number of child descriptors...
436
Vector allChildDescriptors = new Vector(this.getAllChildClassIndicators().size());
437         return getAllChildDescriptors(allChildDescriptors);
438     }
439
440     /**
441      * INTERNAL:
442      * Recursive subroutine of getAllChildDescriptors.
443      */

444     protected Vector getAllChildDescriptors(Vector allChildDescriptors) {
445         for (Enumeration enumtr = getChildDescriptors().elements(); enumtr.hasMoreElements();) {
446             ClassDescriptor childDescriptor = (ClassDescriptor)enumtr.nextElement();
447             allChildDescriptors.addElement(childDescriptor);
448             childDescriptor.getInheritancePolicyOrNull().getAllChildDescriptors(allChildDescriptors);
449         }
450         return allChildDescriptors;
451     }
452
453     /**
454      * INTERNAL:
455      * if reads subclasses, all tables for all read subclasses (indirect included).
456      */

457     public List getChildrenTables() {
458         return childrenTables;
459     }
460     
461     /**
462      * INTERNAL:
463      * join expression for each child table, keyed by the table
464      */

465     public Map getChildrenTablesJoinExpressions() {
466         return childrenTablesJoinExpressions;
467     }
468     
469     /**
470      * INTERNAL:
471      * all expressions from childrenTablesJoinExpressions ANDed together
472      */

473     public Expression getChildrenJoinExpression() {
474         return childrenJoinExpression;
475     }
476     
477     /**
478      * INTERNAL:
479      * all tables for reference class plus childrenTables
480      */

481     public Vector getAllTables() {
482         if(allTables == null) {
483             return this.getDescriptor().getTables();
484         } else {
485             return allTables;
486         }
487     }
488     
489     /**
490      * INTERNAL:
491      * Return all the immediate child descriptors. Only descriptors from
492      * direct subclasses are returned.
493      */

494     public Vector getChildDescriptors() {
495         return childDescriptors;
496     }
497
498     /**
499      * INTERNAL:
500      * Return all the classExtractionMethod
501      */

502     protected Method getClassExtractionMethod() {
503         if (classExtractor instanceof MethodClassExtractor) {
504             return ((MethodClassExtractor)classExtractor).getClassExtractionMethod();
505         } else {
506             return null;
507         }
508     }
509
510     /**
511      * ADVANCED:
512      * A class extraction method can be registered with the descriptor to override the default inheritance mechanism.
513      * This allows for the class indicator field to not be used, and a user defined one instead.
514      * The method registered must be a static method on the class that the descriptor is for,
515      * the method must take DatabaseRow as argument, and must return the class to use for that row.
516      * This method will be used to decide which class to instantiate when reading from the database.
517      * It is the application's responsiblity to populate any typing information in the database required
518      * to determine the class from the row.
519      * If this method is used then the class indicator field and mapping cannot be used,
520      * also the descriptor's withAllSubclasses and onlyInstances expressions must also be setup correctly.
521      *
522      * @see #setWithAllSubclassesExpression(Expression)
523      * @see #setOnlyInstancesExpression(Expression)
524      */

525     public String JavaDoc getClassExtractionMethodName() {
526         if (classExtractor instanceof MethodClassExtractor) {
527             return ((MethodClassExtractor)classExtractor).getClassExtractionMethodName();
528         } else {
529             return null;
530         }
531     }
532
533     /**
534      * ADVANCED:
535      * A class extractor can be registered with the descriptor to override the default inheritance mechanism.
536      * This allows for the class indicator field to not be used, and a user defined one instead.
537      * The instance registered must extend the ClassExtractor class and implement the extractClass(Map) method,
538      * the method must take database row (Map) as argument, and must return the class to use for that row.
539      * This method will be used to decide which class to instantiate when reading from the database.
540      * It is the application's responsiblity to populate any typing information in the database required
541      * to determine the class from the row, such as usage of a direct or transformation mapping for the type fields.
542      * If this method is used then the class indicator field and mapping cannot be used,
543      * also the descriptor's withAllSubclasses and onlyInstances expressions must also be setup correctly.
544      *
545      * @see #setWithAllSubclassesExpression(Expression)
546      * @see #setOnlyInstancesExpression(Expression)
547      */

548     public ClassExtractor getClassExtractor() {
549         return classExtractor;
550     }
551
552     /**
553      * ADVANCED:
554      * A class extractor can be registered with the descriptor to override the default inheritance mechanism.
555      * This allows for the class indicator field to not be used, and a user defined one instead.
556      * The instance registered must extend the ClassExtractor class and implement the extractClass(Map) method,
557      * the method must take database row (Map) as argument, and must return the class to use for that row.
558      * This method will be used to decide which class to instantiate when reading from the database.
559      * It is the application's responsiblity to populate any typing information in the database required
560      * to determine the class from the row, such as usage of a direct or transformation mapping for the type fields.
561      * If this method is used then the class indicator field and mapping cannot be used,
562      * also the descriptor's withAllSubclasses and onlyInstances expressions must also be setup correctly.
563      *
564      * @see #setWithAllSubclassesExpression(Expression)
565      * @see #setOnlyInstancesExpression(Expression)
566      */

567     public void setClassExtractor(ClassExtractor classExtractor) {
568         this.classExtractor = classExtractor;
569     }
570
571     /**
572      * INTERNAL:
573      * Return the class indicator associations for XML.
574      * List of class-name/value associations.
575      */

576     public Vector getClassIndicatorAssociations() {
577         Vector associations = new Vector(getClassNameIndicatorMapping().size() / 2);
578          Iterator classesEnum = getClassNameIndicatorMapping().keySet().iterator();
579          Iterator valuesEnum = getClassNameIndicatorMapping().values().iterator();
580          while (classesEnum.hasNext()) {
581              Object JavaDoc className = classesEnum.next();
582
583             // If the project was built in runtime is a class, MW is a string.
584
if (className instanceof Class JavaDoc) {
585                 className = ((Class JavaDoc)className).getName();
586             }
587              Object JavaDoc value = valuesEnum.next();
588             associations.addElement(new TypedAssociation(className, value));
589         }
590
591         return associations;
592     }
593
594     /**
595      * INTERNAL:
596      * Returns field that the class type indicator is store when using inheritence.
597      */

598     public DatabaseField getClassIndicatorField() {
599         return classIndicatorField;
600     }
601
602     /**
603      * PUBLIC:
604      * Return the class indicator field name.
605      * This is the name of the field in the table that stores what type of object this is.
606      */

607     public String JavaDoc getClassIndicatorFieldName() {
608         if (getClassIndicatorField() == null) {
609             return null;
610         } else {
611             return getClassIndicatorField().getQualifiedName();
612         }
613     }
614
615     /**
616      * INTERNAL:
617      * Return the association of indicators and classes
618      */

619      public Map getClassIndicatorMapping() {
620         return getClassIndicatorMapping(ConversionManager.getDefaultManager());
621     }
622     
623     /**
624      * INTERNAL:
625      * Return the association of indicators and classes using specified ConversionManager
626      */

627     public Map getClassIndicatorMapping(ConversionManager conversionManager) {
628         if (classIndicatorMapping.isEmpty() && !classNameIndicatorMapping.isEmpty()) {
629              Iterator keysEnum = classNameIndicatorMapping.keySet().iterator();
630              Iterator valuesEnum = classNameIndicatorMapping.values().iterator();
631              while (keysEnum.hasNext()) {
632                  Object JavaDoc key = keysEnum.next();
633                  Object JavaDoc value = valuesEnum.next();
634                 Class JavaDoc theClass = (Class JavaDoc)conversionManager.convertObject((String JavaDoc)key, ClassConstants.CLASS);
635                 classIndicatorMapping.put(theClass, value);
636                 classIndicatorMapping.put(value, theClass);
637             }
638         }
639         return classIndicatorMapping;
640     }
641
642     /**
643      * INTERNAL:
644      * Return the mapping from class name to indicator, used by MW.
645      */

646      public Map getClassNameIndicatorMapping() {
647         if (classNameIndicatorMapping.isEmpty() && !classIndicatorMapping.isEmpty()) {
648              Iterator keysEnum = classIndicatorMapping.keySet().iterator();
649              Iterator valuesEnum = classIndicatorMapping.values().iterator();
650              while (keysEnum.hasNext()) {
651                  Object JavaDoc key = keysEnum.next();
652                  Object JavaDoc value = valuesEnum.next();
653                 if (key instanceof Class JavaDoc) {
654                     String JavaDoc className = ((Class JavaDoc)key).getName();
655                     classNameIndicatorMapping.put(className, value);
656                 }
657             }
658         }
659
660         return classNameIndicatorMapping;
661     }
662
663     /**
664      * INTERNAL:
665      * Returns value of the abstract class indicator for the Java class.
666      */

667     protected Object JavaDoc getClassIndicatorValue() {
668         return getClassIndicatorValue(getDescriptor().getJavaClass());
669     }
670
671     /**
672      * INTERNAL:
673      * Returns the indicator field value for the given class
674      * If no abstract indicator mapping is specified, use the class name.
675      */

676     protected Object JavaDoc getClassIndicatorValue(Class JavaDoc javaClass) {
677         if (shouldUseClassNameAsIndicator()) {
678             return javaClass.getName();
679         } else {
680             return getClassIndicatorMapping().get(javaClass);
681         }
682     }
683
684     /**
685      * INTERNAL:
686      * Returns the descriptor which the policy belongs to.
687      */

688     public ClassDescriptor getDescriptor() {
689         return descriptor;
690     }
691
692     /**
693      * ADVANCED:
694      * Return the 'only instances expression'.
695      */

696     public Expression getOnlyInstancesExpression() {
697         return onlyInstancesExpression;
698     }
699
700     /**
701      * PUBLIC:
702      * Return the parent class.
703      */

704     public Class JavaDoc getParentClass() {
705         return parentClass;
706     }
707
708     /**
709      * INTERNAL:
710      * Return the parent class name.
711      */

712     public String JavaDoc getParentClassName() {
713         if ((parentClassName == null) && (parentClass != null)) {
714             parentClassName = parentClass.getName();
715         }
716         return parentClassName;
717     }
718
719     /**
720      * INTERNAL:
721      * Return the parent descirptor
722      */

723     public ClassDescriptor getParentDescriptor() {
724         return parentDescriptor;
725     }
726
727     /**
728      * INTERNAL:
729      * The view can be used to optimize/customize the query for all subclasses where they have multiple tables.
730      * This view can do the outer join, we require the view because we cannot generate dynmic platform independent SQL
731      * for outer joins (i.e. not possible to do so either).
732      */

733     public DatabaseTable getReadAllSubclassesView() {
734         return readAllSubclassesView;
735     }
736
737     /**
738      * ADVANCED:
739      * The view can be used to optimize/customize the query for all subclasses where they have multiple tables.
740      * This view can use outer joins or unions to combine the results of selecting from all of the subclass tables.
741      * If a view is not given then TopLink must make an individual call for each subclass.
742      */

743     public String JavaDoc getReadAllSubclassesViewName() {
744         if (getReadAllSubclassesView() == null) {
745             return null;
746         }
747         return getReadAllSubclassesView().getName();
748     }
749
750     /**
751      * INTERNAL:
752      * Return the root parent descriptor
753      */

754     public ClassDescriptor getRootParentDescriptor() {
755         if (isRootParentDescriptor()) {
756             return getDescriptor();
757         } else {
758             return getParentDescriptor().getInheritancePolicy().getRootParentDescriptor();
759         }
760     }
761
762     /**
763      * INTERNAL:
764      * use aggregate in inheritance
765      */

766     public ClassDescriptor getSubclassDescriptor(Class JavaDoc theClass) {
767         if (hasChildren()) {
768             for (Iterator enumtr = getChildDescriptors().iterator(); enumtr.hasNext();) {
769                 ClassDescriptor childDescriptor = (ClassDescriptor)enumtr.next();
770                 if (childDescriptor.getJavaClass().equals(theClass)) {
771                     return childDescriptor;
772                 } else {
773                     ClassDescriptor descriptor = childDescriptor.getInheritancePolicy().getSubclassDescriptor(theClass);
774                     if (descriptor != null) {
775                         return descriptor;
776                     }
777                 }
778             }
779         }
780         return null;
781     }
782
783     /**
784      * INTERNAL:
785      * return if we should use the descriptor inheritance to determine
786      * if an object can be returned from the identity map or not.
787      */

788     public boolean getUseDescriptorsToValidateInheritedObjects() {
789         return useDescriptorsToValidateInheritedObjects;
790     }
791
792     /**
793      * ADVANCED:
794      * Return the Expression which gets all subclasses.
795      */

796     public Expression getWithAllSubclassesExpression() {
797         return withAllSubclassesExpression;
798     }
799
800     /**
801      * INTERNAL:
802      * Check if descriptor has children
803      */

804     public boolean hasChildren() {
805         return !getChildDescriptors().isEmpty();
806     }
807
808     /**
809      * INTERNAL:
810      */

811     public boolean hasClassExtractor() {
812         return getClassExtractor() != null;
813     }
814
815     /**
816      * INTERNAL:
817      * Checks if the class is invloved in inheritence
818      */

819     public boolean hasClassIndicator() {
820         return getClassIndicatorField() != null;
821     }
822
823     /**
824      * INTERNAL:
825      * Return if any children of this descriptor require information from another table
826      * not specified at the parent level.
827      */

828     public boolean hasMultipleTableChild() {
829         return childrenTables != null;
830     }
831
832     /**
833      * INTERNAL:
834      * Return if a view is used for inheritance reads.
835      */

836     public boolean hasView() {
837         return getReadAllSubclassesView() != null;
838     }
839
840     /**
841      * INTERNAL:
842      * Initialized the inheritence properties of the descriptor once the mappings are initialized.
843      * This is done before formal postInitialize during the end of mapping initialize.
844      */

845     public void initialize(AbstractSession session) {
846         // Must reset this in the case that a child thinks it wants to read its subclasses.
847
if ((shouldReadSubclasses == null) || shouldReadSubclasses()) {
848             setShouldReadSubclasses(!getChildDescriptors().isEmpty());
849         }
850
851         if (isChildDescriptor()) {
852             getDescriptor().setMappings(Helper.concatenateVectors(getParentDescriptor().getMappings(), getDescriptor().getMappings()));
853              getDescriptor().setQueryKeys(Helper.concatenateMaps(getParentDescriptor().getQueryKeys(), getDescriptor().getQueryKeys()));
854             addFieldsToParent(getDescriptor().getFields());
855             // Parents fields must be first for indexing to work.
856
Vector parentsFields = (Vector)getParentDescriptor().getFields().clone();
857
858             //bug fix on Oracle duplicate field SQL using "order by"
859
Helper.addAllUniqueToVector(parentsFields, getDescriptor().getFields());
860             getDescriptor().setFields(parentsFields);
861
862             if (getClassIndicatorValue() != null) {
863                 if (shouldReadSubclasses()) {
864                     getAllChildClassIndicators().addElement(getClassIndicatorValue());
865                 }
866                 addClassIndicatorTypeToParent(getClassIndicatorValue());
867             }
868
869             // CR#3214106, do not override if specified in subclass.
870
if (!getDescriptor().usesOptimisticLocking() && getParentDescriptor().usesOptimisticLocking()) {
871                 getDescriptor().setOptimisticLockingPolicy((OptimisticLockingPolicy)getParentDescriptor().getOptimisticLockingPolicy().clone());
872                 getDescriptor().getOptimisticLockingPolicy().setDescriptor(getDescriptor());
873             }
874
875             // create CMPPolicy on child if parent has one and it does not. Then copy individual fields
876
CMPPolicy parentCMPPolicy = getDescriptor().getInheritancePolicy().getParentDescriptor().getCMPPolicy();
877             if (parentCMPPolicy != null) {
878                 CMPPolicy cmpPolicy = getDescriptor().getCMPPolicy();
879                 if (cmpPolicy == null) {
880                     cmpPolicy = new CMPPolicy();
881                     getDescriptor().setCMPPolicy(cmpPolicy);
882                 }
883             }
884         }
885
886         initializeOnlyInstancesExpression();
887         initializeWithAllSubclassesExpression();
888     }
889
890     /**
891      * INTERNAL:
892      * Setup the default classExtractionMethod, or if one was specified by the user make sure it is valid.
893      */

894     protected void initializeClassExtractor(AbstractSession session) throws DescriptorException {
895         if (getClassExtractor() == null) {
896             if (isChildDescriptor()) {
897                 setClassExtractor(getParentDescriptor().getInheritancePolicy().getClassExtractor());
898             }
899         } else {
900             getClassExtractor().initialize(getDescriptor(), session);
901         }
902     }
903
904     /**
905      * INTERNAL:
906      * Initialize the expression to use to check the specific type field.
907      */

908     protected void initializeOnlyInstancesExpression() throws DescriptorException {
909         if (getOnlyInstancesExpression() == null) {
910             if (hasClassExtractor()) {
911                 return;
912             }
913             Object JavaDoc typeValue = getClassIndicatorValue();
914             if (typeValue == null) {
915                 if (shouldReadSubclasses()) {
916                     return;// No indicator is allowed in this case.
917
}
918
919                 throw DescriptorException.valueNotFoundInClassIndicatorMapping(getParentDescriptor(), getDescriptor());
920             }
921
922             DatabaseField typeField = getClassIndicatorField();
923             if (typeField == null) {
924                 throw DescriptorException.classIndicatorFieldNotFound(getParentDescriptor(), getDescriptor());
925             }
926
927             // cr3546
928
if (shouldAlwaysUseOuterJoin()) {
929                 setOnlyInstancesExpression(new ExpressionBuilder().getField(typeField).equalOuterJoin(typeValue));
930             } else {
931                 setOnlyInstancesExpression(new ExpressionBuilder().getField(typeField).equal(typeValue));
932             }
933         }
934
935         // If subclasses are read, this is anded dynamically.
936
if (!shouldReadSubclasses()) {
937             getDescriptor().getQueryManager().setAdditionalJoinExpression(getOnlyInstancesExpression().and(getDescriptor().getQueryManager().getAdditionalJoinExpression()));
938         }
939     }
940
941     /**
942      * INTERNAL:
943      * Initialize the expression to use for queries to the class and its subclasses.
944      */

945     protected void initializeWithAllSubclassesExpression() throws DescriptorException {
946         if (getWithAllSubclassesExpression() == null) {
947             if (hasClassExtractor()) {
948                 return;
949             }
950             if (isChildDescriptor() && shouldReadSubclasses()) {
951                 setWithAllSubclassesExpression(new ExpressionBuilder().getField(getClassIndicatorField()).in(getAllChildClassIndicators()));
952             }
953         }
954     }
955
956     /**
957      * INTERNAL:
958      * Check if it is a child descriptor.
959      */

960     public boolean isChildDescriptor() {
961         return getParentClassName() != null;
962     }
963     
964     /**
965      * INTERNAL:
966      * Indicate whether a single table or joined inheritance strategy is being used. Since we currently do
967      * not support TABLE_PER_CLASS, indicating either joined/not joined is sufficient.
968      *
969      * @return isJoinedStrategy value
970      */

971     public boolean isJoinedStrategy() {
972         return isJoinedStrategy;
973     }
974     
975     /**
976      * INTERNAL:
977      * Return whether or not is root parent descriptor
978      */

979     public boolean isRootParentDescriptor() {
980         return getParentDescriptor() == null;
981     }
982
983     /**
984      * INTERNAL:
985      * Initialized the inheritence properties that cannot be initialized
986      * unitl after the mappings have been.
987      */

988     public void postInitialize(AbstractSession session) {
989     }
990
991     /**
992      * INTERNAL:
993      * Allow the inheritence properties of the descriptor to be initialized.
994      * The descriptor's parent must first be initialized.
995      */

996     public void preInitialize(AbstractSession session) throws DescriptorException {
997         // Make sure that parent is already preinitialized.
998
if (isChildDescriptor()) {
999             // Unique is required because the builder can add the same table many times.
1000
// This is done after init properties to make sure the default table is the first local one.
1001
getDescriptor().setTables(Helper.concatenateUniqueVectors((Vector)getParentDescriptor().getTables(), getDescriptor().getTables()));
1002
1003            setClassIndicatorMapping(getParentDescriptor().getInheritancePolicy().getClassIndicatorMapping(session.getDatasourcePlatform().getConversionManager()));
1004            setShouldUseClassNameAsIndicator(getParentDescriptor().getInheritancePolicy().shouldUseClassNameAsIndicator());
1005
1006            // Initialize properties.
1007
getDescriptor().setPrimaryKeyFields(getParentDescriptor().getPrimaryKeyFields());
1008             getDescriptor().setAdditionalTablePrimaryKeyFields(Helper.concatenateMaps(getParentDescriptor().getAdditionalTablePrimaryKeyFields(), getDescriptor().getAdditionalTablePrimaryKeyFields()));
1009
1010            Expression localExpression = getDescriptor().getQueryManager().getMultipleTableJoinExpression();
1011            Expression parentExpression = getParentDescriptor().getQueryManager().getMultipleTableJoinExpression();
1012
1013            if (localExpression != null) {
1014                getDescriptor().getQueryManager().setInternalMultipleTableJoinExpression(localExpression.and(parentExpression));
1015            } else if (parentExpression != null) {
1016                getDescriptor().getQueryManager().setInternalMultipleTableJoinExpression(parentExpression);
1017            }
1018
1019            Expression localAdditionalExpression = getDescriptor().getQueryManager().getAdditionalJoinExpression();
1020            Expression parentAdditionalExpression = getParentDescriptor().getQueryManager().getAdditionalJoinExpression();
1021
1022            if (localAdditionalExpression != null) {
1023                getDescriptor().getQueryManager().setAdditionalJoinExpression(localAdditionalExpression.and(parentAdditionalExpression));
1024            } else if (parentAdditionalExpression != null) {
1025                getDescriptor().getQueryManager().setAdditionalJoinExpression(parentAdditionalExpression);
1026            }
1027
1028            setClassIndicatorField(getParentDescriptor().getInheritancePolicy().getClassIndicatorField());
1029
1030            //if child has sequencing setting, do not bother to call the parent
1031
if (!getDescriptor().usesSequenceNumbers()) {
1032                getDescriptor().setSequenceNumberField(getParentDescriptor().getSequenceNumberField());
1033                getDescriptor().setSequenceNumberName(getParentDescriptor().getSequenceNumberName());
1034            }
1035        }
1036
1037        initializeClassExtractor(session);
1038
1039        if (!isChildDescriptor()) {
1040            // build abstract class indicator field.
1041
if ((getClassIndicatorField() == null) && (!hasClassExtractor())) {
1042                session.getIntegrityChecker().handleError(DescriptorException.classIndicatorFieldNotFound(getDescriptor(), getDescriptor()));
1043            }
1044            if (getClassIndicatorField() != null) {
1045                getDescriptor().buildField(getClassIndicatorField());
1046                // Determine and set the class indicator classification.
1047
if (shouldUseClassNameAsIndicator()) {
1048                    getClassIndicatorField().setType(ClassConstants.STRING);
1049                } else if (!getClassIndicatorMapping(session.getDatasourcePlatform().getConversionManager()).isEmpty()) {
1050                    Class JavaDoc type = null;
1051                    Iterator fieldValuesEnum = getClassIndicatorMapping(session.getDatasourcePlatform().getConversionManager()).values().iterator();
1052                     while (fieldValuesEnum.hasNext() && (type == null)) {
1053                         Object JavaDoc value = fieldValuesEnum.next();
1054                        if (value.getClass() != getClass().getClass()) {
1055                            type = value.getClass();
1056                        }
1057                    }
1058                    getClassIndicatorField().setType(type);
1059                }
1060                getDescriptor().getFields().addElement(getClassIndicatorField());
1061            }
1062        }
1063    }
1064
1065    /**
1066     * PUBLIC:
1067     * Set the descriptor to read instance of itself and its subclasses when queried.
1068     * This is used with inheritance to configure the result of queries.
1069     * By default this is true for root inheritance descriptors, and false for all others.
1070     */

1071    public void readSubclassesOnQueries() {
1072        setShouldReadSubclasses(true);
1073    }
1074
1075    /**
1076     * INTERNAL:
1077     * Return if this descriptor has children that define additional tables and needs to read them.
1078     * This case requires a special read, because the query cannot be done through a single SQL call with normal joins.
1079     */

1080    public boolean requiresMultipleTableSubclassRead() {
1081        return hasMultipleTableChild() && shouldReadSubclasses();
1082    }
1083
1084    /**
1085     * INTERNAL:
1086     * Select all rows from a abstract table descriptor.
1087     * This is accomplished by selecting for all of the concrete classes and then merging the rows.
1088     * This does not optimize using type select, as the type infomation is not known.
1089     * @return vector containing database rows.
1090     * @exception DatabaseException - an error has occurred on the database.
1091     */

1092    protected Vector selectAllRowUsingCustomMultipleTableSubclassRead(ReadAllQuery query) throws DatabaseException {
1093        Vector rows = new Vector();
1094        // CR#3701077, it must either have a filter only instances expression, or not have subclasses.
1095
// This method recurses, so even though this is only called when shouldReadSubclasses is true, it may be false for subclasses.
1096
if ((getOnlyInstancesExpression() != null) || (! shouldReadSubclasses())) {
1097            ReadAllQuery concreteQuery = (ReadAllQuery)query.clone();
1098            concreteQuery.setReferenceClass(getDescriptor().getJavaClass());
1099            concreteQuery.setDescriptor(getDescriptor());
1100
1101            Vector concreteRows = ((ExpressionQueryMechanism)concreteQuery.getQueryMechanism()).selectAllRowsFromConcreteTable();
1102            rows = Helper.concatenateVectors(rows, concreteRows);
1103        }
1104
1105        // Recursively collect all rows from all concrete children and their children.
1106
for (Enumeration childrenEnum = getChildDescriptors().elements();
1107                 childrenEnum.hasMoreElements();) {
1108            ClassDescriptor concreteDescriptor = (ClassDescriptor)childrenEnum.nextElement();
1109            Vector concreteRows = concreteDescriptor.getInheritancePolicy().selectAllRowUsingCustomMultipleTableSubclassRead(query);
1110            rows = Helper.concatenateVectors(rows, concreteRows);
1111        }
1112
1113        return rows;
1114    }
1115
1116    /**
1117     * INTERNAL:
1118     * Select all rows from a abstract table descriptor.
1119     * This is accomplished by selecting for all of the concrete classes and then merging the rows.
1120     * @return vector containing database rows.
1121     * @exception DatabaseException - an error has occurred on the database.
1122     */

1123    protected Vector selectAllRowUsingDefaultMultipleTableSubclassRead(ReadAllQuery query) throws DatabaseException, QueryException {
1124        // Get all rows for the given class indicator field
1125
// The indicator select is prepared in the original query, so can just be executed.
1126
Vector classIndicators = ((ExpressionQueryMechanism)query.getQueryMechanism()).selectAllRowsFromTable();
1127
1128        Vector classes = new Vector();
1129        for (Enumeration rowsEnum = classIndicators.elements(); rowsEnum.hasMoreElements();) {
1130            AbstractRecord row = (AbstractRecord)rowsEnum.nextElement();
1131            Class JavaDoc concreteClass = classFromRow(row, query.getSession());
1132            if (!classes.contains(concreteClass)) {//Ensure unique ** we should do a distinct.. we do
1133
classes.addElement(concreteClass);
1134            }
1135        }
1136
1137        Vector rows = new Vector();
1138        // joinedMappingIndexes contains Integer indexes corrsponding to the number of fields
1139
// to which the query rference class is mapped, for instance:
1140
// referenceClass = SmallProject => joinedMappingIndexes(0) = 6;
1141
// referenceClass = LargeProject => joinedMappingIndexes(0) = 8;
1142
// This information should be preserved in the main query against the parent class,
1143
// therefore in this case joinedMappedIndexes contains a Map of classes to Integers:
1144
// referenceClass = Project => joinedMappingIndexes(0) = Map {SmallProject -> 6; LargeProject -> 8}.
1145
// These maps are populated in the loop below, and set into the main query joinedMappingIndexes.
1146
HashMap joinedMappingIndexes = null;
1147        if(query.getJoinedAttributeManager().hasJoinedAttributes()) {
1148            joinedMappingIndexes = new HashMap();
1149        }
1150        for (Enumeration classesEnum = classes.elements(); classesEnum.hasMoreElements();) {
1151            Class JavaDoc concreteClass = (Class JavaDoc)classesEnum.nextElement();
1152            ClassDescriptor concreteDescriptor = query.getSession().getDescriptor(concreteClass);
1153            if (concreteDescriptor == null) {
1154                throw QueryException.noDescriptorForClassFromInheritancePolicy(query, concreteClass);
1155            }
1156            ReadAllQuery concreteQuery = (ReadAllQuery)query.clone();
1157            concreteQuery.setReferenceClass(concreteClass);
1158            concreteQuery.setDescriptor(concreteDescriptor);
1159
1160            Vector concreteRows = ((ExpressionQueryMechanism)concreteQuery.getQueryMechanism()).selectAllRowsFromConcreteTable();
1161            rows = Helper.concatenateVectors(rows, concreteRows);
1162            
1163            if(joinedMappingIndexes != null) {
1164                Iterator it = concreteQuery.getJoinedAttributeManager().getJoinedMappingIndexes_().entrySet().iterator();
1165                while(it.hasNext()) {
1166                    Map.Entry entry = (Map.Entry)it.next();
1167                    HashMap map = (HashMap)joinedMappingIndexes.get(entry.getKey());
1168                    if(map == null) {
1169                        map = new HashMap(classes.size());
1170                        joinedMappingIndexes.put(entry.getKey(), map);
1171                    }
1172                    map.put(concreteClass, entry.getValue());
1173                }
1174            }
1175        }
1176        if(joinedMappingIndexes != null) {
1177            query.getJoinedAttributeManager().setJoinedMappingIndexes_(joinedMappingIndexes);
1178        }
1179
1180        return rows;
1181    }
1182
1183    /**
1184     * INTERNAL:
1185     * Select all rows from a abstract table descriptor.
1186     * This is accomplished by selecting for all of the concrete classes and then merging the rows.
1187     * @return vector containing database rows.
1188     * @exception DatabaseException - an error has occurred on the database.
1189     */

1190    public Vector selectAllRowUsingMultipleTableSubclassRead(ReadAllQuery query) throws DatabaseException {
1191        if (hasClassExtractor()) {
1192            return selectAllRowUsingCustomMultipleTableSubclassRead(query);
1193        } else {
1194            return selectAllRowUsingDefaultMultipleTableSubclassRead(query);
1195        }
1196    }
1197
1198    /**
1199     * INTERNAL:
1200     * Select one rows from a abstract table descriptor.
1201     * This is accomplished by selecting for all of the concrete classes until a row is found.
1202     * This does not optimize using type select, as the type infomation is not known.
1203     * @exception DatabaseException - an error has occurred on the database.
1204     */

1205    protected AbstractRecord selectOneRowUsingCustomMultipleTableSubclassRead(ReadObjectQuery query) throws DatabaseException {
1206        // CR#3701077, it must either have a filter only instances expression, or not have subclasses.
1207
// This method recurses, so even though this is only called when shouldReadSubclasses is true, it may be false for subclasses.
1208
if ((getOnlyInstancesExpression() != null) || (! shouldReadSubclasses())) {
1209            ReadObjectQuery concreteQuery = (ReadObjectQuery)query.clone();
1210            concreteQuery.setReferenceClass(getDescriptor().getJavaClass());
1211            concreteQuery.setDescriptor(getDescriptor());
1212
1213            AbstractRecord row = ((ExpressionQueryMechanism)concreteQuery.getQueryMechanism()).selectOneRowFromConcreteTable();
1214
1215            if (row != null) {
1216                return row;
1217            }
1218        }
1219
1220        // Recursively collect all rows from all concrete children and their children.
1221
for (Enumeration childrenEnum = getChildDescriptors().elements();
1222                 childrenEnum.hasMoreElements();) {
1223            ClassDescriptor concreteDescriptor = (ClassDescriptor)childrenEnum.nextElement();
1224            AbstractRecord row = concreteDescriptor.getInheritancePolicy().selectOneRowUsingCustomMultipleTableSubclassRead(query);
1225
1226            if (row != null) {
1227                return row;
1228            }
1229        }
1230
1231        return null;
1232    }
1233
1234    /**
1235     * INTERNAL:
1236     * Select one row of any concrete subclass,
1237     * This must use two selects, the first retreives the type field only.
1238     */

1239    protected AbstractRecord selectOneRowUsingDefaultMultipleTableSubclassRead(ReadObjectQuery query) throws DatabaseException, QueryException {
1240        // Get the row for the given class indicator field
1241
// The indicator select is prepared in the original query, so can just be executed.
1242
AbstractRecord typeRow = ((ExpressionQueryMechanism)query.getQueryMechanism()).selectOneRowFromTable();
1243
1244        if (typeRow == null) {
1245            return null;
1246        }
1247
1248        Class JavaDoc concreteClass = classFromRow(typeRow, query.getSession());
1249        ClassDescriptor concreteDescriptor = query.getSession().getDescriptor(concreteClass);
1250        if (concreteDescriptor == null) {
1251            throw QueryException.noDescriptorForClassFromInheritancePolicy(query, concreteClass);
1252        }
1253
1254        ReadObjectQuery concreteQuery = (ReadObjectQuery)query.clone();
1255        concreteQuery.setReferenceClass(concreteClass);
1256        concreteQuery.setDescriptor(concreteDescriptor);
1257
1258        AbstractRecord resultRow = ((ExpressionQueryMechanism)concreteQuery.getQueryMechanism()).selectOneRowFromConcreteTable();
1259
1260        return resultRow;
1261    }
1262
1263    /**
1264     * INTERNAL:
1265     * Select one row of any concrete subclass,
1266     * This must use two selects, the first retreives the type field only.
1267     */

1268    public AbstractRecord selectOneRowUsingMultipleTableSubclassRead(ReadObjectQuery query) throws DatabaseException, QueryException {
1269        if (hasClassExtractor()) {
1270            return selectOneRowUsingCustomMultipleTableSubclassRead(query);
1271        } else {
1272            return selectOneRowUsingDefaultMultipleTableSubclassRead(query);
1273        }
1274    }
1275
1276    /**
1277     * INTERNAL:
1278     */

1279    protected void setAllChildClassIndicators(Vector allChildClassIndicators) {
1280        this.allChildClassIndicators = allChildClassIndicators;
1281    }
1282
1283    /**
1284     * INTERNAL:
1285     */

1286    public void setChildDescriptors(Vector theChildDescriptors) {
1287        childDescriptors = theChildDescriptors;
1288    }
1289
1290    /**
1291     * ADVANCED:
1292     * A class extraction method can be registered with the descriptor to override the default inheritance mechanism.
1293     * This allows for the class indicator field to not be used, and a user defined one instead.
1294     * The method registered must be a static method on the class that the descriptor is for,
1295     * the method must take DatabaseRow as argument, and must return the class to use for that row.
1296     * This method will be used to decide which class to instantiate when reading from the database.
1297     * It is the application's responsiblity to populate any typing information in the database required
1298     * to determine the class from the row.
1299     * If this method is used then the class indicator field and mapping cannot be used,
1300     * also the descriptor's withAllSubclasses and onlyInstances expressions must also be setup correctly.
1301     *
1302     * @see #setWithAllSubclassesExpression(Expression)
1303     * @see #setOnlyInstancesExpression(Expression)
1304     */

1305    public void setClassExtractionMethodName(String JavaDoc staticClassClassExtractionMethod) {
1306        if ((staticClassClassExtractionMethod == null) || (staticClassClassExtractionMethod.length() == 0)) {
1307            return;
1308        }
1309        if (!(getClassExtractor() instanceof MethodClassExtractor)) {
1310            setClassExtractor(new MethodClassExtractor());
1311        }
1312        ((MethodClassExtractor)getClassExtractor()).setClassExtractionMethodName(staticClassClassExtractionMethod);
1313    }
1314
1315    /**
1316     * INTERNAL:
1317     * Set the class indicator associations from reading the deployment XML.
1318     */

1319    public void setClassIndicatorAssociations(Vector classIndicatorAssociations) {
1320         setClassNameIndicatorMapping(new HashMap(classIndicatorAssociations.size() + 1));
1321         setClassIndicatorMapping(new HashMap((classIndicatorAssociations.size() * 2) + 1));
1322        for (Enumeration associationsEnum = classIndicatorAssociations.elements();
1323                 associationsEnum.hasMoreElements();) {
1324            Association association = (Association)associationsEnum.nextElement();
1325            Object JavaDoc classValue = association.getKey();
1326            if (classValue instanceof Class JavaDoc) {
1327                // 904 projects will be a class type.
1328
addClassIndicator((Class JavaDoc)association.getKey(), association.getValue());
1329            } else {
1330                addClassNameIndicator((String JavaDoc)association.getKey(), association.getValue());
1331            }
1332        }
1333    }
1334
1335    /**
1336     * ADVANCED:
1337     * To set the class indicator field.
1338     * This can be used for advanced field types, such as XML nodes, or to set the field type.
1339     */

1340    public void setClassIndicatorField(DatabaseField classIndicatorField) {
1341        this.classIndicatorField = classIndicatorField;
1342    }
1343
1344    /**
1345     * PUBLIC:
1346     * To set the class indicator field name.
1347     * This is the name of the field in the table that stores what type of object this is.
1348     */

1349    public void setClassIndicatorFieldName(String JavaDoc fieldName) {
1350        if (fieldName == null) {
1351            setClassIndicatorField(null);
1352        } else {
1353            setClassIndicatorField(new DatabaseField(fieldName));
1354        }
1355    }
1356
1357    /**
1358     * PUBLIC:
1359     * Set the association of indicators and classes.
1360     * This may be desired to be used by clients in strange inheritence models.
1361     */

1362     public void setClassIndicatorMapping(Map classIndicatorMapping) {
1363        this.classIndicatorMapping = classIndicatorMapping;
1364    }
1365
1366    /**
1367     * INTERNAL:
1368     * Set the class name indicator mapping, used by the MW.
1369     */

1370     public void setClassNameIndicatorMapping(Map classNameIndicatorMapping) {
1371        this.classNameIndicatorMapping = classNameIndicatorMapping;
1372    }
1373
1374    /**
1375     * INTERNAL:
1376     * Set the descriptor.
1377     */

1378    public void setDescriptor(ClassDescriptor descriptor) {
1379        this.descriptor = descriptor;
1380    }
1381
1382    /**
1383     * INTERNAL:
1384     * Used to indicate a JOINED inheritance strategy.
1385     *
1386     */

1387    public void setJoinedStrategy() {
1388        isJoinedStrategy = true;
1389    }
1390    
1391    /**
1392     * ADVANCED:
1393     * Sets the expression used to select instance of the class only. Can be used to customize the
1394     * inheritance class indicator expression.
1395     */

1396    public void setOnlyInstancesExpression(Expression onlyInstancesExpression) {
1397        this.onlyInstancesExpression = onlyInstancesExpression;
1398    }
1399
1400    /**
1401     * PUBLIC:
1402     * Set the parent class.
1403     * A descriptor can inherit from another descriptor through defining it as its parent.
1404     * The root descriptor must define a class indicator field and mapping.
1405     * All children must share the same table as their parent but can add additional tables.
1406     * All children must share the root descriptor primary key.
1407     */

1408    public void setParentClass(Class JavaDoc parentClass) {
1409        this.parentClass = parentClass;
1410        if (parentClass != null) {
1411            setParentClassName(parentClass.getName());
1412        }
1413    }
1414
1415    /**
1416     * INTERNAL:
1417     * Set the parent class name, used by MW to avoid referencing the real class for
1418     * deployment XML generation.
1419     */

1420    public void setParentClassName(String JavaDoc parentClassName) {
1421        this.parentClassName = parentClassName;
1422    }
1423
1424    /**
1425     * INTERNAL:
1426     */

1427    public void setParentDescriptor(ClassDescriptor parentDescriptor) {
1428        this.parentDescriptor = parentDescriptor;
1429    }
1430
1431    /**
1432     * INTERNAL:
1433     * The view can be used to optimize/customize the query for all subclasses where they have multiple tables.
1434     * This view can do the outer join, we require the view because we cannot generate dynmic platform independent SQL
1435     * for outer joins (i.e. not possible to do so either).
1436     */

1437    protected void setReadAllSubclassesView(DatabaseTable readAllSubclassesView) {
1438        this.readAllSubclassesView = readAllSubclassesView;
1439    }
1440
1441    /**
1442     * ADVANCED:
1443     * The view can be used to optimize/customize the query for all subclasses where they have multiple tables.
1444     * This view can use outer joins or unions to combine the results of selecting from all of the subclass tables.
1445     * If a view is not given then TopLink must make an individual call for each subclass.
1446     */

1447    public void setReadAllSubclassesViewName(String JavaDoc readAllSubclassesViewName) {
1448        if (readAllSubclassesViewName == null) {
1449            setReadAllSubclassesView(null);
1450        } else {
1451            setReadAllSubclassesView(new DatabaseTable(readAllSubclassesViewName));
1452        }
1453    }
1454
1455    /**
1456     * INTERNAL:
1457     * Set the descriptor to read instance of itself and its subclasses when queried.
1458     * This is used with inheritence to configure the result of queries.
1459     * By default this is true for root inheritence descriptors, and false for all others.
1460     */

1461    public void setShouldReadSubclasses(Boolean JavaDoc shouldReadSubclasses) {
1462        this.shouldReadSubclasses = shouldReadSubclasses;
1463    }
1464
1465    /**
1466     * PUBLIC:
1467     * Set the descriptor to read instance of itself and its subclasses when queried.
1468     * This is used with inheritence to configure the result of queries.
1469     * By default this is true for root inheritence descriptors, and false for all others.
1470     */

1471    public void setShouldReadSubclasses(boolean shouldReadSubclasses) {
1472        this.shouldReadSubclasses = Boolean.valueOf(shouldReadSubclasses);
1473    }
1474
1475    /**
1476     * PUBLIC:
1477     * Set if the descriptor uses the classes fully qualified name as the indicator.
1478     * The class indicator is used with inheritence to determine the class from a row.
1479     * By default a class indicator mapping is required, this can be set to true if usage of the class
1480     * name is desired.
1481     * The field must be of a large enough size to store the fully qualified class name.
1482     */

1483    public void setShouldUseClassNameAsIndicator(boolean shouldUseClassNameAsIndicator) {
1484        this.shouldUseClassNameAsIndicator = shouldUseClassNameAsIndicator;
1485    }
1486
1487    /**
1488     * PUBLIC:
1489     * Sets the inheritance policy to always use an outer join when quering across a relationship of class.
1490     * used when using getAllowingNull(), or anyOfAllowingNone()
1491     */

1492
1493    // cr3546
1494
public void setAlwaysUseOuterJoinForClassType(boolean choice) {
1495        this.shouldAlwaysUseOuterJoin = choice;
1496    }
1497
1498    /**
1499     * INTERNAL:
1500     * Used to indicate a SINGLE_TABLE inheritance strategy. Since only JOINED and SINGLE_TABLE
1501     * strategies are supported at this time (no support for TABLE_PER_CLASS) using a
1502     * !isJoinedStrategy an an indicator for SINGLE_TABLE is sufficient.
1503     *
1504     */

1505    public void setSingleTableStrategy() {
1506        isJoinedStrategy = false;
1507    }
1508
1509    /**
1510     * INTERNAL:
1511     * Sets if we should use the descriptor inheritance to determine
1512     * if an object can be returned from the identity map or not.
1513     */

1514    public void setUseDescriptorsToValidateInheritedObjects(boolean useDescriptorsToValidateInheritedObjects) {
1515        //CR 4005
1516
this.useDescriptorsToValidateInheritedObjects = useDescriptorsToValidateInheritedObjects;
1517    }
1518
1519    /**
1520     * ADVANCED:
1521     * Sets the expression to be used for querying for a class and all its subclasses. Can be used
1522     * to customize the inheritence class indicator expression.
1523     */

1524    public void setWithAllSubclassesExpression(Expression withAllSubclassesExpression) {
1525        this.withAllSubclassesExpression = withAllSubclassesExpression;
1526    }
1527
1528    /**
1529     * PUBLIC:
1530     * Return true if this descriptor should read instances of itself and subclasses on queries.
1531     */

1532    public boolean shouldReadSubclasses() {
1533        if (shouldReadSubclasses == null) {
1534            return true;
1535        }
1536        return shouldReadSubclasses.booleanValue();
1537    }
1538
1539    /**
1540     * INTERNAL:
1541     * Return true if this descriptor should read instances of itself and subclasses on queries.
1542     */

1543    public Boolean JavaDoc shouldReadSubclassesValue() {
1544        return shouldReadSubclasses;
1545    }
1546
1547    /**
1548     * PUBLIC:
1549     * returns if the inheritance policy will always use an outerjoin when selecting class type
1550     */

1551
1552    // cr3546
1553
public boolean shouldAlwaysUseOuterJoin() {
1554        return this.shouldAlwaysUseOuterJoin;
1555    }
1556
1557    /**
1558     * PUBLIC:
1559     * Return true if the descriptor use the classes full name as the indicator.
1560     * The class indicator is used with inheritance to determine the class from a row.
1561     * By default a class indicator mapping is required, this can be set to true if usage of the class
1562     * name is desired.
1563     * The field must be of a large enough size to store the fully qualified class name.
1564     */

1565    public boolean shouldUseClassNameAsIndicator() {
1566        return shouldUseClassNameAsIndicator;
1567    }
1568
1569    /**
1570     * INTERNAL:
1571     */

1572    public String JavaDoc toString() {
1573        return Helper.getShortClassName(getClass()) + "(" + getDescriptor() + ")";
1574    }
1575
1576    /**
1577     * PUBLIC:
1578     * Set the descriptor to use the classes full name as the indicator.
1579     * The class indicator is used with inheritance to determine the class from a row.
1580     * By default a class indicator mapping is required, this can be set to true if usage of the class
1581     * name is desired.
1582     * The field must be of a large enough size to store the fully qualified class name.
1583     */

1584    public void useClassNameAsIndicator() {
1585        setShouldUseClassNameAsIndicator(true);
1586    }
1587}
1588
Popular Tags