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