package com.onaro.util.jfc.grouping; import java.util.Date; import com.onaro.client.DateFormats; /** * A grouping criterion that is associated with multiple columns. The value * it produces encapsulate an array of node values which its toString() * produces the concatenation of the node values. */ public class MultiColumnCriterion implements Criterion { /** * Separates the node values in the string that is returned as the criterion value. */ private String delimiter; /** * The column numbers of the encapsulated table with which this criterion is * associated. The order of concatenation follows the order of column numbers. */ private int columnNumbers[]; /** * Set the column numbers associated with this criterion and the delimiter used * for separating the values. * @param columnNumbers column numbers of the encapsulated table, the order of * concatenation follows the order of column numbers * @param delimiter separates values in the generated criterion value */ public MultiColumnCriterion(int[] columnNumbers, String delimiter) { this.columnNumbers = columnNumbers; this.delimiter = delimiter; } /** * Gets the value identifying the node. The value is a string containing a * {@link MultiColumnCriterion#delimiter} separated list of values from the * columns associated with this criterion. * @param node the node to get the criterion value for * @return the a string with the node's column values */ public Object getValue(Node node) { return new Value(node); } /** * Gets the numbers of the columns used by this criterion. Used for unit * tests only. * @return an array of the column numbers the criterion is using */ public int[] getColumnNumbers() { return columnNumbers; } /** * Encapsulate node values and produces a toString() which is * the concatenation of them. */ class Value { /** * The node values in order of the columns in this criterion. */ Object columnValues[]; /** * The string representation of this value, initialized the first time it * is needed. */ String strVal; /** * The hash code is calculated from all the column values. It is initialized * once it is needed. */ int hash = -1; /** * Gets the values from a node. * @param node the node */ public Value(Node node) { columnValues = new Object[columnNumbers.length]; for (int i = 0; i < columnNumbers.length; i++) { columnValues[i] = node.getValueAt(columnNumbers[i]); } } /** * Gets the hash code of this value. The hash code s calculated once by summing * the hash of all the column values. * @return the hash code */ public int hashCode() { if (hash < 0) { hash = 0; for (int i = 0; i < columnNumbers.length; i++) { hash += (columnValues[i] != null) ? columnValues[i].hashCode() * 29 : 23; } } return hash; } /** * Tests if two values are the equal by comparing the column values in * each of them. * @param obj the other value * @return true if all column values are equal */ public boolean equals(Object obj) { if (obj == null || !(obj instanceof Value)) return false; Value other = (Value)obj; if (columnValues.length != other.columnValues.length) return false; for (int i = 0; i < columnValues.length; i++) { Object colVal = columnValues[i]; Object otherColVal = other.columnValues[i]; if (colVal != otherColVal) { if (colVal == null) return false; if (!colVal.equals(otherColVal)) return false; } } return true; } /** * If its the first time the string presentation is needed, concatenate * the values. * @return the node values concatenated and delimited */ public String toString() { if (strVal == null) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < columnValues.length; i++) { if (i > 0) { sb.append(delimiter); } Object columnValue = columnValues[i]; if (columnValue != null) { if (columnValue instanceof Date) { sb.append(DateFormats.getShortDateTimeFormat().format(columnValue)); } else { sb.append(columnValue); } } else { sb.append("None"); // TODO: NLS this! } } strVal = sb.toString(); } return strVal; } } }