0001: /*
0002: * Copyright (c) 1998 - 2005 Versant Corporation
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * Versant Corporation - initial API and implementation
0010: */
0011: package com.versant.core.metadata;
0012:
0013: import com.versant.core.jdo.QueryDetails;
0014: import com.versant.core.metadata.parser.JdoClass;
0015:
0016: import com.versant.core.util.classhelper.ClassHelper;
0017: import com.versant.core.util.IntArray;
0018:
0019: import javax.jdo.spi.PersistenceCapable;
0020: import java.io.*;
0021: import java.lang.reflect.Field;
0022: import java.util.*;
0023:
0024: import com.versant.core.common.*;
0025:
0026: /**
0027: * Meta data for a class that is common to all DataStore's and the enhancer.
0028: */
0029: public final class ClassMetaData implements Serializable, Comparable {
0030:
0031: /**
0032: * These are class hierarchy level setting for specifying when a ObjectNotFoundException must be
0033: * thrown if this instance is not found.
0034: */
0035: public static final int NULL_NO_ROW_PASSON = 2;
0036: public static final int NULL_NO_ROW_TRUE = 1;
0037: public static final int NULL_NO_ROW_FALSE = 0;
0038:
0039: /**
0040: * This is only used for refFields. If the ref Field is not found then return a null
0041: * instead of a VersantObjectNotFoundException. This is a classLevel setting.
0042: */
0043: public int returnNullForRowNotFound;
0044:
0045: /**
0046: * The meta data we belong to.
0047: */
0048: public final ModelMetaData jmd;
0049: /**
0050: * The fully qualified name of the class.
0051: */
0052: public final String qname;
0053: /**
0054: * The name of the class without package.
0055: */
0056: public final String shortName;
0057: /**
0058: * The abstract schema name of the class. Default is shortName.
0059: */
0060: public String abstractSchemaName;
0061: /**
0062: * The original parsed .jdo meta data.
0063: */
0064: public transient JdoClass jdoClass;
0065: /**
0066: * The class.
0067: */
0068: public Class cls;
0069: /**
0070: * The package name with a trailing dot if not empty.
0071: */
0072: public String packageNameWithDot;
0073: /**
0074: * The unique ID for this class. This is generated from a hash of the
0075: * fully qualified class name. Duplicates are resolved by incrementing
0076: * the classId.
0077: *
0078: * @see #setClassId(int)
0079: */
0080: public int classId;
0081: /**
0082: * The classId as a String.
0083: *
0084: * @see #setClassId(int)
0085: */
0086: public String classIdString;
0087: /**
0088: * The index of this class in the classes array.
0089: *
0090: * @see ModelMetaData#classes
0091: */
0092: public int index;
0093: /**
0094: * The objectid-class (null if none).
0095: */
0096: public Class objectIdClass;
0097: /**
0098: * The persistent superclass (null if none).
0099: */
0100: public Class pcSuperClass;
0101: /**
0102: * The meta data for the persistent superclass (null if none).
0103: */
0104: public ClassMetaData pcSuperMetaData;
0105: /**
0106: * The meta data for the persistent class heirachy. This includes
0107: * all our superclasses in order as well as our selves (i.e. a class
0108: * with no PC superclasses will have a pcHeirachy containing just
0109: * itself).
0110: */
0111: public ClassMetaData[] pcHeirachy;
0112: /**
0113: * The meta data for our persistent subclasses (null if none).
0114: */
0115: public ClassMetaData[] pcSubclasses;
0116: /**
0117: * The topmost class in the heirachy (i.e. pcHeirachy[0]).
0118: */
0119: public ClassMetaData top;
0120: /**
0121: * This flag is set if instances of the class are not allowed. An attempt
0122: * to persist an instance of a class with this flag set will trigger an
0123: * exception.
0124: */
0125: public boolean instancesNotAllowed;
0126: /**
0127: * The type of identity.
0128: *
0129: * @see MDStatics#IDENTITY_TYPE_APPLICATION
0130: * @see MDStatics#IDENTITY_TYPE_DATASTORE
0131: * @see MDStatics#IDENTITY_TYPE_NONDURABLE
0132: */
0133: public int identityType;
0134: /**
0135: * The persistent fields declared in this class (i.e. excluding
0136: * superclasses) in relative fieldNo order. This includes extra fake
0137: * fields created to hold information required by the store (e.g. row
0138: * version values for a JDBC class). The fake fields are always at the
0139: * end of this array after all the real fields.
0140: */
0141: public FieldMetaData[] fields;
0142: /**
0143: * The persistent fields declared in this class and in superclasses in
0144: * State fieldNo order. This includes extra fake fields.
0145: *
0146: * @see State
0147: */
0148: public FieldMetaData[] stateFields;
0149: /**
0150: * Fields as mapped from the horizontal superclass.
0151: */
0152: public FieldMetaData[] horizontalFields;
0153: /**
0154: * The number of real fields in this class. This must be filled in by the
0155: * store owning this class. This excludes fake fields.
0156: */
0157: public int realFieldCount;
0158: /**
0159: * The total number of fields in all of our superclasses (i.e. the
0160: * total of fields.length for all our superclasses). This is useful
0161: * to convert relative fieldNo's to State fieldNos.
0162: */
0163: public int super FieldCount;
0164: /**
0165: * The application primary key fields in alpha (field number) order.
0166: * This is null if not using application identity.
0167: */
0168: public FieldMetaData[] pkFields;
0169: /**
0170: * The field nos of the pk fields.
0171: */
0172: public int[] pkFieldNos;
0173: /**
0174: * If the class is using datastore identity, then this is the java type
0175: * code ({@link MDStatics.INT} etc) of the identity as if it was a
0176: * Java field.
0177: */
0178: public int datastoreIdentityTypeCode;
0179: /**
0180: * If the class is using datastore identity, then this is the java type
0181: * of the identity as if it was a Java field.
0182: */
0183: public Class datastoreIdentityType;
0184: /**
0185: * This is all the fields that must be managed. eg transaction or persistent.
0186: */
0187: public int[] stateFieldNos;
0188: /**
0189: * Array of the managed fields in abs field no order.
0190: */
0191: public FieldMetaData[] managedFields;
0192: /**
0193: * This is all the managed fields. This is an array where the index
0194: * represents the absFieldNo and the value at the index the stateFieldNo. This
0195: * is used to convert between abs and stateFieldNos
0196: */
0197: public int[] absToRel;
0198: /**
0199: * This is an utility array that is filled from 0 to the amount of managed
0200: * fields. It is used to pass as argument to the pc.
0201: */
0202: public int[] allManagedFieldNosArray;
0203: /**
0204: * The abs fieldNos of all fields that is either is pc ref or a collection of pc ref.
0205: */
0206: public int[] absPCTypeFields;
0207: /**
0208: * The fields that are marked as transactional but not persistent.
0209: */
0210: public int[] txFieldNos;
0211: public int[] txfieldManagedFieldNos;
0212: /**
0213: * This holds all the nonAutoSetStateFieldNos. These fields are stateFieldNos.
0214: */
0215: public int[] nonAutoSetStateFieldNos;
0216: /**
0217: * This holds all the autoSetStateFieldNos. These fields are managedFieldNos.
0218: */
0219: public int[] autoSetManagedFieldNos;
0220: /**
0221: * The fields of the persistent fields that may contain direct (e.g.
0222: * foreign key) references to other PC classes. This must be filled in
0223: * by the dataStore owning this class. This information is used to sort
0224: * graphs of persistent objects for persisting in the correct order
0225: * (e.g. to avoid tripping database integrity constraints).
0226: */
0227: public int[] directRefStateFieldNos;
0228: /**
0229: * The reference fields that are used to complete collections
0230: * mapped using a foreign key in the element table. Null if none.
0231: */
0232: public int[] fkCollectionRefStateFieldNos;
0233: /**
0234: * Must orphans be deleted? An instance is considered an orphan if it
0235: * is on the many side of at least one one-to-many (master detail)
0236: * relationship and all of its back references are null (i.e. it has
0237: * no parents).
0238: */
0239: public boolean deleteOrphans;
0240: /**
0241: * This is true if this class or any of its superclasses has any
0242: * secondary fields.
0243: */
0244: public boolean hasSecondaryFields;
0245: /**
0246: * The fields that must be persisted on pass 2 in fieldNo order. This
0247: * is filled using the secondaryField flag on FieldMetaData. Note that
0248: * NOT these are relative fieldNos.
0249: *
0250: * @see FieldMetaData#secondaryField
0251: */
0252: public transient int[] pass2Fields;
0253:
0254: public int[] pass2AbsFieldNos;
0255: /**
0256: * Is this class read-only?
0257: */
0258: public boolean readOnly;
0259: /**
0260: * The caching strategy for this class (one of the CACHE_STRATEGY_xxx
0261: * constants).
0262: */
0263: public int cacheStrategy;
0264: /**
0265: * Flag to indicate that the cacheStrategy was all and all instances
0266: * have been read once.
0267: */
0268: public boolean cacheStrategyAllDone;
0269: /**
0270: * The name of the DataStore this class belongs to. Any DataStore may
0271: * have multiple names for different physical stores. This may be
0272: * null indicating the default.
0273: */
0274: public transient String dataStoreName;
0275: /**
0276: * The fetch groups.
0277: */
0278: public FetchGroup[] fetchGroups;
0279: public FetchGroup[] sortedFetchGroups;
0280: public transient ArrayList fgTmp;
0281: public transient HashMap nameGroupMap;
0282: /**
0283: * The referenced objects fetch group (null if none i.e. this class and
0284: * its superclasses and subclasses have no references to other PC objects).
0285: * This includes polyrefs and collections and is used to do reachability
0286: * searches.
0287: */
0288: public FetchGroup refFetchGroup;
0289: /**
0290: * The dependent objects fetch group (null if none i.e. this class and
0291: * its superclasses and subclasses have no references to dependent PC
0292: * objects). This is used to do a reachability search when deleting.
0293: */
0294: public FetchGroup depFetchGroup;
0295: /**
0296: * This fetch group contains all fields that must be filled in the
0297: * original state (e.g. jdoVersion etc.) when persisting changes to
0298: * instances. It will be null if the class has no such fields (e.g.
0299: * using optimistic locking 'none').
0300: */
0301: public FetchGroup reqFetchGroup;
0302: /**
0303: * The many-to-many fetch group (null if none i.e. this class and
0304: * its superclasses and subclasses have no many-to-many managed
0305: * collection fields). This is used to clear these fields when deleting.
0306: * It also includes all fields that must be present to persist changes
0307: * to an instance.
0308: */
0309: public FetchGroup managedManyToManyFetchGroup;
0310: /**
0311: * The total number of FetchGroups in all of our superclasses (i.e. the
0312: * total of fetchGroups.length for all our superclasses). This is used
0313: * to convert relative fetch group indexes to State fetch group indexes.
0314: */
0315: public int super FetchGroupCount;
0316: /**
0317: * This contains all the fetch groups sorted in fieldNo order. This is
0318: * used to find a fetch group containing a particular set of fieldNos.
0319: */
0320: public transient List allFetchGroups;
0321: public transient Comparator allFComparator = new AllFetchGroupComp();
0322: /**
0323: * Extra store specific meta data.
0324: */
0325: public transient Object storeClass;
0326: /**
0327: * Does this class use changed optimistic locking i.e. include the original
0328: * values of changed fields in the where clause for JDBC.
0329: */
0330: public boolean changedOptimisticLocking;
0331: /**
0332: * If this class uses version or timestamp optimistic locking then this
0333: * is the field holding the value.
0334: */
0335: public FieldMetaData optimisticLockingField;
0336: /**
0337: * Factory for State and OID instances for this class. This is set by
0338: * the StorageManagerFactory.
0339: */
0340: public StateAndOIDFactory stateAndOIDFactory;
0341: /**
0342: * The oid class name for hyperdrive.
0343: */
0344: public String oidClassName;
0345: /**
0346: * The state class name.
0347: */
0348: public String stateClassName;
0349: /**
0350: * The fieldNo's of the sco fields. This is stateFieldNo's
0351: */
0352: public int[] scoFieldNos;
0353:
0354: /**
0355: * If we or any of our superclasses have any autoSet fields then this
0356: * is true.
0357: *
0358: * @see FieldMetaData#autoSet
0359: */
0360: public boolean hasAutoSetFields;
0361: /**
0362: * These are the absolute field numbers of the fields that are loaded into
0363: * an instance when it is populated with the default fetch group. This
0364: * may be a subset of the fields in the FetchGroup instance for the DFG
0365: * as extra fields (e.g. OIDs for references) may be fetched as well but
0366: * not loaded.
0367: *
0368: * @see com.versant.core.jdo.PCStateMan#loadDFGIntoPC
0369: */
0370: public int[] dfgAbsFieldNos;
0371: /**
0372: * The same as {@link ClassMetaData#dfgAbsFieldNos} but only the state field
0373: * numbers instead of abs field numbers.
0374: *
0375: * @see #dfgAbsFieldNos
0376: */
0377: public int[] dfgStateFieldNos;
0378: /**
0379: * The position of this class in the topological sort of the graph created
0380: * by following direct references between classes. Example: If A
0381: * references B, then A.index < B.index and A must be deleted before B
0382: * to avoid tripping constraints.
0383: *
0384: * @see #referenceGraphCycle
0385: */
0386: public int referenceGraphIndex;
0387: /**
0388: * If this class is involved in a reference cycle with other classes then
0389: * this flag will be set (e.g. this is true for classes A -> B -> C -> A).
0390: * Constraints must not be generated for any references between classes
0391: * with this flag set.
0392: *
0393: * @see #referenceGraphIndex
0394: */
0395: public boolean referenceGraphCycle;
0396: /**
0397: * This is true if the keys are created using a key generator.
0398: */
0399: public boolean useKeyGen;
0400: /**
0401: * Must a flush be done if getObjectId is called on a new instance of
0402: * this class? This is set for classes using post-insert key generators.
0403: * This is also used to decide if a full graph sort is required on persist.
0404: */
0405: public boolean postInsertKeyGenerator;
0406: /**
0407: * If the DataStore requires all fields of a dirty instance to store it
0408: * and not just the dirty fields then this flag is true
0409: * (e.g. VdsDataStore).
0410: */
0411: public boolean storeAllFields;
0412: /**
0413: * If the DataStore requires notification before a p-clean instance is made
0414: * dirty or deleted in a datastore tx then this flag is true (e.g.
0415: * VdsDataStore).
0416: */
0417: public boolean notifyDataStoreOnDirtyOrDelete;
0418:
0419: private HashMap namedQueryMap; // query name -> QueryDetails
0420:
0421: /**
0422: * This is a total of all the subClasses (direct and indirect);
0423: */
0424: public transient int totalNoOfSubClasses;
0425:
0426: private transient Object metaDataInstance;
0427: private transient RuntimeException error;
0428: private transient long errorTime = Long.MAX_VALUE;
0429: /**
0430: * This is a List that includes this and all the subCmds of all children and sub-children etc.
0431: */
0432: private transient List heirarchyList;
0433: /**
0434: * If this class is horizontal mapped. i.e. its fields should be in the table
0435: * of the subclass.
0436: */
0437: public boolean horizontal;
0438: /**
0439: * The metadata if this class is the subclass of a horizontal super class.
0440: */
0441: public ClassMetaData horizontalCMD;
0442: /**
0443: * This can be used to override the need for a objectIdClass for appid instances
0444: */
0445: private boolean objectIdClasssRequired = true;
0446:
0447: public ClassMetaData(JdoClass jdoClass, ModelMetaData jmd) {
0448: this .jdoClass = jdoClass;
0449: this .jmd = jmd;
0450: qname = jdoClass.getQName();
0451: int i = qname.lastIndexOf('.');
0452: shortName = i < 0 ? qname : qname.substring(i + 1);
0453: abstractSchemaName = shortName;
0454: }
0455:
0456: /**
0457: * Calculate and set the superFieldCount and superFetchGroup value
0458: * for this class and recursively all of its subclasses. This also
0459: * initializes various arrays of fieldNos etc.
0460: */
0461: public void calcSuperCounts() {
0462: if (pcSuperMetaData != null) {
0463: super FieldCount = pcSuperMetaData.super FieldCount
0464: + pcSuperMetaData.fields.length;
0465: super FetchGroupCount = pcSuperMetaData.super FetchGroupCount
0466: + pcSuperMetaData.fetchGroups.length;
0467:
0468: FieldMetaData[] super StateFields = pcSuperMetaData.stateFields;
0469: int n = super StateFields.length;
0470: stateFields = new FieldMetaData[n + fields.length];
0471: System.arraycopy(super StateFields, 0, stateFields, 0, n);
0472: System.arraycopy(fields, 0, stateFields, n, fields.length);
0473: } else {
0474: stateFields = fields;
0475: }
0476:
0477: if (pcSubclasses != null) {
0478: for (int i = pcSubclasses.length - 1; i >= 0; i--) {
0479: pcSubclasses[i].calcSuperCounts();
0480: }
0481: }
0482:
0483: // this may happen if there have been previous errors
0484: if (stateFields == null)
0485: return;
0486:
0487: // see if we have any timestamp or version fields
0488: for (int i = stateFields.length - 1; i >= 0; i--) {
0489: FieldMetaData f = stateFields[i];
0490: if (hasAutoSetFields = f.autoSet != MDStatics.AUTOSET_NO)
0491: break;
0492: }
0493:
0494: // find all the direct references
0495: IntArray a = new IntArray(stateFields.length);
0496: for (int i = stateFields.length - 1; i >= 0; i--) {
0497: FieldMetaData f = stateFields[i];
0498: if (f.isDirectRef())
0499: a.add(i);
0500: }
0501: directRefStateFieldNos = a.toArray();
0502: }
0503:
0504: /**
0505: * This is called at the end of all metadata creation. This inits all the fieldnos
0506: * arrays.
0507: */
0508: public void initMDFields() {
0509: if (pcSuperMetaData != null) {
0510: initStateFields();
0511: createStateFieldNos();
0512:
0513: pass2Fields = mergeFieldsNos(pcSuperMetaData.pass2Fields,
0514: pass2Fields);
0515:
0516: pkFields = pcSuperMetaData.pkFields;
0517: pkFieldNos = pcSuperMetaData.pkFieldNos;
0518: } else {
0519: initStateFields();
0520: /**
0521: * Create the fieldNo array for the state fields.
0522: */
0523: createStateFieldNos();
0524:
0525: if (pkFields != null) {
0526: int n = pkFields.length;
0527: int[] pkFieldNos = new int[n];
0528: for (int i = 0; i < n; i++) {
0529: pkFieldNos[i] = pkFields[i].managedFieldNo;
0530: }
0531: this .pkFieldNos = pkFieldNos;
0532: }
0533: }
0534: hasSecondaryFields = pass2Fields != null
0535: && pass2Fields.length > 0;
0536:
0537: if (pcSubclasses != null) {
0538: for (int i = pcSubclasses.length - 1; i >= 0; i--) {
0539: pcSubclasses[i].initMDFields();
0540: }
0541: }
0542: }
0543:
0544: /**
0545: * This will iterate through the fmd's of this state and set the state
0546: * field no' s.
0547: */
0548: private void initStateFields() {
0549: if (fields == null)
0550: return; // possible if previous error
0551: for (int i = 0; i < fields.length; i++) {
0552: FieldMetaData field = fields[i];
0553: field.stateFieldNo = (field.fieldNo + super FieldCount);
0554: }
0555: }
0556:
0557: /**
0558: * This creates various fieldNos arrays.
0559: */
0560: private void createStateFieldNos() {
0561: if (stateFields == null)
0562: return; // possible if previous error
0563: stateFieldNos = new int[stateFields.length];
0564: ArrayList mList = new ArrayList();
0565: IntArray nAutoFs = new IntArray();
0566: IntArray autoFs = new IntArray();
0567:
0568: /**
0569: * This is to iterate through all the fields for this PC instance
0570: * and set their field no as defined by the spec. This implies that if
0571: * a Class defines 2 fields 'a' and 'b' that 'a' must be field no '0'
0572: * and 'b' must be field no '1'.
0573: */
0574: if (pcSuperMetaData != null) {
0575: mList.addAll(Arrays.asList(pcSuperMetaData.managedFields));
0576: }
0577: if (horizontalCMD != null) {
0578: mList.addAll(Arrays.asList(horizontalFields));
0579: }
0580: for (int i = 0; i < fields.length; i++) {
0581: FieldMetaData field = fields[i];
0582: if (field.fake)
0583: continue;
0584: mList.add(field);
0585: }
0586:
0587: managedFields = new FieldMetaData[mList.size()];
0588: mList.toArray(managedFields);
0589:
0590: IntArray txManagedFNOs = new IntArray();
0591: absToRel = new int[mList.size()];
0592: allManagedFieldNosArray = new int[mList.size()];
0593: for (int i = 0; i < managedFields.length; i++) {
0594: FieldMetaData mField = managedFields[i];
0595: mField.managedFieldNo = i;
0596: allManagedFieldNosArray[i] = i;
0597: absToRel[i] = mField.stateFieldNo;
0598: if (mField.persistenceModifier == MDStatics.PERSISTENCE_MODIFIER_TRANSACTIONAL) {
0599: txManagedFNOs.add(mField.managedFieldNo);
0600: }
0601: }
0602:
0603: for (int i = 0; i < stateFields.length; i++) {
0604: FieldMetaData stateField = stateFields[i];
0605: if (stateField.autoSet == MDStatics.AUTOSET_NO) {
0606: nAutoFs.add(stateField.stateFieldNo);
0607: } else {
0608: if (stateField.managedFieldNo != -1)
0609: autoFs.add(stateField.managedFieldNo);
0610: }
0611: stateFieldNos[i] = stateField.stateFieldNo;
0612: }
0613:
0614: txfieldManagedFieldNos = txManagedFNOs.toArray();
0615:
0616: IntArray tmpPass2FieldsAbs = new IntArray();
0617: for (int i = 0; i < mList.size(); i++) {
0618: FieldMetaData fieldMetaData = (FieldMetaData) mList.get(i);
0619: if (fieldMetaData.secondaryField) {
0620: tmpPass2FieldsAbs.add(fieldMetaData.managedFieldNo);
0621: }
0622: }
0623: pass2AbsFieldNos = tmpPass2FieldsAbs.toArray();
0624: tmpPass2FieldsAbs = null;
0625:
0626: nonAutoSetStateFieldNos = nAutoFs.toArray();
0627: autoSetManagedFieldNos = autoFs.toArray();
0628:
0629: IntArray dfgFieldNoArray = new IntArray();
0630: IntArray dfgStateFieldNoArray = new IntArray();
0631: for (int i = 0; i < managedFields.length; i++) {
0632: FieldMetaData managedField = managedFields[i];
0633: if (managedField.isJDODefaultFetchGroup()) {
0634: dfgFieldNoArray.add(managedField.managedFieldNo);
0635: dfgStateFieldNoArray.add(managedField.stateFieldNo);
0636: }
0637: }
0638: dfgAbsFieldNos = dfgFieldNoArray.toArray();
0639: dfgStateFieldNos = dfgStateFieldNoArray.toArray();
0640:
0641: IntArray absPCTypeFieldArray = new IntArray();
0642: for (int i = 0; i < managedFields.length; i++) {
0643: FieldMetaData field = managedFields[i];
0644: if (field.elementTypeMetaData != null
0645: || field.typeMetaData != null
0646: || field.keyTypeMetaData != null) {
0647: absPCTypeFieldArray.add(field.managedFieldNo);
0648: }
0649: }
0650: absPCTypeFields = absPCTypeFieldArray.toArray();
0651:
0652: fillSCOFieldNos();
0653: fillValueTypeFieldNos();
0654: fillTxFields();
0655: }
0656:
0657: /**
0658: * Fill in the scoFieldNos array.
0659: */
0660: private void fillSCOFieldNos() {
0661: FieldMetaData[] fields = managedFields;
0662: final int numFields = fields.length;
0663: IntArray fieldNos = new IntArray(numFields);
0664: for (int i = 0; i < numFields; i++) {
0665: FieldMetaData fmd = fields[i];
0666: //TODO Fix this: the 'MDStatics.CATEGORY_ARRAY' check is due to a bug. If this is not set then array does not work.
0667: if (fmd.scoField
0668: && fmd.category != MDStatics.CATEGORY_ARRAY) {
0669: fieldNos.add(fmd.stateFieldNo);
0670: }
0671: }
0672: scoFieldNos = fieldNos.toArray();
0673: }
0674:
0675: // set the fieldNo for each field
0676: private void fillTxFields() {
0677: FieldMetaData[] fields = managedFields;
0678: IntArray txFields = new IntArray();
0679: for (int i = 0; i < fields.length; i++) {
0680: //add all fields mark as transactional to the txFields.
0681: if (fields[i].persistenceModifier == MDStatics.PERSISTENCE_MODIFIER_TRANSACTIONAL) {
0682: txFields.add(fields[i].stateFieldNo);
0683: }
0684: }
0685: txFieldNos = txFields.toArray();
0686: }
0687:
0688: /**
0689: * Fill in the valueTypeFieldNos array for cmd.
0690: */
0691: private void fillValueTypeFieldNos() {
0692:
0693: }
0694:
0695: /**
0696: * Merge two arrays as one. Before the local fieldNo's is merged it is
0697: * bumped up the the superFieldCount.
0698: *
0699: * @param s
0700: * @param l
0701: * @return
0702: */
0703: private final int[] mergeFieldsNos(int[] s, int[] l) {
0704: int[] n = null;
0705: if (s == null && l == null) {
0706: } else if (s == null) {
0707: n = l;
0708: for (int i = 0; i < l.length; i++) {
0709: l[i] = l[i] + super FieldCount;
0710: }
0711: } else if (l == null) {
0712: n = s;
0713: } else {
0714: n = new int[s.length + l.length];
0715: System.arraycopy(s, 0, n, 0, s.length);
0716: for (int i = 0; i < l.length; i++) {
0717: l[i] = l[i] + super FieldCount;
0718: }
0719: System.arraycopy(l, 0, n, s.length, l.length);
0720: }
0721: return n;
0722: }
0723:
0724: /**
0725: * Calculate the pcHeirachy for this class and recursively all of its
0726: * subclasses. This also copies then identityType field down to
0727: * subclasses.
0728: */
0729: public void calcPcHeirachy() {
0730: if (pcSuperMetaData != null) {
0731: ClassMetaData[] super PcHeirachy = pcSuperMetaData.pcHeirachy;
0732: int n = super PcHeirachy.length;
0733: pcHeirachy = new ClassMetaData[n + 1];
0734: System.arraycopy(super PcHeirachy, 0, pcHeirachy, 0, n);
0735: pcHeirachy[n] = this ;
0736: identityType = pcSuperMetaData.identityType;
0737: } else {
0738: pcHeirachy = new ClassMetaData[] { this };
0739: }
0740: top = pcHeirachy[0];
0741: if (pcSubclasses != null) {
0742: for (int i = pcSubclasses.length - 1; i >= 0; i--) {
0743: pcSubclasses[i].calcPcHeirachy();
0744: }
0745: }
0746: }
0747:
0748: /**
0749: * This is called on the base cmd of the heirachy.
0750: * <p/>
0751: * The idea is that pc subs must have the same cache strat as the least derived.
0752: * A strat of yes and all is handled as the same in this case.
0753: *
0754: * @param strat
0755: */
0756: private void overRideCacheStrategy(int strat) {
0757: if (cacheStrategy != strat) {
0758: switch (cacheStrategy) {
0759: case MDStatics.CACHE_STRATEGY_NO:
0760: cacheStrategy = strat;
0761: break;
0762: case MDStatics.CACHE_STRATEGY_YES:
0763: if (strat != MDStatics.CACHE_STRATEGY_ALL) {
0764: cacheStrategy = strat;
0765: }
0766: break;
0767: case MDStatics.CACHE_STRATEGY_ALL:
0768: if (strat != MDStatics.CACHE_STRATEGY_YES) {
0769: cacheStrategy = strat;
0770: }
0771: break;
0772: default:
0773: throw BindingSupportImpl.getInstance().internal(
0774: "Unknown caching strategy : '" + strat + "'");
0775: }
0776: }
0777: if (pcSubclasses != null) {
0778: for (int i = 0; i < pcSubclasses.length; i++) {
0779: pcSubclasses[i].overRideCacheStrategy(strat);
0780: }
0781: }
0782: }
0783:
0784: public void overRideCacheStrategy() {
0785: if (pcSuperMetaData != null) {
0786: throw BindingSupportImpl.getInstance().internal(
0787: "This is only allowed to be "
0788: + "called on the base of heirachy.");
0789: }
0790: overRideCacheStrategy(cacheStrategy);
0791: }
0792:
0793: /**
0794: * Get meta data for the field fname or null if none. This will only
0795: * find real fields declared in this class or one of our superclasses.
0796: */
0797: public FieldMetaData getFieldMetaData(String fname) {
0798: // do a binary search since fields is sorted by name
0799: int low = 0;
0800: int high = realFieldCount - 1;
0801: while (low <= high) {
0802: int mid = (low + high) / 2;
0803: FieldMetaData midVal = fields[mid];
0804: int cmp = midVal.name.compareTo(fname);
0805: if (cmp < 0) {
0806: low = mid + 1;
0807: } else if (cmp > 0) {
0808: high = mid - 1;
0809: } else {
0810: return midVal;
0811: }
0812: }
0813: if (horizontalCMD != null) {
0814: low = 0;
0815: high = horizontalFields.length - 1;
0816: while (low <= high) {
0817: int mid = (low + high) / 2;
0818: FieldMetaData midVal = horizontalFields[mid];
0819: int cmp = midVal.name.compareTo(fname);
0820: if (cmp < 0) {
0821: low = mid + 1;
0822: } else if (cmp > 0) {
0823: high = mid - 1;
0824: } else {
0825: return midVal;
0826: }
0827: }
0828: }
0829: if (horizontalCMD != null) {
0830: low = 0;
0831: high = horizontalFields.length - 1;
0832: while (low <= high) {
0833: int mid = (low + high) / 2;
0834: FieldMetaData midVal = horizontalFields[mid];
0835: int cmp = midVal.origName.compareTo(fname);
0836: if (cmp < 0) {
0837: low = mid + 1;
0838: } else if (cmp > 0) {
0839: high = mid - 1;
0840: } else {
0841: return midVal;
0842: }
0843: }
0844: return null;
0845: }
0846: if (pcSuperMetaData == null)
0847: return null;
0848: return pcSuperMetaData.getFieldMetaData(fname);
0849: }
0850:
0851: /**
0852: * Get the fetch group with gname or null if none.
0853: */
0854: public FetchGroup getFetchGroup(String gname) {
0855: if (gname.equals(FetchGroup.DFG_NAME))
0856: return fetchGroups[0];
0857: // do a binary search since groups is sorted by name
0858: int low = 1;
0859: int high = sortedFetchGroups == null ? 0
0860: : sortedFetchGroups.length - 1;
0861: while (low <= high) {
0862: int mid = (low + high) / 2;
0863: FetchGroup midVal = sortedFetchGroups[mid];
0864: int cmp = midVal.name.compareTo(gname);
0865: if (cmp < 0) {
0866: low = mid + 1;
0867: } else if (cmp > 0) {
0868: high = mid - 1;
0869: } else {
0870: return midVal;
0871: }
0872: }
0873: return null;
0874: }
0875:
0876: /**
0877: * Add a new FetchGroup to the allFetchGroups array maintaining the
0878: * sort order.
0879: */
0880: private void addToAllFetchGroups(FetchGroup fg) {
0881: allFetchGroups.add(fg);
0882: Collections.sort(allFetchGroups, allFComparator);
0883: }
0884:
0885: /**
0886: * Get the fetch group with index fgIndex. If the group does not match
0887: * clsId then the super fetch group is used and so on recursively. If
0888: * no fetch group is found a JDOGenieFatalInternalException is thrown.
0889: */
0890: public final FetchGroup getFetchGroup(int fgIndex, int clsId) {
0891: FetchGroup fg = fetchGroups[fgIndex];
0892: for (; fg.classMetaData.classId != clsId;) {
0893: ClassMetaData smd = fg.classMetaData.pcSuperMetaData;
0894: if (smd == null) {
0895: ClassMetaData t = jmd.getClassMetaData(clsId);
0896: throw BindingSupportImpl.getInstance().internal(
0897: "No FetchGroup found to match fgIndex "
0898: + fgIndex + " classId " + clsId + " ("
0899: + (t == null ? null : t.toString())
0900: + ")" + " on " + this + " (classId "
0901: + classId + ")");
0902: }
0903: fg = smd.fetchGroups[fgIndex];
0904: }
0905: return fg;
0906: }
0907:
0908: /**
0909: * Init the stateFieldNo array for all our FetchGroup's and create
0910: * allFetchGroups.
0911: */
0912: public void finishFetchGroups() {
0913: int n = fetchGroups == null ? 0 : fetchGroups.length;
0914: allFetchGroups = new ArrayList(n);
0915: for (int i = n - 1; i >= 0; i--) {
0916: FetchGroup g = fetchGroups[i];
0917: g.finish();
0918: addToAllFetchGroups(g);
0919: }
0920: }
0921:
0922: /**
0923: * Create the subFetchGroups array on all fetch groups.
0924: */
0925: public void finishFetchGroups2() {
0926: if (pcSubclasses == null)
0927: return;
0928: int sclen = pcSubclasses.length;
0929: ArrayList a = new ArrayList(sclen);
0930: int n = fetchGroups.length;
0931: for (int i = n - 1; i >= 0; i--) {
0932: a.clear();
0933: FetchGroup g = fetchGroups[i];
0934: for (int j = 0; j < sclen; j++) {
0935: ClassMetaData sc = pcSubclasses[j];
0936: FetchGroup sub = sc.findSubFetchGroup(g);
0937: if (sub != null)
0938: a.add(sub);
0939: }
0940: g.subFetchGroups = new FetchGroup[a.size()];
0941: a.toArray(g.subFetchGroups);
0942: }
0943: }
0944:
0945: private FetchGroup findSubFetchGroup(FetchGroup super Group) {
0946: for (int i = 0; i < fetchGroups.length; i++) {
0947: FetchGroup g = fetchGroups[i];
0948: if (g.super FetchGroup == super Group)
0949: return g;
0950: }
0951: return null;
0952: }
0953:
0954: /**
0955: * Sort by classId. Do not change this ordering.
0956: */
0957: public int compareTo(Object o) {
0958: ClassMetaData cmd = (ClassMetaData) o;
0959: if (classId < cmd.classId)
0960: return -1;
0961: if (classId > cmd.classId)
0962: return +1;
0963: return 0;
0964: }
0965:
0966: /**
0967: * Create a new empty OID for this class.
0968: *
0969: * @param resolved Is this a resolved OID?
0970: * @see OID#isResolved
0971: * @see OID#resolve
0972: */
0973: public OID createOID(boolean resolved) {
0974: return stateAndOIDFactory.createOID(this , resolved);
0975: }
0976:
0977: /**
0978: * Create a new empty State for this class.
0979: */
0980: public State createState() {
0981: return stateAndOIDFactory.createState(this );
0982: }
0983:
0984: /**
0985: * Create an OID for a new object of this class.
0986: */
0987: public NewObjectOID createNewObjectOID() {
0988: return stateAndOIDFactory.createNewObjectOID(this );
0989: }
0990:
0991: /**
0992: * Is cmd one of our ancestors or ourself?
0993: */
0994: public boolean isAncestorOrSelf(ClassMetaData cmd) {
0995: if (cmd == this )
0996: return true;
0997: for (ClassMetaData c = pcSuperMetaData; c != null; c = c.pcSuperMetaData) {
0998: if (c == cmd)
0999: return true;
1000: }
1001: return false;
1002: }
1003:
1004: public String toString() {
1005: return "Class " + qname;
1006: }
1007:
1008: /**
1009: * Get the name of this class without package.
1010: */
1011: public String getShortName() {
1012: int i = qname.lastIndexOf('.');
1013: if (i >= 0) {
1014: return qname.substring(i + 1);
1015: } else {
1016: return qname;
1017: }
1018: }
1019:
1020: public void dump() {
1021: dump(System.out, "");
1022: }
1023:
1024: public void dump(PrintStream out, String indent) {
1025: out.println(indent + this );
1026: String is = indent + " ";
1027: out.println(is + "qname = " + qname);
1028: out.println(is + "cls = " + cls);
1029: out.println(is + "classId = " + classId);
1030: out.println(is + "index = " + index);
1031: out.println(is + "objectIdClass = " + objectIdClass);
1032: out.println(is + "pcSuperClass = " + pcSuperClass);
1033: out.println(is + "pcSuperMetaData = " + pcSuperMetaData);
1034: out.println(is + "identityType = "
1035: + MDStaticUtils.toIdentityTypeString(identityType));
1036: out.println(is + "readOnly = " + readOnly);
1037: out.println(is + "cache = "
1038: + MDStaticUtils.toCacheString(cacheStrategy));
1039: out.println(is + "jdoClass = " + jdoClass);
1040: out.println(is + "jdbcClass = " + storeClass);
1041: out.println(is + "realFieldCount = " + realFieldCount);
1042: out.println(is + "superFieldCount = " + super FieldCount);
1043: out.println(is + "superFetchGroupCount = "
1044: + super FetchGroupCount);
1045: out.println(is + "hasAutoSetFields = " + hasAutoSetFields);
1046: StringBuffer s = new StringBuffer();
1047: s.append(is);
1048: s.append("directRefStateFieldNos = ");
1049: if (directRefStateFieldNos == null) {
1050: s.append("null");
1051: } else {
1052: s.append("[");
1053: for (int i = 0; i < directRefStateFieldNos.length; i++) {
1054: if (i > 0)
1055: s.append(", ");
1056: s.append(directRefStateFieldNos[i]);
1057: }
1058: s.append(']');
1059: }
1060: out.println(s);
1061: if (pcHeirachy != null) {
1062: for (int i = 0; i < pcHeirachy.length; i++) {
1063: out.println(is + "pcHeirachy[" + i + "] "
1064: + pcHeirachy[i]);
1065: }
1066: } else {
1067: out.println(is + "pcHeirachy is null");
1068: }
1069: if (pcSubclasses != null) {
1070: out.println(is + pcSubclasses.length
1071: + " persistent subclass(es)");
1072: for (int i = 0; i < pcSubclasses.length; i++) {
1073: out.println(is + "[" + i + "] " + pcSubclasses[i]);
1074: }
1075: }
1076: if (fields != null) {
1077: out.println(is + fields.length + " persistent field(s)");
1078: for (int i = 0; i < fields.length; i++) {
1079: fields[i].dump(out, is);
1080: }
1081: }
1082: if (stateFields != null) {
1083: for (int i = 0; i < stateFields.length; i++) {
1084: out.println(is + "stateFields[" + i + "] = "
1085: + stateFields[i] + " stateFieldNo = "
1086: + stateFields[i].stateFieldNo);
1087: }
1088: } else {
1089: out.println(is + "stateFields is null");
1090: }
1091: if (stateFieldNos != null) {
1092: for (int i = 0; i < stateFieldNos.length; i++) {
1093: out.println(is + "stateFieldNos[" + i + "] = "
1094: + stateFieldNos[i]);
1095: }
1096: } else {
1097: out.println(is + "stateFieldNos is null");
1098: }
1099: if (scoFieldNos != null) {
1100: for (int i = 0; i < scoFieldNos.length; i++) {
1101: out.println(is + "scoFieldNos[" + i + "] = "
1102: + scoFieldNos[i]);
1103: }
1104: } else {
1105: out.println(is + "scoFieldNos is null");
1106: }
1107: if (pkFieldNos != null) {
1108: for (int i = 0; i < pkFieldNos.length; i++) {
1109: out.println(is + "pkFieldNos[" + i + "] = "
1110: + pkFieldNos[i]);
1111: }
1112: } else {
1113: out.println(is + " pkFieldNos is null");
1114: }
1115: if (pass2Fields != null) {
1116: for (int i = 0; i < pass2Fields.length; i++) {
1117: out.println(is + " pass2Fields[" + i + "] = "
1118: + pass2Fields[i]);
1119: }
1120: } else {
1121: out.println(is + " pass2Fields is null");
1122: }
1123: if (fetchGroups != null) {
1124: out.println(is + fetchGroups.length + " fetch group(s)");
1125: for (int i = 0; i < fetchGroups.length; i++) {
1126: out.println(is + "fetchg[" + i + "] = ");
1127: fetchGroups[i].dump(out, is);
1128: }
1129: }
1130: if (absToRel != null) {
1131: out.println(is + "The managedFieldMapping: size = "
1132: + allManagedFieldNosArray);
1133: for (int i = 0; i < absToRel.length; i++) {
1134: int managedFieldNo = absToRel[i];
1135: out.println(is + "mFieldNo " + i + " -> "
1136: + managedFieldNo);
1137: }
1138: }
1139: }
1140:
1141: /**
1142: * Is this class part of a heirachy (i.e. Does this class have super classes
1143: * or sub classes that are PesistentCapable)
1144: *
1145: * @return true if this class has super classes or sub classes that
1146: * are PesistentCapable
1147: */
1148: public boolean isInHeirachy() {
1149: return !(pcHeirachy.length == 1 && pcSubclasses == null);
1150: }
1151:
1152: /**
1153: * Get the classloader that loaded our class.
1154: */
1155: public ClassLoader getClassLoader() {
1156: ClassLoader l = cls.getClassLoader();
1157: if (l == null) {
1158: return ClassHelper.get().getSystemClassLoader();
1159: } else {
1160: return l;
1161: }
1162: }
1163:
1164: public void initMDFields2() {
1165: if (fields == null) {
1166: return;
1167: }
1168: for (int i = 0; i < fields.length; i++) {
1169: FieldMetaData managedField = fields[i];
1170: if (managedField.isEmbeddedRef()
1171: && managedField.embeddedFmds != null) {
1172: FieldMetaData[] embManFields = managedField.managedEmbeddedFields = new FieldMetaData[managedField.typeMetaData.managedFields.length];
1173: for (int j = 0; j < managedField.embeddedFmds.length; j++) {
1174: FieldMetaData embeddedFmd = managedField.embeddedFmds[j];
1175: embManFields[embeddedFmd.origFmd.managedFieldNo] = embeddedFmd;
1176: }
1177: }
1178: }
1179: if (pcSubclasses != null) {
1180: for (int i = pcSubclasses.length - 1; i >= 0; i--) {
1181: pcSubclasses[i].initMDFields2();
1182: }
1183: }
1184: }
1185:
1186: public boolean isEmbeddedRef(int stateFieldNo) {
1187: return stateFields[stateFieldNo].embedded
1188: && stateFields[stateFieldNo].category == MDStatics.CATEGORY_REF;
1189: }
1190:
1191: public void setObjectIdClasssRequired(boolean objectIdClasssRequired) {
1192: this .objectIdClasssRequired = objectIdClasssRequired;
1193: }
1194:
1195: public boolean isObjectIdClasssRequired() {
1196: if (identityType != MDStatics.IDENTITY_TYPE_APPLICATION)
1197: return false;
1198: if (horizontal)
1199: return false;
1200: if (!objectIdClasssRequired)
1201: return false;
1202: return true;
1203: }
1204:
1205: /**
1206: * obfuscator gives problems if its private
1207: */
1208: public static final class AllFetchGroupComp implements Comparator {
1209:
1210: public int compare(Object o1, Object o2) {
1211: return ((FetchGroup) o1).name
1212: .compareTo(((FetchGroup) o2).name);
1213: }
1214:
1215: public int compare(FetchGroup o1, FetchGroup o2) {
1216: return o1.name.compareTo(o2.name);
1217: }
1218: }
1219:
1220: /**
1221: * Set our referenceGraphIndex.
1222: */
1223: public void setReferenceGraphIndex(int referenceGraphIndex) {
1224: this .referenceGraphIndex = referenceGraphIndex;
1225: }
1226:
1227: /**
1228: * Set our referenceGraphCycle and recursively all of our subclasses.
1229: */
1230: public void setReferenceGraphCycle(boolean referenceGraphCycle) {
1231: this .referenceGraphCycle = referenceGraphCycle;
1232: if (pcSubclasses != null) {
1233: for (int i = pcSubclasses.length - 1; i >= 0; i--) {
1234: pcSubclasses[i]
1235: .setReferenceGraphCycle(referenceGraphCycle);
1236: }
1237: }
1238: }
1239:
1240: /**
1241: * Find a primary key field of this class or the topmost superclass in
1242: * its heirachy by name or null if none.
1243: */
1244: public FieldMetaData findPkField(String fname) {
1245: if (pkFields == null) {
1246: if (pcSuperMetaData == null) {
1247: throw BindingSupportImpl.getInstance().internal(
1248: "Not an application identity class: " + qname);
1249: }
1250: return pcSuperMetaData.findPkField(fname);
1251: }
1252: for (int i = pkFields.length - 1; i >= 0; i--) {
1253: FieldMetaData f = pkFields[i];
1254: if (f.name.equals(fname))
1255: return f;
1256: }
1257: return null;
1258: }
1259:
1260: /**
1261: * Find all the fields declared in the class.
1262: */
1263: public FieldInfo[] getDeclaredFields() {
1264: Field[] fa = cls.getDeclaredFields();
1265: int n = fa.length;
1266: FieldInfo[] a = new FieldInfo[n];
1267: for (int i = 0; i < n; i++) {
1268: Field f = fa[i];
1269:
1270: a[i] = new FieldInfo(f.getName(), f.getModifiers(), f
1271: .getType());
1272:
1273: }
1274: return a;
1275: }
1276:
1277: /**
1278: * Is this class PersistenceCapable (i.e. has it been enhanced?).
1279: */
1280: public boolean isPersistenceCapable() {
1281: return PersistenceCapable.class.isAssignableFrom(cls);
1282: }
1283:
1284: /**
1285: * Info about a field collected with reflection.
1286: */
1287: public static class FieldInfo {
1288:
1289: private String name;
1290: private int modifiers;
1291: private Class type;
1292:
1293: public FieldInfo(String name, int modifiers, Class type) {
1294: this .name = name;
1295: this .modifiers = modifiers;
1296: this .type = type;
1297: }
1298:
1299: public String getName() {
1300: return name;
1301: }
1302:
1303: public int getModifiers() {
1304: return modifiers;
1305: }
1306:
1307: public Class getType() {
1308: return type;
1309: }
1310: }
1311:
1312: /**
1313: * Add the indexes of all the classes in the heirachy rooted at this class
1314: * including this class to a.
1315: */
1316: public void findHeirachyIndexes(IntArray a) {
1317: a.add(index);
1318: if (pcSubclasses == null)
1319: return;
1320: for (int i = pcSubclasses.length - 1; i >= 0; i--) {
1321: pcSubclasses[i].findHeirachyIndexes(a);
1322: }
1323: }
1324:
1325: /**
1326: * Get an instance of our class for meta data analysis. If our class is
1327: * abstract then we may return an instance of one of our subclasses. If
1328: * we have no concrete subclasses then null is returned. The instance
1329: * is cached.
1330: */
1331: public Object getMetaDataInstance() {
1332: if (metaDataInstance == null) {
1333: if (cls == null) {
1334: throw BindingSupportImpl.getInstance().internal(
1335: "cls is null: " + qname);
1336: }
1337: try {
1338: metaDataInstance = cls.newInstance();
1339: } catch (InstantiationException e) {
1340: if (pcSubclasses == null)
1341: return null;
1342: for (int i = 0; i < pcSubclasses.length; i++) {
1343: metaDataInstance = pcSubclasses[i]
1344: .getMetaDataInstance();
1345: if (metaDataInstance != null)
1346: break;
1347: }
1348: } catch (IllegalAccessException e) {
1349: BindingSupportImpl.getInstance().invalidOperation(
1350: "Unable to create instance of " + qname + ": "
1351: + e, e);
1352: }
1353: }
1354: return metaDataInstance;
1355: }
1356:
1357: /**
1358: * Check the consistency of the meta data. This will try and validate parts
1359: * of the data structure against other parts to find bugs.
1360: */
1361: public void validate() {
1362:
1363: // make sure that the index of each field in the fields's array
1364: // matches the fieldNo field on FieldMetaData
1365: if (fields != null) {
1366: for (int i = 0; i < fields.length; i++) {
1367: FieldMetaData fmd = fields[i];
1368: if (i != fmd.fieldNo) {
1369: throw createValidationError(fmd.name
1370: + ": i != fields[i].fieldNo: " + i + " != "
1371: + fields[i].fieldNo);
1372: }
1373: }
1374: }
1375:
1376: // make sure that the index of each field in the stateField's array
1377: // matches the stateFieldNo field on FieldMetaData
1378: if (stateFields != null) {
1379: for (int i = 0; i < stateFields.length; i++) {
1380: FieldMetaData fmd = stateFields[i];
1381: if (i != fmd.stateFieldNo) {
1382: throw createValidationError(fmd.name
1383: + ": i != stateFields[i].stateFieldNo: "
1384: + i + " != " + stateFields[i].stateFieldNo);
1385: }
1386: if (i != stateFieldNos[i]) {
1387: throw createValidationError(fmd.name
1388: + ": i != stateFieldNos[i]: " + i + " != "
1389: + stateFieldNos[i]);
1390: }
1391: }
1392: }
1393: }
1394:
1395: private RuntimeException createValidationError(String msg) {
1396: return BindingSupportImpl.getInstance().internal(
1397: "Validation failed: " + qname + ": " + msg);
1398: }
1399:
1400: /**
1401: * Cleanup any data structures not needed after meta data generation.
1402: */
1403: public void cleanupAfterMetaDataGeneration() {
1404: }
1405:
1406: public void setClassId(int classId) {
1407: this .classId = classId;
1408: classIdString = Integer.toString(classId);
1409: }
1410:
1411: public void addError(RuntimeException e, boolean quiet) {
1412: if (Debug.DEBUG) {
1413: e.printStackTrace(System.out);
1414: }
1415: if (error == null) {
1416: errorTime = System.currentTimeMillis();
1417: error = e;
1418: try {
1419: Thread.sleep(1);
1420: } catch (InterruptedException e1) {
1421: // ignore
1422: }
1423: }
1424: if (!quiet)
1425: throw e;
1426: }
1427:
1428: public long getFirstErrorTime() {
1429: return errorTime;
1430: }
1431:
1432: public RuntimeException getFirstError() {
1433: RuntimeException e = null;
1434: long fieldErrorTime = Long.MAX_VALUE;
1435: if (fields != null) {
1436: int length = fields.length;
1437: for (int i = 0; i < length; i++) {
1438: FieldMetaData field = fields[i];
1439: if (field.hasErrors()) {
1440: e = field.getFirstError();
1441: fieldErrorTime = field.getFirstErrorTime();
1442: break;
1443: }
1444: }
1445: }
1446: if (error == null) {
1447: return e;
1448: } else {
1449: if (fieldErrorTime > errorTime) {
1450: return error;
1451: } else if (fieldErrorTime < errorTime) {
1452: return e;
1453: } else {
1454: return error;
1455: }
1456: }
1457: }
1458:
1459: public boolean hasErrors() {
1460: if (fields != null) {
1461: int length = fields.length;
1462: for (int i = 0; i < length; i++) {
1463: FieldMetaData field = fields[i];
1464: if (field.hasErrors()) {
1465: return true;
1466: }
1467: }
1468: }
1469: return error != null;
1470: }
1471:
1472: /**
1473: * Add a NamedQuery to this class.
1474: *
1475: * @throws IllegalArgumentException if there is already one with the
1476: * same name
1477: */
1478: public void addNamedQuery(String queryName, QueryDetails qp) {
1479: if (namedQueryMap == null)
1480: namedQueryMap = new HashMap(17);
1481: if (namedQueryMap.containsKey(queryName)) {
1482: throw BindingSupportImpl.getInstance().illegalArgument(
1483: "Meta data for Class " + qname
1484: + " already has a query called '"
1485: + queryName + "'");
1486: }
1487: namedQueryMap.put(queryName, qp);
1488: }
1489:
1490: /**
1491: * Return QueryDetails for the named query or null if none. The caller
1492: * must not modify the returned instance.
1493: */
1494: public QueryDetails getNamedQuery(String queryName) {
1495: return namedQueryMap == null ? null
1496: : (QueryDetails) namedQueryMap.get(queryName);
1497: }
1498:
1499: /**
1500: * Get Map.Entry's for all of our named queries in alpha order or empty list
1501: * if none. The key of each Entry is the name and the value the QueryDetails
1502: * instance.
1503: */
1504: public List getNamedQueries() {
1505: if (namedQueryMap == null)
1506: return Collections.EMPTY_LIST;
1507: ArrayList ans = new ArrayList(namedQueryMap.entrySet());
1508: Collections.sort(ans, new Comparator() {
1509: public int compare(Object o1, Object o2) {
1510: String a = (String) ((Map.Entry) o1).getKey();
1511: String b = (String) ((Map.Entry) o2).getKey();
1512: return a.compareTo(b);
1513: }
1514: });
1515: return ans;
1516: }
1517:
1518: public transient int weight = 0;
1519:
1520: public List getHeirarchyList() {
1521: if (heirarchyList == null) {
1522: ArrayList subsList = new ArrayList();
1523: subsList.add(this );
1524: int startIndex = 0;
1525: int endIndex = 1;
1526: for (; startIndex < endIndex;) {
1527: for (int j = startIndex; j < endIndex; j++) {
1528: ClassMetaData[] subs = ((ClassMetaData) subsList
1529: .get(j)).pcSubclasses;
1530: if (subs == null)
1531: continue;
1532: for (int i = 0; i < subs.length; i++) {
1533: subsList.add(subs[i]);
1534: }
1535: }
1536: startIndex = endIndex;
1537: endIndex = subsList.size();
1538: }
1539: heirarchyList = subsList;
1540: return subsList;
1541: }
1542: return heirarchyList;
1543: }
1544:
1545: }
|