001: /*
002:
003: This software is OSI Certified Open Source Software.
004: OSI Certified is a certification mark of the Open Source Initiative.
005:
006: The license (Mozilla version 1.0) can be read at the MMBase site.
007: See http://www.MMBase.org/license
008:
009: */
010: package org.mmbase.core;
011:
012: import org.mmbase.bridge.Field;
013: import org.mmbase.bridge.NodeManager;
014: import org.mmbase.datatypes.*;
015: import org.mmbase.module.core.MMObjectBuilder;
016: import org.mmbase.module.core.MMBase;
017: import org.mmbase.storage.*;
018: import org.mmbase.util.*;
019:
020: import java.util.Collection;
021:
022: /**
023: * @since MMBase-1.8
024: */
025: public class CoreField extends AbstractField implements Field,
026: Storable, Cloneable {
027:
028: private static final int NO_POSITION = -1;
029:
030: private int storageType; // JDBC type of this field
031: private int searchPosition = NO_POSITION;
032: private int listPosition = NO_POSITION;
033: private int editPosition = NO_POSITION;
034:
035: private int maxLength = -1;
036:
037: private MMObjectBuilder parent = null;
038: private int storagePosition = -1;
039: private Object storageIdentifier = null;
040:
041: private boolean notNull = false;
042:
043: private int savedHashcode = -1;
044: private boolean hashcodeChanged = true;
045:
046: /**
047: * Creates a CoreField object based on a more generic 'Field'.
048: * @since MMBase-1.8.1
049: */
050: public CoreField(Field field) {
051: this (field.getName(), field.getType(), field.getListItemType(),
052: field.getState(), field.getDataType());
053: }
054:
055: /**
056: * Create a core object
057: * @param name the name of the data type
058: * @param dataType the data type for this field
059: */
060: protected CoreField(String name, int type, int listItemType,
061: int state, DataType dataType) {
062: super (name, type, listItemType, state, dataType);
063: hashcodeChanged = true;
064: // obtain maxlength from datatype where applicable
065: if (dataType instanceof LengthDataType) {
066: // maxlength is an int, but LengthDataType stores longs.
067: // this ispart of the bridge, so the conflict may be hard to solve
068: // without breaking backward compatibility in the bridge
069: long length = ((LengthDataType) dataType).getMaxLength();
070: if (length > Integer.MAX_VALUE) {
071: maxLength = Integer.MAX_VALUE;
072: } else {
073: maxLength = (int) length;
074: }
075: }
076: }
077:
078: /**
079: * Copy constructor.
080: * @param name the name of the data type
081: * @param coreField
082: */
083: protected CoreField(String name, CoreField coreField) {
084: super (name, coreField, true);
085: setSearchPosition(coreField.getSearchPosition());
086: setEditPosition(coreField.getEditPosition());
087: setListPosition(coreField.getListPosition());
088: setStoragePosition(coreField.getStoragePosition());
089: setParent(coreField.getParent());
090: setMaxLength(coreField.getMaxLength());
091: setUnique(coreField.isUnique());
092: hashcodeChanged = true;
093: }
094:
095: public NodeManager getNodeManager() {
096: throw new UnsupportedOperationException(
097: "Core fields currently do not support calls to getNodeManager.");
098: }
099:
100: public Object clone() {
101: return clone(null);
102: }
103:
104: public Object clone(String name) {
105: hashcodeChanged = true;
106: return super .clone(name, true);
107: }
108:
109: public void setReadOnly(boolean readOnly) {
110: hashcodeChanged = true;
111: this .readOnly = readOnly;
112: }
113:
114: public void setNotNull(boolean nl) {
115: hashcodeChanged = true;
116: notNull = nl;
117: }
118:
119: public boolean isNotNull() {
120: return notNull;
121: }
122:
123: /**
124: * Retrieve the position of the field when searching.
125: * A value of -1 indicates the field is unavailable during search.
126: */
127: public int getSearchPosition() {
128: return searchPosition;
129: }
130:
131: /**
132: * Set the position of the field when searching.
133: * @see #getSearchPosition
134: */
135: public void setSearchPosition(int i) {
136: hashcodeChanged = true;
137: searchPosition = i;
138: }
139:
140: /**
141: * Retrieve the position of the field when listing.
142: * A value of -1 indicates the field is unavailable in a list.
143: */
144: public int getListPosition() {
145: return listPosition;
146: }
147:
148: /**
149: * Set the position of the field when listing.
150: * @see #getListPosition
151: */
152: public void setListPosition(int i) {
153: hashcodeChanged = true;
154: listPosition = i;
155: }
156:
157: /**
158: * Retrieve the position of the field when editing.
159: * A value of -1 indicates the field cannot be edited.
160: */
161: public int getEditPosition() {
162: return editPosition;
163: }
164:
165: /**
166: * Set the position of the field when editing.
167: * @see #getEditPosition
168: */
169: public void setEditPosition(int i) {
170: editPosition = i;
171: hashcodeChanged = true;
172: }
173:
174: /**
175: * Retrieve the position of the field in the database table.
176: */
177: public int getStoragePosition() {
178: return storagePosition;
179: }
180:
181: /**
182: * Set the position of the field in the database table.
183: */
184: public void setStoragePosition(int i) {
185: storagePosition = i;
186: hashcodeChanged = true;
187: }
188:
189: /**
190: * Retrieves the parent builder for this field
191: */
192: public MMObjectBuilder getParent() {
193: return parent;
194: }
195:
196: /**
197: * Set the parent builder for this field
198: * @param parent the parent builder
199: */
200: public void setParent(MMObjectBuilder parent) {
201: this .parent = parent;
202: hashcodeChanged = true;
203: }
204:
205: public void setState(int state) {
206: super .setState(state);
207: hashcodeChanged = true;
208: }
209:
210: public void setType(int type) {
211: this .type = type;
212: hashcodeChanged = true;
213: }
214:
215: public void setListItemType(int listItemType) {
216: this .listItemType = listItemType;
217: hashcodeChanged = true;
218: }
219:
220: public Collection<String> validate(Object value) {
221: Collection<LocalizedString> errors = getDataType().validate(
222: value, null, this );
223: return LocalizedString.toStrings(errors, parent.getMMBase()
224: .getLocale());
225: }
226:
227: /**
228: * Whether this CoreField is equal to another for storage purposes (so, ignoring gui and documentation fields)
229: * @since MMBase-1.7
230: */
231: public boolean storageEquals(CoreField f) {
232: return getName().equals(f.getName())
233: && readOnly == f.isReadOnly()
234: && state == f.getState()
235: && getDataType().isRequired() == f.getDataType()
236: .isRequired()
237: && getDataType().isUnique() == f.getDataType()
238: .isUnique()
239: && maxLength == f.getMaxLength()
240: && (parent == null ? f.getParent() == null : parent
241: .equals(f.getParent()))
242: && getStorageIdentifier().equals(
243: f.getStorageIdentifier())
244: && getStorageType() == f.getStorageType() // implies equal MMBase types
245: && storagePosition == f.getStoragePosition();
246: }
247:
248: /**
249: * @see java.lang.Object#equals(java.lang.Object)
250: * @since MMBase-1.7
251: */
252: public boolean equals(Object o) {
253: if (o instanceof CoreField) {
254: CoreField f = (CoreField) o;
255: return storageEquals(f)
256: && getLocalizedDescription().equals(
257: f.getLocalizedDescription())
258: && getLocalizedGUIName().equals(
259: f.getLocalizedGUIName())
260: && searchPosition == f.searchPosition
261: && listPosition == f.listPosition
262: && editPosition == f.editPosition;
263: } else {
264: return false;
265: }
266: }
267:
268: /**
269: * @see java.lang.Object#hashCode()
270: */
271: public int hashCode() {
272: if (hashcodeChanged) {
273: int result = 0;
274: result = HashCodeUtil.hashCode(result, getName());
275: result = HashCodeUtil.hashCode(result, getType());
276: result = HashCodeUtil.hashCode(result, getState());
277: result = HashCodeUtil.hashCode(result, getDataType()
278: .isRequired());
279: result = HashCodeUtil.hashCode(result, getDataType()
280: .isUnique());
281: result = HashCodeUtil.hashCode(result, parent);
282: result = HashCodeUtil.hashCode(result, storagePosition);
283: savedHashcode = result;
284: hashcodeChanged = false;
285: }
286: return savedHashcode;
287: }
288:
289: /**
290: * Compare this object to the supplied one (should be a CoreField)
291: * @param o the object to compare to
292: * @return -1,1, or 0 according to wether this object is smaller, greater, or equal
293: * to the supplied one.
294: */
295: public int compareTo(Field o) {
296: int pos1 = getStoragePosition();
297: int pos2 = ((CoreField) o).getStoragePosition();
298: if (pos1 < pos2) {
299: return -1;
300: } else if (pos1 > pos2) {
301: return 1;
302: } else {
303: return 0;
304: }
305: }
306:
307: public void finish() {
308: dataType.finish(this );
309: }
310:
311: public void rewrite() {
312: dataType.rewrite(this );
313: }
314:
315: /**
316: * Returns the (maximum) size of this field, as determined by the storage layer.
317: * For example if a field contains characters the size indicates the
318: * maximum number of characters it can contain.
319: * If the field is a numeric field (such as an integer), the result is -1.
320: *
321: * @return the maximum size of data this field can contain
322: */
323: public int getMaxLength() {
324: return maxLength;
325: }
326:
327: public void setMaxLength(int size) {
328: this .maxLength = size;
329: if (size > 0 && (dataType instanceof LengthDataType)
330: && size < ((LengthDataType) dataType).getMaxLength()) {
331: if (dataType.isFinished()) {
332: dataType = (DataType) dataType.clone();
333: }
334: ((LengthDataType) dataType).setMaxLength(size);
335: }
336: hashcodeChanged = true;
337: }
338:
339: public void setDataType(DataType dataType)
340: throws IllegalArgumentException {
341: super .setDataType(dataType);
342: // datatype can be influenced by size
343: setMaxLength(maxLength);
344: hashcodeChanged = true;
345: }
346:
347: public void setUnique(boolean unique) {
348: dataType.setUnique(unique);
349: hashcodeChanged = true;
350: }
351:
352: // Storable interface
353: /**
354: * {@inheritDoc}
355: * @since MMBase 1.7
356: */
357: public Object getStorageIdentifier() throws StorageException {
358: // determine the storage identifier from the name
359: if (storageIdentifier == null) {
360: storageIdentifier = MMBase.getMMBase()
361: .getStorageManagerFactory().getStorageIdentifier(
362: this );
363: }
364: return storageIdentifier;
365: }
366:
367: public int getStorageType() {
368: return storageType;
369: }
370:
371: public void setStorageType(int type) {
372: storageType = type;
373: hashcodeChanged = true;
374: }
375:
376: public boolean inStorage() {
377: return !isVirtual();
378: }
379:
380: // deprecated methods
381: /**
382: * Retrieve the GUI type of the field.
383: */
384: public String getGUIType() {
385: return dataType.getName();
386: }
387:
388: public String toString() {
389: return super .toString()
390: + (parent != null ? " of " + parent.getTableName()
391: : " without parent");
392: }
393:
394: }
|