001 /* 002 * Copyright 2005 Stephen J. McConnell. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 013 * implied. 014 * 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package net.dpml.lang; 020 021 import java.beans.Expression; 022 import java.io.Serializable; 023 import java.lang.reflect.Field; 024 import java.lang.reflect.Array; 025 import java.util.ArrayList; 026 import java.util.Arrays; 027 import java.util.Map; 028 029 import net.dpml.util.PropertyResolver; 030 031 /** 032 * A object resolvable from primitive arguments. 033 * 034 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 035 * @version 1.1.0 036 */ 037 public class Construct implements Value, Serializable 038 { 039 /** 040 * Serial version identifier. 041 */ 042 static final long serialVersionUID = 1L; 043 044 /** 045 * Utility operation that consolidates an array of values and supplimentary 046 * arguments to an array of objects. 047 * 048 * @param map a map of keys and values used in symbolic target resolution 049 * @param params the value array 050 * @param args supplimentary arguments 051 * @return the consolidated argument array 052 * @exception Exception if an error occurs in argument resolution 053 */ 054 public static Object[] getArgs( Map map, Value[] params, Object[] args ) throws Exception 055 { 056 ArrayList list = new ArrayList(); 057 for( int i=0; i < params.length; i++ ) 058 { 059 Value value = params[i]; 060 Object object = value.resolve( map ); 061 if( null != object ) 062 { 063 list.add( object ); 064 } 065 } 066 for( int i=0; i < args.length; i++ ) 067 { 068 Object value = args[i]; 069 if( null != value ) 070 { 071 list.add( value ); 072 } 073 } 074 return list.toArray(); 075 } 076 077 private final String m_method; 078 private final String m_target; 079 private final String m_value; 080 private final Value[] m_args; 081 private final boolean m_compound; 082 083 /** 084 * Create a new construct using the default java.lang.String class as the base type. 085 * @param value the construct value 086 */ 087 public Construct( String value ) 088 { 089 this( null, null, value ); 090 } 091 092 /** 093 * Create a new construct using a supplied target defintion. The target argument 094 * may be either a classname or a symbolic reference in the form ${[key]}. If the 095 * argument is symbolic it resolved relative to a context map supplied by the 096 * application resolving construct values. 097 * 098 * @param target a classname or symbolic reference 099 * @param value the construct value 100 */ 101 public Construct( String target, String value ) 102 { 103 this( target, null, value ); 104 } 105 106 /** 107 * Create a new construct using a supplied target defintion. The target argument 108 * may be either a classname or a symbolic reference in the form ${[key]}. If the 109 * argument is symbolic it is resolved relative to a context map supplied by the 110 * application resolving construct values. If the construct value is symbolic 111 * the implementation will attempt to expand the reference relative to a context 112 * map (if supplied) otherwise the implementation will attempt to expand the value 113 * using system properties. 114 * 115 * @param target a classname or symbolic reference 116 * @param method the method to invoke on the target 117 * @param value the construct value 118 */ 119 public Construct( String target, String method, String value ) 120 { 121 m_target = target; 122 m_method = method; 123 m_value = value; 124 m_args = new Value[0]; 125 m_compound = false; 126 } 127 128 /** 129 * Create a new construct using a supplied target defintion. The target argument 130 * may be either a classname or a symbolic reference in the form ${[key]}. If the 131 * argument is symbolic it is resolved relative to a context map supplied by the 132 * application resolving construct values. Instance values resolved from the 133 * supplied Value[] will be used as constructor arguments when resolving the target. 134 * 135 * @param target the construct classname 136 * @param args an array of unresolved parameter values 137 */ 138 public Construct( String target, Value[] args ) 139 { 140 this( target, null, args ); 141 } 142 143 /** 144 * Create a new construct using a supplied target defintion. The target argument 145 * may be either a classname or a symbolic reference in the form ${[key]}. If the 146 * argument is symbolic it is resolved relative to a context map supplied by the 147 * application resolving construct values. Instance values resolved from the 148 * supplied Value[] will be used as method arguments when resolving the target. 149 * 150 * @param target the construct classname 151 * @param method the method to invoke on the target 152 * @param args an array of unresolved parameter values 153 */ 154 public Construct( String target, String method, Value[] args ) 155 { 156 if( null == args ) 157 { 158 m_args = new Value[0]; 159 } 160 else 161 { 162 m_args = args; 163 } 164 m_value = null; 165 m_target = target; 166 m_method = method; 167 m_compound = true; 168 } 169 170 /** 171 * Creation of a new construct using a value directive. 172 * @param directive the value directive 173 */ 174 public Construct( ValueDirective directive ) 175 { 176 m_value = directive.getBaseValue(); 177 m_target = directive.getTargetExpression(); 178 m_method = directive.getMethodName(); 179 m_compound = directive.isCompound(); 180 ValueDirective[] values = directive.getValueDirectives(); 181 int n = values.length; 182 m_args = new Value[ n ]; 183 for( int i=0; i<n; i++ ) 184 { 185 ValueDirective value = values[i]; 186 m_args[i] = new Construct( value ); 187 } 188 } 189 190 /** 191 * Return TRUE if this construct is a compund construct else FALSE. 192 * @return TRUE if this ia a compound construct 193 */ 194 public boolean isCompound() 195 { 196 return m_compound; 197 } 198 199 /** 200 * Return the method name to be applied to the target object. 201 * @return the method name 202 */ 203 public String getMethodName() 204 { 205 return m_method; 206 } 207 208 /** 209 * Return the set of nested values within this value. 210 * @return the nested values array 211 */ 212 public Value[] getValues() 213 { 214 return m_args; 215 } 216 217 /** 218 * Return the classname of the resolved value. 219 * @return the classname 220 */ 221 public String getBaseValue() 222 { 223 return m_value; 224 } 225 226 /** 227 * Return the classname of the resolved value. 228 * @return the classname 229 */ 230 public String getTargetExpression() 231 { 232 return m_target; 233 } 234 235 /** 236 * Resolve an instance from the value using the context classloader. 237 * @return the resolved instance 238 * @exception Exception if an error occurs during value resolution 239 */ 240 public Object resolve() throws Exception 241 { 242 return resolve( null ); 243 } 244 245 /** 246 * Resolve an instance from the value using a supplied map. 247 * @param map the context map 248 * @return the resolved instance 249 * @exception Exception if an error occurs during value resolution 250 */ 251 public Object resolve( Map map ) throws Exception 252 { 253 return resolve( map, false ); 254 } 255 256 /** 257 * Resolve an instance from the value using a supplied isolation policy. 258 * @param isolate the isolation policy 259 * @return the resolved instance 260 * @exception Exception if an error occurs during value resolution 261 */ 262 public Object resolve( boolean isolate ) throws Exception 263 { 264 return resolve( null, isolate ); 265 } 266 267 /** 268 * Resolve an instance from the value using a supplied context map. If any 269 * target expressions in immediate or nested values contain a symbolic 270 * expression the value will be resolved using the supplied map. 271 * 272 * @param map the context map 273 * @param isolate the isolation policy 274 * @return the resolved instance 275 * @exception Exception if error occurs during instance resolution 276 */ 277 public Object resolve( Map map, boolean isolate ) throws Exception 278 { 279 return resolve( null, map, null, isolate ); 280 } 281 282 /** 283 * Resolve an instance from the value using a supplied context map. If any 284 * target expressions in immediate or nested values contain a symbolic 285 * expression the value will be resolved using the supplied map. 286 * 287 * @param classname the default classname 288 * @param map the context map 289 * @param isolate the isolation policy 290 * @return the resolved instance 291 * @exception Exception if error occurs during instance resolution 292 */ 293 public Object resolve( String classname, Map map, boolean isolate ) throws Exception 294 { 295 return resolve( classname, map, null, isolate ); 296 } 297 298 /** 299 * Resolve an instance from the value. 300 * @param map the context map 301 * @param classloader the classloader to use 302 * @param isolate the isolation policy 303 * @return the resolved instance 304 * @exception Exception if an error occurs during value resolution 305 */ 306 private Object resolve( String classname, Map map, ClassLoader classloader, boolean isolate ) throws Exception 307 { 308 ClassLoader loader = resolveClassLoader( classloader ); 309 Object target = getTargetObject( classname, map, loader ); 310 if( isCompound() ) 311 { 312 if( null == target ) 313 { 314 throw new NullPointerException( "target" ); 315 } 316 else 317 { 318 return resolveCompoundExpression( target, map, loader ); 319 } 320 } 321 else 322 { 323 Object value = resolveBaseValue( map ); 324 if( null == target ) 325 { 326 return value; 327 } 328 else 329 { 330 return resolveSimpleExpression( target, map, loader ); 331 } 332 } 333 } 334 335 private Object resolveBaseValue( Map map ) 336 { 337 return expandSymbols( map, m_value ); 338 } 339 340 private Object resolveSimpleExpression( Object target, Map map, ClassLoader classloader ) throws Exception 341 { 342 String method = getMethodName(); 343 Object value = expandSymbols( map, m_value ); 344 boolean isaClass = ( target.getClass() == Class.class ); 345 if( null == method ) 346 { 347 if( isaClass ) 348 { 349 method = "new"; 350 } 351 else 352 { 353 final String error = 354 "Target expression '" 355 + m_target 356 + "' resolving to an instance of the class [" 357 + target.getClass() 358 + "] canot be resolved due to missing method declaration."; 359 throw new ValueException( error ); 360 } 361 } 362 else 363 { 364 if( isaClass && ( null == value ) ) 365 { 366 // check if the method name is a static field 367 Class c = (Class) target; 368 try 369 { 370 Field field = c.getField( method ); 371 return field.get( c ); 372 } 373 catch( NoSuchFieldException e ) 374 { 375 // assume its a method 376 } 377 } 378 } 379 380 if( value == null ) 381 { 382 Expression expression = new Expression( target, method, new Object[0] ); 383 try 384 { 385 return expression.getValue(); 386 } 387 catch( Throwable e ) 388 { 389 final String error = 390 "Internal error while evalating simple expression using:" 391 + "\n target: " 392 + m_target 393 + " (" 394 + target 395 + ")" 396 + "\n method: " 397 + m_method 398 + " (" 399 + method 400 + ")"; 401 throw new ValueException( error, e ); 402 } 403 } 404 else 405 { 406 Expression expression = new Expression( target, method, new Object[]{value} ); 407 try 408 { 409 return expression.getValue(); 410 } 411 catch( Throwable e ) 412 { 413 final String error = 414 "Internal error while evaluating expression using:" 415 + "\n target: " + m_target + " (" + target + ")" 416 + "\n method: " + m_method + " (" + method + ")" 417 + "\n value: " + m_value + " (" + value.getClass().getName() + ")"; 418 throw new ValueException( error, e ); 419 } 420 } 421 } 422 423 private Object resolveCompoundExpression( Object target, Map map, ClassLoader classloader ) throws Exception 424 { 425 Value[] args = getValues(); 426 Object[] instances = getInstanceValues( map, classloader, args ); 427 String method = getMethodName(); 428 boolean isaClass = ( target.getClass() == Class.class ); 429 430 // 431 // check if we are dealing with an array class and if so return and 432 // array created from the array of nested values 433 // 434 435 if( isaClass ) 436 { 437 Class c = (Class) target; 438 if( c.isArray() ) 439 { 440 Class type = c.getComponentType(); 441 if( type.isPrimitive() ) 442 { 443 return buildPrimitiveArray( type, instances ); 444 } 445 else 446 { 447 Object[] result = 448 (Object[]) Array.newInstance( type, instances.length ); 449 for( int i=0; i<instances.length; i++ ) 450 { 451 Object instance = instances[i]; 452 if( type.isAssignableFrom( instance.getClass() ) ) 453 { 454 result[i] = instances[i]; 455 } 456 else 457 { 458 final String error = 459 "Array [" 460 + type.getName() 461 + "] contains an invalid element [" 462 + instance.getClass().getName() 463 + "]."; 464 throw new ValueException( error ); 465 } 466 } 467 return result; 468 } 469 } 470 } 471 472 // otherwise its a regular expression 473 474 if( null == method ) 475 { 476 if( isaClass ) 477 { 478 method = "new"; 479 } 480 else 481 { 482 final String error = 483 "Missing method declaration in a composite value construct." 484 + "\nTarget: " 485 + target 486 + " (" + target.getClass().getName() 487 + ")"; 488 throw new ValueException( error ); 489 } 490 } 491 else 492 { 493 if( isaClass && ( instances.length == 0 ) ) 494 { 495 // check if the method name is a static field 496 Class c = (Class) target; 497 try 498 { 499 Field field = c.getField( method ); 500 return field.get( c ); 501 } 502 catch( NoSuchFieldException e ) 503 { 504 // assume its a method 505 } 506 } 507 } 508 Expression expression = new Expression( target, method, instances ); 509 try 510 { 511 return expression.getValue(); 512 } 513 catch( Throwable e ) 514 { 515 StringBuffer buffer = new StringBuffer(); 516 buffer.append( "Internal error while evaluating compound expression." ); 517 buffer.append( "\n target: " + m_target + " (" + target + ")" ); 518 buffer.append( "\n method: " + m_method + " (" + method + ")" ); 519 for( int i=0; i<instances.length; i++ ) 520 { 521 buffer.append( 522 "\n param " 523 + ( i+1 ) 524 + ": " 525 + instances[i].getClass().getName() 526 ); 527 } 528 String error = buffer.toString(); 529 throw new ValueException( error, e ); 530 } 531 } 532 533 private Object buildPrimitiveArray( Class type, Object[] instances ) throws ValueException 534 { 535 Object result = Array.newInstance( type, instances.length ); 536 if( Integer.TYPE == type ) 537 { 538 return buildIntArray( instances ); 539 } 540 else if( Short.TYPE == type ) 541 { 542 return buildShortArray( instances ); 543 } 544 else if( Long.TYPE == type ) 545 { 546 return buildLongArray( instances ); 547 } 548 else if( Byte.TYPE == type ) 549 { 550 return buildByteArray( instances ); 551 } 552 else if( Double.TYPE == type ) 553 { 554 return buildDoubleArray( instances ); 555 } 556 else if( Float.TYPE == type ) 557 { 558 return buildFloatArray( instances ); 559 } 560 else if( Character.TYPE == type ) 561 { 562 return buildCharacterArray( instances ); 563 } 564 else if( Boolean.TYPE == type ) 565 { 566 return buildBooleanArray( instances ); 567 } 568 else 569 { 570 final String error = 571 "Primitive array class [" 572 + type.getName() 573 + "] is not recognized."; 574 throw new UnsupportedOperationException( error ); 575 } 576 } 577 578 private Object buildIntArray( Object[] instances ) throws ValueException 579 { 580 Object result = Array.newInstance( Integer.TYPE, instances.length ); 581 for( int i=0; i<instances.length; i++ ) 582 { 583 Object instance = instances[i]; 584 if( instance instanceof Integer ) 585 { 586 Integer integer = (Integer) instance; 587 int v = integer.intValue(); 588 Array.setInt( result, i, v ); 589 } 590 else 591 { 592 final String error = 593 "Supplied int array argument class [" 594 + instance.getClass().getName() 595 + "] is not an Integer."; 596 throw new ValueException( error ); 597 } 598 } 599 return result; 600 } 601 602 private Object buildShortArray( Object[] instances ) throws ValueException 603 { 604 Object result = Array.newInstance( Short.TYPE, instances.length ); 605 for( int i=0; i<instances.length; i++ ) 606 { 607 Object instance = instances[i]; 608 if( instance instanceof Short ) 609 { 610 Short primitive = (Short) instance; 611 short v = primitive.shortValue(); 612 Array.setShort( result, i, v ); 613 } 614 else 615 { 616 final String error = 617 "Supplied short array argument class [" 618 + instance.getClass().getName() 619 + "] is not an Short."; 620 throw new ValueException( error ); 621 } 622 } 623 return result; 624 } 625 626 private Object buildLongArray( Object[] instances ) throws ValueException 627 { 628 Object result = Array.newInstance( Long.TYPE, instances.length ); 629 for( int i=0; i<instances.length; i++ ) 630 { 631 Object instance = instances[i]; 632 if( instance instanceof Long ) 633 { 634 Long primitive = (Long) instance; 635 long v = primitive.longValue(); 636 Array.setLong( result, i, v ); 637 } 638 else 639 { 640 final String error = 641 "Supplied long array argument class [" 642 + instance.getClass().getName() 643 + "] is not an instance of Long."; 644 throw new ValueException( error ); 645 } 646 } 647 return result; 648 } 649 650 private Object buildByteArray( Object[] instances ) throws ValueException 651 { 652 Object result = Array.newInstance( Byte.TYPE, instances.length ); 653 for( int i=0; i<instances.length; i++ ) 654 { 655 Object instance = instances[i]; 656 if( instance instanceof Byte ) 657 { 658 Byte primitive = (Byte) instance; 659 byte v = primitive.byteValue(); 660 Array.setByte( result, i, v ); 661 } 662 else 663 { 664 final String error = 665 "Supplied byte array argument class [" 666 + instance.getClass().getName() 667 + "] is not an instance of Byte."; 668 throw new ValueException( error ); 669 } 670 } 671 return result; 672 } 673 674 private Object buildDoubleArray( Object[] instances ) throws ValueException 675 { 676 Object result = Array.newInstance( Double.TYPE, instances.length ); 677 for( int i=0; i<instances.length; i++ ) 678 { 679 Object instance = instances[i]; 680 if( instance instanceof Double ) 681 { 682 Double primitive = (Double) instance; 683 double v = primitive.doubleValue(); 684 Array.setDouble( result, i, v ); 685 } 686 else 687 { 688 final String error = 689 "Supplied double array argument class [" 690 + instance.getClass().getName() 691 + "] is not an instance of Double."; 692 throw new ValueException( error ); 693 } 694 } 695 return result; 696 } 697 698 private Object buildFloatArray( Object[] instances ) throws ValueException 699 { 700 Object result = Array.newInstance( Float.TYPE, instances.length ); 701 for( int i=0; i<instances.length; i++ ) 702 { 703 Object instance = instances[i]; 704 if( instance instanceof Float ) 705 { 706 Float primitive = (Float) instance; 707 float v = primitive.floatValue(); 708 Array.setFloat( result, i, v ); 709 } 710 else 711 { 712 final String error = 713 "Supplied float array argument class [" 714 + instance.getClass().getName() 715 + "] is not an instance of Float."; 716 throw new ValueException( error ); 717 } 718 } 719 return result; 720 } 721 722 private Object buildCharacterArray( Object[] instances ) throws ValueException 723 { 724 Object result = Array.newInstance( Character.TYPE, instances.length ); 725 for( int i=0; i<instances.length; i++ ) 726 { 727 Object instance = instances[i]; 728 if( instance instanceof Character ) 729 { 730 Character primitive = (Character) instance; 731 char v = primitive.charValue(); 732 Array.setChar( result, i, v ); 733 } 734 else 735 { 736 final String error = 737 "Supplied char array argument class [" 738 + instance.getClass().getName() 739 + "] is not an instance of Character."; 740 throw new ValueException( error ); 741 } 742 } 743 return result; 744 } 745 746 private Object buildBooleanArray( Object[] instances ) throws ValueException 747 { 748 Object result = Array.newInstance( Boolean.TYPE, instances.length ); 749 for( int i=0; i<instances.length; i++ ) 750 { 751 Object instance = instances[i]; 752 if( instance instanceof Boolean ) 753 { 754 Boolean primitive = (Boolean) instance; 755 boolean v = primitive.booleanValue(); 756 Array.setBoolean( result, i, v ); 757 } 758 else 759 { 760 final String error = 761 "Supplied boolean array argument class [" 762 + instance.getClass().getName() 763 + "] is not an instance of Boolean."; 764 throw new ValueException( error ); 765 } 766 } 767 return result; 768 } 769 770 private Object[] getInstanceValues( 771 Map map, ClassLoader classloader, Value[] args ) throws Exception 772 { 773 Object[] instances = new Object[ args.length ]; 774 for( int i=0; i < args.length; i++ ) 775 { 776 Value value = args[i]; 777 if( value instanceof Construct ) 778 { 779 Construct construct = (Construct) value; 780 instances[i] = construct.resolve( null, map, classloader, false ); 781 } 782 else 783 { 784 instances[i] = value.resolve( map ); 785 } 786 } 787 return instances; 788 } 789 790 private Object expandSymbols( Map map, String value ) 791 { 792 if( null == value ) 793 { 794 return null; 795 } 796 else 797 { 798 return parseSymbolicValue( map, value ); 799 } 800 } 801 802 private Object parseSymbolicValue( Map map, String value ) 803 { 804 if( null == map ) 805 { 806 return PropertyResolver.resolve( value ); 807 } 808 if( value.startsWith( "${" ) && value.endsWith( "}" ) ) 809 { 810 String pre = value.substring( 2 ); 811 String key = pre.substring( 0, pre.length() -1 ); 812 if( map.containsKey( key ) ) 813 { 814 return map.get( key ); 815 } 816 else 817 { 818 return PropertyResolver.resolve( value ); 819 } 820 } 821 else 822 { 823 return PropertyResolver.resolve( value ); 824 } 825 } 826 827 /** 828 * Return the instance class using the context classloader. 829 * @return the target object or class 830 * @exception ValueException if target related error occurs 831 */ 832 private Object getTargetObject( String classname, Map map, ClassLoader loader ) throws ValueException 833 { 834 if( null == m_target ) 835 { 836 return getTargetObject( map, loader, classname ); 837 } 838 else 839 { 840 return getTargetObject( map, loader, m_target ); 841 } 842 } 843 844 /** 845 * Return the instance class using the context classloader. 846 * @return the target object or class 847 * @exception ValueException if target related error occurs 848 */ 849 private Object getTargetObject( Map map, ClassLoader loader, String target ) throws ValueException 850 { 851 if( null == target ) 852 { 853 return null; 854 } 855 else if( target.startsWith( "${" ) ) 856 { 857 if( null != map ) 858 { 859 String pre = target.substring( 2 ); 860 String key = pre.substring( 0, pre.length() -1 ); 861 if( map.containsKey( key ) ) 862 { 863 return map.get( key ); 864 } 865 else 866 { 867 final String error = 868 "Unresolvable target symbolic expression [" 869 + target 870 + "]."; 871 throw new ValueException( error ); 872 } 873 } 874 else 875 { 876 String resolved = PropertyResolver.resolve( target ); 877 return getTargetObject( map, loader, resolved ); 878 } 879 } 880 else 881 { 882 if( target.endsWith( "[]" ) ) 883 { 884 int n = target.length() - 2; 885 String componentClassname = target.substring( 0, n ); 886 Class componentClass = resolveType( loader, componentClassname ); 887 return Array.newInstance( componentClass, 0 ).getClass(); 888 } 889 else 890 { 891 return resolveClass( loader, target ); 892 } 893 } 894 } 895 896 /** 897 * Return the instance class using the context classloader. 898 * @return the class 899 * @exception ComponentException if the parameter class cannot be resolved 900 */ 901 private Class resolveClass( ClassLoader loader, String classname ) throws ValueException 902 { 903 try 904 { 905 //return loader.loadClass( classname ); // fails under JDK6, see bug parade 6446627 906 return Class.forName( classname, false, loader ); 907 } 908 catch( final ClassNotFoundException e ) 909 { 910 if( classname.equals( "int" ) ) 911 { 912 return Integer.class; 913 } 914 else if( classname.equals( "short" ) ) 915 { 916 return Short.class; 917 } 918 else if( classname.equals( "long" ) ) 919 { 920 return Long.class; 921 } 922 else if( classname.equals( "byte" ) ) 923 { 924 return Byte.class; 925 } 926 else if( classname.equals( "double" ) ) 927 { 928 return Double.class; 929 } 930 else if( classname.equals( "float" ) ) 931 { 932 return Float.class; 933 } 934 else if( classname.equals( "char" ) ) 935 { 936 return Character.class; 937 } 938 else if( classname.equals( "boolean" ) ) 939 { 940 return Boolean.class; 941 } 942 else 943 { 944 final String error = 945 "Class not found [" 946 + classname 947 + "]."; 948 throw new ValueException( error, e ); 949 } 950 } 951 } 952 953 /** 954 * Return the instance class using the context classloader. 955 * @return the class 956 * @exception ComponentException if the parameter class cannot be resolved 957 */ 958 private Class resolveType( ClassLoader loader, String classname ) throws ValueException 959 { 960 try 961 { 962 return loader.loadClass( classname ); 963 } 964 catch( final ClassNotFoundException e ) 965 { 966 if( classname.equals( "int" ) ) 967 { 968 return Integer.TYPE; 969 } 970 else if( classname.equals( "short" ) ) 971 { 972 return Short.TYPE; 973 } 974 else if( classname.equals( "long" ) ) 975 { 976 return Long.TYPE; 977 } 978 else if( classname.equals( "byte" ) ) 979 { 980 return Byte.TYPE; 981 } 982 else if( classname.equals( "double" ) ) 983 { 984 return Double.TYPE; 985 } 986 else if( classname.equals( "float" ) ) 987 { 988 return Float.TYPE; 989 } 990 else if( classname.equals( "char" ) ) 991 { 992 return Character.TYPE; 993 } 994 else if( classname.equals( "boolean" ) ) 995 { 996 return Boolean.TYPE; 997 } 998 else 999 { 1000 final String error = 1001 "Class not found [" 1002 + classname 1003 + "]."; 1004 throw new ValueException( error, e ); 1005 } 1006 } 1007 } 1008 1009 private ClassLoader resolveClassLoader( ClassLoader classloader ) 1010 { 1011 if( null != classloader ) 1012 { 1013 return classloader; 1014 } 1015 else 1016 { 1017 ClassLoader loader = Thread.currentThread().getContextClassLoader(); 1018 if( null == loader ) 1019 { 1020 return Construct.class.getClassLoader(); 1021 } 1022 else 1023 { 1024 return loader; 1025 } 1026 } 1027 } 1028 1029 /** 1030 * Return a string representation of the construct. 1031 * @return the string value 1032 */ 1033 public String toString() 1034 { 1035 if( !m_compound ) 1036 { 1037 return "construct " 1038 + " target: " + m_target 1039 + " method: " + m_method 1040 + " value: " + m_value; 1041 } 1042 else 1043 { 1044 return "construct " 1045 + " target: " + m_target 1046 + " method: " + m_method 1047 + " values: " + m_args.length; 1048 } 1049 } 1050 1051 /** 1052 * Compare this instance with a supplied object for equality. 1053 * @param other the other object 1054 * @return true if the supplied instance is equal to this instance 1055 */ 1056 public boolean equals( Object other ) 1057 { 1058 if( null == other ) 1059 { 1060 return false; 1061 } 1062 if( other instanceof Construct ) 1063 { 1064 Construct construct = (Construct) other; 1065 if( !equals( m_target, construct.m_target ) ) 1066 { 1067 return false; 1068 } 1069 if( m_compound != construct.m_compound ) 1070 { 1071 return false; 1072 } 1073 if( !equals( m_method, construct.m_method ) ) 1074 { 1075 return false; 1076 } 1077 if( m_compound ) 1078 { 1079 return Arrays.equals( m_args, construct.m_args ); 1080 } 1081 else 1082 { 1083 return equals( m_value, construct.m_value ); 1084 } 1085 } 1086 else 1087 { 1088 return false; 1089 } 1090 } 1091 1092 /** 1093 * Compute the instance hashcode value. 1094 * @return the hashcode 1095 */ 1096 public int hashCode() 1097 { 1098 int hash = 0; 1099 if( null != m_target ) 1100 { 1101 hash ^= m_target.hashCode(); 1102 } 1103 if( null != m_method ) 1104 { 1105 hash ^= m_method.hashCode(); 1106 } 1107 if( m_compound ) 1108 { 1109 for( int i=0; i<m_args.length; i++ ) 1110 { 1111 hash ^= m_args[i].hashCode(); 1112 } 1113 } 1114 else 1115 { 1116 if( m_value != null ) 1117 { 1118 hash ^= m_value.hashCode(); 1119 } 1120 } 1121 return hash; 1122 } 1123 1124 private boolean equals( Object a, Object b ) 1125 { 1126 if( null == a ) 1127 { 1128 return ( null == b ); 1129 } 1130 else 1131 { 1132 return a.equals( b ); 1133 } 1134 } 1135 }