KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > versant > core > metadata > ClassMetaData


1
2 /*
3  * Copyright (c) 1998 - 2005 Versant Corporation
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  * Versant Corporation - initial API and implementation
11  */

12 package com.versant.core.metadata;
13
14 import com.versant.core.jdo.QueryDetails;
15 import com.versant.core.metadata.parser.JdoClass;
16
17 import com.versant.core.util.classhelper.ClassHelper;
18 import com.versant.core.util.IntArray;
19
20 import javax.jdo.spi.PersistenceCapable;
21 import java.io.*;
22 import java.lang.reflect.Field JavaDoc;
23 import java.util.*;
24
25 import com.versant.core.common.*;
26
27 /**
28  * Meta data for a class that is common to all DataStore's and the enhancer.
29  */

30 public final class ClassMetaData implements Serializable, Comparable JavaDoc
31  {
32
33     /**
34      * These are class hierarchy level setting for specifying when a ObjectNotFoundException must be
35      * thrown if this instance is not found.
36      */

37     public static final int NULL_NO_ROW_PASSON = 2;
38     public static final int NULL_NO_ROW_TRUE = 1;
39     public static final int NULL_NO_ROW_FALSE = 0;
40
41     /**
42      * This is only used for refFields. If the ref Field is not found then return a null
43      * instead of a VersantObjectNotFoundException. This is a classLevel setting.
44      */

45     public int returnNullForRowNotFound;
46
47     /**
48      * The meta data we belong to.
49      */

50     public final ModelMetaData jmd;
51     /**
52      * The fully qualified name of the class.
53      */

54     public final String JavaDoc qname;
55     /**
56      * The name of the class without package.
57      */

58     public final String JavaDoc shortName;
59     /**
60      * The abstract schema name of the class. Default is shortName.
61      */

62     public String JavaDoc abstractSchemaName;
63     /**
64      * The original parsed .jdo meta data.
65      */

66     public transient JdoClass jdoClass;
67     /**
68      * The class.
69      */

70     public Class JavaDoc cls;
71     /**
72      * The package name with a trailing dot if not empty.
73      */

74     public String JavaDoc packageNameWithDot;
75     /**
76      * The unique ID for this class. This is generated from a hash of the
77      * fully qualified class name. Duplicates are resolved by incrementing
78      * the classId.
79      *
80      * @see #setClassId(int)
81      */

82     public int classId;
83     /**
84      * The classId as a String.
85      *
86      * @see #setClassId(int)
87      */

88     public String JavaDoc classIdString;
89     /**
90      * The index of this class in the classes array.
91      *
92      * @see ModelMetaData#classes
93      */

94     public int index;
95     /**
96      * The objectid-class (null if none).
97      */

98     public Class JavaDoc objectIdClass;
99     /**
100      * The persistent superclass (null if none).
101      */

102     public Class JavaDoc pcSuperClass;
103     /**
104      * The meta data for the persistent superclass (null if none).
105      */

106     public ClassMetaData pcSuperMetaData;
107     /**
108      * The meta data for the persistent class heirachy. This includes
109      * all our superclasses in order as well as our selves (i.e. a class
110      * with no PC superclasses will have a pcHeirachy containing just
111      * itself).
112      */

113     public ClassMetaData[] pcHeirachy;
114     /**
115      * The meta data for our persistent subclasses (null if none).
116      */

117     public ClassMetaData[] pcSubclasses;
118     /**
119      * The topmost class in the heirachy (i.e. pcHeirachy[0]).
120      */

121     public ClassMetaData top;
122     /**
123      * This flag is set if instances of the class are not allowed. An attempt
124      * to persist an instance of a class with this flag set will trigger an
125      * exception.
126      */

127     public boolean instancesNotAllowed;
128     /**
129      * The type of identity.
130      *
131      * @see MDStatics#IDENTITY_TYPE_APPLICATION
132      * @see MDStatics#IDENTITY_TYPE_DATASTORE
133      * @see MDStatics#IDENTITY_TYPE_NONDURABLE
134      */

135     public int identityType;
136     /**
137      * The persistent fields declared in this class (i.e. excluding
138      * superclasses) in relative fieldNo order. This includes extra fake
139      * fields created to hold information required by the store (e.g. row
140      * version values for a JDBC class). The fake fields are always at the
141      * end of this array after all the real fields.
142      */

143     public FieldMetaData[] fields;
144     /**
145      * The persistent fields declared in this class and in superclasses in
146      * State fieldNo order. This includes extra fake fields.
147      *
148      * @see State
149      */

150     public FieldMetaData[] stateFields;
151     /**
152      * Fields as mapped from the horizontal superclass.
153      */

154     public FieldMetaData[] horizontalFields;
155     /**
156      * The number of real fields in this class. This must be filled in by the
157      * store owning this class. This excludes fake fields.
158      */

159     public int realFieldCount;
160     /**
161      * The total number of fields in all of our superclasses (i.e. the
162      * total of fields.length for all our superclasses). This is useful
163      * to convert relative fieldNo's to State fieldNos.
164      */

165     public int superFieldCount;
166     /**
167      * The application primary key fields in alpha (field number) order.
168      * This is null if not using application identity.
169      */

170     public FieldMetaData[] pkFields;
171     /**
172      * The field nos of the pk fields.
173      */

174     public int[] pkFieldNos;
175     /**
176      * If the class is using datastore identity, then this is the java type
177      * code ({@link MDStatics.INT} etc) of the identity as if it was a
178      * Java field.
179      */

180     public int datastoreIdentityTypeCode;
181     /**
182      * If the class is using datastore identity, then this is the java type
183      * of the identity as if it was a Java field.
184      */

185     public Class JavaDoc datastoreIdentityType;
186     /**
187      * This is all the fields that must be managed. eg transaction or persistent.
188      */

189     public int[] stateFieldNos;
190     /**
191      * Array of the managed fields in abs field no order.
192      */

193     public FieldMetaData[] managedFields;
194     /**
195      * This is all the managed fields. This is an array where the index
196      * represents the absFieldNo and the value at the index the stateFieldNo. This
197      * is used to convert between abs and stateFieldNos
198      */

199     public int[] absToRel;
200     /**
201      * This is an utility array that is filled from 0 to the amount of managed
202      * fields. It is used to pass as argument to the pc.
203      */

204     public int[] allManagedFieldNosArray;
205     /**
206      * The abs fieldNos of all fields that is either is pc ref or a collection of pc ref.
207      */

208     public int[] absPCTypeFields;
209     /**
210      * The fields that are marked as transactional but not persistent.
211      */

212     public int[] txFieldNos;
213     public int[] txfieldManagedFieldNos;
214     /**
215      * This holds all the nonAutoSetStateFieldNos. These fields are stateFieldNos.
216      */

217     public int[] nonAutoSetStateFieldNos;
218     /**
219      * This holds all the autoSetStateFieldNos. These fields are managedFieldNos.
220      */

221     public int[] autoSetManagedFieldNos;
222     /**
223      * The fields of the persistent fields that may contain direct (e.g.
224      * foreign key) references to other PC classes. This must be filled in
225      * by the dataStore owning this class. This information is used to sort
226      * graphs of persistent objects for persisting in the correct order
227      * (e.g. to avoid tripping database integrity constraints).
228      */

229     public int[] directRefStateFieldNos;
230     /**
231      * The reference fields that are used to complete collections
232      * mapped using a foreign key in the element table. Null if none.
233      */

234     public int[] fkCollectionRefStateFieldNos;
235     /**
236      * Must orphans be deleted? An instance is considered an orphan if it
237      * is on the many side of at least one one-to-many (master detail)
238      * relationship and all of its back references are null (i.e. it has
239      * no parents).
240      */

241     public boolean deleteOrphans;
242     /**
243      * This is true if this class or any of its superclasses has any
244      * secondary fields.
245      */

246     public boolean hasSecondaryFields;
247     /**
248      * The fields that must be persisted on pass 2 in fieldNo order. This
249      * is filled using the secondaryField flag on FieldMetaData. Note that
250      * NOT these are relative fieldNos.
251      *
252      * @see FieldMetaData#secondaryField
253      */

254     public transient int[] pass2Fields;
255
256     public int[] pass2AbsFieldNos;
257     /**
258      * Is this class read-only?
259      */

260     public boolean readOnly;
261     /**
262      * The caching strategy for this class (one of the CACHE_STRATEGY_xxx
263      * constants).
264      */

265     public int cacheStrategy;
266     /**
267      * Flag to indicate that the cacheStrategy was all and all instances
268      * have been read once.
269      */

270     public boolean cacheStrategyAllDone;
271     /**
272      * The name of the DataStore this class belongs to. Any DataStore may
273      * have multiple names for different physical stores. This may be
274      * null indicating the default.
275      */

276     public transient String JavaDoc dataStoreName;
277     /**
278      * The fetch groups.
279      */

280     public FetchGroup[] fetchGroups;
281     public FetchGroup[] sortedFetchGroups;
282     public transient ArrayList fgTmp;
283     public transient HashMap nameGroupMap;
284     /**
285      * The referenced objects fetch group (null if none i.e. this class and
286      * its superclasses and subclasses have no references to other PC objects).
287      * This includes polyrefs and collections and is used to do reachability
288      * searches.
289      */

290     public FetchGroup refFetchGroup;
291     /**
292      * The dependent objects fetch group (null if none i.e. this class and
293      * its superclasses and subclasses have no references to dependent PC
294      * objects). This is used to do a reachability search when deleting.
295      */

296     public FetchGroup depFetchGroup;
297     /**
298      * This fetch group contains all fields that must be filled in the
299      * original state (e.g. jdoVersion etc.) when persisting changes to
300      * instances. It will be null if the class has no such fields (e.g.
301      * using optimistic locking 'none').
302      */

303     public FetchGroup reqFetchGroup;
304     /**
305      * The many-to-many fetch group (null if none i.e. this class and
306      * its superclasses and subclasses have no many-to-many managed
307      * collection fields). This is used to clear these fields when deleting.
308      * It also includes all fields that must be present to persist changes
309      * to an instance.
310      */

311     public FetchGroup managedManyToManyFetchGroup;
312     /**
313      * The total number of FetchGroups in all of our superclasses (i.e. the
314      * total of fetchGroups.length for all our superclasses). This is used
315      * to convert relative fetch group indexes to State fetch group indexes.
316      */

317     public int superFetchGroupCount;
318     /**
319      * This contains all the fetch groups sorted in fieldNo order. This is
320      * used to find a fetch group containing a particular set of fieldNos.
321      */

322     public transient List allFetchGroups;
323     public transient Comparator allFComparator = new AllFetchGroupComp();
324     /**
325      * Extra store specific meta data.
326      */

327     public transient Object JavaDoc storeClass;
328     /**
329      * Does this class use changed optimistic locking i.e. include the original
330      * values of changed fields in the where clause for JDBC.
331      */

332     public boolean changedOptimisticLocking;
333     /**
334      * If this class uses version or timestamp optimistic locking then this
335      * is the field holding the value.
336      */

337     public FieldMetaData optimisticLockingField;
338     /**
339      * Factory for State and OID instances for this class. This is set by
340      * the StorageManagerFactory.
341      */

342     public StateAndOIDFactory stateAndOIDFactory;
343     /**
344      * The oid class name for hyperdrive.
345      */

346     public String JavaDoc oidClassName;
347     /**
348      * The state class name.
349      */

350     public String JavaDoc stateClassName;
351     /**
352      * The fieldNo's of the sco fields. This is stateFieldNo's
353      */

354     public int[] scoFieldNos;
355
356
357
358     /**
359      * If we or any of our superclasses have any autoSet fields then this
360      * is true.
361      *
362      * @see FieldMetaData#autoSet
363      */

364     public boolean hasAutoSetFields;
365     /**
366      * These are the absolute field numbers of the fields that are loaded into
367      * an instance when it is populated with the default fetch group. This
368      * may be a subset of the fields in the FetchGroup instance for the DFG
369      * as extra fields (e.g. OIDs for references) may be fetched as well but
370      * not loaded.
371      *
372      * @see com.versant.core.jdo.PCStateMan#loadDFGIntoPC
373      */

374     public int[] dfgAbsFieldNos;
375     /**
376      * The same as {@link ClassMetaData#dfgAbsFieldNos} but only the state field
377      * numbers instead of abs field numbers.
378      *
379      * @see #dfgAbsFieldNos
380      */

381     public int[] dfgStateFieldNos;
382     /**
383      * The position of this class in the topological sort of the graph created
384      * by following direct references between classes. Example: If A
385      * references B, then A.index < B.index and A must be deleted before B
386      * to avoid tripping constraints.
387      *
388      * @see #referenceGraphCycle
389      */

390     public int referenceGraphIndex;
391     /**
392      * If this class is involved in a reference cycle with other classes then
393      * this flag will be set (e.g. this is true for classes A -> B -> C -> A).
394      * Constraints must not be generated for any references between classes
395      * with this flag set.
396      *
397      * @see #referenceGraphIndex
398      */

399     public boolean referenceGraphCycle;
400     /**
401      * This is true if the keys are created using a key generator.
402      */

403     public boolean useKeyGen;
404     /**
405      * Must a flush be done if getObjectId is called on a new instance of
406      * this class? This is set for classes using post-insert key generators.
407      * This is also used to decide if a full graph sort is required on persist.
408      */

409     public boolean postInsertKeyGenerator;
410     /**
411      * If the DataStore requires all fields of a dirty instance to store it
412      * and not just the dirty fields then this flag is true
413      * (e.g. VdsDataStore).
414      */

415     public boolean storeAllFields;
416     /**
417      * If the DataStore requires notification before a p-clean instance is made
418      * dirty or deleted in a datastore tx then this flag is true (e.g.
419      * VdsDataStore).
420      */

421     public boolean notifyDataStoreOnDirtyOrDelete;
422
423     private HashMap namedQueryMap; // query name -> QueryDetails
424

425     /**
426      * This is a total of all the subClasses (direct and indirect);
427      */

428     public transient int totalNoOfSubClasses;
429
430     private transient Object JavaDoc metaDataInstance;
431     private transient RuntimeException JavaDoc error;
432     private transient long errorTime = Long.MAX_VALUE;
433     /**
434      * This is a List that includes this and all the subCmds of all children and sub-children etc.
435      */

436     private transient List heirarchyList;
437     /**
438      * If this class is horizontal mapped. i.e. its fields should be in the table
439      * of the subclass.
440      */

441     public boolean horizontal;
442     /**
443      * The metadata if this class is the subclass of a horizontal super class.
444      */

445     public ClassMetaData horizontalCMD;
446     /**
447      * This can be used to override the need for a objectIdClass for appid instances
448      */

449     private boolean objectIdClasssRequired = true;
450
451     public ClassMetaData(JdoClass jdoClass, ModelMetaData jmd) {
452         this.jdoClass = jdoClass;
453         this.jmd = jmd;
454         qname = jdoClass.getQName();
455         int i = qname.lastIndexOf('.');
456         shortName = i < 0 ? qname : qname.substring(i + 1);
457         abstractSchemaName = shortName;
458     }
459
460     /**
461      * Calculate and set the superFieldCount and superFetchGroup value
462      * for this class and recursively all of its subclasses. This also
463      * initializes various arrays of fieldNos etc.
464      */

465     public void calcSuperCounts() {
466         if (pcSuperMetaData != null) {
467             superFieldCount = pcSuperMetaData.superFieldCount +
468                     pcSuperMetaData.fields.length;
469             superFetchGroupCount = pcSuperMetaData.superFetchGroupCount +
470                     pcSuperMetaData.fetchGroups.length;
471
472             FieldMetaData[] superStateFields = pcSuperMetaData.stateFields;
473             int n = superStateFields.length;
474             stateFields = new FieldMetaData[n + fields.length];
475             System.arraycopy(superStateFields, 0, stateFields, 0, n);
476             System.arraycopy(fields, 0, stateFields, n, fields.length);
477         } else {
478             stateFields = fields;
479         }
480
481         if (pcSubclasses != null) {
482             for (int i = pcSubclasses.length - 1; i >= 0; i--) {
483                 pcSubclasses[i].calcSuperCounts();
484             }
485         }
486
487         // this may happen if there have been previous errors
488
if (stateFields == null) return;
489
490         // see if we have any timestamp or version fields
491
for (int i = stateFields.length - 1; i >= 0; i--) {
492             FieldMetaData f = stateFields[i];
493             if (hasAutoSetFields = f.autoSet != MDStatics.AUTOSET_NO) break;
494         }
495
496         // find all the direct references
497
IntArray a = new IntArray(stateFields.length);
498         for (int i = stateFields.length - 1; i >= 0; i--) {
499             FieldMetaData f = stateFields[i];
500             if (f.isDirectRef()) a.add(i);
501         }
502         directRefStateFieldNos = a.toArray();
503     }
504
505     /**
506      * This is called at the end of all metadata creation. This inits all the fieldnos
507      * arrays.
508      */

509     public void initMDFields() {
510         if (pcSuperMetaData != null) {
511             initStateFields();
512             createStateFieldNos();
513
514             pass2Fields = mergeFieldsNos(pcSuperMetaData.pass2Fields,
515                     pass2Fields);
516
517             pkFields = pcSuperMetaData.pkFields;
518             pkFieldNos = pcSuperMetaData.pkFieldNos;
519         } else {
520             initStateFields();
521             /**
522              * Create the fieldNo array for the state fields.
523              */

524             createStateFieldNos();
525
526             if (pkFields != null) {
527                 int n = pkFields.length;
528                 int[] pkFieldNos = new int[n];
529                 for (int i = 0; i < n; i++) {
530                     pkFieldNos[i] = pkFields[i].managedFieldNo;
531                 }
532                 this.pkFieldNos = pkFieldNos;
533             }
534         }
535         hasSecondaryFields = pass2Fields != null && pass2Fields.length > 0;
536
537         if (pcSubclasses != null) {
538             for (int i = pcSubclasses.length - 1; i >= 0; i--) {
539                 pcSubclasses[i].initMDFields();
540             }
541         }
542     }
543
544     /**
545      * This will iterate through the fmd's of this state and set the state
546      * field no' s.
547      */

548     private void initStateFields() {
549         if (fields == null) return; // possible if previous error
550
for (int i = 0; i < fields.length; i++) {
551             FieldMetaData field = fields[i];
552             field.stateFieldNo = (field.fieldNo + superFieldCount);
553         }
554     }
555
556     /**
557      * This creates various fieldNos arrays.
558      */

559     private void createStateFieldNos() {
560         if (stateFields == null) return; // possible if previous error
561
stateFieldNos = new int[stateFields.length];
562         ArrayList mList = new ArrayList();
563         IntArray nAutoFs = new IntArray();
564         IntArray autoFs = new IntArray();
565
566         /**
567          * This is to iterate through all the fields for this PC instance
568          * and set their field no as defined by the spec. This implies that if
569          * a Class defines 2 fields 'a' and 'b' that 'a' must be field no '0'
570          * and 'b' must be field no '1'.
571          */

572         if (pcSuperMetaData != null) {
573             mList.addAll(Arrays.asList(pcSuperMetaData.managedFields));
574         }
575         if (horizontalCMD != null) {
576             mList.addAll(Arrays.asList(horizontalFields));
577         }
578         for (int i = 0; i < fields.length; i++) {
579             FieldMetaData field = fields[i];
580             if (field.fake) continue;
581             mList.add(field);
582         }
583
584         managedFields = new FieldMetaData[mList.size()];
585         mList.toArray(managedFields);
586
587         IntArray txManagedFNOs = new IntArray();
588         absToRel = new int[mList.size()];
589         allManagedFieldNosArray = new int[mList.size()];
590         for (int i = 0; i < managedFields.length; i++) {
591             FieldMetaData mField = managedFields[i];
592             mField.managedFieldNo = i;
593             allManagedFieldNosArray[i] = i;
594             absToRel[i] = mField.stateFieldNo;
595             if (mField.persistenceModifier == MDStatics.PERSISTENCE_MODIFIER_TRANSACTIONAL) {
596                 txManagedFNOs.add(mField.managedFieldNo);
597             }
598         }
599
600         for (int i = 0; i < stateFields.length; i++) {
601             FieldMetaData stateField = stateFields[i];
602             if (stateField.autoSet == MDStatics.AUTOSET_NO) {
603                 nAutoFs.add(stateField.stateFieldNo);
604             } else {
605                 if (stateField.managedFieldNo != -1) autoFs.add(stateField.managedFieldNo);
606             }
607             stateFieldNos[i] = stateField.stateFieldNo;
608         }
609
610         txfieldManagedFieldNos = txManagedFNOs.toArray();
611
612         IntArray tmpPass2FieldsAbs = new IntArray();
613         for (int i = 0; i < mList.size(); i++) {
614             FieldMetaData fieldMetaData = (FieldMetaData)mList.get(i);
615             if (fieldMetaData.secondaryField) {
616                 tmpPass2FieldsAbs.add(fieldMetaData.managedFieldNo);
617             }
618         }
619         pass2AbsFieldNos = tmpPass2FieldsAbs.toArray();
620         tmpPass2FieldsAbs = null;
621
622         nonAutoSetStateFieldNos = nAutoFs.toArray();
623         autoSetManagedFieldNos = autoFs.toArray();
624
625         IntArray dfgFieldNoArray = new IntArray();
626         IntArray dfgStateFieldNoArray = new IntArray();
627         for (int i = 0; i < managedFields.length; i++) {
628             FieldMetaData managedField = managedFields[i];
629             if (managedField.isJDODefaultFetchGroup()) {
630                 dfgFieldNoArray.add(managedField.managedFieldNo);
631                 dfgStateFieldNoArray.add(managedField.stateFieldNo);
632             }
633         }
634         dfgAbsFieldNos = dfgFieldNoArray.toArray();
635         dfgStateFieldNos = dfgStateFieldNoArray.toArray();
636
637         IntArray absPCTypeFieldArray = new IntArray();
638         for (int i = 0; i < managedFields.length; i++) {
639             FieldMetaData field = managedFields[i];
640             if (field.elementTypeMetaData != null
641                     || field.typeMetaData != null
642                     || field.keyTypeMetaData != null) {
643                 absPCTypeFieldArray.add(field.managedFieldNo);
644             }
645         }
646         absPCTypeFields = absPCTypeFieldArray.toArray();
647
648         fillSCOFieldNos();
649         fillValueTypeFieldNos();
650         fillTxFields();
651     }
652
653     /**
654      * Fill in the scoFieldNos array.
655      */

656     private void fillSCOFieldNos() {
657         FieldMetaData[] fields = managedFields;
658         final int numFields = fields.length;
659         IntArray fieldNos = new IntArray(numFields);
660         for (int i = 0; i < numFields; i++) {
661             FieldMetaData fmd = fields[i];
662             //TODO Fix this: the 'MDStatics.CATEGORY_ARRAY' check is due to a bug. If this is not set then array does not work.
663
if (fmd.scoField && fmd.category != MDStatics.CATEGORY_ARRAY) {
664                 fieldNos.add(fmd.stateFieldNo);
665             }
666         }
667         scoFieldNos = fieldNos.toArray();
668     }
669
670     // set the fieldNo for each field
671
private void fillTxFields() {
672         FieldMetaData[] fields = managedFields;
673         IntArray txFields = new IntArray();
674         for (int i = 0; i < fields.length; i++) {
675             //add all fields mark as transactional to the txFields.
676
if (fields[i].persistenceModifier == MDStatics.PERSISTENCE_MODIFIER_TRANSACTIONAL) {
677                 txFields.add(fields[i].stateFieldNo);
678             }
679         }
680         txFieldNos = txFields.toArray();
681     }
682
683     /**
684      * Fill in the valueTypeFieldNos array for cmd.
685      */

686     private void fillValueTypeFieldNos() {
687
688     }
689
690     /**
691      * Merge two arrays as one. Before the local fieldNo's is merged it is
692      * bumped up the the superFieldCount.
693      *
694      * @param s
695      * @param l
696      * @return
697      */

698     private final int[] mergeFieldsNos(int[] s, int[] l) {
699         int[] n = null;
700         if (s == null && l == null) {
701         } else if (s == null) {
702             n = l;
703             for (int i = 0; i < l.length; i++) {
704                 l[i] = l[i] + superFieldCount;
705             }
706         } else if (l == null) {
707             n = s;
708         } else {
709             n = new int[s.length + l.length];
710             System.arraycopy(s, 0, n, 0, s.length);
711             for (int i = 0; i < l.length; i++) {
712                 l[i] = l[i] + superFieldCount;
713             }
714             System.arraycopy(l, 0, n, s.length, l.length);
715         }
716         return n;
717     }
718
719     /**
720      * Calculate the pcHeirachy for this class and recursively all of its
721      * subclasses. This also copies then identityType field down to
722      * subclasses.
723      */

724     public void calcPcHeirachy() {
725         if (pcSuperMetaData != null) {
726             ClassMetaData[] superPcHeirachy = pcSuperMetaData.pcHeirachy;
727             int n = superPcHeirachy.length;
728             pcHeirachy = new ClassMetaData[n + 1];
729             System.arraycopy(superPcHeirachy, 0, pcHeirachy, 0, n);
730             pcHeirachy[n] = this;
731             identityType = pcSuperMetaData.identityType;
732         } else {
733             pcHeirachy = new ClassMetaData[]{this};
734         }
735         top = pcHeirachy[0];
736         if (pcSubclasses != null) {
737             for (int i = pcSubclasses.length - 1; i >= 0; i--) {
738                 pcSubclasses[i].calcPcHeirachy();
739             }
740         }
741     }
742
743     /**
744      * This is called on the base cmd of the heirachy.
745      * <p/>
746      * The idea is that pc subs must have the same cache strat as the least derived.
747      * A strat of yes and all is handled as the same in this case.
748      *
749      * @param strat
750      */

751     private void overRideCacheStrategy(int strat) {
752         if (cacheStrategy != strat) {
753             switch (cacheStrategy) {
754                 case MDStatics.CACHE_STRATEGY_NO:
755                     cacheStrategy = strat;
756                     break;
757                 case MDStatics.CACHE_STRATEGY_YES:
758                     if (strat != MDStatics.CACHE_STRATEGY_ALL) {
759                         cacheStrategy = strat;
760                     }
761                     break;
762                 case MDStatics.CACHE_STRATEGY_ALL:
763                     if (strat != MDStatics.CACHE_STRATEGY_YES) {
764                         cacheStrategy = strat;
765                     }
766                     break;
767                 default:
768                     throw BindingSupportImpl.getInstance().internal(
769                             "Unknown caching strategy : '" + strat + "'");
770             }
771         }
772         if (pcSubclasses != null) {
773             for (int i = 0; i < pcSubclasses.length; i++) {
774                 pcSubclasses[i].overRideCacheStrategy(strat);
775             }
776         }
777     }
778
779     public void overRideCacheStrategy() {
780         if (pcSuperMetaData != null) {
781             throw BindingSupportImpl.getInstance().internal("This is only allowed to be " +
782                     "called on the base of heirachy.");
783         }
784         overRideCacheStrategy(cacheStrategy);
785     }
786
787     /**
788      * Get meta data for the field fname or null if none. This will only
789      * find real fields declared in this class or one of our superclasses.
790      */

791     public FieldMetaData getFieldMetaData(String JavaDoc fname) {
792         // do a binary search since fields is sorted by name
793
int low = 0;
794         int high = realFieldCount - 1;
795         while (low <= high) {
796             int mid = (low + high) / 2;
797             FieldMetaData midVal = fields[mid];
798             int cmp = midVal.name.compareTo(fname);
799             if (cmp < 0) {
800                 low = mid + 1;
801             } else if (cmp > 0) {
802                 high = mid - 1;
803             } else {
804                 return midVal;
805             }
806         }
807         if (horizontalCMD != null) {
808             low = 0;
809             high = horizontalFields.length - 1;
810             while (low <= high) {
811                 int mid = (low + high) / 2;
812                 FieldMetaData midVal = horizontalFields[mid];
813                 int cmp = midVal.name.compareTo(fname);
814                 if (cmp < 0) {
815                     low = mid + 1;
816                 } else if (cmp > 0) {
817                     high = mid - 1;
818                 } else {
819                     return midVal;
820                 }
821             }
822         }
823         if (horizontalCMD != null) {
824             low = 0;
825             high = horizontalFields.length - 1;
826             while (low <= high) {
827                 int mid = (low + high) / 2;
828                 FieldMetaData midVal = horizontalFields[mid];
829                 int cmp = midVal.origName.compareTo(fname);
830                 if (cmp < 0) {
831                     low = mid + 1;
832                 } else if (cmp > 0) {
833                     high = mid - 1;
834                 } else {
835                     return midVal;
836                 }
837             }
838             return null;
839         }
840         if (pcSuperMetaData == null) return null;
841         return pcSuperMetaData.getFieldMetaData(fname);
842     }
843
844     /**
845      * Get the fetch group with gname or null if none.
846      */

847     public FetchGroup getFetchGroup(String JavaDoc gname) {
848         if (gname.equals(FetchGroup.DFG_NAME)) return fetchGroups[0];
849         // do a binary search since groups is sorted by name
850
int low = 1;
851         int high = sortedFetchGroups == null ? 0 : sortedFetchGroups.length - 1;
852         while (low <= high) {
853             int mid = (low + high) / 2;
854             FetchGroup midVal = sortedFetchGroups[mid];
855             int cmp = midVal.name.compareTo(gname);
856             if (cmp < 0) {
857                 low = mid + 1;
858             } else if (cmp > 0) {
859                 high = mid - 1;
860             } else {
861                 return midVal;
862             }
863         }
864         return null;
865     }
866
867     /**
868      * Add a new FetchGroup to the allFetchGroups array maintaining the
869      * sort order.
870      */

871     private void addToAllFetchGroups(FetchGroup fg) {
872         allFetchGroups.add(fg);
873         Collections.sort(allFetchGroups, allFComparator);
874     }
875
876     /**
877      * Get the fetch group with index fgIndex. If the group does not match
878      * clsId then the super fetch group is used and so on recursively. If
879      * no fetch group is found a JDOGenieFatalInternalException is thrown.
880      */

881     public final FetchGroup getFetchGroup(int fgIndex, int clsId) {
882         FetchGroup fg = fetchGroups[fgIndex];
883         for (; fg.classMetaData.classId != clsId;) {
884             ClassMetaData smd = fg.classMetaData.pcSuperMetaData;
885             if (smd == null) {
886                 ClassMetaData t = jmd.getClassMetaData(clsId);
887                 throw BindingSupportImpl.getInstance().internal("No FetchGroup found to match fgIndex " + fgIndex +
888                         " classId " + clsId + " (" +
889                         (t == null ? null : t.toString()) + ")" +
890                         " on " + this + " (classId " + classId + ")");
891             }
892             fg = smd.fetchGroups[fgIndex];
893         }
894         return fg;
895     }
896
897     /**
898      * Init the stateFieldNo array for all our FetchGroup's and create
899      * allFetchGroups.
900      */

901     public void finishFetchGroups() {
902         int n = fetchGroups == null ? 0 : fetchGroups.length;
903         allFetchGroups = new ArrayList(n);
904         for (int i = n - 1; i >= 0; i--) {
905             FetchGroup g = fetchGroups[i];
906             g.finish();
907             addToAllFetchGroups(g);
908         }
909     }
910
911     /**
912      * Create the subFetchGroups array on all fetch groups.
913      */

914     public void finishFetchGroups2() {
915         if (pcSubclasses == null) return;
916         int sclen = pcSubclasses.length;
917         ArrayList a = new ArrayList(sclen);
918         int n = fetchGroups.length;
919         for (int i = n - 1; i >= 0; i--) {
920             a.clear();
921             FetchGroup g = fetchGroups[i];
922             for (int j = 0; j < sclen; j++) {
923                 ClassMetaData sc = pcSubclasses[j];
924                 FetchGroup sub = sc.findSubFetchGroup(g);
925                 if (sub != null) a.add(sub);
926             }
927             g.subFetchGroups = new FetchGroup[a.size()];
928             a.toArray(g.subFetchGroups);
929         }
930     }
931
932     private FetchGroup findSubFetchGroup(FetchGroup superGroup) {
933         for (int i = 0; i < fetchGroups.length; i++) {
934             FetchGroup g = fetchGroups[i];
935             if (g.superFetchGroup == superGroup) return g;
936         }
937         return null;
938     }
939
940     /**
941      * Sort by classId. Do not change this ordering.
942      */

943     public int compareTo(Object JavaDoc o) {
944         ClassMetaData cmd = (ClassMetaData)o;
945         if (classId < cmd.classId) return -1;
946         if (classId > cmd.classId) return +1;
947         return 0;
948     }
949
950     /**
951      * Create a new empty OID for this class.
952      *
953      * @param resolved Is this a resolved OID?
954      * @see OID#isResolved
955      * @see OID#resolve
956      */

957     public OID createOID(boolean resolved) {
958         return stateAndOIDFactory.createOID(this, resolved);
959     }
960
961     /**
962      * Create a new empty State for this class.
963      */

964     public State createState() {
965         return stateAndOIDFactory.createState(this);
966     }
967
968     /**
969      * Create an OID for a new object of this class.
970      */

971     public NewObjectOID createNewObjectOID() {
972         return stateAndOIDFactory.createNewObjectOID(this);
973     }
974
975     /**
976      * Is cmd one of our ancestors or ourself?
977      */

978     public boolean isAncestorOrSelf(ClassMetaData cmd) {
979         if (cmd == this) return true;
980         for (ClassMetaData c = pcSuperMetaData;
981              c != null; c = c.pcSuperMetaData) {
982             if (c == cmd) return true;
983         }
984         return false;
985     }
986
987     public String JavaDoc toString() {
988         return "Class " + qname;
989     }
990
991     /**
992      * Get the name of this class without package.
993      */

994     public String JavaDoc getShortName() {
995         int i = qname.lastIndexOf('.');
996         if (i >= 0) {
997             return qname.substring(i + 1);
998         } else {
999             return qname;
1000        }
1001    }
1002
1003    public void dump() {
1004        dump(System.out, "");
1005    }
1006
1007    public void dump(PrintStream out, String JavaDoc indent) {
1008        out.println(indent + this);
1009        String JavaDoc is = indent + " ";
1010        out.println(is + "qname = " + qname);
1011        out.println(is + "cls = " + cls);
1012        out.println(is + "classId = " + classId);
1013        out.println(is + "index = " + index);
1014        out.println(is + "objectIdClass = " + objectIdClass);
1015        out.println(is + "pcSuperClass = " + pcSuperClass);
1016        out.println(is + "pcSuperMetaData = " + pcSuperMetaData);
1017        out.println(is + "identityType = " +
1018                MDStaticUtils.toIdentityTypeString(identityType));
1019        out.println(is + "readOnly = " + readOnly);
1020        out.println(
1021                is + "cache = " + MDStaticUtils.toCacheString(cacheStrategy));
1022        out.println(is + "jdoClass = " + jdoClass);
1023        out.println(is + "jdbcClass = " + storeClass);
1024        out.println(is + "realFieldCount = " + realFieldCount);
1025        out.println(is + "superFieldCount = " + superFieldCount);
1026        out.println(is + "superFetchGroupCount = " + superFetchGroupCount);
1027        out.println(is + "hasAutoSetFields = " + hasAutoSetFields);
1028        StringBuffer JavaDoc s = new StringBuffer JavaDoc();
1029        s.append(is);
1030        s.append("directRefStateFieldNos = ");
1031        if (directRefStateFieldNos == null) {
1032            s.append("null");
1033        } else {
1034            s.append("[");
1035            for (int i = 0; i < directRefStateFieldNos.length; i++) {
1036                if (i > 0) s.append(", ");
1037                s.append(directRefStateFieldNos[i]);
1038            }
1039            s.append(']');
1040        }
1041        out.println(s);
1042        if (pcHeirachy != null) {
1043            for (int i = 0; i < pcHeirachy.length; i++) {
1044                out.println(is + "pcHeirachy[" + i + "] " + pcHeirachy[i]);
1045            }
1046        } else {
1047            out.println(is + "pcHeirachy is null");
1048        }
1049        if (pcSubclasses != null) {
1050            out.println(is + pcSubclasses.length + " persistent subclass(es)");
1051            for (int i = 0; i < pcSubclasses.length; i++) {
1052                out.println(is + "[" + i + "] " + pcSubclasses[i]);
1053            }
1054        }
1055        if (fields != null) {
1056            out.println(is + fields.length + " persistent field(s)");
1057            for (int i = 0; i < fields.length; i++) {
1058                fields[i].dump(out, is);
1059            }
1060        }
1061        if (stateFields != null) {
1062            for (int i = 0; i < stateFields.length; i++) {
1063                out.println(is + "stateFields[" + i + "] = " + stateFields[i]
1064                        + " stateFieldNo = " + stateFields[i].stateFieldNo);
1065            }
1066        } else {
1067            out.println(is + "stateFields is null");
1068        }
1069        if (stateFieldNos != null) {
1070            for (int i = 0; i < stateFieldNos.length; i++) {
1071                out.println(is + "stateFieldNos[" + i + "] = " +
1072                        stateFieldNos[i]);
1073            }
1074        } else {
1075            out.println(is + "stateFieldNos is null");
1076        }
1077        if (scoFieldNos != null) {
1078            for (int i = 0; i < scoFieldNos.length; i++) {
1079                out.println(is + "scoFieldNos[" + i + "] = " +
1080                        scoFieldNos[i]);
1081            }
1082        } else {
1083            out.println(is + "scoFieldNos is null");
1084        }
1085        if (pkFieldNos != null) {
1086            for (int i = 0; i < pkFieldNos.length; i++) {
1087                out.println(is + "pkFieldNos[" + i + "] = " +
1088                        pkFieldNos[i]);
1089            }
1090        } else {
1091            out.println(is + " pkFieldNos is null");
1092        }
1093        if (pass2Fields != null) {
1094            for (int i = 0; i < pass2Fields.length; i++) {
1095                out.println(is + " pass2Fields[" + i + "] = " +
1096                        pass2Fields[i]);
1097            }
1098        } else {
1099            out.println(is + " pass2Fields is null");
1100        }
1101        if (fetchGroups != null) {
1102            out.println(is + fetchGroups.length + " fetch group(s)");
1103            for (int i = 0; i < fetchGroups.length; i++) {
1104                out.println(is + "fetchg[" + i + "] = ");
1105                fetchGroups[i].dump(out, is);
1106            }
1107        }
1108        if (absToRel != null) {
1109            out.println(
1110                    is + "The managedFieldMapping: size = " + allManagedFieldNosArray);
1111            for (int i = 0; i < absToRel.length; i++) {
1112                int managedFieldNo = absToRel[i];
1113                out.println(is + "mFieldNo " + i + " -> " + managedFieldNo);
1114            }
1115        }
1116    }
1117
1118    /**
1119     * Is this class part of a heirachy (i.e. Does this class have super classes
1120     * or sub classes that are PesistentCapable)
1121     *
1122     * @return true if this class has super classes or sub classes that
1123     * are PesistentCapable
1124     */

1125    public boolean isInHeirachy() {
1126        return !(pcHeirachy.length == 1 && pcSubclasses == null);
1127    }
1128
1129    /**
1130     * Get the classloader that loaded our class.
1131     */

1132    public ClassLoader JavaDoc getClassLoader() {
1133        ClassLoader JavaDoc l = cls.getClassLoader();
1134        if (l == null) {
1135            return ClassHelper.get().getSystemClassLoader();
1136        } else {
1137            return l;
1138        }
1139    }
1140
1141    public void initMDFields2() {
1142        if (fields == null) {
1143            return;
1144        }
1145        for (int i = 0; i < fields.length; i++) {
1146            FieldMetaData managedField = fields[i];
1147            if (managedField.isEmbeddedRef() && managedField.embeddedFmds != null) {
1148                FieldMetaData[] embManFields
1149                        = managedField.managedEmbeddedFields
1150                        = new FieldMetaData[managedField.typeMetaData.managedFields.length];
1151                for (int j = 0; j < managedField.embeddedFmds.length; j++) {
1152                    FieldMetaData embeddedFmd = managedField.embeddedFmds[j];
1153                    embManFields[embeddedFmd.origFmd.managedFieldNo] = embeddedFmd;
1154                }
1155            }
1156        }
1157        if (pcSubclasses != null) {
1158            for (int i = pcSubclasses.length - 1; i >= 0; i--) {
1159                pcSubclasses[i].initMDFields2();
1160            }
1161        }
1162    }
1163
1164    public boolean isEmbeddedRef(int stateFieldNo) {
1165        return stateFields[stateFieldNo].embedded
1166                && stateFields[stateFieldNo].category == MDStatics.CATEGORY_REF;
1167    }
1168
1169    public void setObjectIdClasssRequired(boolean objectIdClasssRequired) {
1170        this.objectIdClasssRequired = objectIdClasssRequired;
1171    }
1172
1173    public boolean isObjectIdClasssRequired() {
1174        if (identityType != MDStatics.IDENTITY_TYPE_APPLICATION) return false;
1175        if (horizontal) return false;
1176        if (!objectIdClasssRequired) return false;
1177        return true;
1178    }
1179
1180    /**
1181     * obfuscator gives problems if its private
1182     */

1183    public static final class AllFetchGroupComp implements Comparator {
1184
1185        public int compare(Object JavaDoc o1, Object JavaDoc o2) {
1186            return ((FetchGroup)o1).name.compareTo(((FetchGroup)o2).name);
1187        }
1188
1189        public int compare(FetchGroup o1, FetchGroup o2) {
1190            return o1.name.compareTo(o2.name);
1191        }
1192    }
1193
1194    /**
1195     * Set our referenceGraphIndex.
1196     */

1197    public void setReferenceGraphIndex(int referenceGraphIndex) {
1198        this.referenceGraphIndex = referenceGraphIndex;
1199    }
1200
1201    /**
1202     * Set our referenceGraphCycle and recursively all of our subclasses.
1203     */

1204    public void setReferenceGraphCycle(boolean referenceGraphCycle) {
1205        this.referenceGraphCycle = referenceGraphCycle;
1206        if (pcSubclasses != null) {
1207            for (int i = pcSubclasses.length - 1; i >= 0; i--) {
1208                pcSubclasses[i].setReferenceGraphCycle(referenceGraphCycle);
1209            }
1210        }
1211    }
1212
1213    /**
1214     * Find a primary key field of this class or the topmost superclass in
1215     * its heirachy by name or null if none.
1216     */

1217    public FieldMetaData findPkField(String JavaDoc fname) {
1218        if (pkFields == null) {
1219            if (pcSuperMetaData == null) {
1220                throw BindingSupportImpl.getInstance().internal(
1221                        "Not an application identity class: " + qname);
1222            }
1223            return pcSuperMetaData.findPkField(fname);
1224        }
1225        for (int i = pkFields.length - 1; i >= 0; i--) {
1226            FieldMetaData f = pkFields[i];
1227            if (f.name.equals(fname)) return f;
1228        }
1229        return null;
1230    }
1231
1232    /**
1233     * Find all the fields declared in the class.
1234     */

1235    public FieldInfo[] getDeclaredFields() {
1236        Field JavaDoc[] fa = cls.getDeclaredFields();
1237        int n = fa.length;
1238        FieldInfo[] a = new FieldInfo[n];
1239        for (int i = 0; i < n; i++) {
1240            Field JavaDoc f = fa[i];
1241
1242            a[i] = new FieldInfo(f.getName(), f.getModifiers(), f.getType());
1243
1244
1245        }
1246        return a;
1247    }
1248
1249    /**
1250     * Is this class PersistenceCapable (i.e. has it been enhanced?).
1251     */

1252    public boolean isPersistenceCapable() {
1253        return PersistenceCapable.class.isAssignableFrom(cls);
1254    }
1255
1256    /**
1257     * Info about a field collected with reflection.
1258     */

1259    public static class FieldInfo {
1260
1261        private String JavaDoc name;
1262        private int modifiers;
1263        private Class JavaDoc type;
1264
1265        public FieldInfo(String JavaDoc name, int modifiers, Class JavaDoc type) {
1266            this.name = name;
1267            this.modifiers = modifiers;
1268            this.type = type;
1269        }
1270
1271        public String JavaDoc getName() {
1272            return name;
1273        }
1274
1275        public int getModifiers() {
1276            return modifiers;
1277        }
1278
1279        public Class JavaDoc getType() {
1280            return type;
1281        }
1282    }
1283
1284    /**
1285     * Add the indexes of all the classes in the heirachy rooted at this class
1286     * including this class to a.
1287     */

1288    public void findHeirachyIndexes(IntArray a) {
1289        a.add(index);
1290        if (pcSubclasses == null) return;
1291        for (int i = pcSubclasses.length - 1; i >= 0; i--) {
1292            pcSubclasses[i].findHeirachyIndexes(a);
1293        }
1294    }
1295
1296    /**
1297     * Get an instance of our class for meta data analysis. If our class is
1298     * abstract then we may return an instance of one of our subclasses. If
1299     * we have no concrete subclasses then null is returned. The instance
1300     * is cached.
1301     */

1302    public Object JavaDoc getMetaDataInstance() {
1303        if (metaDataInstance == null) {
1304            if (cls == null) {
1305                throw BindingSupportImpl.getInstance().internal(
1306                        "cls is null: " + qname);
1307            }
1308            try {
1309                metaDataInstance = cls.newInstance();
1310            } catch (InstantiationException JavaDoc e) {
1311                if (pcSubclasses == null) return null;
1312                for (int i = 0; i < pcSubclasses.length; i++) {
1313                    metaDataInstance = pcSubclasses[i].getMetaDataInstance();
1314                    if (metaDataInstance != null) break;
1315                }
1316            } catch (IllegalAccessException JavaDoc e) {
1317                BindingSupportImpl.getInstance().invalidOperation("Unable to create instance of " + qname +
1318                        ": " + e, e);
1319            }
1320        }
1321        return metaDataInstance;
1322    }
1323
1324    /**
1325     * Check the consistency of the meta data. This will try and validate parts
1326     * of the data structure against other parts to find bugs.
1327     */

1328    public void validate() {
1329
1330        // make sure that the index of each field in the fields's array
1331
// matches the fieldNo field on FieldMetaData
1332
if (fields != null) {
1333            for (int i = 0; i < fields.length; i++) {
1334                FieldMetaData fmd = fields[i];
1335                if (i != fmd.fieldNo) {
1336                    throw createValidationError(fmd.name + ": i != fields[i].fieldNo: " +
1337                            i + " != " + fields[i].fieldNo);
1338                }
1339            }
1340        }
1341
1342        // make sure that the index of each field in the stateField's array
1343
// matches the stateFieldNo field on FieldMetaData
1344
if (stateFields != null) {
1345            for (int i = 0; i < stateFields.length; i++) {
1346                FieldMetaData fmd = stateFields[i];
1347                if (i != fmd.stateFieldNo) {
1348                    throw createValidationError(fmd.name + ": i != stateFields[i].stateFieldNo: " +
1349                            i + " != " + stateFields[i].stateFieldNo);
1350                }
1351                if (i != stateFieldNos[i]) {
1352                    throw createValidationError(fmd.name + ": i != stateFieldNos[i]: " +
1353                            i + " != " + stateFieldNos[i]);
1354                }
1355            }
1356        }
1357    }
1358
1359    private RuntimeException JavaDoc createValidationError(String JavaDoc msg) {
1360        return BindingSupportImpl.getInstance().internal("Validation failed: " + qname +
1361                ": " + msg);
1362    }
1363
1364    /**
1365     * Cleanup any data structures not needed after meta data generation.
1366     */

1367    public void cleanupAfterMetaDataGeneration() {
1368    }
1369
1370    public void setClassId(int classId) {
1371        this.classId = classId;
1372        classIdString = Integer.toString(classId);
1373    }
1374
1375    public void addError(RuntimeException JavaDoc e, boolean quiet) {
1376        if (Debug.DEBUG) {
1377            e.printStackTrace(System.out);
1378        }
1379        if (error == null) {
1380            errorTime = System.currentTimeMillis();
1381            error = e;
1382            try {
1383                Thread.sleep(1);
1384            } catch (InterruptedException JavaDoc e1) {
1385                // ignore
1386
}
1387        }
1388        if (!quiet) throw e;
1389    }
1390
1391    public long getFirstErrorTime() {
1392        return errorTime;
1393    }
1394
1395    public RuntimeException JavaDoc getFirstError() {
1396        RuntimeException JavaDoc e = null;
1397        long fieldErrorTime = Long.MAX_VALUE;
1398        if (fields != null) {
1399            int length = fields.length;
1400            for (int i = 0; i < length; i++) {
1401                FieldMetaData field = fields[i];
1402                if (field.hasErrors()) {
1403                    e = field.getFirstError();
1404                    fieldErrorTime = field.getFirstErrorTime();
1405                    break;
1406                }
1407            }
1408        }
1409        if (error == null) {
1410            return e;
1411        } else {
1412            if (fieldErrorTime > errorTime) {
1413                return error;
1414            } else if (fieldErrorTime < errorTime) {
1415                return e;
1416            } else {
1417                return error;
1418            }
1419        }
1420    }
1421
1422    public boolean hasErrors() {
1423        if (fields != null) {
1424            int length = fields.length;
1425            for (int i = 0; i < length; i++) {
1426                FieldMetaData field = fields[i];
1427                if (field.hasErrors()) {
1428                    return true;
1429                }
1430            }
1431        }
1432        return error != null;
1433    }
1434
1435    /**
1436     * Add a NamedQuery to this class.
1437     *
1438     * @throws IllegalArgumentException if there is already one with the
1439     * same name
1440     */

1441    public void addNamedQuery(String JavaDoc queryName, QueryDetails qp) {
1442        if (namedQueryMap == null) namedQueryMap = new HashMap(17);
1443        if (namedQueryMap.containsKey(queryName)) {
1444            throw BindingSupportImpl.getInstance().illegalArgument("Meta data for Class " + qname +
1445                    " already has a query called '" + queryName + "'");
1446        }
1447        namedQueryMap.put(queryName, qp);
1448    }
1449
1450    /**
1451     * Return QueryDetails for the named query or null if none. The caller
1452     * must not modify the returned instance.
1453     */

1454    public QueryDetails getNamedQuery(String JavaDoc queryName) {
1455        return namedQueryMap == null ? null : (QueryDetails)namedQueryMap.get(
1456                queryName);
1457    }
1458
1459    /**
1460     * Get Map.Entry's for all of our named queries in alpha order or empty list
1461     * if none. The key of each Entry is the name and the value the QueryDetails
1462     * instance.
1463     */

1464    public List getNamedQueries() {
1465        if (namedQueryMap == null) return Collections.EMPTY_LIST;
1466        ArrayList ans = new ArrayList(namedQueryMap.entrySet());
1467        Collections.sort(ans, new Comparator() {
1468            public int compare(Object JavaDoc o1, Object JavaDoc o2) {
1469                String JavaDoc a = (String JavaDoc)((Map.Entry)o1).getKey();
1470                String JavaDoc b = (String JavaDoc)((Map.Entry)o2).getKey();
1471                return a.compareTo(b);
1472            }
1473        });
1474        return ans;
1475    }
1476
1477    public transient int weight = 0;
1478
1479    public List getHeirarchyList() {
1480        if (heirarchyList == null) {
1481            ArrayList subsList = new ArrayList();
1482            subsList.add(this);
1483            int startIndex = 0;
1484            int endIndex = 1;
1485            for (; startIndex < endIndex;) {
1486                for (int j = startIndex; j < endIndex; j++) {
1487                    ClassMetaData[] subs = ((ClassMetaData)subsList.get(j)).pcSubclasses;
1488                    if (subs == null) continue;
1489                    for (int i = 0; i < subs.length; i++) {
1490                        subsList.add(subs[i]);
1491                    }
1492                }
1493                startIndex = endIndex;
1494                endIndex = subsList.size();
1495            }
1496            heirarchyList = subsList;
1497            return subsList;
1498        }
1499        return heirarchyList;
1500    }
1501
1502
1503
1504}
1505
Popular Tags