001: /*
002: * Copyright (c) 1998 - 2005 Versant Corporation
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * Versant Corporation - initial API and implementation
010: */
011: package com.versant.core.metadata.parser;
012:
013: import com.versant.core.metadata.MDStaticUtils;
014: import com.versant.core.metadata.MDStatics;
015: import com.versant.core.common.Debug;
016: import com.versant.core.common.BindingSupportImpl;
017:
018: import java.io.PrintStream;
019: import java.util.*;
020:
021: /**
022: * Field element from a .jdo file.
023: */
024: public final class JdoField extends JdoElement {
025: private final static Set VENDOR_IGNORE_SET = new HashSet();
026:
027: public String name;
028: public String origName;
029: public int persistenceModifier;
030: public boolean primaryKey;
031: public int nullValue;
032: public int defaultFetchGroup;
033: public int embedded;
034:
035: /**
036: * Temp list to hold extensions
037: */
038: public ArrayList extensionList = new ArrayList();
039:
040: public List embeddedFields;
041: public JdoField parentField;
042: public boolean nullIndicator;
043:
044: public JdoCollection collection;
045: public JdoMap map;
046: public JdoArray array;
047:
048: public JdoExtension[] extensions;
049:
050: public JdoClass parent;
051: public int cascadeType;
052:
053: public JdoField() {
054: VENDOR_IGNORE_SET.add(JdoExtension
055: .toKeyString(JdoExtensionKeys.COLLECTION));
056: VENDOR_IGNORE_SET.add(JdoExtension
057: .toKeyString(JdoExtensionKeys.EMBEDDED));
058: VENDOR_IGNORE_SET.add(JdoExtension
059: .toKeyString(JdoExtensionKeys.DEFAULT_FETCH_GROUP));
060: VENDOR_IGNORE_SET.add(JdoExtension
061: .toKeyString(JdoExtensionKeys.MAP));
062: VENDOR_IGNORE_SET.add(JdoExtension
063: .toKeyString(JdoExtensionKeys.ARRAY));
064: }
065:
066: public JdoField createCopy(JdoField parentField,
067: JdoClass parentClass) {
068: JdoField jf = new JdoField(parentField);
069: jf.name = name;
070: jf.persistenceModifier = persistenceModifier;
071: jf.primaryKey = primaryKey;
072: jf.nullValue = nullValue;
073: jf.defaultFetchGroup = defaultFetchGroup;
074: jf.embedded = embedded;
075:
076: jf.parent = parentClass;
077: if (collection != null)
078: jf.collection = collection.createCopy(jf);
079: if (map != null)
080: jf.map = map.createCopy(jf);
081: if (array != null)
082: jf.array = array.createCopy(jf);
083:
084: if (extensions != null) {
085: jf.extensions = new JdoExtension[extensions.length];
086: for (int i = 0; i < extensions.length; i++) {
087: jf.extensions[i] = extensions[i].createCopy(jf);
088: }
089: }
090: return jf;
091: }
092:
093: public JdoField createCopy(JdoField parentField) {
094: return createCopy(parentField, null);
095: }
096:
097: public JdoField createCopy(JdoClass parentClass) {
098: return createCopy(null, parentClass);
099: }
100:
101: public JdoField(JdoField parentField) {
102: this .parentField = parentField;
103: if (parentField != null)
104: parentField.addEmbeddedField(this );
105: }
106:
107: public JdoElement getParent() {
108: return parent;
109: }
110:
111: public void addEmbeddedField(JdoField embeddedField) {
112: if (embeddedFields == null)
113: embeddedFields = new ArrayList();
114: embeddedFields.add(embeddedField);
115: }
116:
117: public boolean isExternalized() {
118: if (extensions != null) {
119: for (int i = 0; i < extensions.length; i++) {
120: if (extensions[i].key == JdoExtensionKeys.EXTERNALIZER) {
121: return true;
122: }
123: }
124: }
125: return false;
126: }
127:
128: /**
129: * Get information for this element to be used in building up a
130: * context string.
131: * @see #getContext
132: */
133: public String getSubContext() {
134: return "field[" + name + "]";
135: }
136:
137: public String toString() {
138: StringBuffer s = new StringBuffer();
139: s.append("field[");
140: s.append(name);
141: s.append("] persistenceModifier=");
142: s.append(MDStaticUtils
143: .toPersistenceModifierString(persistenceModifier));
144: s.append(" primaryKey=");
145: s.append(primaryKey);
146: s.append(" nullValue=");
147: s.append(MDStaticUtils.toNullValueString(nullValue));
148: s.append(" defaultFetchGroup=");
149: s.append(MDStaticUtils.toTriStateString(defaultFetchGroup));
150: s.append(" embedded=");
151: s.append(MDStaticUtils.toTriStateString(embedded));
152: return s.toString();
153: }
154:
155: public void dump() {
156: dump(Debug.OUT, "");
157: }
158:
159: public void dump(PrintStream out, String indent) {
160: out.println(indent + this );
161: String is = indent + " ";
162: if (collection != null)
163: collection.dump(out, is);
164: if (map != null)
165: map.dump(out, is);
166: if (array != null)
167: array.dump(out, is);
168: if (extensions != null) {
169: for (int i = 0; i < extensions.length; i++) {
170: extensions[i].dump(out, is);
171: }
172: }
173: }
174:
175: /**
176: * Update this with non conflicting metadat from the supplied instance.
177: */
178: public void synchWith(JdoField updateFrom, Set exclude,
179: boolean errorOnExclude) {
180: if (persistenceModifier == MDStatics.NOT_SET) {
181: persistenceModifier = updateFrom.persistenceModifier;
182: }
183: if (embedded == MDStatics.NOT_SET) {
184: embedded = updateFrom.embedded;
185: }
186: if (defaultFetchGroup == MDStatics.NOT_SET) {
187: defaultFetchGroup = updateFrom.defaultFetchGroup;
188: }
189: if (nullValue == MDStatics.NOT_SET) {
190: nullValue = updateFrom.nullValue;
191: }
192:
193: if (collection != null) {
194: if (updateFrom.collection == null) {
195: throw BindingSupportImpl.getInstance()
196: .invalidOperation(
197: "Not allowed to change the type of field '"
198: + updateFrom.name
199: + "' to a 'collection'");
200: } else {
201: collection
202: .synchronizeForHorizontal(updateFrom.collection);
203: }
204: } else if (updateFrom.collection != null) {
205: collection = updateFrom.collection.createCopy(this );
206: }
207:
208: if (map != null) {
209: if (updateFrom.map == null) {
210: throw BindingSupportImpl.getInstance()
211: .invalidOperation(
212: "Not allowed to change the type of field '"
213: + updateFrom.name
214: + "' to a 'map'");
215: } else {
216: map.synchronizeForHorizontal(updateFrom.map);
217: }
218: } else if (updateFrom.map != null) {
219: map = updateFrom.map.createCopy(this );
220: }
221:
222: if (array != null) {
223: if (updateFrom.array == null) {
224: throw BindingSupportImpl.getInstance()
225: .invalidOperation(
226: "Not allowed to change the type of field '"
227: + updateFrom.name
228: + "' to a 'map'");
229: } else {
230: array.synchronizeForHorizontal(updateFrom.array);
231: }
232: } else if (updateFrom.array != null) {
233: array = updateFrom.array.createCopy(this );
234: }
235:
236: JdoExtension[] copy = updateFrom.getExtensionCopy(this );
237: JdoExtension.synchronize3(extensions, copy, exclude,
238: errorOnExclude);
239: extensions = copy;
240: }
241:
242: public JdoExtension[] getExtensionCopy(JdoField owner) {
243: if (extensions == null)
244: return null;
245: JdoExtension[] copy = new JdoExtension[extensions.length];
246: for (int i = 0; i < extensions.length; i++) {
247: copy[i] = extensions[i].createCopy(owner);
248: }
249: return copy;
250: }
251:
252: private void processAttributeExtensions(JdoExtension exts[]) {
253: if (exts == null)
254: return;
255: for (int i = 0; i < exts.length; i++) {
256: JdoExtension extension = exts[i];
257: if (extension.isFieldAttribute()) {
258: if (extension.key == JdoExtensionKeys.DEFAULT_FETCH_GROUP) {
259: String value = extension.value;
260: if ("true".equals(value)) {
261: defaultFetchGroup = JdoField.TRUE;
262: } else if ("false".equals(value)) {
263: defaultFetchGroup = JdoField.FALSE;
264: }
265: } else if (extension.key == JdoExtensionKeys.EMBEDDED) {
266: String value = extension.value;
267: if ("true".equals(value)) {
268: embedded = JdoField.TRUE;
269: } else if ("false".equals(value)) {
270: embedded = JdoField.FALSE;
271: }
272: }
273: }
274: }
275: }
276:
277: public void applyEmbeddedExtensions(JdoExtension[] nested) {
278: clearAllJdbcColumnNames();
279:
280: processAttributeExtensions(nested);
281: processVendorExtensions(nested);
282: processCollectionExtensions(nested);
283: processMapExtensions(nested);
284: processArrayExtensions(nested);
285:
286: }
287:
288: private void clearAllJdbcColumnNames() {
289: if (extensions != null) {
290: JdoExtension.clearKey(JdoExtensionKeys.JDBC_COLUMN_NAME, 3,
291: extensions);
292: }
293: if (collection != null && collection.extensions != null) {
294: JdoExtension.clearKey(JdoExtensionKeys.JDBC_COLUMN_NAME, 3,
295: collection.extensions);
296: }
297: }
298:
299: private void processVendorExtensions(JdoExtension[] nested) {
300: extensions = JdoExtension.synchronize4(nested, extensions,
301: VENDOR_IGNORE_SET);
302: if (extensions != null) {
303: JdoExtension ext = JdoExtension.find(
304: JdoExtensionKeys.NULL_INDICATOR, extensions);
305: if (ext != null) {
306: nullIndicator = true;
307: }
308: }
309: }
310:
311: private void processArrayExtensions(JdoExtension[] nested) {
312: if (array == null)
313: return;
314: JdoExtension ext = JdoExtension.find(JdoExtensionKeys.ARRAY,
315: nested);
316: if (ext != null && ext.nested != null) {
317: array.extensions = JdoExtension.synchronize4(ext.nested,
318: array.extensions, Collections.EMPTY_SET);
319: }
320: }
321:
322: private void processMapExtensions(JdoExtension[] nested) {
323: if (map == null)
324: return;
325: JdoExtension ext = JdoExtension.find(JdoExtensionKeys.MAP,
326: nested);
327: if (ext != null && ext.nested != null) {
328: checkForTypeOverride(ext.nested,
329: JdoExtensionKeys.VALUE_TYPE, map.valueType);
330: checkForTypeOverride(ext.nested, JdoExtensionKeys.KEY_TYPE,
331: map.keyType);
332: map.extensions = JdoExtension.synchronize4(ext.nested,
333: map.extensions, Collections.EMPTY_SET);
334: }
335: }
336:
337: private void processCollectionExtensions(JdoExtension[] nested) {
338: if (collection == null)
339: return;
340: JdoExtension ext = JdoExtension.find(
341: JdoExtensionKeys.COLLECTION, nested);
342: if (ext != null && ext.nested != null) {
343: if (ext.nested == null)
344: return;
345: checkForTypeOverride(ext.nested,
346: JdoExtensionKeys.ELEMENT_TYPE,
347: collection.elementType);
348: collection.extensions = JdoExtension.synchronize4(
349: ext.nested, collection.extensions,
350: Collections.EMPTY_SET);
351: }
352: }
353:
354: private void checkForTypeOverride(JdoExtension[] exts, int key,
355: String value) {
356: //may not specify a different element type
357: JdoExtension typeExt = JdoExtension.find(key, exts);
358: if (typeExt != null && !value.equals(typeExt.value)) {
359: throw BindingSupportImpl
360: .getInstance()
361: .invalidOperation(
362: "Key/Values types for Collection/Maps may not be changed in embedded fields");
363: }
364: }
365:
366: /**
367: * Create the extension if it does not exist, else update it if overwrite is true
368: * @param key
369: * @param value
370: * @param overwrite
371: */
372: public JdoExtension findCreate(int key, String value,
373: boolean overwrite) {
374: if (extensions == null) {
375: extensions = new JdoExtension[] { createChild(key, value,
376: this ) };
377: return extensions[0];
378: }
379:
380: JdoExtension ext = JdoExtension.find(key, extensions);
381: if (ext == null) {
382: extensions = addExtension(extensions, (ext = createChild(
383: key, value, this)));
384: } else if (overwrite) {
385: ext.value = value;
386: }
387: return ext;
388: }
389:
390: }
|