KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > versant > core > jdo > query > QueryParser


1
2 /*
3  * Copyright (c) 1998 - 2005 Versant Corporation
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  * Versant Corporation - initial API and implementation
11  */

12 package com.versant.core.jdo.query;
13
14 import com.versant.core.common.Debug;
15 import com.versant.core.jdo.QueryDetails;
16 import com.versant.core.common.CmdBitSet;
17 import com.versant.core.metadata.ClassMetaData;
18 import com.versant.core.metadata.ModelMetaData;
19 import com.versant.core.util.classhelper.ClassHelper;
20
21 import java.io.StringReader JavaDoc;
22
23 import com.versant.core.common.BindingSupportImpl;
24
25 /**
26  * Wrapper around the JavaCC JDOQL parser.
27  */

28 public class QueryParser {
29
30     private JavaCharStream stream;
31     protected ImportNode[] imports;
32     protected ParamNode[] params;
33     protected VarNode[] vars;
34     protected OrderNode[] orders;
35     protected UnaryNode filter;
36     protected ResultNode resultNode;
37     protected GroupingNode groupingNode;
38
39     private JDOQLParser parser;
40     private JDOQLParserTokenManager tokenManager;
41
42     /**
43      * The ClassMetaData of the Candidate class.
44      */

45     protected ClassMetaData cmd;
46     protected ModelMetaData jmd;
47
48     public QueryParser(ModelMetaData jmd) {
49         this.jmd = jmd;
50     }
51
52     public ClassMetaData getCmd() {
53         return cmd;
54     }
55
56     public ImportNode[] getImports() {
57         return imports;
58     }
59
60     public ParamNode[] getParams() {
61         return params;
62     }
63
64     public void setParams(ParamNode[] params) {
65         this.params = params;
66     }
67     
68     public VarNode[] getVars() {
69         return vars;
70     }
71
72     public OrderNode[] getOrders() {
73         return orders;
74     }
75
76     public UnaryNode getFilter() {
77         return filter;
78     }
79
80     public ResultNode getResultNode() {
81         return resultNode;
82     }
83
84     public GroupingNode getGroupingNode() {
85         return groupingNode;
86     }
87
88     public void setGroupingNode(GroupingNode groupingNode) {
89         this.groupingNode = groupingNode;
90     }
91
92     public void parse(QueryDetails q) throws Exception JavaDoc {
93
94             parseJDOQL(q);
95             
96         parseCommon(q);
97     }
98
99     public void parseJDOQL(QueryDetails q) throws Exception JavaDoc {
100         cmd = jmd.getClassMetaData(q.getCandidateClass());
101         String JavaDoc s = q.getImports();
102         if (s != null) {
103             initParser(s);
104             try {
105                 imports = parser.declareImports();
106             } catch (ParseException e) {
107                 throw BindingSupportImpl.getInstance().invalidOperation("Invalid imports:\n" + s + "\n" +
108                         e.getMessage());
109             }
110             if (Debug.DEBUG) {
111                 Debug.OUT.println("imports: ");
112                 dump(imports);
113             }
114         } else {
115             imports = null;
116         }
117
118         // parse the parameters
119
s = q.getParameters();
120         if (s != null) {
121             initParser(s);
122             try {
123                 params = parser.declareParameters();
124             } catch (ParseException e) {
125                 throw BindingSupportImpl.getInstance().invalidOperation("Invalid parameter declarations:\n" + s + "\n" +
126                         e.getMessage());
127             }
128             for (int i = params.length - 1; i >= 0; i--) params[i].setIndex(i);
129             if (Debug.DEBUG) {
130                 Debug.OUT.println("params: ");
131                 dump(params);
132             }
133         } else {
134             params = null;
135         }
136
137         // parse the variables
138
s = q.getVariables();
139         if (s != null) {
140             initParser(s);
141             try {
142                 vars = parser.declareVariables();
143             } catch (ParseException e) {
144                 throw BindingSupportImpl.getInstance().invalidOperation("Invalid variable declarations:\n" + s + "\n" +
145                         e.getMessage());
146             }
147             if (Debug.DEBUG) {
148                 Debug.OUT.println("vars: ");
149                 dump(vars);
150             }
151         } else {
152             vars = null;
153         }
154
155         // parse the ordering
156
s = q.getOrdering();
157         if (s != null) {
158             initParser(s);
159             try {
160                 orders = parser.setOrderings();
161             } catch (ParseException e) {
162                 throw BindingSupportImpl.getInstance().invalidOperation("Invalid ordering:\n" + s + "\n" +
163                         e.getMessage());
164             }
165             for (int i = 0; i < orders.length; i++) orders[i].normalize();
166             if (Debug.DEBUG) {
167                 Debug.OUT.println("normalized orders: ");
168                 dump(orders);
169             }
170         } else {
171             orders = null;
172         }
173
174         // parse the filter
175
s = q.getFilter();
176         if (s != null) {
177             initParser(q.getFilter());
178             try {
179                 Node e = parser.filterExpression();
180                 if (e != null) {
181                     filter = new UnaryNode(e);
182                 } else {
183                     filter = null;
184                 }
185             } catch (ParseException x) {
186                 throw BindingSupportImpl.getInstance().invalidOperation("Invalid filter:\n" + s + "\n" +
187                         x.getMessage());
188             }
189         } else {
190             filter = null;
191         }
192
193         //parse the result
194
s = q.getResult();
195         if (s != null && s.trim().length() > 0) {
196             initParser(s);
197             try {
198                 resultNode = parser.setResults();
199             } catch (ParseException x) {
200                 throw BindingSupportImpl.getInstance().invalidOperation("Invalid result:\n" + s + "\n" +
201                         x.getMessage());
202             }
203         } else {
204             resultNode = null;
205         }
206
207         //parse the grouping
208
s = q.getGrouping();
209         if (s != null) {
210             initParser(s);
211             try {
212                 groupingNode = parser.setGrouping();
213             } catch (ParseException x) {
214                 throw BindingSupportImpl.getInstance().invalidOperation("Invalid grouping:\n" + s + "\n" +
215                         x.getMessage());
216             }
217         } else {
218             groupingNode = null;
219         }
220     }
221
222     private void parseCommon(QueryDetails q) throws Exception JavaDoc {
223
224         // check the types of all vars and lookup their meta data
225
if (vars != null) {
226             for (int i = vars.length - 1; i >= 0; i--) vars[i].resolve(this);
227         }
228
229         if (filter != null) {
230             if (Debug.DEBUG) {
231                 Debug.OUT.println("\n* Filter: " + filter);
232                 Debug.OUT.println("\n* Parsed tree:");
233                 filter.dump("");
234             }
235
236             // simplify some tree constructs
237
filter.normalize();
238             if (Debug.DEBUG) {
239                 Debug.OUT.println("\n* Normalized tree:");
240                 filter.dump("");
241             }
242
243             // resolve field and parameter names etc
244
filter.resolve(this, cmd, false);
245             if (Debug.DEBUG) {
246                 Debug.OUT.println("\n* Resolved tree:");
247                 filter.dump("");
248             }
249
250             // simplify some tree constructs again as some operations
251
// require resolved nodes
252
filter.normalize();
253             if (Debug.DEBUG) {
254                 Debug.OUT.println("\n* Second normalized tree:");
255                 filter.dump("");
256             }
257
258         } else {
259             if (Debug.DEBUG) {
260                 Debug.OUT.println("filter is null");
261             }
262         }
263     }
264
265
266     
267     /**
268      * Parse just an ordering specification. This is used to parse orderings
269      * on their own in the meta data.
270      */

271     public OrderNode[] parseOrdering(ClassMetaData candidateClass, String JavaDoc s)
272             throws ParseException {
273         try {
274             if (s != null) {
275                 cmd = candidateClass;
276                 initParser(s);
277                 return parser.setOrderings();
278             } else {
279                 return null;
280             }
281         } catch (TokenMgrError e) {
282             throw new ParseException(e.toString());
283         }
284     }
285
286     /**
287      * Find the parameter with name or null if none.
288      */

289     public ParamNode findParam(String JavaDoc name) {
290         if (params == null) return null;
291         for (int i = params.length - 1; i >= 0; i--) {
292             ParamNode p = params[i];
293             if (p.getIdentifier().equals(name)) return p;
294         }
295         return null;
296     }
297
298     /**
299      * Find the variable with name or null if none.
300      */

301     public VarNode findVar(String JavaDoc name) {
302         if (vars == null) return null;
303         for (int i = vars.length - 1; i >= 0; i--) {
304             VarNode v = vars[i];
305             if (v.getIdentifier().equals(name)) return v;
306         }
307         return null;
308     }
309
310     public ClassMetaData getCMD(Class JavaDoc cls) {
311         return jmd.getClassMetaData(cls);
312     }
313
314     /**
315      * Convert a variable type name into a class. This makes sure it is a
316      * legal type.
317      */

318     public Class JavaDoc resolveVarType(String JavaDoc type) {
319         Class JavaDoc cls;
320         try {
321             cls = resolveType(type);
322         } catch (ClassNotFoundException JavaDoc e) {
323             throw BindingSupportImpl.getInstance().runtime("Variable class not found: '" +
324                     type + "'", e);
325         }
326         return cls;
327     }
328
329     /**
330      * Convert a parameter type name into a class. This makes sure it is a
331      * legal type.
332      */

333     public Class JavaDoc resolveParamType(String JavaDoc type) {
334         Class JavaDoc cls;
335         try {
336             cls = resolveType(type);
337         } catch (ClassNotFoundException JavaDoc e) {
338             throw BindingSupportImpl.getInstance().runtime("Parameter class not found: '" +
339                     type + "'", e);
340         }
341         return cls;
342     }
343
344     private Class JavaDoc resolveType(String JavaDoc type) throws ClassNotFoundException JavaDoc {
345         try {
346             return resolveTypeImp(type);
347         } catch (ClassNotFoundException JavaDoc e) {
348             int i = type.lastIndexOf('.');
349             if (i >= 0) {
350                 StringBuffer JavaDoc s = new StringBuffer JavaDoc(type);
351                 s.setCharAt(i, '$');
352                 try {
353                     return resolveTypeImp(s.toString());
354                 } catch (ClassNotFoundException JavaDoc e1) {
355                     // ignore
356
}
357             }
358             throw e;
359         }
360     }
361
362     private Class JavaDoc resolveTypeImp(String JavaDoc type) throws ClassNotFoundException JavaDoc {
363         ClassLoader JavaDoc loader = cmd.getClassLoader();
364         try {
365             return ClassHelper.get().classForName(type, true, loader);
366         } catch (ClassNotFoundException JavaDoc e) {
367             if (imports != null) {
368                 int len = imports.length;
369                 for (int i = 0; i < len; i++) {
370                     ImportNode im = imports[i];
371                     if (im.all) {
372                         try {
373                             return ClassHelper.get().classForName(im.name + type, true, loader);
374                         } catch (ClassNotFoundException JavaDoc x) {
375                             // ignore
376
}
377                     } else {
378                         if (type.equals(im.getClassName())) {
379                             return ClassHelper.get().classForName(im.name, true, loader);
380                         }
381                     }
382                 }
383             }
384             try {
385                 return ClassHelper.get().classForName(cmd.packageNameWithDot +
386                                                       type, true, loader);
387             } catch (ClassNotFoundException JavaDoc x) {
388                 return ClassHelper.get().classForName("java.lang." + type, true, loader);
389             }
390         }
391     }
392
393     /**
394      * Convert a cast expression into ClassMetaData or throw a
395      * JDOFatalUserException if not found. If the cast is to an interface
396      * then the array will contain all the possible implementing classes.
397      * TODO: Complete the interface support.
398      */

399     public ClassMetaData[] resolveCastType(String JavaDoc type) {
400         ClassMetaData c = jmd.getClassMetaData(type);
401         if (c == null) {
402             if (imports != null) {
403                 int len = imports.length;
404                 for (int i = 0; i < len && c == null; i++) {
405                     ImportNode im = imports[i];
406                     if (im.all) {
407                         c = jmd.getClassMetaData(im.name + type);
408                     } else if (type.equals(im.getClassName())) {
409                         c = jmd.getClassMetaData(im.name);
410                     }
411                 }
412             }
413             if (c == null) {
414                 c = jmd.getClassMetaData(cmd.packageNameWithDot + type);
415             }
416         }
417         if (c == null) {
418             throw BindingSupportImpl.getInstance().runtime("No persistent class found for cast expression: (" + type +
419                     "): check the query imports");
420         }
421         return new ClassMetaData[]{c};
422     }
423
424     /**
425      * Get the parser ready to parse s.
426      */

427     private void initParser(String JavaDoc s) {
428         StringReader JavaDoc reader = new StringReader JavaDoc(s);
429         if (stream == null) {
430             stream = new JavaCharStream(reader);
431         } else {
432             stream.ReInit(reader);
433         }
434         if (tokenManager == null) {
435             tokenManager = new JDOQLParserTokenManager(stream);
436         } else {
437             tokenManager.ReInit(stream);
438         }
439         if (parser == null) {
440             parser = new JDOQLParser(tokenManager);
441         } else {
442             parser.ReInit(tokenManager);
443         }
444     }
445
446     private void dump(Node[] a) {
447         for (int i = 0; i < a.length; i++) {
448             Debug.OUT.print("[" + i + "] ");
449             a[i].dump(" ");
450         }
451     }
452
453     /**
454      * This will return the CmdBitSet filled with the classMetadata's
455      * that this query depends on.
456      */

457     public CmdBitSet getCmds() {
458         final CmdBitSet bitSet = new CmdBitSet(jmd);
459         bitSet.addPlus(cmd);
460         if (filter != null) {
461             doCmdDependency(filter, bitSet);
462         }
463         if (orders != null) {
464             for (int i = 0; i < orders.length; i++) {
465                 doCmdDependency(orders[i], bitSet);
466             }
467         }
468         return bitSet;
469     }
470
471     private void doCmdDependency(Node node, CmdBitSet bitSet) {
472         if (node == null) return;
473         node.updateEvictionDependency(bitSet);
474         for (Node n = node.childList; n != null; n = n.next) {
475             doCmdDependency(n, bitSet);
476         }
477     }
478
479 }
480
Popular Tags