KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > exp > ExpressionFactory


1 /* ====================================================================
2  *
3  * The ObjectStyle Group Software License, version 1.1
4  * ObjectStyle Group - http://objectstyle.org/
5  *
6  * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
7  * of the software. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if any,
22  * must include the following acknowlegement:
23  * "This product includes software developed by independent contributors
24  * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
29  * or promote products derived from this software without prior written
30  * permission. For written permission, email
31  * "andrus at objectstyle dot org".
32  *
33  * 5. Products derived from this software may not be called "ObjectStyle"
34  * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
35  * names without prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals and hosted on ObjectStyle Group web site. For more
53  * information on the ObjectStyle Group, please see
54  * <http://objectstyle.org/>.
55  */

56
57 package org.objectstyle.cayenne.exp;
58
59 import java.util.ArrayList JavaDoc;
60 import java.util.Collection JavaDoc;
61 import java.util.Iterator JavaDoc;
62 import java.util.List JavaDoc;
63 import java.util.Map JavaDoc;
64
65 import org.objectstyle.cayenne.exp.parser.ASTAdd;
66 import org.objectstyle.cayenne.exp.parser.ASTAnd;
67 import org.objectstyle.cayenne.exp.parser.ASTBetween;
68 import org.objectstyle.cayenne.exp.parser.ASTDbPath;
69 import org.objectstyle.cayenne.exp.parser.ASTDivide;
70 import org.objectstyle.cayenne.exp.parser.ASTEqual;
71 import org.objectstyle.cayenne.exp.parser.ASTGreater;
72 import org.objectstyle.cayenne.exp.parser.ASTGreaterOrEqual;
73 import org.objectstyle.cayenne.exp.parser.ASTIn;
74 import org.objectstyle.cayenne.exp.parser.ASTLess;
75 import org.objectstyle.cayenne.exp.parser.ASTLessOrEqual;
76 import org.objectstyle.cayenne.exp.parser.ASTLike;
77 import org.objectstyle.cayenne.exp.parser.ASTLikeIgnoreCase;
78 import org.objectstyle.cayenne.exp.parser.ASTList;
79 import org.objectstyle.cayenne.exp.parser.ASTMultiply;
80 import org.objectstyle.cayenne.exp.parser.ASTNegate;
81 import org.objectstyle.cayenne.exp.parser.ASTNot;
82 import org.objectstyle.cayenne.exp.parser.ASTNotBetween;
83 import org.objectstyle.cayenne.exp.parser.ASTNotEqual;
84 import org.objectstyle.cayenne.exp.parser.ASTNotIn;
85 import org.objectstyle.cayenne.exp.parser.ASTNotLike;
86 import org.objectstyle.cayenne.exp.parser.ASTNotLikeIgnoreCase;
87 import org.objectstyle.cayenne.exp.parser.ASTObjPath;
88 import org.objectstyle.cayenne.exp.parser.ASTOr;
89 import org.objectstyle.cayenne.exp.parser.ASTSubtract;
90 import org.objectstyle.cayenne.exp.parser.SimpleNode;
91
92 /**
93  * Helper class to build expressions.
94  *
95  * @author Andrei Adamchik
96  */

97 public class ExpressionFactory {
98     private static Class JavaDoc[] typeLookup;
99
100     static {
101         // make sure all types are small integers, then we can use
102
// them as indexes in lookup array
103
int[] allTypes =
104             new int[] {
105                 Expression.AND,
106                 Expression.OR,
107                 Expression.NOT,
108                 Expression.EQUAL_TO,
109                 Expression.NOT_EQUAL_TO,
110                 Expression.LESS_THAN,
111                 Expression.GREATER_THAN,
112                 Expression.LESS_THAN_EQUAL_TO,
113                 Expression.GREATER_THAN_EQUAL_TO,
114                 Expression.BETWEEN,
115                 Expression.IN,
116                 Expression.LIKE,
117                 Expression.LIKE_IGNORE_CASE,
118                 Expression.EXISTS,
119                 Expression.ADD,
120                 Expression.SUBTRACT,
121                 Expression.MULTIPLY,
122                 Expression.DIVIDE,
123                 Expression.NEGATIVE,
124                 Expression.POSITIVE,
125                 Expression.ALL,
126                 Expression.SOME,
127                 Expression.ANY,
128                 Expression.RAW_SQL,
129                 Expression.OBJ_PATH,
130                 Expression.DB_PATH,
131                 Expression.LIST,
132                 Expression.SUBQUERY,
133                 Expression.COUNT,
134                 Expression.SUM,
135                 Expression.AVG,
136                 Expression.MIN,
137                 Expression.MAX,
138                 Expression.NOT_BETWEEN,
139                 Expression.NOT_IN,
140                 Expression.NOT_LIKE,
141                 Expression.NOT_LIKE_IGNORE_CASE };
142
143         int max = 0;
144         int min = 0;
145         int allLen = allTypes.length;
146         for (int i = 0; i < allLen; i++) {
147             if (allTypes[i] > max)
148                 max = allTypes[i];
149             else if (allTypes[i] < min)
150                 min = allTypes[i];
151         }
152
153         // sanity check....
154
if (max > 500)
155             throw new RuntimeException JavaDoc("Types values are too big: " + max);
156         if (min < 0)
157             throw new RuntimeException JavaDoc("Types values are too small: " + min);
158
159         // now we know that if types are used as indexes,
160
// they will fit in array "max + 1" long (though gaps are possible)
161

162         typeLookup = new Class JavaDoc[max + 1];
163
164         typeLookup[Expression.AND] = ASTAnd.class;
165         typeLookup[Expression.OR] = ASTOr.class;
166         typeLookup[Expression.BETWEEN] = ASTBetween.class;
167         typeLookup[Expression.NOT_BETWEEN] = ASTNotBetween.class;
168
169         // binary types
170
typeLookup[Expression.EQUAL_TO] = ASTEqual.class;
171         typeLookup[Expression.NOT_EQUAL_TO] = ASTNotEqual.class;
172         typeLookup[Expression.LESS_THAN] = ASTLess.class;
173         typeLookup[Expression.GREATER_THAN] = ASTGreater.class;
174         typeLookup[Expression.LESS_THAN_EQUAL_TO] = ASTLessOrEqual.class;
175         typeLookup[Expression.GREATER_THAN_EQUAL_TO] = ASTGreaterOrEqual.class;
176         typeLookup[Expression.IN] = ASTIn.class;
177         typeLookup[Expression.NOT_IN] = ASTNotIn.class;
178         typeLookup[Expression.LIKE] = ASTLike.class;
179         typeLookup[Expression.LIKE_IGNORE_CASE] = ASTLikeIgnoreCase.class;
180         typeLookup[Expression.NOT_LIKE] = ASTNotLike.class;
181         typeLookup[Expression.NOT_LIKE_IGNORE_CASE] = ASTNotLikeIgnoreCase.class;
182         typeLookup[Expression.ADD] = ASTAdd.class;
183         typeLookup[Expression.SUBTRACT] = ASTSubtract.class;
184         typeLookup[Expression.MULTIPLY] = ASTMultiply.class;
185         typeLookup[Expression.DIVIDE] = ASTDivide.class;
186
187         typeLookup[Expression.NOT] = ASTNot.class;
188         typeLookup[Expression.NEGATIVE] = ASTNegate.class;
189         typeLookup[Expression.OBJ_PATH] = ASTObjPath.class;
190         typeLookup[Expression.DB_PATH] = ASTDbPath.class;
191         typeLookup[Expression.LIST] = ASTList.class;
192
193         // remainging "old" types
194
typeLookup[Expression.EXISTS] = UnaryExpression.class;
195         typeLookup[Expression.POSITIVE] = UnaryExpression.class;
196         typeLookup[Expression.ALL] = UnaryExpression.class;
197         typeLookup[Expression.SOME] = UnaryExpression.class;
198         typeLookup[Expression.ANY] = UnaryExpression.class;
199         typeLookup[Expression.RAW_SQL] = UnaryExpression.class;
200         typeLookup[Expression.SUBQUERY] = UnaryExpression.class;
201         typeLookup[Expression.SUM] = UnaryExpression.class;
202         typeLookup[Expression.AVG] = UnaryExpression.class;
203         typeLookup[Expression.COUNT] = UnaryExpression.class;
204         typeLookup[Expression.MIN] = UnaryExpression.class;
205         typeLookup[Expression.MAX] = UnaryExpression.class;
206     }
207
208     /**
209      * Creates a new expression for the type requested.
210      * If type is unknown, ExpressionException is thrown.
211      */

212     public static Expression expressionOfType(int type) {
213         if (type < 0 || type >= typeLookup.length) {
214             throw new ExpressionException("Bad expression type: " + type);
215         }
216
217         if (typeLookup[type] == null) {
218             throw new ExpressionException("Bad expression type: " + type);
219         }
220
221         // expected this
222
if (SimpleNode.class.isAssignableFrom(typeLookup[type])) {
223             try {
224                 return (Expression) typeLookup[type].newInstance();
225             }
226             catch (Exception JavaDoc ex) {
227                 throw new ExpressionException("Error creating expression", ex);
228             }
229         }
230
231         // backwards compatibility:
232
if (BinaryExpression.class == typeLookup[type]) {
233             return new BinaryExpression(type);
234         }
235
236         if (UnaryExpression.class == typeLookup[type]) {
237             return new UnaryExpression(type);
238         }
239
240         if (TernaryExpression.class == typeLookup[type]) {
241             return new TernaryExpression(type);
242         }
243
244         if (ListExpression.class == typeLookup[type]) {
245             return new ListExpression(type);
246         }
247
248         throw new ExpressionException("Bad expression type: " + type);
249     }
250
251     /**
252      * Applies a few default rules for adding operands to
253      * expressions. In particular wraps all lists into LIST
254      * expressions. Applied only in path expressions.
255      */

256     protected static Object JavaDoc wrapPathOperand(Object JavaDoc op) {
257         if (op instanceof Collection JavaDoc) {
258             return new ASTList((Collection JavaDoc) op);
259         }
260         else if (op instanceof Object JavaDoc[]) {
261             return new ASTList((Object JavaDoc[]) op);
262         }
263         else {
264             return op;
265         }
266     }
267
268     /**
269      * @deprecated Since 1.1 use {@link Expression#fromString(String)} or one of the more
270      * specific factory methods.
271      */

272     public static Expression unaryExp(int type, Object JavaDoc operand) {
273         Expression exp = expressionOfType(type);
274         exp.setOperand(0, operand);
275         return exp;
276     }
277
278     /**
279      * @deprecated Since 1.1 use {@link Expression#fromString(String)} or one of the more
280      * specific factory methods.
281      */

282     public static Expression binaryExp(
283         int type,
284         Object JavaDoc leftOperand,
285         Object JavaDoc rightOperand) {
286         Expression exp = expressionOfType(type);
287         exp.setOperand(0, leftOperand);
288         exp.setOperand(1, rightOperand);
289         return exp;
290     }
291
292     /**
293      * @deprecated Since 1.1 use {@link Expression#fromString(String)} or one of the more
294      * specific factory methods.
295      */

296     public static Expression binaryPathExp(int type, String JavaDoc pathSpec, Object JavaDoc value) {
297         return binaryExp(
298             type,
299             unaryExp(Expression.OBJ_PATH, pathSpec),
300             wrapPathOperand(value));
301     }
302
303     /**
304      * @deprecated Since 1.1 use {@link Expression#fromString(String)} or one of the more
305      * specific factory methods.
306      */

307     public static Expression binaryDbPathExp(int type, String JavaDoc pathSpec, Object JavaDoc value) {
308         return binaryExp(
309             type,
310             unaryExp(Expression.DB_PATH, pathSpec),
311             wrapPathOperand(value));
312     }
313
314     /**
315      * Creates an expression that matches any of the key-values pairs in <code>map</code>.
316      *
317      * <p>For each pair <code>pairType</code> operator is used to build a binary expression.
318      * Key is considered to be a DB_PATH expression. Therefore all keys must be java.lang.String
319      * objects, or ClassCastException is thrown. OR is used to join pair binary expressions.
320      */

321     public static Expression matchAnyDbExp(Map JavaDoc map, int pairType) {
322         List JavaDoc pairs = new ArrayList JavaDoc();
323
324         Iterator JavaDoc it = map.entrySet().iterator();
325         while (it.hasNext()) {
326             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
327             pairs.add(
328                 binaryDbPathExp(pairType, (String JavaDoc) entry.getKey(), entry.getValue()));
329         }
330
331         return joinExp(Expression.OR, pairs);
332     }
333
334     /**
335      * Creates an expression that matches all key-values pairs in <code>map</code>.
336      *
337      * <p>For each pair <code>pairType</code> operator is used to build a binary expression.
338      * Key is considered to be a DB_PATH expression. Therefore all keys must be java.lang.String
339      * objects, or ClassCastException is thrown. AND is used to join pair binary expressions.
340      */

341     public static Expression matchAllDbExp(Map JavaDoc map, int pairType) {
342         List JavaDoc pairs = new ArrayList JavaDoc();
343
344         Iterator JavaDoc it = map.entrySet().iterator();
345         while (it.hasNext()) {
346             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
347             pairs.add(
348                 binaryDbPathExp(pairType, (String JavaDoc) entry.getKey(), entry.getValue()));
349         }
350
351         return joinExp(Expression.AND, pairs);
352     }
353
354     /**
355      * Creates an expression that matches any of the key-values pairs in the <code>map</code>.
356      *
357      * <p>For each pair <code>pairType</code> operator is used to build a binary expression.
358      * Key is considered to be a OBJ_PATH expression. Therefore all keys must be java.lang.String
359      * objects, or ClassCastException is thrown. OR is used to join pair binary expressions.
360      */

361     public static Expression matchAnyExp(Map JavaDoc map, int pairType) {
362         List JavaDoc pairs = new ArrayList JavaDoc();
363
364         Iterator JavaDoc it = map.entrySet().iterator();
365         while (it.hasNext()) {
366             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
367             pairs.add(binaryPathExp(pairType, (String JavaDoc) entry.getKey(), entry.getValue()));
368         }
369
370         return joinExp(Expression.OR, pairs);
371     }
372
373     /**
374      * Creates an expression that matches all key-values pairs in <code>map</code>.
375      *
376      * <p>For each pair <code>pairType</code> operator is used to build a binary expression.
377      * Key is considered to be a OBJ_PATH expression. Therefore all keys must be java.lang.String
378      * objects, or ClassCastException is thrown. AND is used to join pair binary expressions.
379      */

380     public static Expression matchAllExp(Map JavaDoc map, int pairType) {
381         List JavaDoc pairs = new ArrayList JavaDoc();
382
383         Iterator JavaDoc it = map.entrySet().iterator();
384         while (it.hasNext()) {
385             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
386             pairs.add(binaryPathExp(pairType, (String JavaDoc) entry.getKey(), entry.getValue()));
387         }
388
389         return joinExp(Expression.AND, pairs);
390     }
391
392     /**
393      * A convenience method to create an DB_PATH "equal to" expression.
394      */

395     public static Expression matchDbExp(String JavaDoc pathSpec, Object JavaDoc value) {
396         return new ASTEqual(new ASTDbPath(pathSpec), value);
397     }
398
399     /**
400      * A convenience method to create an DB_PATH "not equal to" expression.
401      */

402     public static Expression noMatchDbExp(String JavaDoc pathSpec, Object JavaDoc value) {
403         return new ASTNotEqual(new ASTDbPath(pathSpec), value);
404     }
405     
406     /**
407      * A convenience shortcut for building IN DB expression.
408      */

409     public static Expression inDbExp(String JavaDoc pathSpec, Object JavaDoc[] values) {
410         return new ASTIn(new ASTDbPath(pathSpec), new ASTList(values));
411     }
412
413     /**
414      * A convenience shortcut for building IN DB expression.
415      */

416     public static Expression inDbExp(String JavaDoc pathSpec, Collection JavaDoc values) {
417         return new ASTIn(new ASTDbPath(pathSpec), new ASTList(values));
418     }
419     
420     /**
421      * A convenience method to create an OBJ_PATH "equal to" expression.
422      */

423     public static Expression matchExp(String JavaDoc pathSpec, Object JavaDoc value) {
424         return new ASTEqual(new ASTObjPath(pathSpec), value);
425     }
426
427     /**
428      * A convenience method to create an OBJ_PATH "not equal to" expression.
429      */

430     public static Expression noMatchExp(String JavaDoc pathSpec, Object JavaDoc value) {
431         return new ASTNotEqual(new ASTObjPath(pathSpec), value);
432     }
433
434     /**
435      * A convenience method to create an OBJ_PATH "less than" expression.
436      */

437     public static Expression lessExp(String JavaDoc pathSpec, Object JavaDoc value) {
438         return new ASTLess(new ASTObjPath(pathSpec), value);
439     }
440
441     /**
442      * A convenience method to create an OBJ_PATH "less than or equal to" expression.
443      */

444     public static Expression lessOrEqualExp(String JavaDoc pathSpec, Object JavaDoc value) {
445         return new ASTLessOrEqual(new ASTObjPath(pathSpec), value);
446     }
447
448     /**
449      * A convenience method to create an OBJ_PATH "greater than" expression.
450      */

451     public static Expression greaterExp(String JavaDoc pathSpec, Object JavaDoc value) {
452         return new ASTGreater(new ASTObjPath(pathSpec), value);
453     }
454
455     /**
456      * A convenience method to create an OBJ_PATH "greater than or equal to" expression.
457      */

458     public static Expression greaterOrEqualExp(String JavaDoc pathSpec, Object JavaDoc value) {
459         return new ASTGreaterOrEqual(new ASTObjPath(pathSpec), value);
460     }
461
462     /**
463      * A convenience shortcut for building IN expression.
464      */

465     public static Expression inExp(String JavaDoc pathSpec, Object JavaDoc[] values) {
466         return new ASTIn(new ASTObjPath(pathSpec), new ASTList(values));
467     }
468
469     /**
470      * A convenience shortcut for building IN expression.
471      */

472     public static Expression inExp(String JavaDoc pathSpec, Collection JavaDoc values) {
473         return new ASTIn(new ASTObjPath(pathSpec), new ASTList(values));
474     }
475
476     /**
477      * A convenience shortcut for building NOT_IN expression.
478      */

479     public static Expression notInExp(String JavaDoc pathSpec, Collection JavaDoc values) {
480         return new ASTNotIn(new ASTObjPath(pathSpec), new ASTList(values));
481     }
482
483     /**
484      * A convenience shortcut for building NOT_IN expression.
485      * @since 1.0.6
486      */

487     public static Expression notInExp(String JavaDoc pathSpec, Object JavaDoc[] values) {
488         return new ASTNotIn(new ASTObjPath(pathSpec), new ASTList(values));
489     }
490
491     /**
492      * A convenience shortcut for building BETWEEN expressions.
493      */

494     public static Expression betweenExp(String JavaDoc pathSpec, Object JavaDoc value1, Object JavaDoc value2) {
495         return new ASTBetween(new ASTObjPath(pathSpec), value1, value2);
496     }
497
498     /**
499      * A convenience shortcut for building NOT_BETWEEN expressions.
500      */

501     public static Expression notBetweenExp(
502         String JavaDoc pathSpec,
503         Object JavaDoc value1,
504         Object JavaDoc value2) {
505         return new ASTNotBetween(new ASTObjPath(pathSpec), value1, value2);
506     }
507
508     /**
509      * A convenience shortcut for building LIKE expression.
510      */

511     public static Expression likeExp(String JavaDoc pathSpec, Object JavaDoc value) {
512         return new ASTLike(new ASTObjPath(pathSpec), value);
513     }
514
515     /**
516      * A convenience shortcut for building NOT_LIKE expression.
517      */

518     public static Expression notLikeExp(String JavaDoc pathSpec, Object JavaDoc value) {
519         return new ASTNotLike(new ASTObjPath(pathSpec), value);
520     }
521
522     /**
523      * A convenience shortcut for building LIKE_IGNORE_CASE expression.
524      */

525     public static Expression likeIgnoreCaseExp(String JavaDoc pathSpec, Object JavaDoc value) {
526         return new ASTLikeIgnoreCase(new ASTObjPath(pathSpec), value);
527     }
528
529     /**
530      * A convenience shortcut for building NOT_LIKE_IGNORE_CASE expression.
531      */

532     public static Expression notLikeIgnoreCaseExp(String JavaDoc pathSpec, Object JavaDoc value) {
533         return new ASTNotLikeIgnoreCase(new ASTObjPath(pathSpec), value);
534     }
535
536     /**
537      * Joins all <code>expressions</code> in a single expression.
538      * <code>type</code> is used as an expression type for expressions joining
539      * each one of the items on the list. <code>type</code> must be binary
540      * expression type.
541      *
542      * <p>For example, if type is Expression.AND, resulting expression would match
543      * all expressions in the list. If type is Expression.OR, resulting expression
544      * would match any of the expressions. </p>
545      */

546     public static Expression joinExp(int type, List JavaDoc expressions) {
547         int len = expressions.size();
548         if (len == 0)
549             return null;
550
551         Expression currentExp = (Expression) expressions.get(0);
552         if (len == 1) {
553             return currentExp;
554         }
555
556         Expression exp = expressionOfType(type);
557         for (int i = 0; i < len; i++) {
558             exp.setOperand(i, expressions.get(i));
559         }
560         return exp;
561     }
562 }
Popular Tags