1 package org.apache.ojb.jdo.jdoql; 2 3 17 18 import java.math.BigDecimal ; 19 import java.math.BigInteger ; 20 import java.util.Collection ; 21 import java.util.Date ; 22 import java.util.HashMap ; 23 import java.util.Iterator ; 24 import java.util.Map ; 25 26 import javax.jdo.JDOUserException; 27 28 import org.apache.ojb.broker.metadata.*; 29 import org.apache.ojb.broker.util.ClassHelper; 30 import org.apache.ojb.jdo.QueryImpl; 31 32 51 public class QueryTreeResolver extends VisitorBase 52 { 53 55 56 private static HashMap _primitiveTypes = new HashMap (); 57 58 static 59 { 60 _primitiveTypes.put(byte.class, new Integer (0)); 61 _primitiveTypes.put(char.class, new Integer (1)); 62 _primitiveTypes.put(short.class, new Integer (2)); 63 _primitiveTypes.put(int.class, new Integer (3)); 64 _primitiveTypes.put(long.class, new Integer (4)); 65 _primitiveTypes.put(BigInteger .class, new Integer (5)); 66 _primitiveTypes.put(float.class, new Integer (6)); 67 _primitiveTypes.put(double.class, new Integer (7)); 68 _primitiveTypes.put(BigDecimal .class, new Integer (8)); 69 } 70 71 72 private QueryImpl _query; 73 74 81 public void resolveAndCheck(QueryImpl query) throws JDOUserException 82 { 83 _query = query; 84 try 85 { 86 checkImports(query.getImports()); 87 visit(query.getVariables()); 88 visit(query.getParameters()); 89 if (query.getFilterExpression() != null) 90 { 91 query.getFilterExpression().accept(this); 92 } 93 visit(query.getOrderings()); 94 } 95 finally 96 { 97 _query = null; 98 } 99 } 100 101 110 private void checkImports(Collection imports) throws JDOUserException 111 { 112 HashMap directlyImportedClasses = new HashMap (); 114 Import importDecl; 115 String shortName; 116 117 for (Iterator it = imports.iterator(); it.hasNext();) 118 { 119 importDecl = (Import)it.next(); 120 if (!importDecl.isOnDemand()) 121 { 122 shortName = importDecl.getSpec().substring(importDecl.getSpec().lastIndexOf('.')); 123 if (directlyImportedClasses.containsKey(shortName)) 124 { 125 throw new JDOUserException("Multiple direct imports of classes with the same unqualified name "+shortName); 126 } 127 else 128 { 129 directlyImportedClasses.put(shortName, null); 130 } 131 } 132 } 133 } 134 135 141 private void visit(Map objects) throws JDOUserException 142 { 143 if (objects != null) 144 { 145 for (Iterator it = objects.values().iterator(); it.hasNext();) 146 { 147 ((Acceptor)it.next()).accept(this); 148 } 149 } 150 } 151 152 158 private void visit(Collection objects) throws JDOUserException 159 { 160 if (objects != null) 161 { 162 for (Iterator it = objects.iterator(); it.hasNext();) 163 { 164 ((Acceptor)it.next()).accept(this); 165 } 166 } 167 } 168 169 172 public void visit(BinaryExpression binExpr) throws JDOUserException 173 { 174 super.visit(binExpr); 175 176 Class leftType = binExpr.getLeftSide().getType(); 183 Class rightType = binExpr.getRightSide().getType(); 184 boolean typeWasSet = false; 185 186 switch (binExpr.getOperator()) 187 { 188 case BinaryExpression.OPERATOR_MULTIPLY : 189 case BinaryExpression.OPERATOR_DIVIDE : 190 case BinaryExpression.OPERATOR_PLUS : 191 case BinaryExpression.OPERATOR_MINUS : 192 if (binExpr.getOperator() == BinaryExpression.OPERATOR_PLUS) 193 { 194 if ((leftType == String .class) && (rightType == String .class)) 195 { 196 binExpr.setType(String .class); 197 typeWasSet = true; 198 break; 199 } 200 } 201 if (isNumeric(leftType) && isNumeric(rightType)) 202 { 203 binExpr.setType(getBroaderType(leftType, rightType)); 204 typeWasSet = true; 205 } 206 break; 207 case BinaryExpression.OPERATOR_BITWISE_AND : 208 case BinaryExpression.OPERATOR_BITWISE_XOR : 209 case BinaryExpression.OPERATOR_BITWISE_OR : 210 if (isInteger(leftType) && isInteger(rightType)) 211 { 212 binExpr.setType(getBroaderType(leftType, rightType)); 213 typeWasSet = true; 214 } 215 else if ((leftType == boolean.class) && (rightType == boolean.class)) 216 { 217 binExpr.setType(boolean.class); 218 typeWasSet = true; 219 } 220 break; 221 case BinaryExpression.OPERATOR_LOWER : 222 case BinaryExpression.OPERATOR_GREATER : 223 case BinaryExpression.OPERATOR_LOWER_OR_EQUAL : 224 case BinaryExpression.OPERATOR_GREATER_OR_EQUAL : 225 if (isNumeric(leftType) && isNumeric(rightType)) 226 { 227 binExpr.setType(boolean.class); 228 typeWasSet = true; 229 } 230 else if ((leftType == String .class) && (rightType == String .class)) 231 { 232 binExpr.setType(boolean.class); 233 typeWasSet = true; 234 } 235 else if ((leftType == Date .class) && (rightType == Date .class)) 236 { 237 binExpr.setType(boolean.class); 238 typeWasSet = true; 239 } 240 break; 241 case BinaryExpression.OPERATOR_EQUAL : 242 case BinaryExpression.OPERATOR_NOT_EQUAL : 243 if (isNumeric(leftType) && isNumeric(rightType)) 244 { 245 binExpr.setType(boolean.class); 246 typeWasSet = true; 247 } 248 else if ((leftType == boolean.class) && (rightType == boolean.class)) 249 { 250 binExpr.setType(boolean.class); 251 typeWasSet = true; 252 } 253 else if (!leftType.isPrimitive() && !rightType.isPrimitive()) 254 { 255 binExpr.setType(boolean.class); 256 typeWasSet = true; 257 } 258 break; 259 case BinaryExpression.OPERATOR_AND : 260 case BinaryExpression.OPERATOR_OR : 261 if ((leftType == boolean.class) && (rightType == boolean.class)) 262 { 263 binExpr.setType(boolean.class); 264 typeWasSet = true; 265 } 266 break; 267 } 268 if (!typeWasSet) 269 { 270 throw new JDOUserException("Binary expression cannot be applied to expressions of types "+leftType.getName()+" and "+rightType.getName()); 271 } 272 } 273 274 277 public void visit(MethodInvocation methodInvoc) throws JDOUserException 278 { 279 super.visit(methodInvoc); 280 281 Class type = methodInvoc.getBaseExpression().getType(); 282 String name = methodInvoc.getName(); 283 284 if (Collection .class.isAssignableFrom(type)) 285 { 286 if ("contains".equals(name)) 287 { 288 if (methodInvoc.getArguments().size() != 1) 289 { 290 throw new JDOUserException("Illegal number of arguments to method Collection.contains"); 291 } 292 } 293 else if ("isEmpty".equals(name)) 294 { 295 if (!methodInvoc.getArguments().isEmpty()) 296 { 297 throw new JDOUserException("Illegal number of arguments to method Collection.isEmpty"); 298 } 299 } 300 else 301 { 302 throw new JDOUserException("Only methods 'contains' and 'isEmpty' are allowed to be called at collection objects"); 303 } 304 methodInvoc.setType(boolean.class); 305 } 306 else if (type == String .class) 307 { 308 if (!"startsWith".equals(name) && !"endsWith".equals(name)) 309 { 310 throw new JDOUserException("Only methods 'contains' and 'isEmpty' are allowed to be called at collection objects"); 311 } 312 if (methodInvoc.getArguments().size() != 1) 313 { 314 throw new JDOUserException("Illegal number of arguments to method String."+name); 315 } 316 if (((Expression)methodInvoc.getArguments().get(0)).getType() != String .class) 317 { 318 throw new JDOUserException("Illegal argument to method Collection."+name); 319 } 320 methodInvoc.setType(boolean.class); 321 } 322 else 323 { 324 throw new JDOUserException("Invocation of method "+methodInvoc.getName()+" at type "+type.getName()+" is not allowed"); 325 } 326 } 327 328 331 public void visit(NameExpression nameExpr) throws JDOUserException 332 { 333 super.visit(nameExpr); 334 335 Expression newExpr = null; 336 Class baseType = null; 337 338 if (!nameExpr.hasBaseExpression()) 345 { 346 LocalVariable var = _query.getVariable(nameExpr.getName()); 348 349 if (var == null) 350 { 351 var = _query.getParameter(nameExpr.getName()); 352 } 353 if (var != null) 354 { 355 LocalVariableAccess varAccess = new LocalVariableAccess(nameExpr.getName()); 356 357 varAccess.setAccessedVariable(var); 358 newExpr = varAccess; 359 } 360 else 361 { 362 baseType = _query.getSearchedClass(); 365 } 366 } 367 else 368 { 369 baseType = nameExpr.getBaseExpression().getType(); 371 } 372 if (newExpr == null) 373 { 374 ClassDescriptor classDesc = findClassDescriptorFor(baseType); 376 377 if (classDesc == null) 378 { 379 throw new JDOUserException("Access to type "+baseType.getName()+" is not allowed because the type is not persistent"); 380 } 381 382 FieldAccess fieldAccess = new FieldAccess(nameExpr.getBaseExpression(), nameExpr.getName()); 383 384 ObjectReferenceDescriptor refDesc = classDesc.getObjectReferenceDescriptorByName(nameExpr.getName()); 388 389 if (refDesc != null) 390 { 391 fieldAccess.setFieldDescriptor(refDesc); 392 } 393 else if (nameExpr.hasParent() && (nameExpr.getParent() instanceof NameExpression)) 394 { 395 throw new JDOUserException("Cannot find reference "+nameExpr.getName()+" in type "+baseType.getName()+" because it is not defined, not persistent or not a reference"); 397 } 398 else 399 { 400 CollectionDescriptor collDesc = classDesc.getCollectionDescriptorByName(nameExpr.getName()); 402 if (collDesc != null) 403 { 404 fieldAccess.setFieldDescriptor(collDesc); 405 } 406 else 407 { 408 FieldDescriptor fieldDesc = classDesc.getFieldDescriptorByName(nameExpr.getName()); 409 410 if (fieldDesc == null) 411 { 412 throw new JDOUserException("Cannot find feature "+nameExpr.getName()+" in type "+baseType.getName()+" because it is not defined or not persistent"); 413 } 414 fieldAccess.setFieldDescriptor(fieldDesc); 415 } 416 } 417 newExpr = fieldAccess; 418 } 419 420 if (nameExpr.hasParent()) 421 { 422 nameExpr.getParent().replaceChild(nameExpr, newExpr); 423 } 424 } 425 426 429 public void visit(NullLiteral nullLit) 430 { 431 Expression parent = nullLit.getParent(); 432 433 if (parent == null) 434 { 435 return; 436 } 437 438 if (parent instanceof BinaryExpression) 442 { 443 Class type = null; 444 445 if (((BinaryExpression)parent).getLeftSide() == nullLit) 446 { 447 type = ((BinaryExpression)parent).getRightSide().getType(); 448 } 449 else 450 { 451 type = ((BinaryExpression)parent).getLeftSide().getType(); 452 } 453 if (type.isPrimitive()) 454 { 455 throw new JDOUserException("Illegal binary expression with a 'null' and a primitive operand"); 456 } 457 nullLit.setType(type); 458 } 459 } 460 461 464 public void visit(ThisExpression thisExpr) 465 { 466 super.visit(thisExpr); 467 thisExpr.setType(_query.getSearchedClass()); 468 } 469 470 473 public void visit(Type type) throws JDOUserException 474 { 475 ClassLoader loader = ClassHelper.getClassLoader(); 476 Class result = null; 477 String name = type.getName(); 478 int pos = name.indexOf('.'); 479 480 if (pos >= 0) 481 { 482 try 491 { 492 result = Class.forName(name, true, loader); 493 } 494 catch (ClassNotFoundException ex) 495 { 496 } 498 } 499 if (result == null) 500 { 501 result = resolveUnqualifiedClassName(loader, name); 502 } 503 if (result == null) 504 { 505 throw new JDOUserException("No such class "+name); 506 } 507 else 508 { 509 type.setType(result); 510 } 511 } 512 513 521 private Class resolveUnqualifiedClassName(ClassLoader loader, String unqualifiedName) throws JDOUserException 522 { 523 Import importDecl; 528 Class result = null; 529 int pos; 530 531 try 533 { 534 result = Class.forName("java.lang." + unqualifiedName, true, loader); 535 } 536 catch (ClassNotFoundException ex) 537 { 538 } 540 for (Iterator it = _query.getImports().iterator(); it.hasNext();) 541 { 542 importDecl = (Import)it.next(); 543 if (importDecl.isOnDemand()) 544 { 545 try 546 { 547 result = Class.forName(importDecl.getSpec() + "." + unqualifiedName, true, loader); 548 } 549 catch (ClassNotFoundException ex) 550 { 551 } 553 } 554 else 555 { 556 pos = importDecl.getSpec().lastIndexOf('.'); 557 if (unqualifiedName.equals(importDecl.getSpec().substring(pos + 1))) 558 { 559 try 560 { 561 return Class.forName(importDecl.getSpec() + "." + unqualifiedName, true, loader); 565 } 566 catch (ClassNotFoundException ex) 567 { 568 throw new JDOUserException("The import "+importDecl.getSpec()+" is invalid"); 570 } 571 } 572 } 573 } 574 return result; 575 } 576 577 580 public void visit(UnaryExpression unaryExpr) throws JDOUserException 581 { 582 super.visit(unaryExpr); 583 584 Class innerType = unaryExpr.getInnerExpression().getType(); 590 boolean typeWasSet = false; 591 592 switch (unaryExpr.getOperator()) 593 { 594 case UnaryExpression.OPERATOR_PLUS : 595 case UnaryExpression.OPERATOR_MINUS : 596 if (isNumeric(innerType)) 597 { 598 unaryExpr.setType(innerType); 599 typeWasSet = true; 600 } 601 break; 602 case UnaryExpression.OPERATOR_BITWISE_COMPLEMENT : 603 if (isInteger(innerType)) 604 { 605 unaryExpr.setType(innerType); 606 typeWasSet = true; 607 } 608 break; 609 case UnaryExpression.OPERATOR_NOT : 610 if (innerType == boolean.class) 611 { 612 unaryExpr.setType(innerType); 613 typeWasSet = true; 614 } 615 break; 616 case UnaryExpression.OPERATOR_CAST : 617 Class castType = unaryExpr.getCastType().getType(); 618 619 if (isNumeric(castType) && isNumeric(innerType)) 620 { 621 unaryExpr.setType(castType); 622 typeWasSet = true; 623 } 624 else 625 { 626 if (castType.isAssignableFrom(innerType) || innerType.isAssignableFrom(castType)) 628 { 629 unaryExpr.setType(castType); 630 typeWasSet = true; 631 } 632 } 633 break; 634 635 } 636 if (!typeWasSet) 637 { 638 if (unaryExpr.getOperator() == UnaryExpression.OPERATOR_CAST) 639 { 640 throw new JDOUserException("Invalid cast expression because inner expression of type "+innerType.getName()+" cannot be cast to "+unaryExpr.getCastType().getName()); 641 } 642 else 643 { 644 throw new JDOUserException("Invalid unary expression"); 645 } 646 } 647 } 648 649 651 657 private ClassDescriptor findClassDescriptorFor(Class type) 658 { 659 return MetadataManager.getInstance().getRepository().getDescriptorFor(type); 660 } 661 662 668 private static boolean isInteger(Class type) 669 { 670 if (type.isPrimitive()) 671 { 672 return (type != boolean.class) && (type != float.class) && (type != double.class); 673 } 674 else 675 { 676 return type == BigInteger .class; 677 } 678 } 679 680 686 private static boolean isFloatingPoint(Class type) 687 { 688 if (type.isPrimitive()) 689 { 690 return (type == float.class) || (type == double.class); 691 } 692 else 693 { 694 return type == BigDecimal .class; 695 } 696 } 697 698 704 private static boolean isNumeric(Class type) 705 { 706 if (type.isPrimitive()) 707 { 708 return type != boolean.class; 709 } 710 else 711 { 712 return (type == BigDecimal .class) || (type == BigInteger .class); 713 } 714 } 715 716 723 private static Class getBroaderType(Class typeA, Class typeB) 724 { 725 Integer numA = (Integer )_primitiveTypes.get(typeA); 726 Integer numB = (Integer )_primitiveTypes.get(typeB); 727 728 return numA.intValue() < numB.intValue() ? typeB : typeA; 729 } 730 } 731 | Popular Tags |