View Javadoc
1 /*** 2 * OrderByOperator.java 3 * 4 * $Author: mballesteros $ 5 * $Date: 2003/11/28 19:18:03 $ 6 * $Revision: 1.1 $ 7 */ 8 package net.sf.jec.namedop; 9 10 import java.util.ArrayList; 11 import java.util.Collection; 12 import java.util.Collections; 13 import java.util.Comparator; 14 import java.util.List; 15 import java.util.Map; 16 17 import net.sf.jec.ConstantOperator; 18 import net.sf.jec.EvaluationException; 19 import net.sf.jec.Operator; 20 21 22 /*** OrderByOperator sorts a Collection of elements by applying the argument operator 23 * to each element and comparing between the resulting values. 24 * The sort mode can be ascendent (by default) or descendent. You can specify a 25 * sort mode for each argument operator by writting it just after the argument 26 * operator. 27 *<p> 28 * Syntax: orderby(argOperator, [sortMode], [argOperator, [sortMode]]) 29 *</p><p> 30 * Examples: 31 *</p><p> 32 * 1. This one orders ascending by the accessor operators customerNumber (primary 33 * field) and customerAge (secondary field). 34 *</p><p> 35 *<code> 36 * orderby(customerNumber, customerAge) 37 *</code> 38 *</p><p> 39 * 2. This one orders by the same criteria but descending. This example ilustrates 40 * where to specify the sort mode when you want to apply the same for all 41 * the argument operators. You must place it as the last argument. 42 *</p><p><code> 43 * orderby(customerNumber, customerAge, 'desc') 44 *</code></p><p> 45 * 3. This one orders the primary field descending and the secondary ascending. 46 *</p><p><code> 47 * orderby(customerNumber, 'desc', customerAge, 'asc') 48 *</code></p><p> 49 * 4. A given sort mode applies to all of the operator arguments preceeding it 50 * until another sort mode is found. In this example, the two last argOperators 51 * are sorted ascending and the first is sorted descending.</br> 52 * Think that the tuple is processed from the right to the left and the sort modes 53 * are switches that fix the current sort mode. 54 *</p><p><code> 55 * orderby(customerNumber, 'desc', customerAge, customerWeight, 'asc') 56 *</code></p><p> 57 * In this case we could remove the last 'asc' argument because this is the default 58 * sort mode. The result would be the same: 59 *</p><p><code> 60 * orderby(customerNumber, 'desc', customerAge, customerWeight) 61 *</code></p><p> 62 * But you should always specify explicitly the desired order. 63 *</p> 64 * @author mballesteros 65 */ 66 public class OrderByOperator extends GroupOperator { 67 68 private boolean throwExceptions; 69 70 /*** 71 * sort options 72 */ 73 private static final int ASCENDING = 1; 74 private static final int DESCENDING = -1; 75 private static final int DEFAULT = ASCENDING; 76 private int sortMode = DEFAULT; 77 78 /*** Creates a new OrderByOperator 79 */ 80 public OrderByOperator() { } 81 82 /*** Returns a function representation String for this operator 83 * @return representation String for this operator 84 */ 85 public String toFunctionString() { 86 return "OrderBy(" + argOps[0] 87 + (nestedOp == null ? "" : ", " + nestedOp) + ")"; 88 } 89 90 /*** Returns an expression String representation for this operator 91 * @return String representation for this operator 92 */ 93 public String toExpressionString() { 94 StringBuffer sb = new StringBuffer(); 95 if (nestedOp != null) { 96 sb.append(nestedOp.toString()); 97 } 98 sb.append(".orderby("); 99 for (int i = 0; i < argOps.length; i++) { 100 if (i > 0) { 101 sb.append(", "); 102 } 103 sb.append(argOps[0]); 104 } 105 sb.append(")"); 106 return sb.toString(); 107 } 108 109 /*** Returns the associated value to the given context and root context 110 * @param rootCtx The root context, needed for operators that require 111 * expression evaluation from root point. Example: Indexer operators 112 * @param ctx The current context where the operator will work over 113 * @throws EvaluationException when the operator can not be applied to the given context. 114 * @return The result of applying THIS Operator to the given context. 115 */ 116 protected Object directMap(Object rootCtx, Object ctx) throws net.sf.jec.EvaluationException { 117 if (ctx instanceof Collection) { 118 return orderBy( rootCtx, (Collection) ctx ); 119 } else if (ctx instanceof java.util.Map) { 120 return applyToGroup(rootCtx, (Map) ctx ); 121 } else { 122 return null; 123 } 124 } 125 126 /*** Sorts the given Collection using the argOps criteria. 127 * This criteria consists on one or more pairs (field_list [, sort_mode]) 128 * Syntax: orderby(field_list [ , {'asc'|'desc'} ]) 129 * where, 130 * <I>field_list</I> is a coma-separated list of operators with at least one element 131 * <I>sort_mode</I> 'asc' for ascendent sort (default) and 'desc' for descendent sort. 132 */ 133 private Object orderBy(Object rootCtx, Collection c) throws EvaluationException { 134 Collection out = null; 135 for (int i = argOps.length - 1; i >= 0; i--) { 136 out = sort(rootCtx, c, argOps[i]); 137 } 138 return (Object) out; 139 } 140 141 /*** Sorts the given Collection using the op criteria. 142 */ 143 private Collection sort(final Object rootCtx, final Collection c, Operator op) 144 throws EvaluationException { 145 146 if (op instanceof ConstantOperator) { 147 Object arg = op.apply(rootCtx, c); 148 if (arg.equals("asc")) { 149 sortMode = ASCENDING; 150 } else if (arg.equals("desc")) { 151 sortMode = DESCENDING; 152 } 153 return c; 154 } else { 155 Comparator comp = new ContextComparator(rootCtx, op); 156 List out = new ArrayList(c); 157 Collections.sort(out, comp); 158 if (sortMode == DESCENDING) { 159 reverseList(out); 160 } 161 return out; 162 } 163 } 164 165 private List reverseList(List out) { 166 for (int i = out.size() - 1, j = 0; i > j; i--, j++) { 167 Object o = out.get(i); 168 out.set(i, out.get(j)); 169 out.set(j, o); 170 } 171 return out; 172 } 173 }

This page was automatically generated by Maven