KickJava   Java API By Example, From Geeks To Geeks.

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


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.VersantPersistenceManagerImp;
15 import com.versant.core.jdo.VersantStateManager;
16 import com.versant.core.jdo.sco.*;
17 import com.versant.core.metadata.parser.JdoArray;
18 import com.versant.core.metadata.parser.JdoCollection;
19 import com.versant.core.metadata.parser.JdoField;
20 import com.versant.core.metadata.parser.JdoMap;
21 import com.versant.core.jdo.query.OrderNode;
22 import com.versant.core.jdo.externalizer.Externalizer;
23 import com.versant.core.util.classhelper.ClassHelper;
24
25 import javax.jdo.spi.PersistenceCapable;
26 import java.io.*;
27 import java.lang.reflect.Field JavaDoc;
28 import java.lang.reflect.Modifier JavaDoc;
29 import java.util.*;
30
31 import com.versant.core.common.*;
32
33 /**
34  * Meta data for a persistent or transactional field that is common to all
35  * DataStore's and the enhancer.
36  */

37 public class FieldMetaData implements Externalizable, Comparable JavaDoc, MDStatics,
38         VersantFieldMetaData
39  {
40
41     /**
42      * The class this field belongs to.
43      */

44     public ClassMetaData classMetaData;
45     /**
46      * The parsed info for this field (null if none i.e. meta data created
47      * using reflection).
48      */

49     public JdoField jdoField;
50     /**
51      * The name of the field.
52      */

53     public String JavaDoc name;
54     public String JavaDoc origName;
55     /**
56      * The relative field number of this field.
57      */

58     public int fieldNo;
59     /**
60      * The state field no for this field.
61      */

62     public int stateFieldNo;
63     /**
64      * The absolute fieldNo for this field.
65      */

66     public int managedFieldNo = -1;
67     /**
68      * Is this an artificial field created to hold some store specific
69      * information (e.g. row version column values for a JDBC store)?
70      */

71     public boolean fake;
72     /**
73      * If this is a fake field then these are the real fields it is linked
74      * to. This is typically used to make sure the fake field is in all
75      * the same fetch groups as its associated fields. This may be null in
76      * which case the fake field is added to all fetch groups.
77      */

78     public FieldMetaData[] fakeLinks;
79     /**
80      * The persistence-modifier of the field.
81      *
82      * @see MDStatics#PERSISTENCE_MODIFIER_PERSISTENT
83      * @see MDStatics#PERSISTENCE_MODIFIER_TRANSACTIONAL
84      */

85     public int persistenceModifier;
86     /**
87      * What sort of field is this? This is a general classification to make
88      * it easier to work with the field.
89      *
90      * @see MDStatics#CATEGORY_SIMPLE
91      * @see MDStatics#CATEGORY_COLLECTION
92      * @see MDStatics#CATEGORY_ARRAY
93      * @see MDStatics#CATEGORY_MAP
94      * @see MDStatics#CATEGORY_REF
95      * @see MDStatics#CATEGORY_TRANSACTIONAL
96      * @see MDStatics#CATEGORY_EXTERNALIZED
97      */

98     public int category;
99     /**
100      * Is this field transformed into a different type when going to/from
101      * storage? Null if not.
102      */

103     public Externalizer externalizer;
104     /**
105      * If this field transported using a CollectionDiff subclass
106      * (e.g. List, Set and Map fields) ?
107      */

108     public boolean collectionDiffType;
109
110     /**
111      * Is this field persisted as part of the object itself in the datastore?
112      * This is set by the store for the class (e.g. the JdbcDataStore will
113      * set this for fields stored in the main table and the VdsDataStore will
114      * set this for fields stored with the object itself).
115      */

116     public boolean primaryField;
117     /**
118      * Is this field persisted separately to the object itself? This is set by
119      * the store for the class (e.g. the JdbcDataStore will set this for fields
120      * stored using a link table and the VdsDataStore will set this for fields
121      * not stored as part of the Object e.g. Collections).
122      */

123     public boolean secondaryField;
124     /**
125      * The java type of this field.
126      */

127     public Class JavaDoc type;
128     /**
129      * The java type code of this field if it is a simple type (int, Integer,
130      * String etc.).
131      *
132      * @see MDStatics
133      */

134     public int typeCode;
135
136     /**
137      * This is just the method name on state to call to retrieve this field.
138      */

139     public String JavaDoc stateGetMethodName;
140     /**
141      * If this field is an array then this is the type of the entries (null
142      * otherwise).
143      */

144     public Class JavaDoc componentType;
145     /**
146      * The type code for componentType (0 if none).
147      * @see MDStatics
148      * @see #componentType
149      */

150     public int componentTypeCode;
151     /**
152      * If the type or componentType is a PC class then this is its meta data.
153      * This is null for Collection's.
154      *
155      * @see #componentType
156      * @see #elementType
157      * @see #elementTypeMetaData
158      */

159     public ClassMetaData typeMetaData;
160     /**
161      * The java modifiers for this field (transient etc).
162      *
163      * @see java.lang.reflect.Modifier
164      */

165     public int modifiers;
166     /**
167      * Is this field part of the primary key?
168      */

169     public boolean primaryKey;
170     /**
171      * Cache for the value of this field in a new objectid-class instance
172      *
173      * @see #getPKDefaultValue()
174      */

175     private Object JavaDoc pkDefaultValue;
176     /**
177      * If this field is part of the primary key and this class uses application
178      * identity then this is the corresponding field from the objectid-class.
179      */

180     private transient Field objectidClassField;
181     /**
182      * How are nulls handled (null-value attribute)?
183      *
184      * @see MDStatics#NULL_VALUE_DEFAULT
185      * @see MDStatics#NULL_VALUE_EXCEPTION
186      * @see MDStatics#NULL_VALUE_NONE
187      */

188     public int nullValue;
189     /**
190      * Is this field in the default-fetch-group?
191      */

192     public boolean defaultFetchGroup;
193     /**
194      * Is this field in the default-fetch-group by default (true for ints etc
195      * false for references and so on)?
196      */

197     public boolean defaultFetchGroupDefault;
198     /**
199      * Should this field embedded (hint to the store)?
200      */

201     public boolean embedded;
202
203     /**
204      * The parsed collection element (null if none).
205      */

206     public JdoCollection jdoCollection;
207     /**
208      * The parsed array element (null if none).
209      */

210     public JdoArray jdoArray;
211     /**
212      * The parsed map element (null if none).
213      */

214     public JdoMap jdoMap;
215     /**
216      * The type stored in the collection or the value type for a map or the
217      * component type for an array.
218      */

219     public Class JavaDoc elementType;
220     /**
221      * The type code for elementType (0 if none).
222      *
223      * @see MDStatics
224      * @see #elementType
225      */

226     public int elementTypeCode;
227     /**
228      * The meta data for elementType if it is a PC class (null otherwise).
229      */

230     public ClassMetaData elementTypeMetaData;
231     /**
232      * Should the collection or array elements (or values for a map)
233      * be embedded?
234      */

235     public boolean embeddedElement;
236     /**
237      * The key type (null if not a map).
238      */

239     public Class JavaDoc keyType;
240     /**
241      * The type code for keyType (0 if none).
242      *
243      * @see MDStatics
244      * @see #keyType
245      */

246     public int keyTypeCode;
247     /**
248      * The meta data for keyType if it is a PC class (null otherwise).
249      */

250     public ClassMetaData keyTypeMetaData;
251     /**
252      * Should the keys be embedded?
253      */

254     public boolean embeddedKey;
255     /**
256      * Is this an ordered collection?
257      */

258     public boolean ordered;
259     /**
260      * The fetch group for this field. This is the fetch group used when
261      * the field is requested and no fetch group is specified.
262      */

263     public FetchGroup fetchGroup;
264
265     /**
266      * Are the objects referenced by this field dependent? This is only valid
267      * for references, collections, arrays and maps etc. Dependent objects
268      * are deleted when their owner (i.e. the object with this field) is
269      * deleted. For a map this refers to the values.
270      *
271      * @see #dependentKeys
272      */

273     public boolean dependentValues;
274     /**
275      * This is only valid for map fields. It provides the same functionality
276      * for the keys of the map as the the dependentValues flag does for the
277      * values.
278      *
279      * @see #dependentValues
280      */

281     public boolean dependentKeys;
282
283     /**
284      * Is this fields value set automatically on commit? This feature is used
285      * to implement row version and timestamp optimistic locking but can be
286      * used for other purposes.
287      */

288     public int autoSet;
289
290     /**
291      * Extra store specific meta data for this field.
292      */

293     public transient Object JavaDoc storeField;
294     /**
295      * If this is a collection, array or map and this field is true then all
296      * data must be provided in the diff instance instead of just the changes
297      * on commit or flush. This is used for datastores like VDS that always
298      * write everything.
299      */

300     public boolean includeAllDataInDiff;
301     /**
302      * Is this field a master (one) in a master/detail (one-to-many)
303      * relationship
304      */

305     public boolean isMaster;
306     /**
307      * Is this field a detail (many) in a master/detail (one-to-many)
308      * relationship? This field is set both for managed and unmanaged
309      * relationships.
310      */

311     public boolean isDetail;
312     /**
313      * Is this field in a many-to-many relationship?
314      */

315     public boolean isManyToMany;
316     /**
317      * Is this field read only (e.g. the inverse side of a many-to-many)?
318      */

319     public boolean isReadOnly;
320     /**
321      * If isMaster, isDetail or isManyToMany is set then this is the fieldNo of
322      * the field on the other side of the relationship.
323      */

324     public int inverseFieldNo = -1;
325     /**
326      * Is isMaster or isManyToMany is set then this indicates if
327      * the relationship is managed by the SCOs or not. Note that this field
328      * is filled in by the JdbcField involved.
329      */

330     public boolean managed;
331     /**
332      * If isMaster, isDetail or isManyToMany is set then this is the field
333      * on the other side of the relationship.
334      */

335     public FieldMetaData inverseFieldMetaData;
336     /**
337      * If the field is a sco field.
338      */

339     public boolean scoField;
340     /**
341      * Should the field be returned as null if the referenced object is not
342      * found? This is useful for references with all of their columns shared
343      * with the primary key.
344      */

345     public boolean nullIfNotFound;
346     /**
347      * This is filled for unordered collection fields with an ordering
348      * extension. Only required on server so is transient.
349      */

350     public transient OrderNode[] ordering;
351     /**
352      * The cascade type for this field.
353      * This is currently only used by entitymanager.
354      * @see MDStatics.CASCADE_ALL
355      * @see MDStatics.CASCADE_MERGE
356      * @see MDStatics.CASCADE_PERSIST
357      * @see MDStatics.CASCADE_REFRESH
358      * @see MDStatics.CASCADE_REMOVE
359      */

360     public int cascadeType = 0;
361
362     private transient Comparator comparator;
363     private transient boolean comparatorInitDone;
364     private RuntimeException JavaDoc error;
365     private long errorTime = Long.MAX_VALUE;
366     private Object JavaDoc scoFactory;
367     public VersantSCOFactory simpleSCOFactory;
368     public VersantSCOCollectionFactory collectionFactory;
369     public VersantSCOMapFactory mapFactory;
370     public static final String JavaDoc NO_FIELD_TEXT = "{auto}";
371     //If this is a fmd that was created from a embedded pc instance then this
372
//is the link back to the original field
373
public FieldMetaData origFmd;
374     public FieldMetaData[] embeddedFmds;
375     /**
376      * If this field acts a nullIndicator
377      */

378     public FieldMetaData nullIndicatorFmd;
379     public FieldMetaData[] managedEmbeddedFields;
380     /**
381      * Is this field embedded from another class into this class.
382      */

383     public boolean embeddedFakeField;
384     /**
385      * If this is a fake field that is created from the horizontal super class.
386      */

387     public boolean horizontalFakeField;
388
389     public FieldMetaData() {
390     }
391
392     public String JavaDoc toString() {
393         return "Field " + name;
394     }
395
396     /**
397      * Return the fully qualified name of this field.
398      */

399     public String JavaDoc getQName() {
400         return classMetaData.qname + "." + name;
401     }
402
403     /**
404      * Return the type and fully qualified name of this field.
405      */

406     public String JavaDoc getTypeQName() {
407         return type.getName() + " " + getQName();
408     }
409
410     /**
411      * Get the meta data for the class we reference. If this field is an
412      * array, collection or map of a PC class then this will be the meta data
413      * for the value class. If this is a simple reference then this will
414      * be the meta data of the referenced class. Otherwise null is returned.
415      * Always returns null for externalized fields.
416      *
417      * @see #typeMetaData
418      * @see #elementTypeMetaData
419      */

420     public ClassMetaData getRefOrValueClassMetaData() {
421         if (category == MDStatics.CATEGORY_EXTERNALIZED) return null;
422         if (typeMetaData != null) return typeMetaData;
423         return elementTypeMetaData;
424     }
425
426     /**
427      * Add all fetch groups we belong to to a.
428      */

429     public void findFetchGroups(ArrayList a) {
430         FetchGroup[] groups = classMetaData.fetchGroups;
431         int n = groups.length;
432         for (int i = 0; i < n; i++) {
433             FetchGroup g = groups[i];
434             if (g.contains(this)) a.add(g);
435         }
436     }
437
438     public void dump() {
439         dump(Debug.OUT, "");
440     }
441
442     public void dump(PrintStream out, String JavaDoc indent) {
443         out.println(indent + this);
444         String JavaDoc is = indent + " ";
445         out.println(is + "persistenceModifier = " +
446                 MDStaticUtils.toPersistenceModifierString(persistenceModifier));
447         out.println(is + "category = " +
448                 MDStaticUtils.toCategoryString(category));
449         out.println(is + "isPass1Field = " + primaryField);
450         out.println(is + "isPass2Field = " + secondaryField);
451         out.println(is + "fieldNo = " + fieldNo);
452         out.println(is + "stateFieldNo = " + stateFieldNo);
453         out.println(is + "fake = " + fake);
454         StringBuffer JavaDoc s = new StringBuffer JavaDoc();
455         s.append(is + "fakeLinks = ");
456         if (fakeLinks == null) {
457             s.append("null");
458         } else {
459             for (int i = 0; i < fakeLinks.length; i++) {
460                 if (i > 0) s.append(", ");
461                 s.append(fakeLinks[i].name);
462             }
463             s.append(']');
464         }
465         out.println(s.toString());
466         out.println(is + "type = " + type);
467         out.println(is + "typeCode = " + typeCode);
468         out.println(is + "componentType = " + componentType);
469         out.println(is + "componentTypeCode = " + componentTypeCode);
470         out.println(is + "typeMetaData = " + typeMetaData);
471         out.println(is + "modifiers = " + modifiers);
472         out.println(is + "primaryKey = " + primaryKey);
473         out.println(is + "nullValue = " +
474                 MDStaticUtils.toNullValueString(nullValue));
475         out.println(is + "defaultFetchGroup = " + defaultFetchGroup);
476         out.println(
477                 is + "defaultFetchGroupDefault = " + defaultFetchGroupDefault);
478         out.println(is + "embedded = " + embedded);
479         out.println(is + "jdoCollection = " + jdoCollection);
480         out.println(is + "jdoArray = " + jdoArray);
481         out.println(is + "jdoMap = " + jdoMap);
482         out.println(is + "elementType = " + elementType);
483         out.println(is + "elementTypeCode = " + elementTypeCode);
484         out.println(is + "elementTypeMetaData = " + elementTypeMetaData);
485         out.println(is + "embeddedElement = " + embeddedElement);
486         out.println(is + "keyType = " + keyType);
487         out.println(is + "keyTypeCode = " + keyTypeCode);
488         out.println(is + "keyTypeMetaData = " + keyTypeMetaData);
489         out.println(is + "embeddedKey = " + embeddedKey);
490         out.println(is + "ordered = " + ordered);
491         out.println(is + "fetchGroup = " + fetchGroup);
492         out.println(is + "dependentValues = " + dependentValues);
493         out.println(is + "dependentKeys = " + dependentKeys);
494         out.println(is + "autoSet = " + MDStaticUtils.toAutoSetString(autoSet));
495
496         out.println(is + "isMaster = " + isMaster);
497         out.println(is + "isDetail = " + isDetail);
498         out.println(is + "isManyToMany = " + isManyToMany);
499         out.println(is + "isReadOnly = " + isReadOnly);
500         out.println(is + "inverseFieldNo = " + inverseFieldNo);
501
502         out.println(is + "storeField = " + storeField);
503     }
504
505     /**
506      * Sort by name. Do not change this ordering as it is used to order fields
507      * for fieldNos and so on.
508      */

509     public int compareTo(Object JavaDoc o) {
510         return name.compareTo(((FieldMetaData)o).name);
511     }
512
513     public void setType(Class JavaDoc type) {
514         this.type = type;
515         if (type == null) {
516             typeCode = 0;
517         } else {
518             typeCode = MDStaticUtils.toTypeCode(type);
519         }
520     }
521
522     public static void setStateMethodName(FieldMetaData fmd) {
523         switch (fmd.category) {
524             case MDStatics.CATEGORY_SIMPLE:
525                 switch (fmd.typeCode) {
526                     case MDStatics.INT:
527
528                         fmd.stateGetMethodName = MDStatics.STATE_METHOD_INT;
529                         break;
530                     case MDStatics.LONG:
531
532                         fmd.stateGetMethodName = MDStatics.STATE_METHOD_LONG;
533                         break;
534                     case MDStatics.SHORT:
535
536                         fmd.stateGetMethodName = MDStatics.STATE_METHOD_SHORT;
537                         break;
538                     case MDStatics.STRING:
539                         fmd.stateGetMethodName = MDStatics.STATE_METHOD_STRING;
540                         break;
541                     case MDStatics.BOOLEAN:
542                         fmd.stateGetMethodName = MDStatics.STATE_METHOD_BOOLEAN;
543                         break;
544                     case MDStatics.BYTE:
545
546                         fmd.stateGetMethodName = MDStatics.STATE_METHOD_BYTE;
547                         break;
548                     case MDStatics.CHAR:
549                         fmd.stateGetMethodName = MDStatics.STATE_METHOD_CHAR;
550                         break;
551                     case MDStatics.DOUBLE:
552                         fmd.stateGetMethodName = MDStatics.STATE_METHOD_DOUBLE;
553                         break;
554                     case MDStatics.FLOAT:
555                         fmd.stateGetMethodName = MDStatics.STATE_METHOD_FLOAT;
556                         break;
557                     default:
558                         fmd.stateGetMethodName = MDStatics.STATE_METHOD_OBJECT;
559                         break;
560                 }
561                 break;
562             default:
563                 fmd.stateGetMethodName = MDStatics.STATE_METHOD_OBJECT;
564                 break;
565         }
566     }
567
568     public void setComponentType(Class JavaDoc componentType) {
569         this.componentType = componentType;
570         if (componentType == null) {
571             componentTypeCode = 0;
572         } else {
573             componentTypeCode = MDStaticUtils.toTypeCode(componentType);
574         }
575     }
576
577     public void setElementType(Class JavaDoc elementType) {
578         this.elementType = elementType;
579         if (elementType == null) {
580             elementTypeCode = 0;
581         } else {
582             elementTypeCode = MDStaticUtils.toTypeCode(elementType);
583         }
584     }
585
586     public void setKeyType(Class JavaDoc keyType) {
587         this.keyType = keyType;
588         if (keyType == null) {
589             keyTypeCode = 0;
590         } else {
591             keyTypeCode = MDStaticUtils.toTypeCode(keyType);
592         }
593     }
594
595     public void setScoField(boolean scoField) {
596         this.scoField = scoField;
597     }
598
599     /**
600      * Is this field a reference to another PC class? Note the PolyRef's are
601      * not considered direct references.
602      */

603     public boolean isDirectRef() {
604         return category == MDStatics.CATEGORY_REF;
605     }
606
607     public void setAutoSet(int autoSet) {
608         this.autoSet = autoSet;
609     }
610
611     /**
612      * Is the element type a persistent class?
613      */

614     public boolean isElementTypePC() {
615         return elementTypeMetaData != null
616                 || elementType == Object JavaDoc.class
617                 || (elementType != null && elementType.isInterface());
618     }
619
620     /**
621      * If the key field of the map is a PersistenceCapable instance.
622      *
623      * @see javax.jdo.spi.PersistenceCapable
624      */

625     public boolean isMapKeyRef() {
626         return (category == MDStatics.CATEGORY_MAP ? isKeyTypePC() : false);
627     }
628
629     /**
630      * If the value field of the map is a PersistenceCapable instance.
631      *
632      * @see javax.jdo.spi.PersistenceCapable
633      */

634     public boolean isMapValueRef() {
635         return (category == MDStatics.CATEGORY_MAP ? isElementTypePC() : false);
636     }
637
638     /**
639      * Must this field be removed from the state after commit of a transaction
640      * with retainValues true? This is used to ensure that autoSet fields
641      * are reread after an update or insert.
642      */

643     public boolean isClearOnRetainValues() {
644         return autoSet == MDStatics.AUTOSET_NO;
645     }
646
647     /**
648      * Must this field be included in all fetch groups? This is true for
649      * fields that are always required (e.g. row version fields for optimistic
650      * locking).
651      * <p/>
652      * App Id fields are also always included in all fetchGroups. This is done to
653      * enable existence checking for a join.(if the owners id fields and the id fieds of the
654      * joined row are the same. If the joined key fields are null then the ref is null)
655      */

656     public boolean includeInAllFGs() {
657         // TODO make only version fields and timestamp fields used for locking
658
return autoSet != AUTOSET_NO;
659     }
660
661     /**
662      * Does this field have default-fetch-group set to true i.e. this was
663      * done explicitly in the JDO meta data ?
664      */

665     public boolean isDefaultFetchGroupTrue() {
666         return jdoField != null && jdoField.defaultFetchGroup == MDStatics.TRUE;
667     }
668
669     public boolean isJDODefaultFetchGroup() {
670         if (isEmbeddedRef()) return false;
671         if (defaultFetchGroupDefault || isDefaultFetchGroupTrue()) {
672             if (!defaultFetchGroup) {
673                 return false;
674             } else {
675                 return true;
676             }
677         }
678         return false;
679     }
680
681 // /**
682
// * Get the default value of this field in the objectid-class. This is
683
// * only valid for primary key fields.
684
// */
685
// public Object getPKDefaultValue() {
686
// if (Debug.DEBUG) {
687
// if (!primaryKey || classMetaData.identityType != MDStatics.IDENTITY_TYPE_APPLICATION) {
688
// throw BindingSupportImpl.getInstance().internal(
689
// "Not an application identity class: " + getQName());
690
// }
691
// }
692
// if (!primaryKey) {
693
// throw BindingSupportImpl.getInstance().internal("Not a primary-key field: " +
694
// getQName());
695
// }
696
// if (pkDefaultValue == null) {
697
// try {
698
// Object o = classMetaData.objectIdClass.newInstance();
699
// pkDefaultValue = classMetaData.objectIdClass.getField(getPkFieldName()).get(
700
// o);
701
// } catch (Exception e) {
702
// throw BindingSupportImpl.getInstance().exception("Unable to get primary key field from objectid-class: " +
703
// getQName() + ": " + e, e);
704
// }
705
// }
706
// return pkDefaultValue;
707
// }
708

709     /**
710      * Get the default value of this field in the objectid-class. This is
711      * only valid for primary key fields.
712      */

713     public Object JavaDoc getPKDefaultValue() {
714         if (Debug.DEBUG) {
715             if (!primaryKey || classMetaData.identityType != MDStatics.IDENTITY_TYPE_APPLICATION) {
716                 throw BindingSupportImpl.getInstance().internal(
717                         "Not an application identity class: " + getQName());
718             }
719         }
720         if (!primaryKey) {
721             throw BindingSupportImpl.getInstance().internal("Not a primary-key field: " +
722                     getQName());
723         }
724         return pkDefaultValue;
725     }
726
727     public void initPkDefaultValue(Object JavaDoc pkClassInst) {
728         if (Debug.DEBUG) {
729             if (!primaryKey || classMetaData.identityType != MDStatics.IDENTITY_TYPE_APPLICATION) {
730                 throw BindingSupportImpl.getInstance().internal(
731                         "Not an application identity class: " + getQName());
732             }
733         }
734         if (!primaryKey) {
735             throw BindingSupportImpl.getInstance().internal("Not a primary-key field: " +
736                     getQName());
737         }
738         if (pkDefaultValue == null) {
739             try {
740                 pkDefaultValue = classMetaData.objectIdClass.getField(getPkFieldName()).get(
741                         pkClassInst);
742             } catch (Exception JavaDoc e) {
743                 throw BindingSupportImpl.getInstance().exception("Unable to get primary key field from objectid-class: " +
744                         getQName() + ": " + e, e);
745             }
746         }
747     }
748
749     public void setPkDefaultValue(Object JavaDoc pkDefaultValue) {
750         this.pkDefaultValue = pkDefaultValue;
751     }
752
753     public void writeExternal(ObjectOutput out) throws IOException {
754 // if (Debug.DEBUG) {
755
// System.out.println("%%% FieldMetaData.writeExternal " + getQName());
756
// }
757
out.writeObject(classMetaData);
758         out.writeObject(jdoField);
759         out.writeObject(name);
760         out.writeObject(origName);
761         out.writeInt(fieldNo);
762         out.writeInt(stateFieldNo);
763         out.writeInt(managedFieldNo);
764         out.writeBoolean(fake);
765         out.writeObject(fakeLinks);
766         out.writeInt(persistenceModifier);
767         out.writeInt(category);
768         out.writeBoolean(primaryField);
769         out.writeBoolean(secondaryField);
770         out.writeInt(typeCode);
771         if (MDStaticUtils.toSimpleClass(MDStaticUtils.toSimpleName(typeCode)) == null) {
772             out.writeObject(type);
773         }
774         out.writeObject(componentType);
775         out.writeInt(componentTypeCode);
776         out.writeObject(typeMetaData);
777         out.writeInt(modifiers);
778         out.writeInt(nullValue);
779         out.writeBoolean(defaultFetchGroup);
780         out.writeBoolean(defaultFetchGroupDefault);
781         out.writeBoolean(embedded);
782         out.writeObject(jdoCollection);
783         out.writeObject(jdoArray);
784         out.writeObject(elementType);
785         out.writeInt(elementTypeCode);
786         out.writeObject(elementTypeMetaData);
787         out.writeBoolean(embeddedElement);
788         out.writeObject(keyType);
789         out.writeInt(keyTypeCode);
790         out.writeObject(keyTypeMetaData);
791         out.writeBoolean(embeddedKey);
792         out.writeBoolean(ordered);
793         out.writeObject(fetchGroup);
794         out.writeBoolean(dependentValues);
795         out.writeBoolean(dependentKeys);
796         out.writeInt(autoSet);
797         out.writeBoolean(scoField);
798         out.writeBoolean(primaryKey);
799         out.writeBoolean(collectionDiffType);
800         if (stateGetMethodName == null) {
801             out.writeBoolean(false);
802         } else {
803             out.writeBoolean(true);
804             out.writeUTF(stateGetMethodName);
805         }
806         out.writeBoolean(isMaster);
807         out.writeBoolean(isDetail);
808         out.writeBoolean(isManyToMany);
809         out.writeBoolean(managed);
810         out.writeBoolean(isReadOnly);
811         out.writeInt(inverseFieldNo);
812         out.writeObject(simpleSCOFactory);
813         out.writeObject(collectionFactory);
814         out.writeObject(mapFactory);
815         out.writeBoolean(includeAllDataInDiff);
816         out.writeObject(inverseFieldMetaData);
817         out.writeObject(externalizer);
818
819         out.writeObject(managedEmbeddedFields);
820         out.writeObject(nullIndicatorFmd);
821         out.writeBoolean(embeddedFakeField);
822         out.writeObject(origFmd);
823         out.writeObject(embeddedFmds);
824     }
825
826     public void readExternal(ObjectInput in) throws IOException,
827             ClassNotFoundException JavaDoc {
828         classMetaData = (ClassMetaData)in.readObject();
829         jdoField = (JdoField)in.readObject();
830         name = (String JavaDoc)in.readObject();
831         origName = (String JavaDoc)in.readObject();
832         fieldNo = in.readInt();
833         stateFieldNo = in.readInt();
834         managedFieldNo = in.readInt();
835         fake = in.readBoolean();
836         fakeLinks = (FieldMetaData[])in.readObject();
837         persistenceModifier = in.readInt();
838         category = in.readInt();
839         primaryField = in.readBoolean();
840         secondaryField = in.readBoolean();
841         typeCode = in.readInt();
842         type = MDStaticUtils.toSimpleClass(
843                 MDStaticUtils.toSimpleName(typeCode));
844         if (type == null) {
845             type = (Class JavaDoc)in.readObject();
846         }
847         componentType = (Class JavaDoc)in.readObject();
848         componentTypeCode = in.readInt();
849         typeMetaData = (ClassMetaData)in.readObject();
850         modifiers = in.readInt();
851         nullValue = in.readInt();
852         defaultFetchGroup = in.readBoolean();
853         defaultFetchGroupDefault = in.readBoolean();
854         embedded = in.readBoolean();
855         jdoCollection = (JdoCollection)in.readObject();
856         jdoArray = (JdoArray)in.readObject();
857         elementType = (Class JavaDoc)in.readObject();
858         elementTypeCode = in.readInt();
859         elementTypeMetaData = (ClassMetaData)in.readObject();
860         embeddedElement = in.readBoolean();
861         keyType = (Class JavaDoc)in.readObject();
862         keyTypeCode = in.readInt();
863         keyTypeMetaData = (ClassMetaData)in.readObject();
864         embeddedKey = in.readBoolean();
865         ordered = in.readBoolean();
866         fetchGroup = (FetchGroup)in.readObject();
867         dependentValues = in.readBoolean();
868         dependentKeys = in.readBoolean();
869         autoSet = in.readInt();
870         scoField = in.readBoolean();
871         primaryKey = in.readBoolean();
872         collectionDiffType = in.readBoolean();
873         if (in.readBoolean()) {
874             stateGetMethodName = in.readUTF();
875         } else {
876             stateGetMethodName = null;
877         }
878         isMaster = in.readBoolean();
879         isDetail = in.readBoolean();
880         isManyToMany = in.readBoolean();
881         managed = in.readBoolean();
882         isReadOnly = in.readBoolean();
883         inverseFieldNo = in.readInt();
884         simpleSCOFactory = (VersantSCOFactory)in.readObject();
885         collectionFactory = (VersantSCOCollectionFactory)in.readObject();
886         mapFactory = (VersantSCOMapFactory)in.readObject();
887         includeAllDataInDiff = in.readBoolean();
888         inverseFieldMetaData = (FieldMetaData)in.readObject();
889         externalizer = (Externalizer)in.readObject();
890
891         managedEmbeddedFields = (FieldMetaData[]) in.readObject();
892         nullIndicatorFmd = (FieldMetaData) in.readObject();
893         embeddedFakeField = in.readBoolean();
894         origFmd = (FieldMetaData)in.readObject();
895         embeddedFmds = (FieldMetaData[])in.readObject();
896     }
897
898     /**
899      * Get the name for use in comments in SQL files and so on. This will
900      * include the name of the class if this field is in a subclass.
901      */

902     public String JavaDoc getCommentName() {
903         if (classMetaData.pcSuperMetaData == null) return name;
904         if (classMetaData.jdoClass == null) return getQName();
905         return classMetaData.jdoClass.name + "." + name;
906     }
907
908     /**
909      * Get the comparator for this field if it makes sense i.e. this
910      * is a sorted Collection or Map with Comparator. This is cached.
911      */

912     public Comparator getComparator() {
913         if (!comparatorInitDone) {
914             comparatorInitDone = true;
915             boolean set = SortedSet.class.isAssignableFrom(type);
916             boolean map = !set && SortedMap.class.isAssignableFrom(type);
917             if (set || map) {
918                 Object JavaDoc o = classMetaData.getMetaDataInstance();
919                 if (o != null) {
920                     Field f = getReflectField();
921                     try {
922                         Object JavaDoc v = ClassHelper.get().getFieldValue(f, o);
923                         if (v != null) {
924                             if (set) {
925                                 comparator = ((SortedSet)v).comparator();
926                             } else {
927                                 comparator = ((SortedMap)v).comparator();
928                             }
929                         }
930                     } catch (Exception JavaDoc x) {
931                         throw BindingSupportImpl.getInstance().invalidOperation("Unable get Field comparator with reflection: " +
932                                 getQName() + ": " + x, x);
933                     }
934                 }
935             }
936         }
937         return comparator;
938     }
939
940     /**
941      * Get a Field instance for this field using reflection. This will have
942      * setAccessible(true) called on it.
943      */

944     public Field getReflectField() {
945         try {
946             Field f = classMetaData.cls.getDeclaredField(origName);
947             ClassHelper.get().setAccessible(f, true);
948             return f;
949         } catch (Exception JavaDoc x) {
950             throw BindingSupportImpl.getInstance().invalidOperation("Unable get Field with reflection: " +
951                     getQName() + ": " + x, x);
952         }
953     }
954
955     public void addError(RuntimeException JavaDoc e, boolean quiet) {
956         if (Debug.DEBUG) e.printStackTrace(System.out);
957         if (error == null) {
958             errorTime = System.currentTimeMillis();
959             error = e;
960             try {
961                 Thread.sleep(1);
962             } catch (InterruptedException JavaDoc e1) {
963                 // ignore
964
}
965         }
966         if (!quiet) throw e;
967     }
968
969     public RuntimeException JavaDoc getFirstError() {
970         return error;
971     }
972
973     public long getFirstErrorTime() {
974         return errorTime;
975     }
976
977     public boolean hasErrors() {
978         return error != null;
979     }
980
981     /**
982      * The name of the field.
983      */

984     public String JavaDoc getName() {
985         return name;
986     }
987
988     /**
989      * Is this an ordered collection?
990      */

991     public boolean isOrdered() {
992         return ordered;
993     }
994
995     /**
996      * The type code for elementType (0 if none).
997      *
998      * @see MDStatics
999      * @see #elementType
1000     */

1001    public int getElementTypeCode() {
1002        return elementTypeCode;
1003    }
1004
1005    /**
1006     * The absolute fieldNo for this field.
1007     */

1008    public int getManagedFieldNo() {
1009        return managedFieldNo;
1010    }
1011
1012    /**
1013     * The meta data for keyType if it is a PC class (null otherwise).
1014     */

1015    public boolean isKeyTypePC() {
1016        return keyTypeMetaData != null || keyType == Object JavaDoc.class
1017                || (keyType != null && keyType.isInterface());
1018    }
1019
1020    /**
1021     * The type code for keyType (0 if none).
1022     *
1023     * @see MDStatics
1024     * @see #keyType
1025     */

1026    public int getKeyTypeCode() {
1027        return keyTypeCode;
1028    }
1029
1030    /**
1031     * The type stored in the collection or the value type for a map or the
1032     * component type for an array.
1033     */

1034    public Class JavaDoc getElementType() {
1035        return elementType;
1036    }
1037
1038    /**
1039     * The key type (null if not a map).
1040     */

1041    public Class JavaDoc getKeyType() {
1042        return keyType;
1043    }
1044
1045    /**
1046     * Is isMaster or isManyToMany is set then this indicates if
1047     * the relationship is managed by the SCOs or not. Note that this field
1048     * is filled in by the JdbcField involved.
1049     */

1050    public boolean isManaged() {
1051        return managed;
1052    }
1053
1054    /**
1055     * Is this field a master (one) in a master/detail (one-to-many)
1056     * relationship
1057     */

1058    public boolean isMaster() {
1059        return isMaster;
1060    }
1061
1062    /**
1063     * Is this field in a many-to-many relationship?
1064     */

1065    public boolean isManyToMany() {
1066        return isManyToMany;
1067    }
1068
1069    /**
1070     * If isMaster, isDetail or isManyToMany is set then this is the fieldNo of
1071     * the field on the other side of the relationship.
1072     */

1073    public int getInverseFieldNo() {
1074        return inverseFieldNo;
1075    }
1076
1077    /**
1078     * If isMaster, isDetail or isManyToMany is set then this is the field
1079     * on the other side of the relationship.
1080     */

1081    public VersantFieldMetaData getInverseFieldMetaData() {
1082        return inverseFieldMetaData;
1083    }
1084
1085    public VersantSimpleSCO createSCO(PersistenceContext pm,
1086            VersantStateManager sm, FieldMetaData fmd,
1087            PersistenceCapable owner, Object JavaDoc data) {
1088        //create a new SCO data
1089
switch (fmd.category) {
1090            case MDStatics.CATEGORY_SIMPLE:
1091                return createSimpleSCO(pm, sm, fmd, owner, data);
1092            case MDStatics.CATEGORY_COLLECTION:
1093                return createCollectionSCO(pm, sm, fmd, owner, data);
1094            case MDStatics.CATEGORY_MAP:
1095                return createMapSCO(pm, sm, fmd, owner, data);
1096        }
1097        return null;
1098    }
1099
1100    public VersantSimpleSCO createSimpleSCO(PersistenceContext pm,
1101            VersantStateManager sm, FieldMetaData fmd,
1102            PersistenceCapable owner, Object JavaDoc data) {
1103        if (data == null) return null;
1104        if (data instanceof VersantAdvancedSCO) {
1105            VersantAdvancedSCO sco = (VersantAdvancedSCO)data;
1106            if (sco.getOwner() != null && sco.getOwner() == owner) {
1107                //may re-use
1108
sco.reset();
1109                return sco;
1110            }
1111        }
1112        //create a new SCO data
1113
return simpleSCOFactory.createSCO(owner, pm, sm, fmd, data);
1114    }
1115
1116    public VersantSimpleSCO createCollectionSCO(
1117            PersistenceContext pm,
1118            VersantStateManager sm, FieldMetaData fmd,
1119            PersistenceCapable owner, Object JavaDoc data) {
1120        if (data == null) return null;
1121        if (data instanceof VersantAdvancedSCO) {
1122            VersantAdvancedSCO sco = (VersantAdvancedSCO)data;
1123            if (sco.getOwner() != null && sco.getOwner() == owner) {
1124                //may re-use
1125
sco.reset();
1126                return sco;
1127            }
1128        }
1129        //create a new SCO data
1130
if (data instanceof CollectionData) {
1131            CollectionData collectionData = (CollectionData)data;
1132            return collectionFactory.createSCOCollection(owner, pm, sm, fmd,
1133                    collectionData);
1134        } else if (data instanceof Object JavaDoc[]) {
1135            Object JavaDoc[] objects = (Object JavaDoc[])data;
1136            CollectionData collectionData = new CollectionData();
1137            collectionData.valueCount = objects.length;
1138            collectionData.values = objects;
1139            return collectionFactory.createSCOCollection(owner, pm, sm, fmd,
1140                    collectionData);
1141        } else if (data instanceof Collection) {
1142            Collection collection = (Collection)data;
1143            return collectionFactory.createSCOCollection(owner, pm, sm, fmd,
1144                    collection);
1145
1146        } else {
1147            throw BindingSupportImpl.getInstance().internal("data is not CollectionData, Object[] or Collection: " + fmd.getQName() +
1148                    " data " + data);
1149        }
1150    }
1151
1152    public VersantSimpleSCO createMapSCO(PersistenceContext pm,
1153            VersantStateManager sm, FieldMetaData fmd,
1154            PersistenceCapable owner, Object JavaDoc data) {
1155        if (data == null) return null;
1156        if (data instanceof VersantAdvancedSCO) {
1157            VersantAdvancedSCO sco = (VersantAdvancedSCO)data;
1158            if (sco.getOwner() != null && sco.getOwner() == owner) {
1159                //may re-use
1160
sco.reset();
1161                return sco;
1162            }
1163        }
1164        //create a new SCO data
1165
if (data == null) return null;
1166        if (data instanceof MapData) {
1167            MapData mapData = (MapData)data;
1168            return mapFactory.createSCOHashMap(owner, pm, sm, fmd, mapData);
1169        } else if (data instanceof MapEntries) {
1170            MapEntries entries = (MapEntries)data;
1171            MapData mapData = new MapData();
1172            mapData.entryCount = entries.keys.length;
1173            mapData.keys = entries.keys;
1174            mapData.values = entries.values;
1175            return mapFactory.createSCOHashMap(owner, pm, sm, fmd, mapData);
1176        } else if (data instanceof Map) {
1177            return mapFactory.createSCOHashMap(owner, pm, sm, fmd, (Map)data);
1178
1179        } else {
1180            throw BindingSupportImpl.getInstance().internal("data is not MapData, MapEntries or MAp: " + fmd.getQName() +
1181                    " data " + data);
1182        }
1183    }
1184
1185    /**
1186     * If this is a collection, array or map and this field is true then all
1187     * data must be provided in the diff instance instead of just the changes
1188     * on commit or flush. This is used for datastores like VDS that always
1189     * write everything.
1190     */

1191    public boolean isIncludeAllDataInDiff() {
1192        return includeAllDataInDiff;
1193    }
1194
1195    /**
1196     * Is this an artificial field created to hold some store specific
1197     * information (e.g. row version column values for a JDBC store)?
1198     */

1199    public boolean isFake() {
1200        return fake;
1201    }
1202
1203    public void setScoFactory(Object JavaDoc factory) {
1204        this.scoFactory = factory;
1205    }
1206
1207    public boolean checkCustomFactory() {
1208        if (scoFactory != null) {
1209            switch (category) {
1210                case MDStatics.CATEGORY_SIMPLE:
1211                    simpleSCOFactory = (VersantSCOFactory)scoFactory;
1212                    break;
1213                case MDStatics.CATEGORY_COLLECTION:
1214                    collectionFactory = (VersantSCOCollectionFactory)scoFactory;
1215                    break;
1216                case MDStatics.CATEGORY_MAP:
1217                    mapFactory = (VersantSCOMapFactory)scoFactory;
1218                    break;
1219                default:
1220                    throw BindingSupportImpl.getInstance().runtime("SCO factory '" + scoFactory.getClass().getName() +
1221                            "' set on non SCO field. class: " + classMetaData.cls.getName() +
1222                            " field: " + name);
1223            }
1224            return true;
1225        } else {
1226            return false;
1227        }
1228    }
1229
1230    /**
1231     * Return the {@link Externalizer transformer} for this field.
1232     */

1233    public Externalizer getSerializer(VersantPersistenceManagerImp pm) {
1234        if (Debug.DEBUG) {
1235            if (category != MDStatics.CATEGORY_EXTERNALIZED) {
1236                throw BindingSupportImpl.getInstance().internal("This field '"
1237                        + name + "' is not a 'Serialized' field");
1238            }
1239        }
1240        return externalizer;
1241    }
1242
1243
1244    
1245    public boolean isEmbeddedRef() {
1246        return embedded && category == MDStatics.CATEGORY_REF;
1247    }
1248
1249    /**
1250     * If this field is part of the primary key and this class uses application
1251     * identity then this is the corresponding field from the objectid-class.
1252     */

1253    public Field getObjectidClassField() {
1254        if (objectidClassField == null) {
1255            Class JavaDoc idClass = classMetaData.objectIdClass;
1256            Field field = getRField(idClass);
1257            if (field == null) {
1258                throw BindingSupportImpl.getInstance().runtime("Application id class '"
1259                        + idClass.getName()
1260                        + "' must have field: 'public " + type.getName() +
1261                        " " + name + "'");
1262            }
1263            if (!Modifier.isPublic(field.getModifiers())) {
1264                throw BindingSupportImpl.getInstance().runtime("Application id class '"
1265                        + idClass.getName()
1266                        + "' field '" + name + "' is not public");
1267            }
1268
1269            if (type != field.getType()) {
1270                throw BindingSupportImpl.getInstance().runtime(
1271                        "Application id class '"
1272                        + idClass.getName()
1273                        + "' field '" + name + "' has wrong type '" +
1274                        type.getName() + "' (should be " + type + ")");
1275            }
1276            objectidClassField = field;
1277        }
1278        return objectidClassField;
1279    }
1280
1281    private Field getRField(Class JavaDoc idClass) {
1282        for (; idClass != null; idClass = idClass.getSuperclass()) {
1283            Field[] fields = idClass.getFields();
1284            Field ans = null;
1285            for (int i = 0; i < fields.length; i++) {
1286                Field field = fields[i];
1287                if (field.getName().equals(getPkFieldName())) {
1288                    if (Modifier.isPublic(field.getModifiers())) return field;
1289                    ans = field;
1290                }
1291
1292            }
1293            if (ans != null) return ans;
1294        }
1295        return null;
1296    }
1297
1298    public FieldMetaData findEmbeddedFmd(String JavaDoc name) {
1299        if(embeddedFmds == null){
1300            return null;
1301        }
1302        // do a binary search since fields is sorted by name
1303
int low = 0;
1304        int high = embeddedFmds.length - 1;
1305        name = this.name+"/"+name;
1306        while (low <= high) {
1307            int mid = (low + high) / 2;
1308            FieldMetaData midVal = embeddedFmds[mid];
1309            String JavaDoc name2 = midVal.name;
1310            int cmp = name2.compareTo(name);
1311            if (cmp < 0) {
1312                low = mid + 1;
1313            } else if (cmp > 0) {
1314                high = mid - 1;
1315            } else {
1316                return midVal;
1317            }
1318        }
1319        return null;
1320    }
1321
1322    public String JavaDoc getPkFieldName() {
1323        if (fake) return origFmd.name;
1324        return name;
1325    }
1326
1327    public void setNullIndicatorFmd(FieldMetaData fmd) {
1328        if (isEmbeddedRef()) {
1329            if (nullIndicatorFmd == null) {
1330                nullIndicatorFmd = fmd;
1331            } else {
1332                throw BindingSupportImpl.getInstance().invalidOperation(
1333                        "Attempting to set more that one 'Null-Indicator' " +
1334                        "field for Embedded field '"
1335                        + classMetaData.qname + "." + name + "'. " +
1336                        "Please correct the metadata.");
1337            }
1338        } else {
1339            throw BindingSupportImpl.getInstance().internal(
1340                    "Not allowed to set NullIndicator '"
1341                    + fmd.classMetaData.qname + "." + fmd.name
1342                    + "' on a non-embedded ref: '"
1343                    + classMetaData.qname + "." + name + "'");
1344        }
1345    }
1346}
1347
Popular Tags