KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > wocompat > EOQuery


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 package org.objectstyle.cayenne.wocompat;
57
58 import java.util.Collection JavaDoc;
59 import java.util.HashMap JavaDoc;
60 import java.util.Iterator JavaDoc;
61 import java.util.List JavaDoc;
62 import java.util.Map JavaDoc;
63 import java.util.ArrayList JavaDoc;
64
65 import org.objectstyle.cayenne.exp.Expression;
66 import org.objectstyle.cayenne.exp.ExpressionFactory;
67 import org.objectstyle.cayenne.exp.ExpressionParameter;
68 import org.objectstyle.cayenne.exp.ExpressionException;
69 import org.objectstyle.cayenne.exp.parser.ASTObjPath;
70 import org.objectstyle.cayenne.map.Entity;
71 import org.objectstyle.cayenne.map.ObjAttribute;
72 import org.objectstyle.cayenne.map.ObjEntity;
73 import org.objectstyle.cayenne.map.ObjRelationship;
74 import org.objectstyle.cayenne.query.SelectQuery;
75
76 /**
77  * A descriptor of SelectQuery loaded from EOModel. It is an informal "decorator" of
78  * Cayenne SelectQuery to provide access to the extra information of WebObjects
79  * EOFetchSpecification.
80  *
81  * @author Andrei Adamchik
82  * @since 1.1
83  */

84 public class EOQuery extends SelectQuery {
85
86     protected Map JavaDoc plistMap;
87     protected Map JavaDoc bindings;
88
89     public EOQuery(ObjEntity root, Map JavaDoc plistMap) {
90         super(root);
91         this.plistMap = plistMap;
92         initFromPlist(plistMap);
93     }
94
95     protected void initFromPlist(Map JavaDoc plistMap) {
96
97         setResolvingInherited("YES".equalsIgnoreCase((String JavaDoc) plistMap.get("isDeep")));
98         setRefreshingObjects("YES".equalsIgnoreCase((String JavaDoc) plistMap
99                 .get("refreshesRefetchedObjects")));
100
101         setDistinct("YES".equalsIgnoreCase((String JavaDoc) plistMap.get("usesDistinct")));
102
103         Object JavaDoc fetchLimit = plistMap.get("fetchLimit");
104         if (fetchLimit != null) {
105             try {
106                 if (fetchLimit instanceof Number JavaDoc) {
107                     setFetchLimit(((Number JavaDoc) fetchLimit).intValue());
108                 }
109                 else {
110                     setFetchLimit(Integer.parseInt(fetchLimit.toString()));
111                 }
112             }
113             catch (NumberFormatException JavaDoc nfex) {
114                 // ignoring...
115
}
116         }
117
118         // sort orderings
119
List JavaDoc orderings = (List JavaDoc) plistMap.get("sortOrderings");
120         if (orderings != null && !orderings.isEmpty()) {
121             Iterator JavaDoc it = orderings.iterator();
122             while (it.hasNext()) {
123                 Map JavaDoc ordering = (Map JavaDoc) it.next();
124                 boolean asc = !"compareDescending:".equals(ordering.get("selectorName"));
125                 String JavaDoc key = (String JavaDoc) ordering.get("key");
126                 if (key != null) {
127                     addOrdering(key, asc);
128                 }
129             }
130         }
131
132         //qualifiers
133
Map JavaDoc qualifierMap = (Map JavaDoc) plistMap.get("qualifier");
134         if (qualifierMap != null && !qualifierMap.isEmpty()) {
135             this.setQualifier(makeQualifier(qualifierMap));
136         }
137     }
138
139     public String JavaDoc getEOName() {
140         if (getRoot() instanceof EOObjEntity) {
141             return ((EOObjEntity) getRoot()).localQueryName(getName());
142         }
143         else {
144             return getName();
145         }
146     }
147
148     public Collection JavaDoc getBindingNames() {
149         if (bindings == null) {
150             initBindings();
151         }
152
153         return bindings.keySet();
154     }
155
156     public String JavaDoc bindingClass(String JavaDoc name) {
157         if (bindings == null) {
158             initBindings();
159         }
160
161         return (String JavaDoc) bindings.get(name);
162     }
163
164     private synchronized void initBindings() {
165         if (bindings != null) {
166             return;
167         }
168
169         bindings = new HashMap JavaDoc();
170
171         if (!(getRoot() instanceof Entity)) {
172             return;
173         }
174
175         Map JavaDoc qualifier = (Map JavaDoc) plistMap.get("qualifier");
176         initBindings(bindings, (Entity) getRoot(), qualifier);
177     }
178
179     private void initBindings(Map JavaDoc bindings, Entity entity, Map JavaDoc qualifier) {
180         if (qualifier == null) {
181             return;
182         }
183
184         if ("EOKeyValueQualifier".equals(qualifier.get("class"))) {
185             String JavaDoc key = (String JavaDoc) qualifier.get("key");
186             if (key == null) {
187                 return;
188             }
189
190             Object JavaDoc value = qualifier.get("value");
191             if (!(value instanceof Map JavaDoc)) {
192                 return;
193             }
194
195             Map JavaDoc valueMap = (Map JavaDoc) value;
196             if (!"EOQualifierVariable".equals(valueMap.get("class"))
197                     || !valueMap.containsKey("_key")) {
198                 return;
199             }
200
201             String JavaDoc name = (String JavaDoc) valueMap.get("_key");
202             String JavaDoc className = null;
203
204             // we don't know whether its obj path or db path, so the expression can blow
205
// ... in fact we can't support DB Path as the key is different from external
206
// name,
207
// so we will use Object type for all DB path...
208
try {
209                 Object JavaDoc lastObject = new ASTObjPath(key).evaluate(entity);
210
211                 if (lastObject instanceof ObjAttribute) {
212                     className = ((ObjAttribute) lastObject).getType();
213                 }
214                 else if (lastObject instanceof ObjRelationship) {
215                     ObjEntity target = (ObjEntity) ((ObjRelationship) lastObject)
216                             .getTargetEntity();
217                     if (target != null) {
218                         className = target.getClassName();
219                     }
220                 }
221             }
222             catch (ExpressionException ex) {
223                 className = "java.lang.Object";
224             }
225
226             if (className == null) {
227                 className = "java.lang.Object";
228             }
229
230             bindings.put(name, className);
231
232             return;
233         }
234
235         List JavaDoc children = (List JavaDoc) qualifier.get("qualifiers");
236         if (children != null) {
237             Iterator JavaDoc it = children.iterator();
238             while (it.hasNext()) {
239                 initBindings(bindings, entity, (Map JavaDoc) it.next());
240             }
241         }
242     }
243
244     /**
245      * Creates the Expression equivalent of the EOFetchSpecification represented by the
246      * Map.
247      *
248      * @param qualifierMap - FetchSpecification to translate
249      * @return Expression equivalent to FetchSpecification
250      */

251     public synchronized Expression makeQualifier(Map JavaDoc qualifierMap) {
252         if (qualifierMap == null) {
253             return null;
254         }
255
256         return EOFetchSpecificationParser.makeQualifier(qualifierMap);
257     }
258
259     /**
260      * EOFetchSpecificationParser parses EOFetchSpecifications from a WebObjects-style
261      * EOModel. It recursively builds Cayenne Expression objects and assembles them into
262      * the final aggregate Expression.
263      *
264      * @author Travis Cripps
265      */

266     static class EOFetchSpecificationParser {
267
268         // selector strings
269
public static final String JavaDoc IS_EQUAL_TO = "isEqualTo:";
270         public static final String JavaDoc IS_NOT_EQUAL_TO = "isNotEqualTo:";
271         public static final String JavaDoc IS_LIKE = "isLike:";
272         public static final String JavaDoc CASE_INSENSITIVE_LIKE = "isCaseInsensitiveLike:";
273         public static final String JavaDoc IS_LESS_THAN = "isLessThan:";
274         public static final String JavaDoc IS_LESS_THAN_OR_EQUAL_TO = "isLessThanOrEqualTo:";
275         public static final String JavaDoc IS_GREATER_THAN = "isGreaterThan:";
276         public static final String JavaDoc IS_GREATER_THAN_OR_EQUAL_TO = "isGreaterThanOrEqualTo:";
277
278         private static HashMap JavaDoc selectorToExpressionBridge;
279
280         /**
281          * selectorToExpressionBridge is just a mapping of EOModeler's selector types to
282          * Cayenne Expression types.
283          *
284          * @return HashMap of Expression types, keyed by the corresponding selector name
285          */

286         public static HashMap JavaDoc selectorToExpressionBridge() {
287             if (null == selectorToExpressionBridge) {
288                 // initialize selectorToExpressionBridge
289
selectorToExpressionBridge = new HashMap JavaDoc(8);
290                 selectorToExpressionBridge.put(IS_EQUAL_TO, new Integer JavaDoc(
291                         Expression.EQUAL_TO));
292                 selectorToExpressionBridge.put(IS_NOT_EQUAL_TO, new Integer JavaDoc(
293                         Expression.NOT_EQUAL_TO));
294                 selectorToExpressionBridge.put(IS_LIKE, new Integer JavaDoc(Expression.LIKE));
295                 selectorToExpressionBridge.put(CASE_INSENSITIVE_LIKE, new Integer JavaDoc(
296                         Expression.LIKE_IGNORE_CASE));
297                 selectorToExpressionBridge.put(IS_LESS_THAN, new Integer JavaDoc(
298                         Expression.LESS_THAN));
299                 selectorToExpressionBridge.put(IS_LESS_THAN_OR_EQUAL_TO, new Integer JavaDoc(
300                         Expression.LESS_THAN_EQUAL_TO));
301                 selectorToExpressionBridge.put(IS_GREATER_THAN, new Integer JavaDoc(
302                         Expression.GREATER_THAN));
303                 selectorToExpressionBridge.put(IS_GREATER_THAN_OR_EQUAL_TO, new Integer JavaDoc(
304                         Expression.GREATER_THAN_EQUAL_TO));
305             }
306             return selectorToExpressionBridge;
307         }
308
309         /**
310          * isAggregate determines whether a qualifier is "aggregate" -- has children -- or
311          * "simple".
312          *
313          * @param qualifier - a Map containing the qualifier settings
314          * @return boolean indicating whether the qualifier is "aggregate" qualifier
315          */

316         public static boolean isAggregate(Map JavaDoc qualifier) {
317             boolean result = true;
318
319             String JavaDoc theClass = (String JavaDoc) qualifier.get("class");
320             if (theClass == null) {
321                 return false; // should maybe throw an exception?
322
}
323             if (theClass.equalsIgnoreCase("EOKeyValueQualifier")
324                     || theClass.equalsIgnoreCase("EOKeyComparisonQualifier")) {
325                 result = false;
326             }
327
328             return result;
329         }
330
331         /**
332          * expressionTypeForQualifier looks at a qualifier containing the EOModeler
333          * FetchSpecification and returns the equivalent Cayenne Expression type for its
334          * selector.
335          *
336          * @param qualifierMap - a Map containing the qualifier settings to examine.
337          * @return int Expression type
338          */

339         public static int expressionTypeForQualifier(Map JavaDoc qualifierMap) {
340             // get selector
341
String JavaDoc selector = (String JavaDoc) qualifierMap.get("selectorName");
342             return expressionTypeForSelector(selector);
343         }
344
345         /**
346          * expressionTypeForSelector looks at a selector from an EOModeler
347          * FetchSpecification and returns the equivalent Cayenne Expression type.
348          *
349          * @param selector - a String containing the selector name.
350          * @return int Expression type
351          */

352         public static int expressionTypeForSelector(String JavaDoc selector) {
353             Integer JavaDoc expType = (Integer JavaDoc) selectorToExpressionBridge().get(selector);
354             return (expType != null ? expType.intValue() : -1);
355         }
356
357         /**
358          * aggregateExpressionClassForQualifier looks at a qualifer and returns the
359          * aggregate type: one of Expression.AND, Expression.OR, or Expression.NOT
360          *
361          * @param qualifierMap - containing the qualifier to examine
362          * @return int aggregate Expression type
363          */

364         public static int aggregateExpressionClassForQualifier(Map JavaDoc qualifierMap) {
365             String JavaDoc qualifierClass = (String JavaDoc) qualifierMap.get("class");
366             if (qualifierClass != null) {
367                 if (qualifierClass.equalsIgnoreCase("EOAndQualifier")) {
368                     return Expression.AND;
369                 }
370                 else if (qualifierClass.equalsIgnoreCase("EOOrQualifier")) {
371                     return Expression.OR;
372                 }
373                 else if (qualifierClass.equalsIgnoreCase("EONotQualifier")) {
374                     return Expression.NOT;
375                 }
376             }
377
378             return -1; // error
379
}
380
381         /**
382          * makeQualifier recursively builds an Expression for each condition in the
383          * qualifierMap and assembles from them the complex Expression to represent the
384          * entire EOFetchSpecification.
385          *
386          * @param qualifierMap - Map representation of EOFetchSpecification
387          * @return Expression translation of the EOFetchSpecification
388          */

389         public static Expression makeQualifier(Map JavaDoc qualifierMap) {
390             if (isAggregate(qualifierMap)) {
391                 // the fetch specification has more than one qualifier
392
int aggregateClass = aggregateExpressionClassForQualifier(qualifierMap); // AND,
393
// OR,
394
// NOT
395

396                 if (aggregateClass == Expression.NOT) {
397                     // NOT qualifiers only have one child, keyed with "qualifier"
398
Map JavaDoc child = (Map JavaDoc) qualifierMap.get("qualifier");
399                     // build the child expression
400
Expression childExp = makeQualifier(child);
401
402                     return childExp.notExp(); // add the "not" clause and return the
403
// result
404

405                 }
406                 else {
407                     // AND, OR qualifiers can have multiple children, keyed with
408
// "qualifiers"
409
// get the list of children
410
List JavaDoc children = (List JavaDoc) qualifierMap.get("qualifiers");
411                     if (children != null) {
412                         ArrayList JavaDoc childExpressions = new ArrayList JavaDoc();
413                         // build an Expression for each child
414
Iterator JavaDoc it = children.iterator();
415                         while (it.hasNext()) {
416                             Expression childExp = makeQualifier((Map JavaDoc) it.next());
417                             childExpressions.add(childExp);
418                         }
419                         // join the child expressions and return the result
420
return ExpressionFactory
421                                 .joinExp(aggregateClass, childExpressions);
422                     }
423                 }
424
425             } // end if isAggregate(qualifierMap)...
426

427             // the query has a single qualifier
428
// get expression selector type
429
int expType = expressionTypeForQualifier(qualifierMap); // =, like, >. <. etc.
430
String JavaDoc qualifierClass = (String JavaDoc) qualifierMap.get("class");
431
432             // the key or key path we're comparing
433
String JavaDoc key = null;
434             // the key, keyPath, value, or parameterized value against which we're
435
// comparing the key
436
Object JavaDoc comparisonValue = null;
437
438             if ("EOKeyComparisonQualifier".equals(qualifierClass)) {
439                 // Comparing two keys or key paths
440
key = (String JavaDoc) qualifierMap.get("leftValue");
441                 comparisonValue = (String JavaDoc) qualifierMap.get("rightValue");
442
443                 // FIXME: I think EOKeyComparisonQualifier sytle Expressions are not
444
// supported...
445
return null;
446             }
447             else if ("EOKeyValueQualifier".equals(qualifierClass)) {
448                 // Comparing key with a value or parameterized value
449
key = (String JavaDoc) qualifierMap.get("key");
450                 Object JavaDoc value = qualifierMap.get("value");
451
452                 if (value instanceof Map JavaDoc) {
453                     Map JavaDoc valueMap = (Map JavaDoc) value;
454                     String JavaDoc objClass = (String JavaDoc) valueMap.get("class"); // can be a
455
// qualifier class
456
// or java type
457

458                     if ("EOQualifierVariable".equals(objClass)
459                             && valueMap.containsKey("_key")) {
460                         // make a parameterized expression
461
String JavaDoc paramName = (String JavaDoc) valueMap.get("_key");
462                         comparisonValue = new ExpressionParameter(paramName);
463                     }
464                     else {
465                         Object JavaDoc queryVal = valueMap.get("value");
466                         if ("NSNumber".equals(objClass)) {
467                             // comparison to NSNumber -- cast
468
comparisonValue = (Number JavaDoc) queryVal;
469                         }
470                         else if ("EONull".equals(objClass)) {
471                             // comparison to null
472
comparisonValue = null;
473                         }
474                         else { // Could there be other types? boolean, date, etc.???
475
// no cast
476
comparisonValue = queryVal;
477                         }
478                     }
479
480                 }
481                 else if (value instanceof String JavaDoc) {
482                     // value expression
483
comparisonValue = value;
484                 } // end if (value instanceof Map) else...
485
}
486
487             // Now create the correct Expression type for the comparison class
488
// and return it.
489
switch (expType) {
490                 case Expression.EQUAL_TO:
491                     return ExpressionFactory.matchExp(key, comparisonValue);
492                 case Expression.NOT_EQUAL_TO:
493                     return ExpressionFactory.noMatchExp(key, comparisonValue);
494                 case Expression.LIKE:
495                     return ExpressionFactory.likeExp(key, comparisonValue);
496                 case Expression.LIKE_IGNORE_CASE:
497                     return ExpressionFactory.likeIgnoreCaseExp(key, comparisonValue);
498                 case Expression.LESS_THAN:
499                     return ExpressionFactory.lessExp(key, comparisonValue);
500                 case Expression.LESS_THAN_EQUAL_TO:
501                     return ExpressionFactory.lessOrEqualExp(key, comparisonValue);
502                 case Expression.GREATER_THAN:
503                     return ExpressionFactory.greaterExp(key, comparisonValue);
504                 case Expression.GREATER_THAN_EQUAL_TO:
505                     return ExpressionFactory.greaterOrEqualExp(key, comparisonValue);
506                 default:
507                     return null;
508             }
509         }
510     }
511 }
Popular Tags