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:
011: package org.mmbase.core;
012:
013: import org.mmbase.bridge.*;
014: import org.mmbase.core.util.Fields;
015: import org.mmbase.datatypes.DataType;
016: import org.mmbase.util.logging.*;
017:
018: /**
019: * @javadoc
020: *
021: * @author Pierre van Rooden
022: * @author Michiel Meeuwissen
023: * @since MMBase-1.8
024: * @version $Id: AbstractField.java,v 1.17 2008/02/16 22:13:53 nklasens Exp $
025: */
026:
027: abstract public class AbstractField extends AbstractDescriptor
028: implements Field {
029:
030: private static final Logger log = Logging
031: .getLoggerInstance(AbstractField.class);
032:
033: protected DataType<Object> dataType = null;
034: protected int type = TYPE_UNKNOWN;
035: protected int state = STATE_UNKNOWN;
036: protected int listItemType = TYPE_UNKNOWN;
037: protected boolean readOnly = true;
038:
039: /**
040: * Create a field object based on another field.
041: * The newly created field shared the datatype of it's parent
042: * (which means that any changes to the datatype affects both fields).
043: * @param name the name of the field
044: * @param field the parent field
045: */
046: protected AbstractField(String name, Field field) {
047: this (name, field, false);
048: }
049:
050: /**
051: * Create a field object based on another field.
052: * @param name the name of the field
053: * @param field the parent field
054: * @param cloneDataForRewrite determines whether the datatype of the parent field is copied (which means it can be altered
055: * without affecting the original datatype)
056: */
057: protected AbstractField(String name, Field field,
058: boolean cloneDataForRewrite) {
059: super (name, field, cloneDataForRewrite);
060: type = field.getType();
061: setState(field.getState());
062: readOnly = field.isReadOnly();
063: listItemType = field.getListItemType();
064: if (cloneDataForRewrite) {
065: setDataType((DataType<Object>) field.getDataType().clone());
066: } else {
067: setDataType(dataType = field.getDataType());
068: }
069: }
070:
071: /**
072: * Create a field object
073: * @param name the name of the field
074: * @param type the identifier for the MMBase base type for this field
075: * @param listItemType If the type of this field is TYPE_LIST, then this is the MMBase base type for the list elements.
076: * @param state identifier (virtual, persistent, system, systemvirtual)
077: * @param dataType the data type of the field
078: */
079: protected AbstractField(String name, int type, int listItemType,
080: int state, DataType<Object> dataType) {
081: super (name);
082: this .type = type;
083: this .listItemType = listItemType;
084: setState(state);
085: setDataType(dataType);
086: }
087:
088: abstract public NodeManager getNodeManager();
089:
090: public int compareTo(Field f) {
091: int compared = getName().compareTo(f.getName());
092: if (compared == 0)
093: compared = dataType.compareTo(f.getDataType());
094: return compared;
095: }
096:
097: /**
098: * Whether data type equals to other data type. Only key and type are considered. DefaultValue and
099: * required properties are only 'utilities'.
100: * @param o the reference object with which to compare.
101: * @return true if o is a DataType of which key and type equal to this' key and type.
102: */
103: public boolean equals(Object o) {
104: if (o instanceof Field) {
105: Field f = (Field) o;
106: return getName().equals(f.getName())
107: && dataType.equals(f.getDataType());
108: }
109: return false;
110: }
111:
112: public int hashCode() {
113: return getName().hashCode() * 13 + dataType.hashCode();
114: }
115:
116: public int getState() {
117: return state;
118: }
119:
120: protected void setState(int state) {
121: if (this .state == STATE_UNKNOWN) {
122: readOnly = state == STATE_SYSTEM
123: || state == STATE_SYSTEM_VIRTUAL;
124: }
125: this .state = state;
126: }
127:
128: public int getType() {
129: return type;
130: }
131:
132: public int getListItemType() {
133: return listItemType;
134: }
135:
136: public DataType<Object> getDataType() {
137: return dataType;
138: }
139:
140: /**
141: * Sets the datatype of a field.
142: * It is possible that the datatype of a field is different from the actual field type.
143: * @param dataType
144: * @throws IllegalArgumentException
145: * @see #getType
146: */
147: public void setDataType(DataType<Object> dataType)
148: throws IllegalArgumentException {
149: int dataTypeType = dataType.getBaseType();
150: if (dataTypeType != type) {
151: log.debug("DataType (" + dataType.getBaseTypeIdentifier()
152: + ") is different from db type ("
153: + Fields.getTypeDescription(type) + ").");
154: }
155: this .dataType = dataType;
156: }
157:
158: public boolean hasIndex() {
159: return (getType() == Field.TYPE_NODE)
160: || getName().equals("number");
161: }
162:
163: abstract public int getSearchPosition();
164:
165: abstract public int getListPosition();
166:
167: abstract public int getEditPosition();
168:
169: abstract public int getStoragePosition();
170:
171: /**
172: * Retrieve whether the field is a key and thus need be unique.
173: * @return <code>true</code> when field is unique
174: */
175: public boolean isUnique() {
176: return dataType.isUnique();
177: }
178:
179: abstract public int getMaxLength();
180:
181: /**
182: * @see org.mmbase.bridge.Field#isRequired()
183: */
184: public boolean isRequired() {
185: return dataType.isRequired();
186: }
187:
188: /**
189: * @see org.mmbase.bridge.Field#isVirtual()
190: */
191: public boolean isVirtual() {
192: return getState() == STATE_VIRTUAL
193: || getState() == STATE_SYSTEM_VIRTUAL;
194: }
195:
196: /**
197: * Returns whether a field is a temporary field.
198: * Temporary fields hold data needed by a builder to facilitate certain functionality,
199: * such as holding node references in a transaction.
200: * Temporary fields are never persistent and should normally be ignored.
201: * @return <code>true</code> when temporary
202: * @since MMBase-1.8
203: */
204: public boolean isTemporary() {
205: // this way of determining if a field is temporary is a bit odd,
206: // but it is how it worked in the past - should be changed in the future
207: // with possibly a setTemporary() method.
208: String fieldName = getName();
209: return fieldName != null ? fieldName.startsWith("_") : false;
210: }
211:
212: /**
213: * Returns whether a field is a read only.
214: * @return <code>true</code> when read only
215: * @see org.mmbase.bridge.Field#isVirtual()
216: */
217: public boolean isReadOnly() {
218: return readOnly;
219: }
220:
221: abstract public String getGUIType();
222:
223: /**
224: * Returns a description for this field.
225: * @return a string representation of the object.
226: */
227: public String toString() {
228: return getName() + ":" + Fields.getTypeDescription(getType())
229: + " / " + Fields.getStateDescription(getState()) + "/"
230: + getDataType();
231: }
232:
233: public Object clone() {
234: return clone(null, false);
235: }
236:
237: public Object clone(String name, boolean copyDataTypeForRewrite) {
238: try {
239: AbstractField clone = (AbstractField) super .clone(name);
240: if (copyDataTypeForRewrite) {
241: clone.dataType = (DataType<Object>) dataType.clone();
242: }
243: return clone;
244: } catch (CloneNotSupportedException cnse) {
245: // should not happen
246: throw new RuntimeException("Cannot clone this Field", cnse);
247: }
248: }
249:
250: }
|