Clover coverage report - ATP library for Java - 3.6.4-stable-060214
Coverage timestamp: Вт фев 14 2006 13:45:22 MSK
file stats: LOC: 982   Methods: 29
NCLOC: 479   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
Accessor.java 69,7% 71,8% 86,2% 72,9%
coverage coverage
 1    /*
 2    * Copyright (c) 2001-2004,
 3    * RedVerst Group, ISP RAS http://www.ispras.ru
 4    * All rights reserved.
 5    *
 6    * Redistribution and use in source and binary forms, with or without
 7    * modification, are permitted provided that the following conditions are met:
 8    *
 9    * 1. Redistributions of source code must retain the above copyright notice, this
 10    * list of conditions and the following disclaimer.
 11    *
 12    * 2. Redistributions in binary form must reproduce the above copyright notice,
 13    * this list of conditions and the following disclaimer in the documentation
 14    * and/or other materials provided with the distribution.
 15    *
 16    * 3. The names "ATP", "TreeDL", "RedVerst", "ISP RAS"
 17    * may not be used to endorse or promote products derived from this software
 18    * without specific prior written permission.
 19    *
 20    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 21    * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 22    * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 23    * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 24    * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 25    * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 26    * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 27    * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 28    * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 29    * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 30    */
 31   
 32    package com.unitesk.atp.dynattrs;
 33   
 34    import java.lang.reflect.Array;
 35    import java.lang.reflect.Method;
 36    import java.util.HashMap;
 37    import java.util.List;
 38    import java.util.Map;
 39    import java.util.Set;
 40   
 41    /**
 42    * This is a collection of static methods to work with
 43    * different implementations of attributes.
 44    *
 45    * @author <A href="mailto:demakov@ispras.ru">Alexey Demakov</A>
 46    * @author <A href="mailto:monakhov@ispras.ru">Alexander Monakhov</A>
 47    * @version $Id: Accessor.java,v 1.8 2006/02/09 06:30:07 all-x Exp $
 48    */
 49    public class Accessor
 50    {
 51    //--------------------------------------------------------------------------
 52    // access to properties using JavaBeans naming conventions
 53   
 54    /**
 55    * Converts the first char of a string to upper case.
 56    *
 57    * @param s The string to convert.
 58    * @return The parameter string with the first character converted
 59    * to uppercase if possible.
 60    * @throws NullPointerException
 61    * when <code>s == null</code>.
 62    */
 63  1 public static String capitalize( String s )
 64    {
 65  1 if( s.length() == 0 )
 66    {
 67  0 return s;
 68    }
 69   
 70  1 char chars[] = s.toCharArray();
 71  1 chars[0] = Character.toUpperCase( chars[0] );
 72  1 return new String( chars );
 73    }
 74   
 75    /**
 76    * Converts the first char of a string to lower case.
 77    *
 78    * @param s The string to convert.
 79    * @return The parameter string with the first character converted
 80    * to lowercase if possible.
 81    * @throws NullPointerException
 82    * when <code>s == null</code>.
 83    */
 84  45 public static String decapitalize( String s )
 85    {
 86  45 if( s.length() == 0 )
 87    {
 88  0 return s;
 89    }
 90   
 91  45 char chars[] = s.toCharArray();
 92  45 chars[0] = Character.toLowerCase( chars[0] );
 93  45 return new String( chars );
 94    }
 95   
 96    /**
 97    * Checks existence of bean property of the specified object.
 98    *
 99    * @param bean The specified object.
 100    * @param name The specified bean property name.
 101    * @return <code>true</code> if there are bean property read method.
 102    * @throws NullPointerException
 103    * If <code>bean</code> is <code>null</code>.
 104    * @throws AttributeException
 105    * Some possible reasons:
 106    * <UL>
 107    * <LI><CODE>name == null</CODE></LI>
 108    * </UL>
 109    * (analyze exception parameters).
 110    * @see #getBeanPropertyReadMethod(Object,String)
 111    */
 112  6 public static boolean hasBeanProperty( Object bean, String name )
 113    {
 114  6 return getBeanPropertyReadMethod( bean, name ) != null;
 115    }
 116   
 117    /**
 118    * Checks writability of bean property of the specified object.
 119    *
 120    * @param bean The specified object.
 121    * @param name The specified bean property name.
 122    * @return <code>true</code> if there are bean property write method.
 123    * @throws NullPointerException
 124    * If <code>bean</code> is <code>null</code>.
 125    * @throws AttributeException
 126    * Some possible reasons:
 127    * <UL>
 128    * <LI><CODE>name == null</CODE></LI>
 129    * </UL>
 130    * (analyze exception parameters).
 131    * @see #getBeanPropertyWriteMethod(Object,String)
 132    */
 133  5 public static boolean isBeanPropertyWritable( Object bean, String name )
 134    {
 135  5 return getBeanPropertyWriteMethod( bean, name ) != null;
 136    }
 137   
 138    /**
 139    * Returns a value of the specified bean property.
 140    *
 141    * @param bean The specified object.
 142    * @param name The specified bean property name.
 143    * @return The value of bean property of specified object.
 144    * @throws NullPointerException
 145    * If <code>bean</code> is <code>null</code>.
 146    * @throws AttributeException
 147    * Some possible reasons:
 148    * <UL>
 149    * <LI><CODE>name == null</CODE></LI>
 150    * <LI>there is no attribute with the specified name</LI>
 151    * <LI>there was an underlying exception</LI>
 152    * </UL>
 153    * (analyze exception parameters).
 154    * @see #hasBeanProperty(Object,String)
 155    */
 156  18 public static Object getBeanProperty( Object bean, String name )
 157    {
 158  18 Method method = getBeanPropertyReadMethod( bean, name );
 159   
 160  18 if( method == null )
 161    {
 162  1 throw new AttributeException( bean, name );
 163    }
 164   
 165  17 try
 166    {
 167  17 return method.invoke( bean, get_par );
 168    }
 169    catch( Exception e )
 170    {
 171  0 throw new AttributeException( bean, name, null, e );
 172    }
 173    }
 174   
 175    /**
 176    * Checks if a value of the bean property can be indexed.
 177    * This method uses {@link #getBeanProperty(Object, String) getBeanProperty(bean,name)}
 178    * to get property value.
 179    *
 180    * @param bean The specified object.
 181    * @param name The specified bean property name.
 182    * @return <code>true</code> if value of bean property {@link #isIndexed(Object) is indexed}.
 183    * @throws NullPointerException
 184    * If <code>bean</code> is <code>null</code>.
 185    * @throws AttributeException
 186    * Some possible reasons:
 187    * <UL>
 188    * <LI><CODE>name == null</CODE></LI>
 189    * <LI>there is no attribute with the specified name</LI>
 190    * <LI>attribute value is null</LI>
 191    * <LI>there was an underlying exception</LI>
 192    * </UL>
 193    * (analyze exception parameters).
 194    * @throws AttributeException
 195    * If bean property with the specified name doesn't exist (cause == null),
 196    * or there was an underlying exception (see cause).
 197    */
 198  6 public static boolean isBeanPropertyIndexed( Object bean, String name )
 199    {
 200  6 Object value = getBeanProperty( bean, name );
 201   
 202  5 try
 203    {
 204  5 return isIndexed( value );
 205    }
 206    catch( Exception e )
 207    {
 208  0 throw new AttributeException( bean, name, value, e );
 209    }
 210    }
 211   
 212    /**
 213    * Sets the new value of the specified bean property.
 214    *
 215    * @param bean The specified object.
 216    * @param name The specified bean property name.
 217    * @param value The new value of bean property.
 218    * @throws NullPointerException
 219    * If <code>bean</code> is <code>null</code>.
 220    * @throws AttributeException
 221    * Some possible reasons:
 222    * <UL>
 223    * <LI><CODE>name == null</CODE></LI>
 224    * <LI>there is no attribute with the specified name</LI>
 225    * <LI>there was an underlying exception</LI>
 226    * </UL>
 227    * (analyze exception parameters).
 228    */
 229  1 public static void setBeanProperty( Object bean, String name, Object value )
 230    {
 231  1 Method method = getBeanPropertyWriteMethod( bean, name );
 232   
 233  1 if( method == null )
 234    {
 235  0 throw new AttributeException( bean, name, value );
 236    }
 237   
 238  1 set_par[0] = value;
 239  1 try
 240    {
 241  1 method.invoke( bean, set_par );
 242    }
 243    catch( Exception e )
 244    {
 245  0 throw new AttributeException( bean, name, value, e );
 246    }
 247    }
 248   
 249    /**
 250    * Returns the set of names of bean properties of the specified object.
 251    * @param bean The specified object.
 252    * @return The set that contains names of all object's bean properties.
 253    * @throws NullPointerException
 254    * If bean is null.
 255    */
 256  6 public static Set/*String*/ getBeanPropertyNames( Object bean )
 257    {
 258  6 return getBeanClassPropertyNames( bean.getClass() );
 259    }
 260   
 261    /**
 262    * Returns the set of names of bean properties for objects of the specified class.
 263    * @param cls The specified class.
 264    * @return The set that contains names of bean properties for objects of
 265    * the specified class.
 266    * @throws NullPointerException
 267    * If cls is null.
 268    */
 269  7 public static Set/*String*/ getBeanClassPropertyNames( Class cls )
 270    {
 271  7 return getBeanClassPropertyDescriptors( cls ).keySet();
 272    }
 273   
 274    //--------------------------------------------------------------------------
 275    // indexed values
 276   
 277    /**
 278    * Checks if value can be indexed.
 279    * A value is indexed if it is an array or instance of {@link List}.
 280    * <CODE>null</CODE> is not indexed value.
 281    *
 282    * @param value The specified value.
 283    * @return <code>true</code> if the specified value is array
 284    * or instance of {@link List}.
 285    */
 286  11 public static boolean isIndexed( Object value )
 287    {
 288  11 return value != null && (value.getClass().isArray() || value instanceof List);
 289    }
 290   
 291    /**
 292    * Returns the size of the indexed value.
 293    *
 294    * @param value The specified indexed value.
 295    * @return Size of the specified indexed value.
 296    * @throws NullPointerException
 297    * If the specified value is <code>null</code>.
 298    * @throws ClassCastException
 299    * If the specified value {@link #isIndexed(Object) is not indexed}.
 300    */
 301  5 public static int sizeIndexed( Object value )
 302    {
 303  5 if( value.getClass().isArray() )
 304    {
 305  3 return Array.getLength( value );
 306    }
 307  2 return ((List)value).size();
 308    }
 309   
 310    /**
 311    * Returns element of the specified index value.
 312    *
 313    * @param value The specified indexed value.
 314    * @param index The specified index.
 315    * @return An element of array or list with the specified index.
 316    * @throws NullPointerException
 317    * If the specified value is <code>null</code>.
 318    * @throws ClassCastException
 319    * If the specified value {@link #isIndexed(Object) is not indexed}.
 320    * @throws IndexOutOfBoundsException
 321    * If the specified index is out of bounds of indexed value.
 322    */
 323  6 public static Object getIndexed( Object value, int index )
 324    {
 325  6 if( value.getClass().isArray() )
 326    {
 327  2 return Array.get( value, index );
 328    }
 329  4 return ((List)value).get( index );
 330    }
 331   
 332    /**
 333    * Sets the new element's value of indexed value.
 334    *
 335    * @param value The specified indexed value.
 336    * @param index The specified index.
 337    * @param elem The new value of element.
 338    * @throws NullPointerException
 339    * If <code>value</code> is <code>null</code>.
 340    * @throws ClassCastException
 341    * If the specified value {@link #isIndexed(Object) is not indexed}.
 342    * @throws IndexOutOfBoundsException
 343    * If the specified index is out of bounds of indexed value.
 344    */
 345  1 public static void setIndexed( Object value, int index, Object elem )
 346    {
 347  1 if( value.getClass().isArray() )
 348    {
 349  0 Array.set( value, index, elem );
 350    } else {
 351  1 ((List)value).set( index, elem );
 352    }
 353    }
 354   
 355    //--------------------------------------------------------------------------
 356    // attributes for any object. if object is instance of Attributed,
 357    // interface Attributed is used else interface JavaBeans is used
 358   
 359    /**
 360    * Checks existence of an attribute with the specified name of the specified object.
 361    *
 362    * @param obj The specified object.
 363    * @param name The specified attribute name.
 364    * @return If <code>obj</code> implements {@link Attributed} interface use
 365    * {@link Attributed#hasAttribute(String) its method} to get attribute value.
 366    * Otherwise {@link #hasBeanProperty(Object,String) check existence of bean property}.
 367    * @throws NullPointerException
 368    * If <code>obj</code> is <code>null</code>.
 369    * @throws AttributeException
 370    * Some possible reasons:
 371    * <UL>
 372    * <LI><CODE>name == null</CODE></LI>
 373    * <LI>there was an underlying exception</LI>
 374    * </UL>
 375    * (analyze exception parameters).
 376    * @since 3.6.3
 377    */
 378  0 public static boolean hasAttribute( Object obj, String name )
 379    {
 380  0 if( obj instanceof Attributed )
 381    {
 382  0 return ((Attributed)obj).hasAttribute( name );
 383    } else {
 384  0 return hasBeanProperty( obj, name );
 385    }
 386    }
 387   
 388    /**
 389    * Returns value of attribute of the specified object.
 390    *
 391    * @param obj The specified object.
 392    * @param name The specified attribute name.
 393    * @return If <code>obj</code> implements {@link Attributed} interface use
 394    * {@link Attributed#getAttribute(String) its method} to get attribute value.
 395    * Otherwise return {@link #getBeanProperty(Object,String) bean property value}.
 396    * @throws NullPointerException
 397    * If <code>obj</code> is <code>null</code>.
 398    * @throws AttributeException
 399    * Some possible reasons:
 400    * <UL>
 401    * <LI><CODE>name == null</CODE></LI>
 402    * <LI>there is no attribute with the specified name</LI>
 403    * <LI>there was an underlying exception</LI>
 404    * </UL>
 405    * (analyze exception parameters).
 406    */
 407  4 public static Object getAttribute( Object obj, String name )
 408    {
 409  4 if( obj instanceof Attributed )
 410    {
 411  1 return ((Attributed)obj).getAttribute( name );
 412    } else {
 413  3 return getBeanProperty( obj, name );
 414    }
 415    }
 416   
 417    /**
 418    * Returns size of indexed attribute of the specified object.
 419    *
 420    * @param obj The specified object.
 421    * @param name The specified attribute name.
 422    * @return If <code>obj</code> implements {@link Attributed} interface use
 423    * {@link Attributed#sizeAttribute(String) its method} to get attribute size.
 424    * Otherwise {@link #getAttribute(Object,String) get attribute value}
 425    * and return {@link #sizeIndexed(Object) its size}.
 426    * @throws NullPointerException
 427    * If <code>obj</code> is <code>null</code>.
 428    * @throws AttributeException
 429    * Some possible reasons:
 430    * <UL>
 431    * <LI><CODE>name == null</CODE></LI>
 432    * <LI>there is no attribute with the specified name</LI>
 433    * <LI>attribute value is not indexed</LI>
 434    * <LI>there was an underlying exception</LI>
 435    * </UL>
 436    * (analyze exception parameters).
 437    */
 438  1 public static int sizeAttribute( Object obj, String name )
 439    {
 440  1 if( obj instanceof Attributed )
 441    {
 442  1 return ((Attributed)obj).sizeAttribute( name );
 443    } else {
 444  0 Object value = getAttribute( obj, name );
 445  0 try
 446    {
 447  0 return sizeIndexed( value );
 448    }
 449    catch( Exception e )
 450    {
 451  0 throw new AttributeException( obj, name, value, e );
 452    }
 453    }
 454    }
 455   
 456    /**
 457    * Returns element of indexed attribute by index.
 458    *
 459    * @param obj The specified object.
 460    * @param name The specified attribute name.
 461    * @param index The specified index.
 462    * @return If <code>obj</code> implements {@link Attributed} interface use
 463    * {@link Attributed#getAttribute(String,int) its method} to get
 464    * attribute element.
 465    * Otherwise {@link #getAttribute(Object,String) get attribute value}
 466    * and return {@link #getIndexed(Object,int) its element by index}.
 467    * @throws NullPointerException
 468    * If <code>obj</code> is <code>null</code>.
 469    * @throws AttributeException
 470    * Some possible reasons:
 471    * <UL>
 472    * <LI><CODE>name == null</CODE></LI>
 473    * <LI>there is no attribute with the specified name</LI>
 474    * <LI>attribute value is not indexed</LI>
 475    * <LI>there was an underlying exception</LI>
 476    * </UL>
 477    * (analyze exception parameters).
 478    */
 479  2 public static Object getAttribute( Object obj, String name, int index )
 480    {
 481  2 if( obj instanceof Attributed )
 482    {
 483  1 return ((Attributed)obj).getAttribute( name, index );
 484    } else {
 485  1 Object value = getAttribute( obj, name );
 486  1 try
 487    {
 488  1 return getIndexed( value, index );
 489    }
 490    catch( Exception e )
 491    {
 492  0 throw new AttributeException( obj, name, value, e );
 493    }
 494    }
 495    }
 496   
 497    /**
 498    * Sets the new value of attribute.
 499    * If <code>obj</code> implements {@link Attributed} interface use
 500    * {@link Attributed#setAttribute(String,Object) its method} to set
 501    * attribute.
 502    * Otherwise tries {@link #setBeanProperty(Object, String, Object) to set bean property}
 503    *
 504    * @param obj The specified object.
 505    * @param name The specified attribute name.
 506    * @param value The new value of attribute.
 507    * @throws AttributeException
 508    * Some possible reasons:
 509    * <UL>
 510    * <LI><CODE>name == null</CODE></LI>
 511    * <LI>there is no attribute with the specified name</LI>
 512    * <LI>attribute is not writable</LI>
 513    * <LI>attribute element type is not compatible with <CODE>elem</CODE></LI>
 514    * <LI>there was an underlying exception</LI>
 515    * </UL>
 516    * (analyze exception parameters).
 517    * @since 3.5.3
 518    */
 519  0 public static void setAttribute( Object obj
 520    , String name
 521    , Object value
 522    )
 523    {
 524  0 if( obj instanceof Attributed )
 525    {
 526  0 ((Attributed)obj).setAttribute( name, value);
 527    } else {
 528  0 setBeanProperty( obj, name, value );
 529    }
 530    }
 531   
 532    /**
 533    * Sets the new value of element of indexed attribute by index.
 534    * If <code>obj</code> implements {@link Attributed} interface use
 535    * {@link Attributed#setAttribute(String,int,Object) its method} to set
 536    * attribute element.
 537    * Otherwise {@link #getAttribute(Object,String) get attribute value}
 538    * and {@link #setIndexed(Object,int,Object) set its element by index}.
 539    *
 540    * @param obj The specified object.
 541    * @param name The specified attribute name.
 542    * @param index The specified index.
 543    * @param elem The new value of element.
 544    * @throws AttributeException
 545    * Some possible reasons:
 546    * <UL>
 547    * <LI><CODE>name == null</CODE></LI>
 548    * <LI>there is no attribute with the specified name</LI>
 549    * <LI>attribute is not writable</LI>
 550    * <LI>attribute is not indexed</LI>
 551    * <LI>attribute index is out of bounds</LI>
 552    * <LI>attribute element type is not compatible with <CODE>elem</CODE></LI>
 553    * <LI>there was an underlying exception</LI>
 554    * </UL>
 555    * (analyze exception parameters).
 556    */
 557  0 public static void setAttribute( Object obj
 558    , String name
 559    , int index
 560    , Object elem
 561    )
 562    {
 563  0 if( obj instanceof Attributed )
 564    {
 565  0 ((Attributed)obj).setAttribute( name, index, elem);
 566    } else {
 567  0 Object value = getAttribute( obj, name );
 568  0 try
 569    {
 570  0 setIndexed( value, index, elem );
 571    }
 572    catch( Exception e )
 573    {
 574  0 throw new AttributeException( obj, name, value, e );
 575    }
 576    }
 577    }
 578   
 579    /**
 580    * Returns the set of attribute names the specified object.
 581    * @param obj The specified object.
 582    * @return If <code>obj</code> implements {@link Attributed} interface use
 583    * {@link Attributed#getAttributeNames() its method} to get attribute names.
 584    * Otherwise {@link #getBeanPropertyNames(Object) get bean property names}.
 585    */
 586  0 public static Set/*String*/ getAttributeNames( Object obj )
 587    {
 588  0 if( obj instanceof Attributed )
 589    {
 590  0 return ((Attributed)obj).getAttributeNames();
 591    } else {
 592  0 return getBeanPropertyNames( obj );
 593    }
 594    }
 595   
 596    /**
 597    * Checks whether the given name is a valid identifier.
 598    * This method uses {@link Character#isUnicodeIdentifierStart(char)}
 599    * and {@link Character#isUnicodeIdentifierPart(char)} methods.
 600    *
 601    * @param name the name to check
 602    * @return <code>true</code> if the given name is a valid identifier,
 603    * <code>false</code> otherwise.
 604    */
 605  3 public static boolean isID( String name )
 606    {
 607  3 int l = name.length();
 608   
 609  3 if( l == 0 )
 610    {
 611  0 return false;
 612    }
 613   
 614  3 char[] chars = name.toCharArray();
 615   
 616  3 if( !Character.isUnicodeIdentifierStart( chars[0] ) )
 617    {
 618  2 return false;
 619    }
 620   
 621  1 for( int i = 1; i < chars.length; i++ )
 622    {
 623  2 if( !Character.isUnicodeIdentifierPart( chars[i] ) )
 624    {
 625  0 return false;
 626    }
 627    }
 628  1 return true;
 629    }
 630   
 631    /**
 632    * Возвращает значение, на которое указывает заданная цепочка атрибутов для данного объекта.
 633    * Цепочка атрибутов имеет следующий вид:
 634    * <P><BLOCKQUOTE><code>
 635    * path ::= attribute ( "." attribute )* ;<BR>
 636    * attribute ::= &lt;attr_name:ID&gt; ( "[" index "]" )? ;<BR>
 637    * index ::= &lt;index_var:ID&gt; | number ;<BR>
 638    * number ::= ( "-" )? ( &lt;DIGIT&gt; )+ ;<BR>
 639    * </BLOCKQUOTE></code>
 640    * <P>Каждый элемент цепочки является либо именем атрибута, либо именем списочного атрибута
 641    * с указанным в скобках индексом элемента. Индекс может быть задан именем переменной
 642    * <code>index_var</code>, значение которой берется из <code>variable_map</code> как значение
 643    * соответствующего атрибута, или целочисленным литералом <code>number</code>.
 644    * Отрицательному индексу -i соответствует элемент списка с индексом L-i, где L - длина списка.
 645    * <P>Значение, на которое указывает цепочка атрибутов, определяется рекурсивно:
 646    * <UL>
 647    * <LI>Для цепочки длины нуль это значение самого объекта.</LI>
 648    * <LI>Для цепочки длины k рекурсивно находим объект, на который указывает цепочка длины k-1.
 649    * Результатом является значение k-го элемента цепочки, применённого к этого объекту.</LI>
 650    * </UL>
 651    *
 652    * @param obj The specified object.
 653    * @param path The chain of attribute names.
 654    * @param variableMap Defined variables.
 655    * @return The value pointed by path of attributes.
 656    * @see #getAttribute(Object,String)
 657    * @see #getAttribute(Object, String, int)
 658    */
 659  2 public static Object getAttribute( Object obj
 660    , String path
 661    , Attributed variableMap
 662    )
 663    {
 664  2 int from = 0;
 665  2 int to = 0;
 666   
 667  2 Object nextobj;
 668  2 String attrname;
 669  2 int realindex = -1;
 670   
 671  2 while( true )
 672    {
 673  3 to = path.indexOf( '.', from );
 674  3 if( to == -1 )
 675    {
 676  2 to = path.length();
 677    }
 678   
 679  3 int bracket = path.indexOf ( '[', from );
 680  3 if( bracket >= 0 && bracket < to )
 681    {
 682   
 683  1 attrname = path.substring( from, bracket );
 684  1 if( path.charAt( to - 1 ) != ']' )
 685    {
 686  0 throw new AttributePathException( AttributePathException.NO_CLOSING_BRACKET
 687    , obj
 688    , path
 689    , bracket
 690    , null
 691    );
 692    }
 693   
 694  1 String index_string = path.substring( bracket + 1, to - 1 );
 695   
 696  1 if( isID( index_string ) ) // if NAME
 697    {
 698  0 Object mapped_index;
 699  0 try
 700    {
 701  0 mapped_index = variableMap.getAttribute( index_string );
 702    }
 703    catch( AttributeException e )
 704    {
 705  0 throw new AttributePathException
 706    ( AttributePathException.ATTRIBUTED_EXCEPTION
 707    , obj
 708    , path
 709    , bracket + 1
 710    , e
 711    );
 712    }
 713  0 try
 714    {
 715  0 realindex = ((Integer)mapped_index).intValue();
 716    }
 717    catch( ClassCastException e )
 718    {
 719  0 throw new AttributePathException( AttributePathException.INDEX_VALUE
 720    , obj
 721    , path
 722    , bracket + 1
 723    , e
 724    );
 725    }
 726    } else {
 727    // if DIGITAL INDEX
 728  1 try
 729    {
 730  1 realindex = Integer.parseInt( index_string );
 731    }
 732    catch ( NumberFormatException e )
 733    {
 734  0 throw new AttributePathException( AttributePathException.INDEX_VALUE
 735    , obj
 736    , path
 737    , bracket + 1
 738    , e
 739    );
 740    }
 741  1 if( realindex < 0 )
 742    {
 743  0 try
 744    {
 745  0 realindex = sizeAttribute( obj, attrname ) + realindex;
 746    }
 747    catch( AttributeException e )
 748    {
 749  0 throw new AttributePathException
 750    ( AttributePathException.ATTRIBUTED_EXCEPTION
 751    , obj
 752    , path
 753    , from
 754    , e
 755    );
 756    }
 757    }
 758    }
 759  1 try
 760    {
 761  1 nextobj = getAttribute( obj, attrname, realindex );
 762    }
 763    catch( AttributeException e )
 764    {
 765  0 throw new AttributePathException( AttributePathException.ATTRIBUTED_EXCEPTION
 766    , obj
 767    , path
 768    , from
 769    , e
 770    );
 771    }
 772    } else {
 773  2 attrname = path.substring( from, to );
 774  2 try
 775    {
 776  2 nextobj = getAttribute( obj, attrname );
 777    }
 778    catch( AttributeException e )
 779    {
 780  0 throw new AttributePathException( AttributePathException.ATTRIBUTED_EXCEPTION
 781    , obj
 782    , path
 783    , from
 784    , e
 785    );
 786    }
 787    }
 788   
 789  3 if( to != path.length() )
 790    {
 791  1 from = to + 1;
 792  1 realindex = -1;
 793  1 obj = nextobj;
 794    } else {
 795  2 return nextobj;
 796    }
 797    }
 798    }
 799   
 800    //--------------------------------------------------------------------------
 801    // auxilary methods
 802   
 803    private static class PropertyDescriptor
 804    {
 805    private Method read_method;
 806    private Method write_method;
 807   
 808  44 public PropertyDescriptor( Method read_method, Method write_method )
 809    {
 810  44 this.read_method = read_method;
 811  44 this.write_method = write_method;
 812    }
 813   
 814  21 public Method getReadMethod()
 815    {
 816  21 return read_method;
 817    }
 818   
 819  5 public Method getWriteMethod()
 820    {
 821  5 return write_method;
 822    }
 823    }
 824   
 825  36 private static Map/*Class,Map(String,PropertyDescriptor)*/
 826    getBeanClassPropertyDescriptors( Class cls )
 827    {
 828  36 if( class_to_properties_descriptor.containsKey( cls ) )
 829    {
 830  32 return (Map/*Class,Map(String,PropertyDescriptor)*/)
 831    class_to_properties_descriptor.get( cls );
 832    }
 833   
 834  4 Method[] methods = cls.getMethods();
 835  4 Map/*String,PropertyDescriptor*/ res
 836    = new HashMap/*String,PropertyDescriptor*/();
 837   
 838  4 for( int i = 0; i < methods.length; i++ )
 839    {
 840  186 if( methods[i].getParameterTypes().length == 0
 841    && !methods[i].getReturnType().equals( void.class )
 842    )
 843    {
 844  72 String method_name = methods[i].getName();
 845   
 846    // if( methods[i].getReturnType().equals( boolean.class )
 847    // && method_name.startsWith( "is" )
 848    // && method_name.length() > 2
 849    // )
 850    // {
 851    // String capitalized_property_name
 852    // = method_name.substring( 2 );
 853    // Method read_method = methods[i];
 854    //
 855    // res.put( decapitalize( capitalized_property_name )
 856    // , new PropertyDescriptor
 857    // ( read_method
 858    // , findWriteMethod( cls
 859    // , read_method
 860    // , capitalized_property_name
 861    // )
 862    // )
 863    // );
 864    // } else
 865  72 if( method_name.startsWith( "get" )
 866    && method_name.length() > "get".length()
 867    )
 868    {
 869  44 String capitalized_property_name
 870    = method_name.substring( "get".length() );
 871  44 Method read_method = methods[i];
 872  44 read_method.setAccessible( true );
 873   
 874  44 res.put( decapitalize( capitalized_property_name )
 875    , new PropertyDescriptor
 876    ( read_method
 877    , findWriteMethod( cls
 878    , read_method
 879    , capitalized_property_name
 880    )
 881    )
 882    );
 883    }
 884    }
 885    }
 886   
 887  4 class_to_properties_descriptor.put( cls, res );
 888   
 889  4 return res;
 890    }
 891   
 892  44 private static Method findWriteMethod( Class cls
 893    , Method read_method
 894    , String capitalizedPropertyName
 895    )
 896    {
 897  44 try
 898    {
 899  44 set_type[0] = read_method.getReturnType();
 900  44 Method write_method = cls.getMethod( "set" + capitalizedPropertyName
 901    , set_type
 902    );
 903  4 if( write_method != null ) write_method.setAccessible( true );
 904  4 return write_method;
 905    }
 906    catch( Exception e )
 907    {
 908  40 return null;
 909    }
 910    }
 911   
 912    /**
 913    * Returns read method for the specified property of the specified bean.
 914    * @param bean Object to get read method from.
 915    * @param name Property name.
 916    * @return Read method or <code>null</code> if object has
 917    * no property with such name.
 918    * @throws NullPointerException
 919    * If <code>bean</code> is <code>null</code>.
 920    * @throws AttributeException
 921    * Some possible reasons:
 922    * <UL>
 923    * <LI><CODE>name == null</CODE></LI>
 924    * </UL>
 925    * (analyze exception parameters).
 926    */
 927  24 protected static Method getBeanPropertyReadMethod( Object bean
 928    , String name
 929    )
 930    {
 931  24 if( name == null )
 932    {
 933  1 throw new AttributeException( bean, name );
 934    }
 935  23 PropertyDescriptor pd
 936    = (PropertyDescriptor)
 937    getBeanClassPropertyDescriptors( bean.getClass() )
 938    .get( name );
 939   
 940  23 return pd != null ? pd.getReadMethod() : null;
 941    }
 942   
 943    /**
 944    * Returns write method for the specified property of the specified bean.
 945    * @param bean Object to get write method from.
 946    * @param name Property name.
 947    * @return Write method or <code>null</code> if object has
 948    * no property with such name.
 949    * @throws NullPointerException
 950    * If <code>bean</code> is <code>null</code>.
 951    * @throws AttributeException
 952    * Some possible reasons:
 953    * <UL>
 954    * <LI><CODE>name == null</CODE></LI>
 955    * </UL>
 956    * (analyze exception parameters).
 957    */
 958  6 protected static Method getBeanPropertyWriteMethod( Object bean
 959    , String name
 960    )
 961    {
 962  6 if( name == null )
 963    {
 964  0 throw new AttributeException( bean, name );
 965    }
 966  6 PropertyDescriptor pd
 967    = (PropertyDescriptor)
 968    getBeanClassPropertyDescriptors( bean.getClass() )
 969    .get( name );
 970   
 971  6 return pd != null ? pd.getWriteMethod() : null;
 972    }
 973   
 974    private static Class[] set_type = new Class[1];
 975   
 976    private static Object[] get_par = new Object[0];
 977    private static Object[] set_par = new Object[1];
 978   
 979    private static Map/*Class,Map(String,PropertyDescriptor)*/
 980    class_to_properties_descriptor
 981    = new HashMap/*Class,Map(String,PropertyDescriptor)*/();
 982    }