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.storage.search.implementation;
011:
012: import org.mmbase.bridge.Field;
013: import org.mmbase.core.CoreField;
014: import org.mmbase.storage.search.*;
015:
016: /**
017: * Basic implementation.
018: * The field alias is not set on default.
019: *
020: * @author Rob van Maris
021: * @version $Id: BasicStepField.java,v 1.27 2007/08/08 09:38:28 michiel Exp $
022: * @since MMBase-1.7
023: */
024: public class BasicStepField implements StepField {
025:
026: /** Associated field definition. */
027: private CoreField field = null;
028:
029: /** Associated step. */
030: private Step step = null;
031:
032: /** Alias property. */
033: private String alias = null;
034:
035: /**
036: * Tests if a value is acceptable for comparison with a certain field.
037: * @param value The value to be tested.
038: * @param field The non-null field.
039: * @throws IllegalArgumentException when the value is not acceptable
040: * for this field.
041: */
042: // package visibility!
043: static void testValue(Object value, StepField field) {
044: int type = field.getType();
045:
046: // Test for null value.
047: if (value == null) {
048: throw new IllegalArgumentException("Invalid value for "
049: + org.mmbase.core.util.Fields
050: .getTypeDescription(type) + " field: "
051: + value);
052: }
053:
054: // Test for compatible type.
055: boolean ok;
056: switch (type) {
057: case Field.TYPE_BINARY:
058: ok = value instanceof byte[];
059: break;
060: // Numerical types.
061: case Field.TYPE_INTEGER:
062: case Field.TYPE_LONG:
063: ok = value instanceof Number
064: || value instanceof java.util.Date;
065: break;
066: case Field.TYPE_FLOAT:
067: case Field.TYPE_DOUBLE:
068: case Field.TYPE_NODE:
069: ok = value instanceof Number;
070: break;
071:
072: // String types.
073: case Field.TYPE_XML:
074:
075: case Field.TYPE_STRING:
076: ok = value instanceof String;
077: break;
078: case Field.TYPE_BOOLEAN:
079: ok = value instanceof Boolean;
080: break;
081: case Field.TYPE_DATETIME:
082: ok = value instanceof java.util.Date
083: || value instanceof Number;
084: break;
085: case Field.TYPE_LIST:
086: ok = value instanceof java.util.List;
087: break;
088:
089: default: // Unknown field type, should not occur.
090: throw new IllegalStateException("Unknown field type: "
091: + type);
092: }
093:
094: if (!ok) {
095: throw new IllegalArgumentException("Invalid value for "
096: + org.mmbase.core.util.Fields
097: .getTypeDescription(type) + " field: "
098: + value + ", of type " + value.getClass().getName());
099: }
100: }
101:
102: /**
103: * Compares two field values for equality.
104: * Numerical fields are compared based on their numerical value, as they
105: * may be of different type.
106: *
107: * @param value1 The first value, either a <code>String</code>
108: * or a <code>Number</code>
109: * @param value2 The second value, either a <code>String</code>
110: * or a <code>Number</code>
111: * @return True if both values represent the same string or numerical value.
112: */
113: // package visibility!
114: static boolean equalFieldValues(Object value1, Object value2) {
115: if (value1 instanceof Number) {
116: if (value2 instanceof Number) {
117: Number number1 = (Number) value1;
118: Number number2 = (Number) value2;
119: return Double.doubleToLongBits(number1.doubleValue()) == Double
120: .doubleToLongBits(number2.doubleValue());
121: } else {
122: return false;
123: }
124: } else {
125: return (value1 == null ? value2 == null : value1
126: .equals(value2));
127: }
128: }
129:
130: /**
131: * Constructor.
132: *
133: * @param step The associated step.
134: * @param field The associated field.
135: * @throws IllegalArgumentException when an invalid argument is supplied.
136: */
137: public BasicStepField(Step step, CoreField field) {
138: if (step == null) {
139: throw new IllegalArgumentException("Invalid step value: "
140: + step);
141: }
142: this .step = step;
143:
144: if (field == null) {
145: throw new IllegalArgumentException("Invalid field value: "
146: + field + " for " + step);
147: }
148: // Check field belongs to step
149: if (!step.getTableName().equals(
150: field.getParent().getTableName())) {
151: throw new IllegalArgumentException(
152: "Invalid field value, belongs to step "
153: + field.getParent().getTableName()
154: + " instead of step " + step.getTableName()
155: + ": " + field);
156: }
157: this .field = field;
158: }
159:
160: /**
161: * Sets alias property.
162: *
163: * @param alias The alias property.
164: * @return This <code>BasicStepField</code> instance.
165: * @throws IllegalArgumentException when an invalid argument is supplied.
166: */
167: public BasicStepField setAlias(String alias) {
168: if (alias != null && alias.trim().length() == 0) {
169: throw new IllegalArgumentException("Invalid alias value: "
170: + alias);
171: }
172: this .alias = alias;
173: return this ;
174: }
175:
176: /**
177: * Gets the associated field.
178: *
179: * @return The field.
180: */
181: public CoreField getField() {
182: return field;
183: }
184:
185: // javadoc is inherited
186: public String getFieldName() {
187: return field.getName();
188: }
189:
190: // javadoc is inherited
191: public String getAlias() {
192: return alias;
193: }
194:
195: // javadoc is inherited
196: public Step getStep() {
197: return step;
198: }
199:
200: // javadoc in inherited
201: public int getType() {
202: return field.getType();
203: }
204:
205: // javadoc is inherited
206: public boolean equals(Object obj) {
207: if (obj instanceof StepField) {
208: StepField field = (StepField) obj;
209: return BasicStepField.compareSteps(getStep(), field
210: .getStep())
211: && getFieldName().equals(field.getFieldName())
212: && (alias == null ? field.getAlias() == null
213: : alias.equals(field.getAlias()));
214: } else {
215: return false;
216: }
217: }
218:
219: // javadoc is inherited
220: public int hashCode() {
221: return (getStep().getAlias() == null ? 47 * getStep()
222: .getTableName().hashCode() : 51 * getStep().getAlias()
223: .hashCode())
224: + 53
225: * getFieldName().hashCode()
226: + (alias == null ? 0 : 59 * alias.hashCode());
227: }
228:
229: /**
230: * Utility method, compares steps by their alias or table name.
231: * Steps are considered equal if their aliases are equal.
232: * When their aliases are <code>null</code>, the steps are considered
233: * equal if their tablenames are equal as well.
234: * <p>
235: * This can be used to verify that both steps refer to the same step
236: * in a <code>SearchQuery</code> object.
237: * Note that this differs from the equality defined by their
238: * {@link org.mmbase.storage.search.Step#equals() equals()} method.
239: *
240: * @param step1 The first step.
241: * @param step2 The second step.
242: * @return <code>true</code> when the steps are considered equal,
243: * <code>false</code> otherwise.
244: */
245: // package visibility!
246: static boolean compareSteps(Step step1, Step step2) {
247: String alias1 = step1.getAlias();
248: if (alias1 == null) {
249: return step2.getAlias() == null
250: && step1.getTableName()
251: .equals(step2.getTableName());
252: } else {
253: return alias1.equals(step2.getAlias());
254: }
255: }
256:
257: /**
258: * Returns the field's fieldname, possibly extended with the step's name if known.
259: * May return null or partial fieldnames if not all data is available (for use in debugging).
260: * @param field the fieldname whose name to return
261: */
262: static public String getFieldName(StepField field) {
263: String fieldName = null;
264: if (field != null) {
265: fieldName = field.getAlias();
266: if (fieldName == null) {
267: fieldName = field.getFieldName();
268: }
269: Step step = field.getStep();
270: if (step != null) {
271: if (step.getAlias() != null) {
272: fieldName = step.getAlias() + "." + fieldName;
273: } else {
274: fieldName = step.getTableName() + "." + fieldName;
275: }
276: }
277: }
278: return fieldName;
279: }
280:
281: // javadoc is inherited
282: public String toString() {
283: StringBuilder sb = new StringBuilder();
284: Step step = getStep();
285: if (step == null) {
286: sb.append("null");
287: } else {
288: String stepAlias = step.getAlias();
289: if (stepAlias == null) {
290: sb.append(getStep().getTableName());
291: } else {
292: sb.append(stepAlias);
293: }
294: }
295: sb.append(".").append(getFieldName());
296: String alias = getAlias();
297: if (alias != null) {
298: sb.append(" as ").append(alias);
299: }
300: return sb.toString();
301: }
302:
303: }
|