KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > speedo > query > parser > SpeedoQLVariableVisitor


1 /**
2  * Speedo: an implementation of JDO compliant personality on top of JORM generic
3  * I/O sub-system.
4  * Copyright (C) 2001-2004 France Telecom R&D
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  *
21  *
22  * Contact: speedo@objectweb.org
23  *
24  * Authors: S. Chassande-Barrioz
25  *
26  */

27 package org.objectweb.speedo.query.parser;
28
29 import java.util.ArrayList JavaDoc;
30 import java.util.HashMap JavaDoc;
31 import java.util.HashSet JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.Stack JavaDoc;
35
36 import javax.jdo.JDOUserException;
37
38 import org.objectweb.jorm.metainfo.api.Class;
39 import org.objectweb.jorm.metainfo.api.Manager;
40 import org.objectweb.medor.api.Field;
41 import org.objectweb.medor.api.MedorException;
42 import org.objectweb.medor.query.api.QueryTree;
43 import org.objectweb.medor.query.api.QueryTreeField;
44 import org.objectweb.medor.query.jorm.lib.ClassExtent;
45 import org.objectweb.medor.query.jorm.lib.PNameField;
46 import org.objectweb.medor.query.jorm.lib.QueryBuilder;
47 import org.objectweb.speedo.api.SpeedoException;
48 import org.objectweb.util.monolog.api.BasicLevel;
49 import org.objectweb.util.monolog.api.Logger;
50
51 /**
52  * @author S.Chassande-Barrioz
53  */

54 public class SpeedoQLVariableVisitor extends SpeedoQLAbstractVisitor {
55
56     private Manager jmiManager;
57     
58
59     /**
60      * ids is a temporary structure to store variables, parameters, name
61      * definitions, and build corresponding QueryTree(s)
62      * key: the name to resolve
63      * value: an IdValue object which contains the name, the paths, and the
64      * corresponding QueryTree (see the definition of IdValue object in
65      * SpeedoQLAbstractVisitor object)
66      */

67     private Map JavaDoc ids = new HashMap JavaDoc();
68     
69     private HashSet JavaDoc testcontains = new HashSet JavaDoc();
70     private HashSet JavaDoc isEmptys = new HashSet JavaDoc();
71
72     /**
73      * qt is the built QueryTree from the current object.
74      */

75     private QueryTree qt = null;
76
77     /**
78      * speedoql is the result of the filter parsing
79      */

80     private SimpleNode speedoql = null;
81
82     private int nbNot = 0;
83
84     private List JavaDoc orders;
85
86     /**
87      * field for each defined identifiers of the query.
88      */

89     private HashMap JavaDoc fields = new HashMap JavaDoc();
90
91     private QueryBuilder qb = new QueryBuilder();
92     
93     private boolean includeSubClasses;
94
95     public SpeedoQLVariableVisitor(SimpleNode speedoql,
96             Manager jmim,
97             Logger logger,
98             Map JavaDoc hparam,
99             Map JavaDoc hvar,
100             List JavaDoc orders,
101             String JavaDoc classname,
102             boolean includeSubClasses
103             ) throws SpeedoException {
104         this.speedoql = speedoql;
105         this.jmiManager= jmim;
106         setLogger(logger);
107         setParams(hparam);
108         setVars(hvar);
109         setOrders(orders);
110         setCurrentClass(classname);
111         this.includeSubClasses = includeSubClasses;
112         startVisiting();
113     }
114
115     public Map JavaDoc getFields() {
116         return fields;
117     }
118     
119     public QueryBuilder getQueryBuilder() {
120         return qb;
121     }
122     
123     public QueryTree getQueryTree() {
124         return qb.getQueryTree();
125     }
126     
127     public void setOrders(List JavaDoc orders) {
128         this.orders = orders;
129     }
130
131     /**
132      * The visit of the tree starts here.
133      * Please setup current class, params and vars hashtable before calling
134      * this method.
135      */

136     public Map JavaDoc startVisiting() throws SpeedoException {
137         debug = logger != null && logger.isLoggable(BasicLevel.DEBUG);
138         nbNot = 0;
139
140         //Add the initial class as the first IdValue. The key is 'this'
141
if (curClass != null) {
142             logger.log(BasicLevel.DEBUG, "create a new IdValue object " +
143                     "with the current class (" + curClass + ")");
144             IdValue iv = new IdValue(new String JavaDoc[] {curClass}, EXTENT);
145             iv.alias = "this";
146             ids.put(iv.alias, iv);
147         }
148         try {
149             //visit the tree
150
visit(speedoql);
151         } catch (Exception JavaDoc e) {
152             throw new SpeedoException("Error during the parsing of JDOQL:", e);
153         }
154         if (orders != null) {
155             for(int i=0; i<orders.size(); i++) {
156                 String JavaDoc fieldName = (String JavaDoc) orders.get(i);
157                 int idx = fieldName.indexOf(' ');
158                 if (idx != -1) {
159                     fieldName = fieldName.substring(0, idx).trim();
160                 }
161                 visitPath(null, fieldName);
162             }
163         }
164         ArrayList JavaDoc toTreat = new ArrayList JavaDoc(ids.values());
165         while(!toTreat.isEmpty()) {
166             treatIdValue((IdValue) toTreat.get(0), toTreat);
167         }
168         return fields;
169     }
170     private void treatIdValue(IdValue iv, List JavaDoc toTreat) throws SpeedoException {
171         if (iv.nameType != EXTENT) {
172             IdValue dependency = (IdValue) ids.get(iv.name[0]);
173             if (dependency == null) {
174                 throw new SpeedoException("Dependency unresolved: " + iv.name[0]);
175             }
176             if (toTreat.contains(dependency)) {
177                 treatIdValue(dependency, toTreat);
178             }
179         }
180         toTreat.remove(iv);
181
182         QueryBuilder theqb = qb;
183         if (iv.nameType == MEMBEROF) {
184             //a.b.cs.contains(x) ==> a.b.PNAME IN cs.id
185
String JavaDoc rest = mergePath(iv.name, 1, iv.name.length - 1);
186             theqb = new QueryBuilder(qb);
187             try {
188                 theqb.define("", qb.navigate(iv.name[0]));
189             } catch (MedorException e) {
190                 throw new SpeedoException(e);
191             }
192         }
193
194         try {
195             String JavaDoc n = iv.alias + "." + Field.PNAMENAME;
196             fields.put(n, theqb.project(iv.alias, define(theqb, iv.alias, iv.alias)));
197             for (int i = 0; i < iv.getDeclaredPathLength(); i++) {
198                 String JavaDoc path = iv.getMergedPath(i);
199                 if (!testcontains.contains(path) && !isEmptys.contains(path)) {
200                     fields.put(path, theqb.project(path, define(theqb, path, null)));
201                 }
202             }
203         } catch (Exception JavaDoc e) {
204             throw new SpeedoException("Error during the parsing of JDOQL:", e);
205         }
206     }
207     public QueryTreeField getField(String JavaDoc path) throws SpeedoException {
208         String JavaDoc[] splitted = splitPath(path);
209         if (params != null && params.containsKey(splitted[0])) {
210             if (splitted.length > 1) {
211                 //not managed
212
}
213         } else if (vars != null && vars.containsKey(splitted[0])) {
214         } else { // this
215
if (!splitted[0].equals("this")) {
216                 path = "this." + path;
217                 String JavaDoc[] newsplitted = new String JavaDoc[splitted.length + 1];
218                 newsplitted[0] = "this";
219                 System.arraycopy(splitted, 0, newsplitted, 1, splitted.length);
220                 splitted = newsplitted;
221             }
222         }
223         QueryTreeField qtf = (QueryTreeField) fields.get(path);
224         if (qtf == null) {
225             try {
226                 qtf = qb.project(define(qb, path, null));
227             } catch (Exception JavaDoc e) {
228                 throw new SpeedoException(e);
229             }
230             fields.put(path, qtf);
231         }
232         return qtf;
233     }
234     private QueryTreeField define(QueryBuilder theqb, String JavaDoc id, String JavaDoc alias) throws ParseException, MedorException {
235         String JavaDoc[] path = splitPath(id);
236
237         if (!theqb.contains(path[0])) {
238             IdValue idv = (IdValue) ids.get(path[0]);
239             String JavaDoc[] name = idv.name;
240
241             PNameField pnf;
242             if (name.length == 1) {
243                 pnf = extent(name[0], path[0]);
244                 theqb.define(path[0], pnf);
245             } else {
246                 pnf = (PNameField) define(theqb, mergePath(name), alias);
247                 if (!path[0].equals(alias)) {
248                     theqb.define(path[0], pnf);
249                 }
250             }
251         }
252
253         return theqb.navigate(path,alias);
254     }
255
256     private PNameField extent(String JavaDoc classname, String JavaDoc alias) throws ParseException, MedorException {
257         if (classname == null) {
258             throw new NullPointerException JavaDoc("class name not defined");
259         }
260         Class JavaDoc theClass = jmiManager.getClass(classname);
261         if (theClass == null) {
262             throw new ParseException
263                 ("Class '" + classname +
264                  "' has not been declared in the jorm meta information");
265         }
266         ClassExtent ext = new ClassExtent(theClass, alias, Field.PNAMENAME, false);
267         if (classname.equals(this.curClass)) {
268             ext.setWithSubClasses(includeSubClasses);
269         }
270         return (PNameField) ext.getField(ext.getPNameFieldName());
271     }
272     
273
274     /**
275      * ********************* VISITOR METHODS ***********************************
276      */

277
278     public Object JavaDoc visit(ASTSpeedoPrimary node, Object JavaDoc data) {
279         visit((SimpleNode) node, data);
280         return null;
281     }
282
283     public Object JavaDoc visit(ASTSpeedoQL node, Object JavaDoc data) {
284         visit((SimpleNode) node, data);
285         return null;
286     }
287
288     public Object JavaDoc visit(ASTPrimary node, Object JavaDoc data) {
289         visit((SimpleNode) node, data);
290         return null;
291     }
292
293     public Object JavaDoc visit(ASTRelationalExpression node, Object JavaDoc data) {
294         visit((SimpleNode) node, data);
295         return null;
296     }
297
298     public Object JavaDoc visit(ASTAdditiveExpression node, Object JavaDoc data) {
299
300         visit((SimpleNode) node, data);
301         return null;
302     }
303
304     public Object JavaDoc visit(ASTUnaryExpression node, Object JavaDoc data) {
305         boolean hasNot = node.ops.size() > 0
306                 && ((Integer JavaDoc) node.ops.get(0)).intValue() == SpeedoQLConstants.NOT;
307         if (hasNot) {
308             nbNot ++;
309             if (debug) {
310                 logger.log(BasicLevel.DEBUG, "remember a Not: "+ nbNot);
311             }
312         }
313         visit((SimpleNode) node, data);
314         if (hasNot && nbNot> 0) {
315             nbNot--;
316             if (debug) {
317                 logger.log(BasicLevel.DEBUG, "forget a Not: "+ nbNot);
318             }
319         }
320         //logger.log(BasicLevel.DEBUG, "End of Visit UnaryExpression");
321
return null;
322     }
323
324     public Object JavaDoc visit(ASTCastExpression node, Object JavaDoc data) {
325         return null;
326     }
327
328     public Object JavaDoc visit(ASTArgumentList node, Object JavaDoc data) {
329         visit((SimpleNode) node, data);
330         return null;
331     }
332
333     public Object JavaDoc visit(ASTLiteral node, Object JavaDoc data) {
334         visit((SimpleNode) node, data);
335         return null;
336     }
337
338     public Object JavaDoc visit(ASTType node, Object JavaDoc data) {
339         //voir cast , donc on s'en fout
340
visit((SimpleNode) node, data);
341         return null;
342     }
343
344     public Object JavaDoc visit(ASTQualifiedName node, Object JavaDoc data) {
345         Stack JavaDoc stack = (Stack JavaDoc) data;
346         String JavaDoc name = (String JavaDoc) node.value;
347         if (debug) {
348             logger.log(BasicLevel.DEBUG, "variable visitor: qualifiedname=<" + name + ">");
349         }
350         visitPath(stack, name);
351         if (debug) {
352             logger.log(BasicLevel.DEBUG, "variable visitor: qualifiedname=<" + name + ">-end");
353         }
354         return null;
355     }
356     
357     private void visitPath(Stack JavaDoc stack, String JavaDoc path) {
358         String JavaDoc[] splitted = splitPath(path);
359         if (params != null && params.containsKey(splitted[0])) {
360             visitParameterUse(stack, splitted);
361         } else if (vars != null && vars.containsKey(splitted[0])) {
362             visitVariableUse(stack, path, splitted);
363         } else { // this
364
if (!splitted[0].equals("this")) {
365                 path = "this." + path;
366                 String JavaDoc[] newsplitted = new String JavaDoc[splitted.length + 1];
367                 newsplitted[0] = "this";
368                 System.arraycopy(splitted, 0, newsplitted, 1, splitted.length);
369                 splitted = newsplitted;
370             }
371             visitThisUse(stack, path, splitted);
372         }
373     }
374
375     /**
376      * Manages a path using a parameter
377      * @param stack
378      * @param splitted
379      */

380     private void visitParameterUse(Stack JavaDoc stack, String JavaDoc[] splitted) {
381         if (stack.size() > 0 && stack.peek() instanceof String JavaDoc) {
382             String JavaDoc setpath = (String JavaDoc) stack.pop();
383             if (debug) {
384                 logger.log(BasicLevel.DEBUG, "The parameter '" + splitted[0]
385                     + "' is used in a contains expression: "
386                     + setpath + ".contains(" + splitted[0] + ")");
387             }
388         } else if (debug) {
389             logger.log(BasicLevel.DEBUG, "Use of the parameter " + splitted[0]);
390         }
391     }
392     
393     /**
394      * Manages a path using a variable
395      * @param stack
396      * @param path
397      * @param splitted
398      */

399     private void visitVariableUse(Stack JavaDoc stack, String JavaDoc path, String JavaDoc[] splitted) {
400         if (debug) {
401             logger.log(BasicLevel.DEBUG, "Use of the variable " + splitted[0]
402                 + " : " + path);
403         }
404         //fetch or create an IdValue
405
IdValue iv = (IdValue) ids.get(splitted[0]);
406         if (iv == null) {
407             if (debug) {
408                 logger.log(BasicLevel.DEBUG, "Create a new IdValue for the variable " + splitted[0] + " for the path " + path);
409             }
410             iv = new IdValue();
411             // The definition of the variable is not yet knwon but by default
412
// the variable is used a simple extent (JORM_NAME)
413
iv.nameType = EXTENT;
414             iv.alias = splitted[0];
415             ids.put(iv.alias, iv);
416         } else {
417             if (iv.alias !=null && !iv.alias.equals(splitted[0])) {
418                 logger.log(BasicLevel.WARN,
419                         "Redefine a different alias for a variable, old="
420                         + iv.alias + ", new=" + splitted[0]);
421             }
422             iv.alias = splitted[0];
423             if (debug) {
424                 logger.log(BasicLevel.DEBUG, "Use the IdValue of the variable " + splitted[0] + " by the path " + path);
425             }
426         }
427         if (stack.size() > 0 && stack.peek() instanceof String JavaDoc) {
428             // Define the IdValue from previous (contains)
429
String JavaDoc definition = (String JavaDoc) stack.pop();
430             if (debug) {
431                 logger.log(BasicLevel.DEBUG, "Define the variable " + splitted[0]
432                     + " to " + definition);
433             }
434             if (iv.name != null) {
435                 throw new JDOUserException("Variable '"
436                         + splitted[0] + "' defined several times : \n\t"
437                         + iv.name + "\n\t" + definition);
438             }
439             iv.nameType = ((nbNot%2)==1 ? MEMBEROF : NAVIGATION);
440             iv.name = splitPath(definition);
441             testcontains.add(definition);
442         }
443         visitThisOrVarUseEnd(stack, path, splitted);
444     }
445     
446     private void visitThisUse(Stack JavaDoc stack, String JavaDoc path, String JavaDoc[] splitted) {
447         if (debug) {
448             logger.log(BasicLevel.DEBUG, "Use of this " + splitted[0]
449                 + " : " + path);
450         }
451         IdValue iv = (IdValue) ids.get(splitted[0]);
452         if (stack != null && stack.size() > 0 && stack.peek() instanceof String JavaDoc) {
453             // Define the IdValue from previous (contains)
454
String JavaDoc collectionpath = (String JavaDoc) stack.pop();
455             if (debug) {
456                 logger.log(BasicLevel.DEBUG, "test collection membering " + path
457                     + " IN " + collectionpath);
458             }
459             testcontains.add(collectionpath);
460         }
461         visitThisOrVarUseEnd(stack, path, splitted);
462         
463     }
464     /**
465      * manage a path starting with 'this' or a variable
466      * @param stack
467      * @param path is the path using 'this' or a varible
468      * @param splitted is the splitted path. The first String must be "this" or
469      * a varible
470      */

471     private void visitThisOrVarUseEnd(Stack JavaDoc stack, String JavaDoc path, String JavaDoc[] splitted) {
472         int operatorId = isMethodOperator(splitted[splitted.length - 1]);
473         if (operatorId != -1) {
474             //the last element is an operator
475
String JavaDoc begin = buildStringwithout(splitted, splitted.length-1, ".");
476             ((IdValue) ids.get(splitted[0])).addPath(begin);
477             switch(operatorId) {
478             case CONTAINS_OPERATOR:
479                 if (debug) {
480                     logger.log(BasicLevel.DEBUG, "contains case, path: " + begin);
481                 }
482                 //stock in stack a mean to find the contains stuff...
483
if (stack != null) {
484                     stack.push(begin);
485                 }
486                 break;
487             case IS_EMPTY_OPERATOR:
488                 if (debug) {
489                     logger.log(BasicLevel.DEBUG, "isEmpty case, path: " + begin);
490                 }
491                 isEmptys.add(begin);
492                 break;
493             }
494             return;
495         } else {
496             if (debug) {
497                 logger.log(BasicLevel.DEBUG,
498                         "Navigation case without operator, path:" + path);
499             }
500             ((IdValue) ids.get(splitted[0])).addPath(path);
501         }
502     }
503
504 }
505
Popular Tags