| 1 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 ; 79 import java.util.Map ; 80 import java.util.Stack ; 81 82 85 public class SpeedoQLQueryFilterVisitor extends SpeedoQLAbstractVisitor { 86 87 private final static String CONTAINS_PATH_SET = "Next element is the contain path set"; 88 private final static String REMOVER = "Remover"; 89 90 91 94 private Expression qf = null; 95 96 99 private QueryTree qt = null; 100 101 private SelectProject root; 102 103 106 private ASTSpeedoQL speedoql = null; 107 108 Map fields; 109 110 QueryBuilder qb; 111 112 private int nbNot = 0; 113 114 private String tab =""; 115 116 private JormFactory jf = null; 117 118 private Class clazz = null; 119 120 public SpeedoQLQueryFilterVisitor(Map _fields, 121 SelectProject _root, 122 ASTSpeedoQL speedoql, 123 Logger logger, 124 Map hparam, 125 Map vparam, 126 Class clazz, 127 QueryBuilder _qb, 128 JormFactory jf) throws SpeedoException { 129 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 148 public void startVisiting() throws SpeedoException { 149 debug = logger.isLoggable(BasicLevel.DEBUG); 150 nbNot = 0; 151 try { 152 visit(speedoql); 153 } catch (Exception 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 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 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 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 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 op.setExpression(i, new BasicOperand(val, ptype)); 209 } else { 210 me = new ME(new IsNull(other, exprFilter instanceof NotEqual)); 212 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 ME ime = replaceNullNode(op.getExpression(i)); 223 if (ime != null && ime.modified) { 224 op.setExpression(i, ime.e); 226 if (me == null) { me = new ME(exprFilter); 229 } 230 me.modified = true; 231 } 232 } 233 } 234 return me; } 236 237 240 public Expression getQueryFilter() { 241 return qf; 242 } 243 244 public Object visit(ASTPrimary node, Object data) { 245 Stack stack = (Stack ) 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 methodName = (String ) 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 visit(ASTSpeedoPrimary node, Object data) { 269 visit((SimpleNode) node, data); 270 Stack stack = (Stack ) 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 } return null; 278 } 279 280 283 public Object visit(ASTRelationalExpression node, Object 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 stack = (Stack ) 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 ) node.ops.get(node.jjtGetNumChildren() - 2 - i)).intValue(); 305 if (usedInRelationalExpresssion(op)) { 306 Object child2 = stack.pop(); 307 Object 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 } 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 visit(ASTAdditiveExpression node, Object 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 stack = (Stack ) 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 ) 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 ) 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 visit(ASTUnaryExpression node, Object 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 ) 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 stack = (Stack ) 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 o = stack.pop(); 480 if (node.ops.size() > 0) { 481 switch (((Integer ) 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 ) 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 public Object visit(ASTCastExpression node, Object data) { 504 ((Stack ) data).push(node); 505 return null; 506 } 507 508 515 public Object visit(ASTArgumentList node, Object data) { 516 visit((SimpleNode) node, data); 517 return null; 518 } 519 520 public Object visit(ASTLiteral node, Object data) { 521 Stack stack = (Stack ) data; 522 Expression e = null; 523 if (node.value == null) { 524 e = new DummyOperand(); 526 } else if (node.value instanceof Integer ) { 527 e = new BasicOperand(((Integer ) node.value).intValue()); 528 } else if (node.value instanceof Float ) { 529 e = new BasicOperand(((Float ) node.value).floatValue()); 530 } else if (node.value instanceof Character ) { 531 e = new BasicOperand(((Character ) node.value).charValue()); 532 } else if (node.value instanceof String ) { 533 String s = (String ) (node.value); 534 s = s.substring(1, s.length()-1); 535 e = new BasicOperand(s); 536 } else if (node.value instanceof Boolean ) { 537 e = new BasicOperand(((Boolean ) node.value).booleanValue()); 538 } 539 if (stack.size() > 0) { 540 Object top = stack.peek(); 541 if (CONTAINS_PATH_SET.equals(top)) { 542 logger.log(BasicLevel.ERROR, "The path.contains(path) operator is not yet implemented"); 544 return null; 545 } else if (top instanceof String ) { 546 e = treatMethodOperator((String ) 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 opName, 559 Stack 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 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 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 break; 611 case MATCHES_OPERATOR: 612 { 613 stack.pop(); 614 Object oe = stack.pop(); 615 if (debug) { 616 logger.log(BasicLevel.DEBUG, "pop expression: " + oe); 617 } 618 Expression str = ( |