KickJava   Java API By Example, From Geeks To Geeks.

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


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
28 package org.objectweb.speedo.query.parser;
29
30 import org.objectweb.jorm.naming.api.PName;
31 import org.objectweb.jorm.type.api.PType;
32 import org.objectweb.medor.api.Field;
33 import org.objectweb.medor.expression.api.Expression;
34 import org.objectweb.medor.expression.api.Operator;
35 import org.objectweb.medor.expression.api.ParameterOperand;
36 import org.objectweb.medor.expression.api.TypingException;
37 import org.objectweb.medor.expression.lib.And;
38 import org.objectweb.medor.expression.lib.BasicOperand;
39 import org.objectweb.medor.expression.lib.BasicParameterOperand;
40 import org.objectweb.medor.expression.lib.Bitwize;
41 import org.objectweb.medor.expression.lib.ConditionalAnd;
42 import org.objectweb.medor.expression.lib.ConditionalOr;
43 import org.objectweb.medor.expression.lib.DivideBy;
44 import org.objectweb.medor.expression.lib.Equal;
45 import org.objectweb.medor.expression.lib.Greater;
46 import org.objectweb.medor.expression.lib.GreaterEqual;
47 import org.objectweb.medor.expression.lib.Length;
48 import org.objectweb.medor.expression.lib.Like;
49 import org.objectweb.medor.expression.lib.Lower;
50 import org.objectweb.medor.expression.lib.LowerEqual;
51 import org.objectweb.medor.expression.lib.Minus;
52 import org.objectweb.medor.expression.lib.Mult;
53 import org.objectweb.medor.expression.lib.Not;
54 import org.objectweb.medor.expression.lib.NotEqual;
55 import org.objectweb.medor.expression.lib.Or;
56 import org.objectweb.medor.expression.lib.Plus;
57 import org.objectweb.medor.expression.lib.StringComparatorParameterOperand;
58 import org.objectweb.medor.expression.lib.StringLower;
59 import org.objectweb.medor.expression.lib.StringUpper;
60 import org.objectweb.medor.expression.lib.UMinus;
61 import org.objectweb.medor.expression.lib.Substring;
62 import org.objectweb.medor.filter.lib.BasicFieldOperand;
63 import org.objectweb.medor.filter.lib.ExpressionPrinter;
64 import org.objectweb.medor.filter.lib.InCollection;
65 import org.objectweb.medor.filter.lib.IsEmpty;
66 import org.objectweb.medor.filter.lib.IsNull;
67 import org.objectweb.medor.filter.lib.MemberOf;
68 import org.objectweb.medor.query.api.QueryTree;
69 import org.objectweb.medor.query.api.QueryTreeField;
70 import org.objectweb.medor.query.jorm.lib.QueryBuilder;
71 import org.objectweb.medor.query.lib.SelectProject;
72 import org.objectweb.speedo.api.SpeedoException;
73 import org.objectweb.speedo.mapper.api.JormFactory;
74 import org.objectweb.util.monolog.api.BasicLevel;
75 import org.objectweb.util.monolog.api.Logger;
76
77 import javax.jdo.JDOException;
78 import java.util.Collections JavaDoc;
79 import java.util.Map JavaDoc;
80 import java.util.Stack JavaDoc;
81
82 /**
83  * Implementation of a visitor that creates the filter
84  */

85 public class SpeedoQLQueryFilterVisitor extends SpeedoQLAbstractVisitor {
86
87     private final static String JavaDoc CONTAINS_PATH_SET = "Next element is the contain path set";
88     private final static String JavaDoc REMOVER = "Remover";
89
90
91     /**
92      * qf is the transformation of the filter into a MEDOR expression
93      */

94     private Expression qf = null;
95
96     /**
97      * qt is built by the SpeedoQLVariableVisitor and is just used here
98      */

99     private QueryTree qt = null;
100     
101     private SelectProject root;
102
103     /**
104      * speedoql is the result of the filter parsing
105      */

106     private ASTSpeedoQL speedoql = null;
107     
108     Map JavaDoc fields;
109     
110     QueryBuilder qb;
111
112     private int nbNot = 0;
113
114     private String JavaDoc tab ="";
115     
116     private JormFactory jf = null;
117     
118     private Class JavaDoc clazz = null;
119
120     public SpeedoQLQueryFilterVisitor(Map JavaDoc _fields,
121             SelectProject _root,
122             ASTSpeedoQL speedoql,
123             Logger logger,
124             Map JavaDoc hparam,
125             Map JavaDoc vparam,
126             Class JavaDoc clazz,
127             QueryBuilder _qb,
128             JormFactory jf) throws SpeedoException {
129         //qt = qtree;
130
this.fields = _fields;
131         this.speedoql = speedoql;
132         this.qt = _root;
133         this.root = _root;
134         this.qb = _qb;
135         this.jf = jf;
136         setLogger(logger);
137         setParams(hparam);
138         setVars(vparam);
139         setCurrentClass(clazz.getName());
140         this.clazz = clazz;
141         startVisiting();
142     }
143
144     /**
145      * the visit starts here, please before sets a list of variables.
146      * @throws java.lang.Exception
147      */

148     public void startVisiting() throws SpeedoException {
149         debug = logger.isLoggable(BasicLevel.DEBUG);
150         nbNot = 0;
151         try {
152             visit(speedoql);
153         } catch (Exception JavaDoc e) {
154             if (e instanceof SpeedoQLAbstractVisitor.VisitorException) {
155                 e = ((SpeedoQLAbstractVisitor.VisitorException) e).getNestedException();
156             }
157             throw new SpeedoException(
158                     "Impossible to built the queryTree during the filter visit", e);
159         }
160         // this expression is the filter of the SelectProject
161
Expression exprFilter = getQueryFilter();
162         if (exprFilter != null) {
163             ME me = replaceNullNode(exprFilter);
164             if (me != null && me.modified) {
165                 qf = me.e;
166                 exprFilter = getQueryFilter();
167             }
168             if (debug) {
169                 logger.log(BasicLevel.DEBUG, "filter = " + exprFilter.getClass().getName());
170             }
171             root.setQueryFilter(exprFilter);
172         }
173         
174     }
175
176     private static class ME {
177         public Expression e;
178         public boolean modified;
179         public ME(Expression _e) {
180             this.e = _e;
181             this.modified = true;
182         }
183     }
184     
185     /**
186      * Replace null node.
187      * @param exprFilter
188      */

189     private ME replaceNullNode(Expression exprFilter) throws SpeedoException {
190         ME me = null;
191         if ((exprFilter instanceof Equal) || (exprFilter instanceof NotEqual)){
192             Operator op = (Operator) exprFilter;
193             for (int i = 0; i < op.getOperandNumber(); i++) {
194                 if (op.getExpression(i) instanceof DummyOperand) {
195                     //get the other child operand
196
int j = (i+1) % 2;
197                     Expression other = op.getExpression(j);
198                     PType ptype = other.getType();
199                     if (ptype.getTypeCode() == PType.TYPECODE_REFERENCE) {
200                         PName val = null;
201                         try {
202                             val = jf.getPClassMapping(ptype.getJormName(), clazz.getClassLoader()).getPBinder().getNull();
203                         } catch (Exception JavaDoc e) {
204                             throw new SpeedoException(
205                                     "Try to replace null node. Impossible to find the null PName for the type " + ptype.getJormName(), e);
206                         }
207                         //replace the null node with null PName
208
op.setExpression(i, new BasicOperand(val, ptype));
209                     } else {
210                         //Transform the null [not]equality into a IsNull operator
211
me = new ME(new IsNull(other, exprFilter instanceof NotEqual));
212                         //recursion is done on the other operand
213
exprFilter = me.e;
214                     }
215                 }
216             }
217         }
218         if (exprFilter instanceof Operator) {
219             Operator op = (Operator) exprFilter;
220             for (int i = 0; i < op.getOperandNumber(); i++) {
221                 //recursivity
222
ME ime = replaceNullNode(op.getExpression(i));
223                 if (ime != null && ime.modified) {
224                     //replace the child
225
op.setExpression(i, ime.e);
226                     //mark the result as modified
227
if (me == null) {//create if not already done
228
me = new ME(exprFilter);
229                     }
230                     me.modified = true;
231                 }
232             }
233         }
234         return me; //can be null
235
}
236     
237     /**
238      * get the query filter that was built from visiting the syntaxic tree
239      */

240     public Expression getQueryFilter() {
241         return qf;
242     }
243
244     public Object JavaDoc visit(ASTPrimary node, Object JavaDoc data) {
245         Stack JavaDoc stack = (Stack JavaDoc) data;
246         boolean hasMethod = node.value != null;
247         if (hasMethod) {
248             stack.push(node.value);
249         }
250         visit((SimpleNode) node, data);
251         if (hasMethod) {
252             Expression e2 = (Expression) stack.pop();
253             Expression e1 = (Expression) stack.pop();
254             String JavaDoc methodName = (String JavaDoc) stack.pop();
255             if (methodName.startsWith("null.")) {
256                 methodName = methodName.substring("null.".length());
257             }
258             stack.push(e1);
259             stack.push(methodName);
260             e1 = treatMethodOperator(methodName, stack, e2);
261             if (e1 != null) {
262                 stack.push(e1);
263             }
264         }
265         return null;
266     }
267
268     public Object JavaDoc visit(ASTSpeedoPrimary node, Object JavaDoc data) {
269         visit((SimpleNode) node, data);
270         Stack JavaDoc stack = (Stack JavaDoc) data;
271         while(stack.size() >0 && REMOVER.equals(stack.peek())) {
272             stack.pop();
273         }
274         if (stack.size() >0) {
275             qf = (Expression) stack.pop();
276         } // else there is no filter
277
return null;
278     }
279
280     /**
281      *
282      */

283     public Object JavaDoc visit(ASTRelationalExpression node, Object JavaDoc data) {
284         if (debug) {
285             logger.log(BasicLevel.DEBUG, tab + "Visit RelationalExpression: " + node);
286         }
287         tab += '\t';
288         visit((SimpleNode) node, data);
289         tab = tab.substring(1);
290         Stack JavaDoc stack = (Stack JavaDoc) data;
291         if (stack.size() > 0) {
292             if (CONTAINS_PATH_SET.equals(stack.peek())) {
293                 if (debug) {
294                     logger.log(BasicLevel.ERROR, "remove the element of the stack");
295                 }
296             } else {
297                 if (debug) {
298                     logger.log(BasicLevel.DEBUG, "manage relational expression: "
299                         + "(children: " + node.jjtGetNumChildren()
300                         + ", stack: " + stack.size()
301                         + ", peek:" + stack.peek() + ")");
302                 }
303                 for (int i = 0; (i < (node.jjtGetNumChildren() - 1) && stack.size() > 0); i++) {
304                     int op = ((Integer JavaDoc) node.ops.get(node.jjtGetNumChildren() - 2 - i)).intValue();
305                     if (usedInRelationalExpresssion(op)) {
306                         Object JavaDoc child2 = stack.pop();
307                         Object JavaDoc child1 = stack.pop();
308
309                         if (debug) {
310                             logger.log(BasicLevel.DEBUG, "pop child1: " + child1);
311                             logger.log(BasicLevel.DEBUG, "pop child2: " + child2);
312                         }
313                         if (REMOVER.equals(child1)) {
314                             if (REMOVER.equals(child2)) {
315                                 //nothin
316
} else {
317                                 stack.push(child2);
318                                 if (debug) {
319                                     logger.log(BasicLevel.DEBUG, "push(" + child2 + ")");
320                                 }
321                             }
322                         } else {
323                             if (REMOVER.equals(child2)) {
324                                 stack.push(child1);
325                                 if (debug) {
326                                     logger.log(BasicLevel.DEBUG, "push(" + child1 + ")");
327                                 }
328                             } else {
329                                 Expression ret = null;
330                                 switch (op) {
331                                 case SpeedoQLConstants.OR:
332                                     ret = new ConditionalOr((Expression) child1, (Expression) child2);
333                                     break;
334                                 case SpeedoQLConstants.AND:
335                                     ret = new ConditionalAnd((Expression) child1, (Expression) child2);
336                                     break;
337                                 case SpeedoQLConstants.BITWISEOR:
338                                     ret = new Or((Expression) child1, (Expression) child2);
339                                     break;
340                                 case SpeedoQLConstants.BITWISEXOR:
341                                     ret = null;
342                                     break;
343                                 case SpeedoQLConstants.BITWISEAND:
344                                     ret = new And((Expression) child1, (Expression) child2);
345                                     break;
346                                 case SpeedoQLConstants.EQ:
347                                     ret = new Equal((Expression) child1, (Expression) child2);
348                                     break;
349                                 case SpeedoQLConstants.NEQ:
350                                     ret = new NotEqual((Expression) child1, (Expression) child2);
351                                     break;
352                                 case SpeedoQLConstants.LT:
353                                     ret = new Lower((Expression) child1, (Expression) child2);
354                                     break;
355                                 case SpeedoQLConstants.GT:
356                                     ret = new Greater((Expression) child1, (Expression) child2);
357                                     break;
358                                 case SpeedoQLConstants.GTE:
359                                     ret = new GreaterEqual((Expression) child1, (Expression) child2);
360                                     break;
361                                 case SpeedoQLConstants.LTE:
362                                     ret = new LowerEqual((Expression) child1, (Expression) child2);
363                                     break;
364                                 }
365                                 if (debug) {
366                                     logger.log(BasicLevel.DEBUG, "push(" + ret + ")");
367                                 }
368                                 stack.push(ret);
369                             }
370                         }
371                     }
372                 }
373             }
374         }
375         if (debug) {
376             logger.log(BasicLevel.DEBUG, "children:" + node.jjtGetNumChildren()
377                 + " / stack: " + stack.size());
378             logger.log(BasicLevel.DEBUG, tab + "End of Visit RelationalExpression: " + node);
379         }
380         return null;
381     }
382
383     private boolean usedInRelationalExpresssion(int op) {
384         switch (op) {
385         case SpeedoQLConstants.OR:
386         case SpeedoQLConstants.AND:
387         case SpeedoQLConstants.BITWISEOR:
388         case SpeedoQLConstants.BITWISEXOR:
389         case SpeedoQLConstants.BITWISEAND:
390         case SpeedoQLConstants.EQ:
391         case SpeedoQLConstants.NEQ:
392         case SpeedoQLConstants.LT:
393         case SpeedoQLConstants.GT:
394         case SpeedoQLConstants.GTE:
395         case SpeedoQLConstants.LTE:
396             if (debug) {
397                 logger.log(BasicLevel.DEBUG, "node useful");
398             }
399             return true;
400         default:
401             if (debug) {
402                 logger.log(BasicLevel.DEBUG, "node useless");
403             }
404             return false;
405         }
406     }
407
408     public Object JavaDoc visit(ASTAdditiveExpression node, Object JavaDoc data) {
409         if (debug) {
410             logger.log(BasicLevel.DEBUG, tab + "Visit AdditiveExpression: " + node);
411         }
412         tab += '\t';
413         visit((SimpleNode) node, data);
414         tab = tab.substring(1);
415         Stack JavaDoc stack = (Stack JavaDoc) data;
416         if (stack.size() > 0
417                 && !CONTAINS_PATH_SET.equals(stack.peek())
418                 && !REMOVER.equals(stack.peek())) {
419             Expression ret = (Expression) stack.pop();
420             for (int i = 0; i < node.jjtGetNumChildren() - 1; i++) {
421                 if (debug) {
422                     logger.log(BasicLevel.DEBUG, "Visit ConditionalExpression... children...[" + i + "]");
423                 }
424
425                 switch (((Integer JavaDoc) node.ops.get(node.jjtGetNumChildren() - 2 - i)).intValue()) {
426
427                 case SpeedoQLConstants.PLUS:
428                     ret = new Plus((Expression) stack.pop(), ret);
429                     break;
430                 case SpeedoQLConstants.MINUS:
431                     ret = new Minus((Expression) stack.pop(), ret);
432                     break;
433                 case SpeedoQLConstants.MULT:
434                     ret = new Mult((Expression) stack.pop(), ret);
435                     break;
436                 case SpeedoQLConstants.DIV:
437                     ret = new DivideBy((Expression) stack.pop(), ret);
438                     break;
439                 default:
440
441                 }
442             }
443             ((Stack JavaDoc) data).push(ret);
444         }
445         if (debug) {
446             logger.log(BasicLevel.DEBUG, tab + "End of Visit AdditiveExpression: " + node);
447         }
448         return null;
449     }
450
451     public Object JavaDoc visit(ASTUnaryExpression node, Object JavaDoc data) {
452         if (debug) {
453             logger.log(BasicLevel.DEBUG, tab + "Visit UnaryExpression" + node);
454         }
455         tab += '\t';
456         boolean hasNot = node.ops.size() > 0
457             && ((Integer JavaDoc) node.ops.get(0)).intValue() == SpeedoQLConstants.NOT;
458         if (hasNot) {
459             nbNot ++;
460             if (debug) {
461                 logger.log(BasicLevel.DEBUG, "remember a Not: "+ nbNot);
462             }
463         }
464         visit((SimpleNode) node, data);
465         if (hasNot && nbNot> 0) {
466             nbNot--;
467             if (debug) {
468                 logger.log(BasicLevel.DEBUG, "forget a Not: "+ nbNot);
469             }
470         }
471         tab = tab.substring(1);
472         Stack JavaDoc stack = (Stack JavaDoc) data;
473         if (debug && stack.size() > 0) {
474             logger.log(BasicLevel.DEBUG, tab + "stack.peek:" + stack.peek());
475         }
476         if (stack.size() > 0
477                 && !CONTAINS_PATH_SET.equals(stack.peek())
478                 && !REMOVER.equals(stack.peek())) {
479             Object JavaDoc o = stack.pop();
480             if (node.ops.size() > 0) {
481                 switch (((Integer JavaDoc) node.ops.get(0)).intValue()) {
482                 case SpeedoQLConstants.MINUS:
483                     o = new UMinus((Expression) o);
484                     break;
485                 case SpeedoQLConstants.BITWISECOMPL:
486                     o = new Bitwize((Expression) o);
487                     break;
488                 case SpeedoQLConstants.NOT:
489                     logger.log(BasicLevel.DEBUG, "NOT(" + o + "): " + node);
490                     o = new Not((Expression) o);
491                     break;
492                 }
493             }
494             ((Stack JavaDoc) data).push(o);
495         }
496         if (debug) {
497             logger.log(BasicLevel.DEBUG, tab + "End of Visit UnaryExpression: " + node);
498         }
499         return null;
500     }
501
502     // to be done
503
public Object JavaDoc visit(ASTCastExpression node, Object JavaDoc data) {
504         ((Stack JavaDoc) data).push(node);
505         return null;
506     }
507
508     /**
509      * 4 cases to manage: (en cours par equipe MEDOR)
510      * - Collection.contains(Object o)
511      * - Collection.isEmpty()
512      * - String.startsWith(String s)
513      * - String.endsWith(String s)
514      */

515     public Object JavaDoc visit(ASTArgumentList node, Object JavaDoc data) {
516         visit((SimpleNode) node, data);
517         return null;
518     }
519
520     public Object JavaDoc visit(ASTLiteral node, Object JavaDoc data) {
521         Stack JavaDoc stack = (Stack JavaDoc) data;
522         Expression e = null;
523         if (node.value == null) {
524             //special case for null: will be replaced later
525
e = new DummyOperand();
526         } else if (node.value instanceof Integer JavaDoc) {
527             e = new BasicOperand(((Integer JavaDoc) node.value).intValue());
528         } else if (node.value instanceof Float JavaDoc) {
529             e = new BasicOperand(((Float JavaDoc) node.value).floatValue());
530         } else if (node.value instanceof Character JavaDoc) {
531             e = new BasicOperand(((Character JavaDoc) node.value).charValue());
532         } else if (node.value instanceof String JavaDoc) {
533             String JavaDoc s = (String JavaDoc) (node.value);
534             s = s.substring(1, s.length()-1);
535             e = new BasicOperand(s);
536         } else if (node.value instanceof Boolean JavaDoc) {
537             e = new BasicOperand(((Boolean JavaDoc) node.value).booleanValue());
538         }
539         if (stack.size() > 0) {
540             Object JavaDoc top = stack.peek();
541             if (CONTAINS_PATH_SET.equals(top)) {
542 //TODO: Support the path.contains(path) operator
543
logger.log(BasicLevel.ERROR, "The path.contains(path) operator is not yet implemented");
544                 return null;
545             } else if (top instanceof String JavaDoc) {
546                 e = treatMethodOperator((String JavaDoc) top, stack, e);
547             }
548         }
549         if (e != null) {
550             if (debug) {
551                 logger.log(BasicLevel.DEBUG, "push(" + ExpressionPrinter.e2str(e) + ")");
552             }
553             stack.push(e);
554         }
555         return null;
556     }
557
558     private Expression treatMethodOperator(String JavaDoc opName,
559                                      Stack JavaDoc stack,
560                                      Expression e) {
561         int op = isMethodOperator(opName);
562         if (op == -1) {
563             return e;
564         }
565         switch (op) {
566         case STARTS_WITH_OPERATOR:
567             {
568                 stack.pop();
569                 Object JavaDoc oe = stack.pop();
570                 if (debug) {
571                     logger.log(BasicLevel.DEBUG, "pop expression: " + oe);
572                 }
573                 Expression str = (Expression) oe;
574                 if (e instanceof BasicParameterOperand) {
575                     e = new StringComparatorParameterOperand((BasicParameterOperand) e, null, "%");
576                 } else if (e instanceof BasicOperand) {
577                     try {
578                         e = new BasicOperand(((BasicOperand) e).getString() + "%");
579                     } catch (TypingException e1) {
580                         throw new JDOException(
581                             "Bad parameter type for the 'startsWith' method", e1);
582                     }
583                 }
584                 e = new Like(str, e);
585                 break;
586             }
587         case ENDS_WITH_OPERATOR:
588             {
589                 stack.pop();
590                 Object JavaDoc oe = stack.pop();
591                 if (debug) {
592                     logger.log(BasicLevel.DEBUG, "pop expression: " + oe);
593                 }
594                 Expression str = (Expression) oe;
595                 if (e instanceof BasicParameterOperand) {
596                     e = new StringComparatorParameterOperand((BasicParameterOperand) e, "%", null);
597                 } else if (e instanceof BasicOperand) {
598                     try {
599                         e = new BasicOperand("%" + ((BasicOperand) e).getString());
600                     } catch (TypingException e1) {
601                         throw new JDOException(
602                             "Bad parameter type for the 'startsWith' method", e1);
603                     }
604                 }
605                 e = new Like(str, e);
606                 break;
607             }
608         case EQUALS_OPERATOR:
609 //TODO: Support the equals operator
610
break;
611         case MATCHES_OPERATOR:
612             {
613                 stack.pop();
614                 Object JavaDoc oe = stack.pop();
615                 if (debug) {
616                     logger.log(BasicLevel.DEBUG, "pop expression: " + oe);
617                 }
618                 Expression str = (Expression) oe;
619                 if (e instanceof BasicParameterOperand) {
620                     e = new StringComparatorParameterOperand((BasicParameterOperand) e, "%", "%");
621                 } else if (e instanceof BasicOperand) {
622                     try {
623                         e = new BasicOperand("%" + ((BasicOperand) e).getString() + "%");
624                     } catch (TypingException e1) {
625                         throw new JDOException(
626                             "Bad parameter type for the 'startsWith' method", e1);
627                     }
628                 }
629                 e = new Like(str, e);
630                 break;
631             }
632         case SUBSTRING_OPERATOR:
633             {
634             stack.pop();
635                 Object JavaDoc o = stack.pop();
636                 if (o == STR_OPERAND_SUBSTRING) {
637                     if (debug) {
638                         logger.log(BasicLevel.DEBUG, "push(" + ExpressionPrinter.e2str(e) + ")");
639                     }
640                     stack.push(e);
641                     if (debug) {
642                         logger.log(BasicLevel.DEBUG, "push(BEGIN_OPERAND_SUBSTRING)");
643                     }
644                     stack.push(BEGIN_OPERAND_SUBSTRING);
645                     if (debug) {
646                         logger.log(BasicLevel.DEBUG, "push(" + opName + ")");
647                     }
648                     stack.push(opName);
649                     return null;
650                 } else if (o == BEGIN_OPERAND_SUBSTRING) {
651                     Expression begin = (Expression) stack.pop();
652                     Expression str = (Expression) stack.pop();
653                     e = new Substring(str, begin, e);
654                 } else {
655                     throw new JDOException("Protocol error: " + o);
656                 }
657                 break;
658             }
659         }
660         return e;
661     }
662
663     public Object JavaDoc visit(ASTType node, Object JavaDoc data) {
664         if (debug) {
665             logger.log(BasicLevel.DEBUG, "Visit Type: " + node);
666         }
667
668         ((Stack JavaDoc) data).push(node);
669
670         if (debug) {
671             logger.log(BasicLevel.DEBUG, "End of Visit Type");
672         }
673         return null;
674     }
675
676     /**
677      * qualifiedname could be:
678      * - a class field (salary from Employee)
679      * - a parameter
680      * - a variable
681      *
682      */

683     public Object JavaDoc visit(ASTQualifiedName node, Object JavaDoc data) {
684         String JavaDoc name = (String JavaDoc) node.value;
685         String JavaDoc[] splitted = splitPath(name);
686         Stack JavaDoc stack = (Stack JavaDoc) data;
687         if (debug) {
688             logger.log(BasicLevel.DEBUG, tab + "Visit QualifiedName value=["
689                     + node.value + "] stack size=" + stack.size());
690         }
691         try {
692             if (params != null && params.get(splitted[0]) != null) {
693                 visitParameter(stack, splitted, name);
694             } else {
695                 if (!"this".equals(splitted[0])
696                         && (vars == null || vars.get(splitted[0]) == null)) {
697                     //It is not a variable, but a navigation from the current
698
// class without 'this' at the begin. then add the
699
// class name in first
700
name = "this." + name;
701                     String JavaDoc[] newsplitted = new String JavaDoc[splitted.length + 1];
702                     newsplitted[0] = "this";
703                     System.arraycopy(splitted, 0, newsplitted, 1, splitted.length);
704                     splitted = newsplitted;
705                 }
706                 visitFieldAccess(stack, splitted, name);
707             }
708         } catch (Exception JavaDoc e) {
709             throw new SpeedoQLAbstractVisitor.VisitorException(e);
710         }
711         return null;
712     }
713     
714     private void visitParameter(Stack JavaDoc stack,
715             String JavaDoc[] splitted,
716             String JavaDoc name) throws Exception JavaDoc {
717         if (stack.size() > 0 && CONTAINS_PATH_SET.equals(stack.peek())) {
718             //x.y.bs.contains(myParam)
719
stack.pop(); // forget the CONTAINS_PATH_SET
720
Object JavaDoc o = stack.pop(); // pop the pathset
721
String JavaDoc pathset = (String JavaDoc) o;
722             if (debug) {
723                 logger.log(BasicLevel.DEBUG, tab
724                         + "parameter(" + name + ") MemberOf " + pathset);
725             }
726             String JavaDoc[] spli = splitPath(pathset);
727             String JavaDoc rest = mergePath(spli, 1, spli.length - 1);
728             QueryBuilder subquery = new QueryBuilder(qb);
729             subquery.define("", qb.navigate(spli[0]));
730             QueryTreeField setField = subquery.project(subquery.navigate(rest));
731             Expression e = new MemberOf(
732                     Collections.singletonList(((Object JavaDoc[]) params.get(name))[1]),
733                     Collections.singletonList(new BasicFieldOperand(setField)));
734             if (debug) {
735                 logger.log(BasicLevel.DEBUG, tab + "push(" + ExpressionPrinter.e2str(e) + ")");
736             }
737             stack.push(e);
738         } else if (splitted.length == 1) {
739             if (debug) {
740                 logger.log(BasicLevel.DEBUG, tab + "Push the parameterOperand " + name);
741             }
742             Expression e = (Expression) ((Object JavaDoc[]) params.get(name))[1];
743             if (stack.size() > 0 && stack.peek() instanceof String JavaDoc) {
744                 e = treatMethodOperator((String JavaDoc) stack.peek(), stack, e);
745             }
746             stack.push(e);
747         } else if (splitted.length == 2 && "contains".equals(splitted[1])) {
748                 if (debug) {
749                     logger.log(BasicLevel.DEBUG, tab + "Push the parameterOperand " + splitted[0]);
750                 }
751                 ParameterOperand po = (ParameterOperand)
752                     ((Object JavaDoc[]) params.get(splitted[0]))[1];
753                 
754                 stack.push(po);
755                 stack.push(CONTAINS_PATH_SET);
756         } else {
757                 throw new Exception JavaDoc("Does not support the naviation over a parameter: " + name);
758         }
759     }
760    
761     private void visitFieldAccess(Stack JavaDoc stack,
762             String JavaDoc[] splitted,
763             String JavaDoc name) throws Exception JavaDoc {
764         int operatorId = -1;
765         if (stack.size() > 0 && CONTAINS_PATH_SET.equals(stack.peek())) {
766             stack.pop(); // forget the CONTAINS_PATH_SET
767
Object JavaDoc o = stack.pop(); // pop the pathset
768
if (o instanceof ParameterOperand) {
769                 //myParam.contains(...)
770
if (debug) {
771                     logger.log(BasicLevel.DEBUG, tab + "(" + name + ") InCollection (" + o + ")");
772                 }
773                 Field qtf = (Field) fields.get(name);
774                 Expression e = new InCollection(
775                         new BasicFieldOperand(qtf),
776                         (ParameterOperand) o, qtf.getType());
777                 stack.push(e);
778                 
779             } else if (o instanceof String JavaDoc) {
780                 String JavaDoc pathset = (String JavaDoc) o;
781                 String JavaDoc[] spli = splitPath(pathset);
782                 if (vars.containsKey(splitted[0])) {
783                     //x.y.bs.contains(b)
784
//The variable definition is managed by the Variable visitor
785
//thus forget the expression
786
if ((nbNot % 2) == 0) {
787                         stack.push(REMOVER);
788                     } else {
789                         QueryTreeField f = (QueryTreeField) fields.get(name);
790                         stack.push(new Not(new IsEmpty(new BasicFieldOperand(f))));
791                     }
792                 } else {
793                     //x.y.bs.contains(u.v.b)
794
String JavaDoc rest = mergePath(spli, 1, spli.length - 2);
795                     QueryBuilder subquery = new QueryBuilder(qb);
796                     subquery.define("", qb.navigate(spli[0]));
797                     QueryTreeField setField = subquery.project(subquery.navigate(rest));
798                     QueryTreeField f = (QueryTreeField) fields.get(name);
799
800                     stack.push(new MemberOf(
801                             Collections.singletonList(
802                                     new BasicFieldOperand(f)),
803                             Collections.singletonList(
804                                     new BasicFieldOperand(setField))
805                             ));
806                 }
807             } else {
808                 if (debug) {
809                     logger.log(BasicLevel.DEBUG, tab + "Do not use the pathset of the contain operator");
810                 }
811                 stack.push(REMOVER);
812             }
813             return;
814         }
815
816         //maybe there is an operator
817
String JavaDoc last = splitted[splitted.length - 1];
818         operatorId = isMethodOperator(last);
819         if (operatorId == -1) {
820             //No operator found ==> default case
821
if (debug) {
822                 logger.log(BasicLevel.DEBUG, tab + "create a fieldOperand with:" + name);
823             }
824             Field f = (Field) fields.get(name);
825             if (f == null) {
826                 throw new SpeedoException("Internal error: No field '" + name + "' found during filter parsing");
827             }
828             stack.push(new BasicFieldOperand(f));
829             return;
830         }
831         //There is an operator
832
String JavaDoc begin = buildStringwithout(splitted, splitted.length-1, ".");
833         if (operatorId == CONTAINS_OPERATOR) {
834             //The contains contraint is managed during the QueryTree creation
835
//see the variable vistor
836
//However push some stuff in the stack in order to known that
837
// the next qualifiedName is used in a contain constraint.
838
if (debug) {
839                 logger.log(BasicLevel.DEBUG, tab + "contains operator: set=" + begin);
840             }
841             stack.push(begin);
842             stack.push(CONTAINS_PATH_SET);
843             return;
844         } else if (operatorId == IS_EMPTY_OPERATOR) {
845             if (debug) {
846                logger.log(BasicLevel.DEBUG, tab + "Visit IsEmpty: " + begin);
847             }
848             String JavaDoc rest = mergePath(splitted, 1, splitted.length - 2);
849             QueryBuilder subquery = new QueryBuilder(qb);
850             subquery.define("", qb.navigate(splitted[0]));
851             Field f = subquery.project(subquery.navigate(rest));
852             stack.push(new IsEmpty(new BasicFieldOperand(f)));
853             return;
854         }
855                 
856         if (debug) {
857             logger.log(BasicLevel.DEBUG, tab + "create a fieldOperand with:" + begin);
858         }
859         Field f = (Field) fields.get(begin);
860         Expression e = new BasicFieldOperand(f);
861         switch (operatorId) {
862         case TO_LOWER_OPERATOR:
863             e = new StringLower(e);
864             stack.push(e);
865             break;
866         case TO_UPPER_OPERATOR:
867             e = new StringUpper(e);
868             stack.push(e);
869             break;
870         case LENGTH_OPERATOR:
871             e = new Length(e);
872             stack.push(e);
873             break;
874         case SUBSTRING_OPERATOR:
875             stack.push(e);
876             stack.push(STR_OPERAND_SUBSTRING);
877             stack.push(last);
878             break;
879         default:
880             stack.push(e);
881             stack.push(last);
882             break;
883         }
884     }
885     
886     static class DummyOperand extends BasicOperand {
887         
888         public DummyOperand(){
889             super();
890         }
891     }
892 }
893
Popular Tags