1 16 19 package org.apache.xalan.extensions; 20 21 import java.lang.reflect.Constructor ; 22 import java.lang.reflect.Method ; 23 import java.lang.reflect.Modifier ; 24 25 import javax.xml.transform.TransformerException ; 26 27 import org.apache.xalan.res.XSLMessages; 28 import org.apache.xalan.res.XSLTErrorResources; 29 import org.apache.xml.dtm.DTM; 30 import org.apache.xml.dtm.DTMIterator; 31 import org.apache.xml.dtm.ref.DTMNodeIterator; 32 import org.apache.xpath.objects.XObject; 33 import org.apache.xpath.objects.XRTreeFrag; 34 import org.apache.xpath.objects.XString; 35 import org.w3c.dom.Node ; 36 import org.w3c.dom.NodeList ; 37 import org.w3c.dom.traversal.NodeIterator; 38 39 43 public class MethodResolver 44 { 45 46 49 public static final int STATIC_ONLY = 1; 50 51 54 public static final int INSTANCE_ONLY = 2; 55 56 59 public static final int STATIC_AND_INSTANCE = 3; 60 61 67 public static final int DYNAMIC = 4; 68 69 81 public static Constructor getConstructor(Class classObj, 82 Object [] argsIn, 83 Object [][] argsOut, 84 ExpressionContext exprContext) 85 throws NoSuchMethodException , 86 SecurityException , 87 TransformerException 88 { 89 Constructor bestConstructor = null; 90 Class [] bestParamTypes = null; 91 Constructor [] constructors = classObj.getConstructors(); 92 int nMethods = constructors.length; 93 int bestScore = Integer.MAX_VALUE; 94 int bestScoreCount = 0; 95 for(int i = 0; i < nMethods; i++) 96 { 97 Constructor ctor = constructors[i]; 98 Class [] paramTypes = ctor.getParameterTypes(); 99 int numberMethodParams = paramTypes.length; 100 int paramStart = 0; 101 boolean isFirstExpressionContext = false; 102 int scoreStart; 103 if(numberMethodParams == (argsIn.length+1)) 107 { 108 Class javaClass = paramTypes[0]; 109 if(ExpressionContext.class.isAssignableFrom(javaClass)) 111 { 112 isFirstExpressionContext = true; 113 scoreStart = 0; 114 paramStart++; 115 } 117 else 118 continue; 119 } 120 else 121 scoreStart = 1000; 122 123 if(argsIn.length == (numberMethodParams - paramStart)) 124 { 125 int score = scoreMatch(paramTypes, paramStart, argsIn, scoreStart); 127 if(-1 == score) 129 continue; 130 if(score < bestScore) 131 { 132 bestConstructor = ctor; 134 bestParamTypes = paramTypes; 135 bestScore = score; 136 bestScoreCount = 1; 137 } 138 else if (score == bestScore) 139 bestScoreCount++; 140 } 141 } 142 143 if(null == bestConstructor) 144 { 145 throw new NoSuchMethodException (errString("function", "constructor", classObj, 146 "", 0, argsIn)); 147 } 148 153 else 154 convertParams(argsIn, argsOut, bestParamTypes, exprContext); 155 156 return bestConstructor; 157 } 158 159 160 173 public static Method getMethod(Class classObj, 174 String name, 175 Object [] argsIn, 176 Object [][] argsOut, 177 ExpressionContext exprContext, 178 int searchMethod) 179 throws NoSuchMethodException , 180 SecurityException , 181 TransformerException 182 { 183 if (name.indexOf("-")>0) 186 name = replaceDash(name); 187 Method bestMethod = null; 188 Class [] bestParamTypes = null; 189 Method [] methods = classObj.getMethods(); 190 int nMethods = methods.length; 191 int bestScore = Integer.MAX_VALUE; 192 int bestScoreCount = 0; 193 boolean isStatic; 194 for(int i = 0; i < nMethods; i++) 195 { 196 Method method = methods[i]; 197 int xsltParamStart = 0; 199 if(method.getName().equals(name)) 200 { 201 isStatic = Modifier.isStatic(method.getModifiers()); 202 switch(searchMethod) 203 { 204 case STATIC_ONLY: 205 if (!isStatic) 206 { 207 continue; 208 } 209 break; 210 211 case INSTANCE_ONLY: 212 if (isStatic) 213 { 214 continue; 215 } 216 break; 217 218 case STATIC_AND_INSTANCE: 219 break; 220 221 case DYNAMIC: 222 if (!isStatic) 223 xsltParamStart = 1; 224 } 225 int javaParamStart = 0; 226 Class [] paramTypes = method.getParameterTypes(); 227 int numberMethodParams = paramTypes.length; 228 boolean isFirstExpressionContext = false; 229 int scoreStart; 230 int argsLen = (null != argsIn) ? argsIn.length : 0; 234 if(numberMethodParams == (argsLen-xsltParamStart+1)) 235 { 236 Class javaClass = paramTypes[0]; 237 if(ExpressionContext.class.isAssignableFrom(javaClass)) 238 { 239 isFirstExpressionContext = true; 240 scoreStart = 0; 241 javaParamStart++; 242 } 243 else 244 { 245 continue; 246 } 247 } 248 else 249 scoreStart = 1000; 250 251 if((argsLen - xsltParamStart) == (numberMethodParams - javaParamStart)) 252 { 253 int score = scoreMatch(paramTypes, javaParamStart, argsIn, scoreStart); 255 if(-1 == score) 257 continue; 258 if(score < bestScore) 259 { 260 bestMethod = method; 262 bestParamTypes = paramTypes; 263 bestScore = score; 264 bestScoreCount = 1; 265 } 266 else if (score == bestScore) 267 bestScoreCount++; 268 } 269 } 270 } 271 272 if (null == bestMethod) 273 { 274 throw new NoSuchMethodException (errString("function", "method", classObj, 275 name, searchMethod, argsIn)); 276 } 277 281 else 282 convertParams(argsIn, argsOut, bestParamTypes, exprContext); 283 284 return bestMethod; 285 } 286 287 292 private static String replaceDash(String name) 293 { 294 char dash = '-'; 295 StringBuffer buff = new StringBuffer (""); 296 for (int i=0; i<name.length(); i++) 297 { 298 if (name.charAt(i) == dash) 299 {} 300 else if (i > 0 && name.charAt(i-1) == dash) 301 buff.append(Character.toUpperCase(name.charAt(i))); 302 else 303 buff.append(name.charAt(i)); 304 } 305 return buff.toString(); 306 } 307 308 317 public static Method getElementMethod(Class classObj, 318 String name) 319 throws NoSuchMethodException , 320 SecurityException , 321 TransformerException 322 { 323 Method bestMethod = null; 326 Method [] methods = classObj.getMethods(); 327 int nMethods = methods.length; 328 int bestScoreCount = 0; 329 for(int i = 0; i < nMethods; i++) 330 { 331 Method method = methods[i]; 332 if(method.getName().equals(name)) 334 { 335 Class [] paramTypes = method.getParameterTypes(); 336 if ( (paramTypes.length == 2) 337 && paramTypes[1].isAssignableFrom(org.apache.xalan.templates.ElemExtensionCall.class) 338 && paramTypes[0].isAssignableFrom(org.apache.xalan.extensions.XSLProcessorContext.class) ) 339 { 340 if ( ++bestScoreCount == 1 ) 341 bestMethod = method; 342 else 343 break; 344 } 345 } 346 } 347 348 if (null == bestMethod) 349 { 350 throw new NoSuchMethodException (errString("element", "method", classObj, 351 name, 0, null)); 352 } 353 else if (bestScoreCount > 1) 354 throw new TransformerException (XSLMessages.createMessage(XSLTErrorResources.ER_MORE_MATCH_ELEMENT, new Object []{name})); 356 return bestMethod; 357 } 358 359 360 370 public static void convertParams(Object [] argsIn, 371 Object [][] argsOut, Class [] paramTypes, 372 ExpressionContext exprContext) 373 throws javax.xml.transform.TransformerException 374 { 375 if (paramTypes == null) 377 argsOut[0] = null; 378 else 379 { 380 int nParams = paramTypes.length; 381 argsOut[0] = new Object [nParams]; 382 int paramIndex = 0; 383 if((nParams > 0) 384 && ExpressionContext.class.isAssignableFrom(paramTypes[0])) 385 { 386 argsOut[0][0] = exprContext; 387 paramIndex++; 389 } 390 391 if (argsIn != null) 392 { 393 for(int i = argsIn.length - nParams + paramIndex ; paramIndex < nParams; i++, paramIndex++) 394 { 395 argsOut[0][paramIndex] = convert(argsIn[i], paramTypes[paramIndex]); 397 } 398 } 399 } 400 } 401 402 406 static class ConversionInfo 407 { 408 ConversionInfo(Class cl, int score) 409 { 410 m_class = cl; 411 m_score = score; 412 } 413 414 Class m_class; int m_score; } 417 418 private static final int SCOREBASE=1; 419 420 424 static ConversionInfo[] m_javaObjConversions = { 425 new ConversionInfo(Double.TYPE, 11), 426 new ConversionInfo(Float.TYPE, 12), 427 new ConversionInfo(Long.TYPE, 13), 428 new ConversionInfo(Integer.TYPE, 14), 429 new ConversionInfo(Short.TYPE, 15), 430 new ConversionInfo(Character.TYPE, 16), 431 new ConversionInfo(Byte.TYPE, 17), 432 new ConversionInfo(java.lang.String .class, 18) 433 }; 434 435 439 static ConversionInfo[] m_booleanConversions = { 440 new ConversionInfo(Boolean.TYPE, 0), 441 new ConversionInfo(java.lang.Boolean .class, 1), 442 new ConversionInfo(java.lang.Object .class, 2), 443 new ConversionInfo(java.lang.String .class, 3) 444 }; 445 446 450 static ConversionInfo[] m_numberConversions = { 451 new ConversionInfo(Double.TYPE, 0), 452 new ConversionInfo(java.lang.Double .class, 1), 453 new ConversionInfo(Float.TYPE, 3), 454 new ConversionInfo(Long.TYPE, 4), 455 new ConversionInfo(Integer.TYPE, 5), 456 new ConversionInfo(Short.TYPE, 6), 457 new ConversionInfo(Character.TYPE, 7), 458 new ConversionInfo(Byte.TYPE, 8), 459 new ConversionInfo(Boolean.TYPE, 9), 460 new ConversionInfo(java.lang.String .class, 10), 461 new ConversionInfo(java.lang.Object .class, 11) 462 }; 463 464 468 static ConversionInfo[] m_stringConversions = { 469 new ConversionInfo(java.lang.String .class, 0), 470 new ConversionInfo(java.lang.Object .class, 1), 471 new ConversionInfo(Character.TYPE, 2), 472 new ConversionInfo(Double.TYPE, 3), 473 new ConversionInfo(Float.TYPE, 3), 474 new ConversionInfo(Long.TYPE, 3), 475 new ConversionInfo(Integer.TYPE, 3), 476 new ConversionInfo(Short.TYPE, 3), 477 new ConversionInfo(Byte.TYPE, 3), 478 new ConversionInfo(Boolean.TYPE, 4) 479 }; 480 481 485 static ConversionInfo[] m_rtfConversions = { 486 new ConversionInfo(org.w3c.dom.traversal.NodeIterator.class, 0), 487 new ConversionInfo(org.w3c.dom.NodeList .class, 1), 488 new ConversionInfo(org.w3c.dom.Node .class, 2), 489 new ConversionInfo(java.lang.String .class, 3), 490 new ConversionInfo(java.lang.Object .class, 5), 491 new ConversionInfo(Character.TYPE, 6), 492 new ConversionInfo(Double.TYPE, 7), 493 new ConversionInfo(Float.TYPE, 7), 494 new ConversionInfo(Long.TYPE, 7), 495 new ConversionInfo(Integer.TYPE, 7), 496 new ConversionInfo(Short.TYPE, 7), 497 new ConversionInfo(Byte.TYPE, 7), 498 new ConversionInfo(Boolean.TYPE, 8) 499 }; 500 501 505 static ConversionInfo[] m_nodesetConversions = { 506 new ConversionInfo(org.w3c.dom.traversal.NodeIterator.class, 0), 507 new ConversionInfo(org.w3c.dom.NodeList .class, 1), 508 new ConversionInfo(org.w3c.dom.Node .class, 2), 509 new ConversionInfo(java.lang.String .class, 3), 510 new ConversionInfo(java.lang.Object .class, 5), 511 new ConversionInfo(Character.TYPE, 6), 512 new ConversionInfo(Double.TYPE, 7), 513 new ConversionInfo(Float.TYPE, 7), 514 new ConversionInfo(Long.TYPE, 7), 515 new ConversionInfo(Integer.TYPE, 7), 516 new ConversionInfo(Short.TYPE, 7), 517 new ConversionInfo(Byte.TYPE, 7), 518 new ConversionInfo(Boolean.TYPE, 8) 519 }; 520 521 525 static ConversionInfo[][] m_conversions = 526 { 527 m_javaObjConversions, m_booleanConversions, m_numberConversions, m_stringConversions, m_nodesetConversions, m_rtfConversions }; 534 535 549 public static int scoreMatch(Class [] javaParamTypes, int javaParamsStart, 550 Object [] xsltArgs, int score) 551 { 552 if ((xsltArgs == null) || (javaParamTypes == null)) 553 return score; 554 int nParams = xsltArgs.length; 555 for(int i = nParams - javaParamTypes.length + javaParamsStart, javaParamTypesIndex = javaParamsStart; 556 i < nParams; 557 i++, javaParamTypesIndex++) 558 { 559 Object xsltObj = xsltArgs[i]; 560 int xsltClassType = (xsltObj instanceof XObject) 561 ? ((XObject)xsltObj).getType() 562 : XObject.CLASS_UNKNOWN; 563 Class javaClass = javaParamTypes[javaParamTypesIndex]; 564 565 568 if(xsltClassType == XObject.CLASS_NULL) 569 { 570 if(!javaClass.isPrimitive()) 573 { 574 score += 10; 576 continue; 577 } 578 else 579 return -1; } 581 582 ConversionInfo[] convInfo = m_conversions[xsltClassType]; 583 int nConversions = convInfo.length; 584 int k; 585 for(k = 0; k < nConversions; k++) 586 { 587 ConversionInfo cinfo = convInfo[k]; 588 if(javaClass.isAssignableFrom(cinfo.m_class)) 589 { 590 score += cinfo.m_score; 591 break; } 593 } 594 595 if (k == nConversions) 596 { 597 602 608 620 623 if (XObject.CLASS_UNKNOWN == xsltClassType) 624 { 625 Class realClass = null; 626 627 if (xsltObj instanceof XObject) 628 { 629 Object realObj = ((XObject) xsltObj).object(); 630 if (null != realObj) 631 { 632 realClass = realObj.getClass(); 633 } 634 else 635 { 636 score += 10; 638 continue; 639 } 640 } 641 else 642 { 643 realClass = xsltObj.getClass(); 644 } 645 646 if (javaClass.isAssignableFrom(realClass)) 647 { 648 score += 0; } 650 else 651 return -1; 652 } 653 else 654 return -1; 655 } 656 } 657 return score; 658 } 659 660 670 static Object convert(Object xsltObj, Class javaClass) 671 throws javax.xml.transform.TransformerException 672 { 673 if(xsltObj instanceof XObject) 674 { 675 XObject xobj = ((XObject)xsltObj); 676 int xsltClassType = xobj.getType(); 677 678 switch(xsltClassType) 679 { 680 case XObject.CLASS_NULL: 681 return null; 682 683 case XObject.CLASS_BOOLEAN: 684 { 685 if(javaClass == java.lang.String .class) 686 return xobj.str(); 687 else 688 return new Boolean (xobj.bool()); 689 } 690 case XObject.CLASS_NUMBER: 692 { 693 if(javaClass == java.lang.String .class) 694 return xobj.str(); 695 else if(javaClass == Boolean.TYPE) 696 return new Boolean (xobj.bool()); 697 else 698 { 699 return convertDoubleToNumber(xobj.num(), javaClass); 700 } 701 } 702 704 case XObject.CLASS_STRING: 705 { 706 if((javaClass == java.lang.String .class) || 707 (javaClass == java.lang.Object .class)) 708 return xobj.str(); 709 else if(javaClass == Character.TYPE) 710 { 711 String str = xobj.str(); 712 if(str.length() > 0) 713 return new Character (str.charAt(0)); 714 else 715 return null; } 717 else if(javaClass == Boolean.TYPE) 718 return new Boolean (xobj.bool()); 719 else 720 { 721 return convertDoubleToNumber(xobj.num(), javaClass); 722 } 723 } 724 726 case XObject.CLASS_RTREEFRAG: 727 { 728 if ( (javaClass == NodeIterator.class) || 735 (javaClass == java.lang.Object .class) ) 736 { 737 DTMIterator dtmIter = ((XRTreeFrag) xobj).asNodeIterator(); 738 return new DTMNodeIterator(dtmIter); 739 } 740 else if (javaClass == NodeList .class) 741 { 742 return ((XRTreeFrag) xobj).convertToNodeset(); 743 } 744 else if(javaClass == Node .class) 747 { 748 DTMIterator iter = ((XRTreeFrag) xobj).asNodeIterator(); 749 int rootHandle = iter.nextNode(); 750 DTM dtm = iter.getDTM(rootHandle); 751 return dtm.getNode(dtm.getFirstChild(rootHandle)); 752 } 753 else if(javaClass == java.lang.String .class) 754 { 755 return xobj.str(); 756 } 757 else if(javaClass == Boolean.TYPE) 758 { 759 return new Boolean (xobj.bool()); 760 } 761 else if(javaClass.isPrimitive()) 762 { 763 return convertDoubleToNumber(xobj.num(), javaClass); 764 } 765 else 766 { 767 DTMIterator iter = ((XRTreeFrag) xobj).asNodeIterator(); 768 int rootHandle = iter.nextNode(); 769 DTM dtm = iter.getDTM(rootHandle); 770 Node child = dtm.getNode(dtm.getFirstChild(rootHandle)); 771 772 if(javaClass.isAssignableFrom(child.getClass())) 773 return child; 774 else 775 return null; 776 } 777 } 778 780 case XObject.CLASS_NODESET: 781 { 782 if ( (javaClass == NodeIterator.class) || 789 (javaClass == java.lang.Object .class) ) 790 { 791 return xobj.nodeset(); 792 } 793 else if(javaClass == NodeList .class) 796 { 797 return xobj.nodelist(); 798 } 799 else if(javaClass == Node .class) 802 { 803 DTMIterator ni = xobj.iter(); 806 int handle = ni.nextNode(); 807 if (handle != DTM.NULL) 808 return ni.getDTM(handle).getNode(handle); else 810 return null; 811 } 812 else if(javaClass == java.lang.String .class) 813 { 814 return xobj.str(); 815 } 816 else if(javaClass == Boolean.TYPE) 817 { 818 return new Boolean (xobj.bool()); 819 } 820 else if(javaClass.isPrimitive()) 821 { 822 return convertDoubleToNumber(xobj.num(), javaClass); 823 } 824 else 825 { 826 DTMIterator iter = xobj.iter(); 827 int childHandle = iter.nextNode(); 828 DTM dtm = iter.getDTM(childHandle); 829 Node child = dtm.getNode(childHandle); 830 if(javaClass.isAssignableFrom(child.getClass())) 831 return child; 832 else 833 return null; 834 } 835 } 836 838 } xsltObj = xobj.object(); 841 842 } 844 if (null != xsltObj) 846 { 847 if(javaClass == java.lang.String .class) 848 { 849 return xsltObj.toString(); 850 } 851 else if(javaClass.isPrimitive()) 852 { 853 XString xstr = new XString(xsltObj.toString()); 855 double num = xstr.num(); 856 return convertDoubleToNumber(num, javaClass); 857 } 858 else if(javaClass == java.lang.Class .class) 859 { 860 return xsltObj.getClass(); 861 } 862 else 863 { 864 return xsltObj; 866 } 867 } 868 else 869 { 870 return xsltObj; 872 } 873 } 874 875 881 static Object convertDoubleToNumber(double num, Class javaClass) 882 { 883 if((javaClass == Double.TYPE) || 887 (javaClass == java.lang.Double .class)) 888 return new Double (num); 889 else if(javaClass == Float.TYPE) 890 return new Float (num); 891 else if(javaClass == Long.TYPE) 892 { 893 return new Long ((long)num); 896 } 897 else if(javaClass == Integer.TYPE) 898 { 899 return new Integer ((int)num); 902 } 903 else if(javaClass == Short.TYPE) 904 { 905 return new Short ((short)num); 908 } 909 else if(javaClass == Character.TYPE) 910 { 911 return new Character ((char)num); 914 } 915 else if(javaClass == Byte.TYPE) 916 { 917 return new Byte ((byte)num); 920 } 921 else { 923 return new Double (num); 924 } 925 } 926 927 928 932 private static String errString(String callType, String searchType, Class classObj, 935 String funcName, 936 int searchMethod, 937 Object [] xsltArgs) 938 { 939 String resultString = "For extension " + callType 940 + ", could not find " + searchType + " "; 941 switch (searchMethod) 942 { 943 case STATIC_ONLY: 944 return resultString + "static " + classObj.getName() + "." 945 + funcName + "([ExpressionContext,] " + errArgs(xsltArgs, 0) + ")."; 946 947 case INSTANCE_ONLY: 948 return resultString + classObj.getName() + "." 949 + funcName + "([ExpressionContext,] " + errArgs(xsltArgs, 0) + ")."; 950 951 case STATIC_AND_INSTANCE: 952 return resultString + classObj.getName() + "." + funcName + "([ExpressionContext,] " + errArgs(xsltArgs, 0) + ").\n" 953 + "Checked both static and instance methods."; 954 955 case DYNAMIC: 956 return resultString + "static " + classObj.getName() + "." + funcName 957 + "([ExpressionContext, ]" + errArgs(xsltArgs, 0) + ") nor\n" 958 + classObj + "." + funcName + "([ExpressionContext,] " + errArgs(xsltArgs, 1) + ")."; 959 960 default: 961 if (callType.equals("function")) { 963 return resultString + classObj.getName() 964 + "([ExpressionContext,] " + errArgs(xsltArgs, 0) + ")."; 965 } 966 else { 968 return resultString + classObj.getName() + "." + funcName 969 + "(org.apache.xalan.extensions.XSLProcessorContext, " 970 + "org.apache.xalan.templates.ElemExtensionCall)."; 971 } 972 } 973 974 } 975 976 977 private static String errArgs(Object [] xsltArgs, int startingArg) 978 { 979 StringBuffer returnArgs = new StringBuffer (); 980 for (int i = startingArg; i < xsltArgs.length; i++) 981 { 982 if (i != startingArg) 983 returnArgs.append(", "); 984 if (xsltArgs[i] instanceof XObject) 985 returnArgs.append(((XObject) xsltArgs[i]).getTypeString()); 986 else 987 returnArgs.append(xsltArgs[i].getClass().getName()); 988 } 989 return returnArgs.toString(); 990 } 991 992 } 993 | Popular Tags |