1 15 package org.josql.expressions; 16 17 import java.util.List ; 18 import java.util.ArrayList ; 19 import java.util.Arrays ; 20 import java.util.Map ; 21 import java.util.TreeMap ; 22 23 import java.lang.reflect.Method ; 24 import java.lang.reflect.Modifier ; 25 26 import com.gentlyweb.utils.Getter; 27 28 import org.josql.Query; 29 import org.josql.QueryExecutionException; 30 import org.josql.QueryParseException; 31 32 import org.josql.internal.Utilities; 33 34 41 public class Function extends ValueExpression 42 { 43 44 private String name = null; 45 private List params = null; 46 private Method function = null; 47 private Object handler = null; 48 private boolean fixedResult = true; 49 private Object fixedValue = null; 50 private String acc = null; 51 private Getter get = null; 52 53 public Getter getGetter () 54 { 55 56 return this.get; 57 58 } 59 60 public String getAccessor () 61 { 62 63 return this.acc; 64 65 } 66 67 public void setAccessor (String acc) 68 { 69 70 this.acc = acc; 71 72 } 73 74 81 public Class getExpectedReturnType (Query q) 82 { 83 84 if (this.get != null) 85 { 86 87 return this.get.getType (); 88 89 } 90 91 return this.function.getReturnType (); 92 93 } 94 95 107 public void init (Query q) 108 throws QueryParseException 109 { 110 111 if (this.params != null) 114 { 115 116 int s = this.params.size (); 117 118 for (int i = 0; i < s; i++) 119 { 120 121 Expression exp = (Expression) this.params.get (i); 122 123 exp.init (q); 124 125 } 126 127 } 128 129 Class [] ps = null; 130 131 if (this.params != null) 132 { 133 134 int s = params.size (); 135 136 ps = new Class [s]; 137 138 for (int i = 0; i < s; i++) 139 { 140 141 Expression exp = (Expression) params.get (i); 143 144 ps[i] = exp.getExpectedReturnType (q); 145 146 } 147 148 } 149 150 List fhs = q.getFunctionHandlers (); 153 154 if (fhs != null) 155 { 156 157 int s = fhs.size (); 158 159 TreeMap ms = new TreeMap (); 160 161 for (int i = 0; i < s; i++) 162 { 163 164 Object fh = fhs.get (i); 165 166 this.getMethods (fh.getClass (), 167 q, 168 ms); 169 170 } 171 172 if (ms.size () > 0) 174 { 175 176 this.function = (Method ) ms.get (ms.lastKey ()); 177 178 Class c = this.function.getDeclaringClass (); 179 180 for (int i = 0; i < fhs.size (); i++) 182 { 183 184 Object o = fhs.get (i); 185 186 if (o.getClass ().isAssignableFrom (c)) 187 { 188 189 this.handler = o; 190 191 } 192 193 } 194 195 } 196 197 } 198 199 List dfhs = q.getDefaultFunctionHandlers (); 200 201 if (this.function == null) 202 { 203 204 TreeMap ms = new TreeMap (); 205 206 for (int i = 0; i < dfhs.size (); i++) 207 { 208 209 Object dfh = dfhs.get (i); 210 211 this.getMethods (dfh.getClass (), 212 q, 213 ms); 214 215 } 216 217 if (ms.size () > 0) 219 { 220 221 this.function = (Method ) ms.get (ms.lastKey ()); 222 223 Class c = this.function.getDeclaringClass (); 224 225 for (int i = 0; i < dfhs.size (); i++) 227 { 228 229 Object o = dfhs.get (i); 230 231 if (o.getClass ().isAssignableFrom (c)) 232 { 233 234 this.handler = o; 235 236 } 237 238 } 239 240 } 241 242 } 243 244 if (this.function == null) 245 { 246 247 throw new QueryParseException ("Unable to find function (method): \"" + 249 Utilities.formatSignature (this.name, 250 ps) + 251 "\" in any user-defined function handlers or the default function handler"); 252 253 } 254 255 if (this.acc != null) 257 { 258 259 Class retType = this.function.getReturnType (); 261 262 if (Void.TYPE.isAssignableFrom (retType)) 264 { 265 266 throw new QueryParseException ("Function: " + 268 this + 269 " maps to method: " + 270 this.function + 271 " however methods return type is \"void\" and an accessor: " + 272 this.acc + 273 " has been defined."); 274 275 } 276 277 if (!retType.getName ().equals (Object .class.getName ())) 281 { 282 283 try 286 { 287 288 this.get = new Getter (this.acc, 289 retType); 290 291 } catch (Exception e) { 292 293 throw new QueryParseException ("Function: " + 294 this + 295 " maps to method: " + 296 this.function + 297 " and has accessor: " + 298 this.acc + 299 " however no valid accessor has been found in return type: " + 300 retType.getName (), 301 e); 302 303 } 304 305 } 306 307 } 308 309 if (this.params != null) 313 { 314 315 for (int i = 0; i < this.params.size (); i++) 316 { 317 318 Expression exp = (Expression) this.params.get (i); 319 320 if (!exp.hasFixedResult (q)) 321 { 322 323 this.fixedResult = false; 324 break; 325 326 } 327 328 } 329 330 } else { 331 332 this.fixedResult = false; 333 334 } 335 336 } 337 338 344 public List getParameters () 345 { 346 347 return this.params; 348 349 } 350 351 public void setParameters (List ps) 352 { 353 354 this.params = ps; 355 356 } 357 358 public void setName (String name) 359 { 360 361 362 this.name = name; 363 364 } 365 366 public String getName () 367 { 368 369 return this.name; 370 371 } 372 373 384 public Object evaluate (Object o, 385 Query q) 386 throws QueryExecutionException 387 { 388 389 if (this.fixedResult) 391 { 392 393 if (this.fixedValue != null) 395 { 396 397 return this.fixedValue; 398 399 } 400 401 } 402 403 Object [] ps = null; 405 406 if (this.params != null) 407 { 408 409 int s = this.params.size (); 410 411 ps = new Object [s]; 412 413 for (int i = 0; i < s; i++) 414 { 415 416 Expression exp = (Expression) this.params.get (i); 417 418 if (Expression.class.isAssignableFrom (this.function.getParameterTypes ()[i])) 419 { 420 421 ps[i] = exp; 423 424 } else { 425 426 try 428 { 429 430 ps[i] = exp.getValue (o, 431 q); 432 433 } catch (Exception e) { 434 435 throw new QueryExecutionException ("Unable to get parameter: " + 436 i + 437 " (\"" + 438 exp.toString () + 439 "\") for function: " + 440 this.name, 441 e); 442 443 } 444 445 } 446 447 } 448 449 } 450 451 Object v = null; 452 453 try 454 { 455 456 v = this.function.invoke (this.handler, 457 ps); 458 459 } catch (Exception e) { 460 461 throw new QueryExecutionException ("Unable to execute function: " + 462 this.name + 463 " (\"" + 464 this.toString () + 465 "\") with values: " + 466 Arrays.asList (ps), 467 e); 468 469 } 470 471 if (v != null) 472 { 473 474 if (this.acc != null) 476 { 477 478 if (this.get == null) 480 { 481 482 try 485 { 486 487 this.get = new Getter (this.acc, 488 v.getClass ()); 489 490 } catch (Exception e) { 491 492 throw new QueryExecutionException ("Unable to create accessor for: " + 493 this.acc + 494 " from return type: " + 495 v.getClass ().getName () + 496 " after execution of function: " + 497 this, 498 e); 499 500 } 501 502 } 503 504 try 505 { 506 507 v = this.get.getValue (v); 508 509 } catch (Exception e) { 510 511 throw new QueryExecutionException ("Unable to get value for accessor: " + 512 this.acc + 513 " from return type: " + 514 v.getClass ().getName () + 515 " after execution of function: " + 516 this, 517 e); 518 519 } 520 521 } 522 523 } 524 525 if (this.fixedResult) 526 { 527 528 this.fixedValue = v; 529 530 } 531 532 return v; 533 534 } 535 536 547 public boolean isTrue (Object o, 548 Query q) 549 throws QueryExecutionException 550 { 551 552 o = this.evaluate (o, 553 q); 554 555 if (o == null) 556 { 557 558 return false; 559 560 } 561 562 if (Utilities.isNumber (o)) 563 { 564 565 return Utilities.getDouble (o) > 0; 566 567 } 568 569 if (o instanceof Boolean ) 570 { 571 572 return ((Boolean ) o).booleanValue (); 573 574 } 575 576 return true; 578 579 } 580 581 587 public String toString () 588 { 589 590 StringBuffer buf = new StringBuffer (); 591 592 buf.append (this.name); 593 buf.append ("("); 594 595 if (this.params != null) 596 { 597 598 for (int i = 0; i < this.params.size (); i++) 599 { 600 601 Expression p = (Expression) this.params.get (i); 602 603 buf.append (p); 604 605 if (i < (this.params.size () - 1)) 606 { 607 608 buf.append (","); 609 610 } 611 612 } 613 614 } 615 616 buf.append (")"); 617 618 if (this.acc != null) 619 { 620 621 buf.append ("."); 622 buf.append (this.acc); 623 624 } 625 626 if (this.isBracketed ()) 627 { 628 629 buf.insert (0, 630 "("); 631 632 buf.append (")"); 633 634 } 635 636 return buf.toString (); 637 638 } 639 640 646 public boolean hasFixedResult (Query q) 647 { 648 649 return this.fixedResult; 650 651 } 652 653 private int matchMethodArgs (Class [] methArgs, 654 Query q) 655 throws QueryParseException 656 { 657 658 int score = 0; 662 663 for (int i = 0; i < methArgs.length; i++) 664 { 665 666 Class c = methArgs[i]; 667 668 Expression exp = (Expression) this.params.get (i); 669 670 if (c.getClass ().getName ().equals (Object .class.getName ())) 672 { 673 674 score += 1; 675 676 continue; 677 678 } 679 680 Class expC = exp.getExpectedReturnType (q); 682 683 if (expC == null) 684 { 685 686 continue; 688 689 } else { 690 691 if (c.isAssignableFrom (expC)) 692 { 693 694 score += 2; 695 696 continue; 697 698 } 699 700 } 701 702 if (Expression.class.isAssignableFrom (c)) 703 { 704 705 score += 1; 706 707 continue; 710 711 } 712 713 if ((Utilities.isNumber (expC)) 714 && 715 ((Utilities.isNumber (c)) 716 || 717 (c.getName ().equals (Object .class.getName ())) 718 ) 719 ) 720 { 721 722 score += 1; 723 724 continue; 726 727 } 728 729 if ((Utilities.isPrimitiveClass (c)) 730 && 731 (Utilities.isPrimitiveClass (expC)) 732 ) 733 { 734 735 if (Utilities.getPrimitiveClass (c).isAssignableFrom (Utilities.getPrimitiveClass (expC))) 737 { 738 739 score += 1; 740 741 continue; 743 744 } 745 746 } 747 748 if (expC.getName ().equals (Object .class.getName ())) 751 { 752 753 score += 1; 754 755 continue; 756 757 } 758 759 return 0; 762 763 } 764 765 return score; 767 768 } 769 770 private void getMethods (Class c, 771 Query q, 772 Map matches) 773 throws QueryParseException 774 { 775 776 Method [] meths = c.getMethods (); 777 778 for (int i = 0; i < meths.length; i++) 779 { 780 781 Method m = meths[i]; 782 783 if (!m.getName ().equals (this.name)) 784 { 785 786 continue; 787 788 } 789 790 if (!Modifier.isPublic (m.getModifiers ())) 792 { 793 794 continue; 795 796 } 797 798 Class [] mpt = m.getParameterTypes (); 800 801 int ps = 0; 802 int fps = 0; 803 804 if (mpt != null) 805 { 806 807 ps = mpt.length; 808 809 } 810 811 if (this.params != null) 812 { 813 814 fps = this.params.size (); 815 816 } 817 818 if (ps != fps) 819 { 820 821 continue; 822 823 } 824 825 int score = this.matchMethodArgs (mpt, 826 q); 827 828 if (score > 0) 829 { 830 831 matches.put (new Integer (score), 832 m); 833 834 } 835 836 } 837 838 } 839 840 } 841
| Popular Tags
|