KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.wocompat;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.Collection JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Map JavaDoc;
28
29 import org.apache.cayenne.exp.Expression;
30 import org.apache.cayenne.exp.ExpressionException;
31 import org.apache.cayenne.exp.ExpressionFactory;
32 import org.apache.cayenne.exp.ExpressionParameter;
33 import org.apache.cayenne.exp.parser.ASTObjPath;
34 import org.apache.cayenne.map.Entity;
35 import org.apache.cayenne.map.ObjAttribute;
36 import org.apache.cayenne.map.ObjEntity;
37 import org.apache.cayenne.map.ObjRelationship;
38 import org.apache.cayenne.query.SelectQuery;
39
40 /**
41  * A descriptor of SelectQuery loaded from EOModel. It is an informal "decorator" of
42  * Cayenne SelectQuery to provide access to the extra information of WebObjects
43  * EOFetchSpecification.
44  *
45  * @author Andrus Adamchik
46  * @since 1.1
47  */

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

230     public synchronized Expression makeQualifier(Map JavaDoc qualifierMap) {
231         if (qualifierMap == null) {
232             return null;
233         }
234
235         return EOFetchSpecificationParser.makeQualifier(
236                 (EOObjEntity) getRoot(),
237                 qualifierMap);
238     }
239
240     /**
241      * EOFetchSpecificationParser parses EOFetchSpecifications from a WebObjects-style
242      * EOModel. It recursively builds Cayenne Expression objects and assembles them into
243      * the final aggregate Expression.
244      *
245      * @author Travis Cripps
246      */

247     static class EOFetchSpecificationParser {
248
249         // selector strings
250
static final String JavaDoc IS_EQUAL_TO = "isEqualTo:";
251         static final String JavaDoc IS_NOT_EQUAL_TO = "isNotEqualTo:";
252         static final String JavaDoc IS_LIKE = "isLike:";
253         static final String JavaDoc CASE_INSENSITIVE_LIKE = "isCaseInsensitiveLike:";
254         static final String JavaDoc IS_LESS_THAN = "isLessThan:";
255         static final String JavaDoc IS_LESS_THAN_OR_EQUAL_TO = "isLessThanOrEqualTo:";
256         static final String JavaDoc IS_GREATER_THAN = "isGreaterThan:";
257         static final String JavaDoc IS_GREATER_THAN_OR_EQUAL_TO = "isGreaterThanOrEqualTo:";
258
259         private static HashMap JavaDoc selectorToExpressionBridge;
260
261         /**
262          * selectorToExpressionBridge is just a mapping of EOModeler's selector types to
263          * Cayenne Expression types.
264          *
265          * @return HashMap of Expression types, keyed by the corresponding selector name
266          */

267         static HashMap JavaDoc selectorToExpressionBridge() {
268             if (null == selectorToExpressionBridge) {
269                 // initialize selectorToExpressionBridge
270
selectorToExpressionBridge = new HashMap JavaDoc(8);
271                 selectorToExpressionBridge.put(IS_EQUAL_TO, new Integer JavaDoc(
272                         Expression.EQUAL_TO));
273                 selectorToExpressionBridge.put(IS_NOT_EQUAL_TO, new Integer JavaDoc(
274                         Expression.NOT_EQUAL_TO));
275                 selectorToExpressionBridge.put(IS_LIKE, new Integer JavaDoc(Expression.LIKE));
276                 selectorToExpressionBridge.put(CASE_INSENSITIVE_LIKE, new Integer JavaDoc(
277                         Expression.LIKE_IGNORE_CASE));
278                 selectorToExpressionBridge.put(IS_LESS_THAN, new Integer JavaDoc(
279                         Expression.LESS_THAN));
280                 selectorToExpressionBridge.put(IS_LESS_THAN_OR_EQUAL_TO, new Integer JavaDoc(
281                         Expression.LESS_THAN_EQUAL_TO));
282                 selectorToExpressionBridge.put(IS_GREATER_THAN, new Integer JavaDoc(
283                         Expression.GREATER_THAN));
284                 selectorToExpressionBridge.put(IS_GREATER_THAN_OR_EQUAL_TO, new Integer JavaDoc(
285                         Expression.GREATER_THAN_EQUAL_TO));
286             }
287             return selectorToExpressionBridge;
288         }
289
290         /**
291          * isAggregate determines whether a qualifier is "aggregate" -- has children -- or
292          * "simple".
293          *
294          * @param qualifier - a Map containing the qualifier settings
295          * @return boolean indicating whether the qualifier is "aggregate" qualifier
296          */

297         static boolean isAggregate(Map JavaDoc qualifier) {
298             boolean result = true;
299
300             String JavaDoc theClass = (String JavaDoc) qualifier.get("class");
301             if (theClass == null) {
302                 return false; // should maybe throw an exception?
303
}
304             if (theClass.equalsIgnoreCase("EOKeyValueQualifier")
305                     || theClass.equalsIgnoreCase("EOKeyComparisonQualifier")) {
306                 result = false;
307             }
308
309             return result;
310         }
311
312         /**
313          * expressionTypeForQualifier looks at a qualifier containing the EOModeler
314          * FetchSpecification and returns the equivalent Cayenne Expression type for its
315          * selector.
316          *
317          * @param qualifierMap - a Map containing the qualifier settings to examine.
318          * @return int Expression type
319          */

320         static int expressionTypeForQualifier(Map JavaDoc qualifierMap) {
321             // get selector
322
String JavaDoc selector = (String JavaDoc) qualifierMap.get("selectorName");
323             return expressionTypeForSelector(selector);
324         }
325
326         /**
327          * expressionTypeForSelector looks at a selector from an EOModeler
328          * FetchSpecification and returns the equivalent Cayenne Expression type.
329          *
330          * @param selector - a String containing the selector name.
331          * @return int Expression type
332          */

333         static int expressionTypeForSelector(String JavaDoc selector) {
334             Integer JavaDoc expType = (Integer JavaDoc) selectorToExpressionBridge().get(selector);
335             return (expType != null ? expType.intValue() : -1);
336         }
337
338         /**
339          * aggregateExpressionClassForQualifier looks at a qualifer and returns the
340          * aggregate type: one of Expression.AND, Expression.OR, or Expression.NOT
341          *
342          * @param qualifierMap - containing the qualifier to examine
343          * @return int aggregate Expression type
344          */

345         static int aggregateExpressionClassForQualifier(Map JavaDoc qualifierMap) {
346             String JavaDoc qualifierClass = (String JavaDoc) qualifierMap.get("class");
347             if (qualifierClass != null) {
348                 if (qualifierClass.equalsIgnoreCase("EOAndQualifier")) {
349                     return Expression.AND;
350                 }
351                 else if (qualifierClass.equalsIgnoreCase("EOOrQualifier")) {
352                     return Expression.OR;
353                 }
354                 else if (qualifierClass.equalsIgnoreCase("EONotQualifier")) {
355                     return Expression.NOT;
356                 }
357             }
358
359             return -1; // error
360
}
361
362         /**
363          * makeQualifier recursively builds an Expression for each condition in the
364          * qualifierMap and assembles from them the complex Expression to represent the
365          * entire EOFetchSpecification.
366          *
367          * @param qualifierMap - Map representation of EOFetchSpecification
368          * @return Expression translation of the EOFetchSpecification
369          */

370         static Expression makeQualifier(EOObjEntity entity, Map JavaDoc qualifierMap) {
371             if (isAggregate(qualifierMap)) {
372                 // the fetch specification has more than one qualifier
373
int aggregateClass = aggregateExpressionClassForQualifier(qualifierMap); // AND,
374
// OR,
375
// NOT
376

377                 if (aggregateClass == Expression.NOT) {
378                     // NOT qualifiers only have one child, keyed with "qualifier"
379
Map JavaDoc child = (Map JavaDoc) qualifierMap.get("qualifier");
380                     // build the child expression
381
Expression childExp = makeQualifier(entity, child);
382
383                     return childExp.notExp(); // add the "not" clause and return the
384
// result
385
}
386                 else {
387                     // AND, OR qualifiers can have multiple children, keyed with
388
// "qualifiers"
389
// get the list of children
390
List JavaDoc children = (List JavaDoc) qualifierMap.get("qualifiers");
391                     if (children != null) {
392                         ArrayList JavaDoc childExpressions = new ArrayList JavaDoc();
393                         // build an Expression for each child
394
Iterator JavaDoc it = children.iterator();
395                         while (it.hasNext()) {
396                             Expression childExp = makeQualifier(entity, (Map JavaDoc) it.next());
397                             childExpressions.add(childExp);
398                         }
399                         // join the child expressions and return the result
400
return ExpressionFactory
401                                 .joinExp(aggregateClass, childExpressions);
402                     }
403                 }
404
405             } // end if isAggregate(qualifierMap)...
406

407             // the query has a single qualifier
408
// get expression selector type
409
String JavaDoc qualifierClass = (String JavaDoc) qualifierMap.get("class");
410
411             // the key or key path we're comparing
412
String JavaDoc key = null;
413             // the key, keyPath, value, or parameterized value against which we're
414
// comparing the key
415
Object JavaDoc comparisonValue = null;
416
417             if ("EOKeyComparisonQualifier".equals(qualifierClass)) {
418                 // Comparing two keys or key paths
419
key = (String JavaDoc) qualifierMap.get("leftValue");
420                 comparisonValue = (String JavaDoc) qualifierMap.get("rightValue");
421
422                 // FIXME: I think EOKeyComparisonQualifier sytle Expressions are not
423
// supported...
424
return null;
425             }
426             else if ("EOKeyValueQualifier".equals(qualifierClass)) {
427                 // Comparing key with a value or parameterized value
428
key = (String JavaDoc) qualifierMap.get("key");
429                 Object JavaDoc value = qualifierMap.get("value");
430
431                 if (value instanceof Map JavaDoc) {
432                     Map JavaDoc valueMap = (Map JavaDoc) value;
433                     String JavaDoc objClass = (String JavaDoc) valueMap.get("class"); // can be a
434
// qualifier class
435
// or java type
436

437                     if ("EOQualifierVariable".equals(objClass)
438                             && valueMap.containsKey("_key")) {
439                         // make a parameterized expression
440
String JavaDoc paramName = (String JavaDoc) valueMap.get("_key");
441                         comparisonValue = new ExpressionParameter(paramName);
442                     }
443                     else {
444                         Object JavaDoc queryVal = valueMap.get("value");
445                         if ("NSNumber".equals(objClass)) {
446                             // comparison to NSNumber -- cast
447
comparisonValue = (Number JavaDoc) queryVal;
448                         }
449                         else if ("EONull".equals(objClass)) {
450                             // comparison to null
451
comparisonValue = null;
452                         }
453                         else { // Could there be other types? boolean, date, etc.???
454
// no cast
455
comparisonValue = queryVal;
456                         }
457                     }
458
459                 }
460                 else if (value instanceof String JavaDoc) {
461                     // value expression
462
comparisonValue = value;
463                 } // end if (value instanceof Map) else...
464
}
465
466             // check whether the key is an object path; if at least one component is not,
467
// switch to db path..
468

469             Expression keyExp = Expression.fromString(key);
470             try {
471                 entity.lastPathComponent(keyExp);
472             }
473             catch (ExpressionException e) {
474                 keyExp = entity.translateToDbPath(keyExp);
475             }
476
477             try {
478                 Expression exp = ExpressionFactory
479                         .expressionOfType(expressionTypeForQualifier(qualifierMap));
480
481                 exp.setOperand(0, keyExp);
482                 exp.setOperand(1, comparisonValue);
483                 return exp;
484             }
485             catch (ExpressionException e) {
486                 return null;
487             }
488         }
489     }
490 }
491
Popular Tags