001: /*
002: * Copyright 2004 (C) TJDO.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the TJDO License version 1.0.
006: * See the terms of the TJDO License in the documentation provided with this software.
007: *
008: * $Id: FieldMetaData.java,v 1.9 2004/03/22 04:58:12 jackknifebarber Exp $
009: */
010:
011: package com.triactive.jdo.model;
012:
013: import com.triactive.jdo.ClassNotPersistenceCapableException;
014: import com.triactive.jdo.store.NoSuchPersistentFieldException;
015: import java.lang.reflect.Field;
016: import java.util.Arrays;
017: import java.util.Collection;
018: import java.util.List;
019: import java.util.Map;
020: import java.util.Set;
021: import org.w3c.dom.Element;
022: import org.w3c.dom.Node;
023:
024: public class FieldMetaData extends MetaData implements Comparable,
025: ColumnOptions {
026: public static final int PERSISTENCE_MODIFIER_NONE = 0;
027: public static final int PERSISTENCE_MODIFIER_PERSISTENT = 1;
028: public static final int PERSISTENCE_MODIFIER_TRANSACTIONAL = 2;
029:
030: public static final int NULL_VALUE_NONE = 0;
031: public static final int NULL_VALUE_DEFAULT = 1;
032: public static final int NULL_VALUE_EXCEPTION = 2;
033:
034: private static final List persistenceModifierValues = Arrays
035: .asList(new String[] { "none", "persistent",
036: "transactional" });
037:
038: private static final List nullValueValues = Arrays
039: .asList(new String[] { "none", "default", "exception" });
040:
041: protected final ClassMetaData owner;
042: protected final Field field;
043: protected final Class type;
044: protected final boolean embedded;
045: protected final int persistenceModifier;
046: protected final boolean primaryKey;
047: protected final int nullValue;
048: protected boolean defaultFetchGroup;
049: protected final ArrayMetaData arrayMetaData;
050: protected final CollectionMetaData collectionMetaData;
051: protected final MapMetaData mapMetaData;
052:
053: public static FieldMetaData forField(Class clazz, String fieldName) {
054: ClassMetaData cmd = ClassMetaData.forClass(clazz);
055:
056: if (cmd == null)
057: throw new ClassNotPersistenceCapableException(clazz);
058:
059: int fieldNumber = cmd.getAbsoluteFieldNumber(fieldName);
060:
061: if (fieldNumber < 0)
062: throw new NoSuchPersistentFieldException(clazz, fieldName);
063:
064: return cmd.getFieldAbsolute(fieldNumber);
065: }
066:
067: public FieldMetaData(ClassMetaData owner, Element fldElement) {
068: super (owner.getSourceURL(), fldElement);
069:
070: this .owner = owner;
071:
072: String fieldName = fldElement.getAttribute("name");
073:
074: try {
075: this .field = owner.getPCClass().getDeclaredField(fieldName);
076: } catch (NoSuchFieldException e) {
077: throw new XMLMetaDataException(owner.getSourceURL(),
078: "Field " + fieldName + " not found in "
079: + owner.getPCClass(), e);
080: }
081:
082: this .type = field.getType();
083:
084: /*
085: * Process the "embedded" attribute.
086: */
087: String embeddedAttr = fldElement.getAttribute("embedded");
088: boolean embedded;
089:
090: if (embeddedAttr.length() > 0)
091: this .embedded = Boolean.valueOf(embeddedAttr)
092: .booleanValue();
093: else
094: this .embedded = Types.isDefaultEmbeddedType(type);
095:
096: /*
097: * Process the "persistence-modifier" attribute.
098: */
099: String pmAttr = fldElement.getAttribute("persistence-modifier");
100:
101: if (pmAttr.length() > 0) {
102: persistenceModifier = persistenceModifierValues
103: .indexOf(pmAttr);
104:
105: if (persistenceModifier < 0)
106: throw new XMLMetaDataException(owner.getSourceURL(),
107: "Unrecognized persistence-modifier " + pmAttr);
108: } else
109: persistenceModifier = PERSISTENCE_MODIFIER_PERSISTENT;
110:
111: /*
112: * Process the "primary-key" attribute.
113: */
114: primaryKey = Boolean.valueOf(
115: fldElement.getAttribute("primary-key")).booleanValue();
116:
117: /*
118: * Process the "null-value" attribute.
119: */
120: String nvAttr = fldElement.getAttribute("null-value");
121:
122: if (nvAttr.length() > 0) {
123: nullValue = nullValueValues.indexOf(nvAttr);
124:
125: if (nullValue < 0)
126: throw new XMLMetaDataException(owner.getSourceURL(),
127: "Unrecognized null-value " + nvAttr);
128: } else
129: nullValue = NULL_VALUE_NONE;
130:
131: /*
132: * Process the "default-fetch-group" attribute.
133: */
134: String defaultFetchGroupAttr = fldElement
135: .getAttribute("default-fetch-group");
136:
137: if (defaultFetchGroupAttr.length() > 0)
138: defaultFetchGroup = Boolean.valueOf(defaultFetchGroupAttr)
139: .booleanValue();
140: else
141: defaultFetchGroup = persistenceModifier == PERSISTENCE_MODIFIER_PERSISTENT
142: && Types.isDefaultFetchGroupType(type);
143:
144: ArrayMetaData amd = null;
145: CollectionMetaData cmd = null;
146: MapMetaData mmd = null;
147:
148: for (Node node = fldElement.getFirstChild(); node != null; node = node
149: .getNextSibling()) {
150: if (node instanceof Element) {
151: Element child = (Element) node;
152: String childTag = child.getTagName();
153:
154: if (childTag.equals("array")) {
155: if (!type.isArray())
156: throw new XMLMetaDataException(
157: owner.getSourceURL(),
158: "Field "
159: + getName()
160: + " has an array element but is not an array");
161:
162: if (amd != null)
163: throw new XMLMetaDataException(owner
164: .getSourceURL(),
165: "Duplicate array element in " + this );
166:
167: amd = new ArrayMetaData(this , child);
168: } else if (childTag.equals("collection")) {
169: if (!Collection.class.isAssignableFrom(type))
170: throw new XMLMetaDataException(
171: owner.getSourceURL(),
172: "Field "
173: + getName()
174: + " has a collection element but is not a Collection");
175:
176: if (cmd != null)
177: throw new XMLMetaDataException(owner
178: .getSourceURL(),
179: "Duplicate collection element in "
180: + this );
181:
182: cmd = new CollectionMetaData(this , child);
183: } else if (childTag.equals("map")) {
184: if (!Map.class.isAssignableFrom(type))
185: throw new XMLMetaDataException(owner
186: .getSourceURL(), "Field " + getName()
187: + " has a map element but is not a Map");
188:
189: if (mmd != null)
190: throw new XMLMetaDataException(owner
191: .getSourceURL(),
192: "Duplicate map element in " + this );
193:
194: mmd = new MapMetaData(this , child);
195: }
196: }
197: }
198:
199: arrayMetaData = amd;
200: collectionMetaData = cmd;
201: mapMetaData = mmd;
202: }
203:
204: public FieldMetaData(ClassMetaData owner, Field field) {
205: super ();
206:
207: this .owner = owner;
208: this .field = field;
209:
210: type = field.getType();
211: embedded = Types.isDefaultEmbeddedType(type);
212: persistenceModifier = PERSISTENCE_MODIFIER_PERSISTENT;
213: primaryKey = false;
214: nullValue = NULL_VALUE_NONE;
215: defaultFetchGroup = Types.isDefaultFetchGroupType(type);
216: arrayMetaData = null;
217: collectionMetaData = null;
218: mapMetaData = null;
219: }
220:
221: public Class getType() {
222: return type;
223: }
224:
225: public boolean isEmbedded() {
226: return embedded;
227: }
228:
229: public String getJavaName() {
230: return owner.getJavaName() + '.' + field.getName();
231: }
232:
233: public ClassMetaData getClassMetaData() {
234: return owner;
235: }
236:
237: public String getName() {
238: return field.getName();
239: }
240:
241: public Field getField() {
242: return field;
243: }
244:
245: public int getPersistenceModifier() {
246: return persistenceModifier;
247: }
248:
249: public boolean isPrimaryKeyPart() {
250: return primaryKey;
251: }
252:
253: public int getNullValueHandling() {
254: return nullValue;
255: }
256:
257: public boolean isInDefaultFetchGroup() {
258: return defaultFetchGroup;
259: }
260:
261: public void setDefaultFetchGroup(boolean defaultFetchGroup) {
262: this .defaultFetchGroup = defaultFetchGroup;
263: }
264:
265: public String getLength() {
266: return getVendorExtension(MY_VENDOR, "length");
267: }
268:
269: public String getPrecision() {
270: return getVendorExtension(MY_VENDOR, "precision");
271: }
272:
273: public String getScale() {
274: return getVendorExtension(MY_VENDOR, "scale");
275: }
276:
277: public ArrayMetaData getArrayMetaData() {
278: return arrayMetaData;
279: }
280:
281: public CollectionMetaData getCollectionMetaData() {
282: return collectionMetaData;
283: }
284:
285: public MapMetaData getMapMetaData() {
286: return mapMetaData;
287: }
288:
289: public FieldMetaData getOwnedByCollection() {
290: String collFieldName = getVendorExtension(MY_VENDOR,
291: "collection-field");
292:
293: if (collFieldName == null)
294: collFieldName = getVendorExtension("sunw", "inverse");
295:
296: return collFieldName == null ? null : forField(type,
297: collFieldName);
298: }
299:
300: public FieldMetaData getOwnedByMap() {
301: String mapFieldName = getVendorExtension(MY_VENDOR, "map-field");
302:
303: return mapFieldName == null ? null : forField(type,
304: mapFieldName);
305: }
306:
307: void getReferencedClasses(final String vendorID,
308: final List ordered, final Set referenced) {
309: ClassMetaData cmd = ClassMetaData.forClass(type);
310:
311: if (cmd != null)
312: cmd.getReferencedClasses(vendorID, ordered, referenced);
313:
314: if (arrayMetaData != null)
315: arrayMetaData.getReferencedClasses(vendorID, ordered,
316: referenced);
317:
318: if (collectionMetaData != null)
319: collectionMetaData.getReferencedClasses(vendorID, ordered,
320: referenced);
321:
322: if (mapMetaData != null)
323: mapMetaData.getReferencedClasses(vendorID, ordered,
324: referenced);
325: }
326:
327: public int compareTo(Object obj) {
328: return getName().compareTo(((FieldMetaData) obj).getName());
329: }
330:
331: public String toString() {
332: return "Metadata for " + owner.getPCClass().getName() + '.'
333: + getName();
334: }
335: }
|