< prev index next >

core/JemmyCore/src/org/jemmy/control/Wrap.java

Print this page




  36 import org.jemmy.env.TestOut;
  37 import org.jemmy.env.Timeout;
  38 import org.jemmy.image.Image;
  39 import org.jemmy.interfaces.*;
  40 import org.jemmy.timing.State;
  41 
  42 /**
  43  * This is a wrap which holds reference to a control without UI hierarchy. It
  44  * also encapsulates all the logic to deal with the underlying control, in terms
  45  * of implementations of ControlInterface.
  46  *
  47  * @see Wrap#as(java.lang.Class)
  48  * @see Wrap#is(java.lang.Class)
  49  * @param <CONTROL> type of the encapsulated object.
  50  * @author shura, erikgreijus
  51  */
  52 @ControlType(Object.class)
  53 @ControlInterfaces({Mouse.class, Keyboard.class, Drag.class})
  54 public abstract class Wrap<CONTROL extends Object> {
  55 
  56     /**
  57      *
  58      */
  59     public static final String BOUNDS_PROP_NAME = "bounds";
  60     /**
  61      *
  62      */
  63     public static final String CLICKPOINT_PROP_NAME = "clickPoint";
  64     /**
  65      *
  66      */
  67     public static final String CONTROL_CLASS_PROP_NAME = "control.class";
  68     /**
  69      *
  70      */
  71     public static final String CONTROL_PROP_NAME = "control";
  72     /**
  73      *
  74      */
  75     public static final String INPUT_FACTORY_PROPERTY = "input.control.interface.factory";
  76     /**
  77      *
  78      */
  79     public static final String IMAGE_LOADER_PROPERTY = "image.loader";
  80     /**
  81      *
  82      */
  83     public static final String IMAGE_CAPTURER_PROPERTY = "image.capturer";
  84     /**
  85      *
  86      */
  87     public static final String TEXT_PROP_NAME = "text";
  88     /**
  89      *
  90      */
  91     public static final String POSITION_PROP_NAME = "position";
  92     /**
  93      *
  94      */
  95     public static final String VALUE_PROP_NAME = "value";
  96     /**
  97      *
  98      */
  99     public static final String WRAPPER_CLASS_PROP_NAME = "wrapper.class";
 100     /**
 101      *
 102      */
 103     public static final String TOOLTIP_PROP_NAME = "tooltip";
 104     /**
 105      *
 106      */
 107     public static final String NAME_PROP_NAME = "name";
 108     /**
 109      *
 110      */
 111     public static final Timeout WAIT_STATE_TIMEOUT = new Timeout("wait.state", 1000);
 112     /**
 113      *
 114      */
 115     public static final String OUTPUT = Wrap.class.getName() + ".OUTPUT";
 116     private static DefaultWrapper theWrapper = new DefaultWrapper(Environment.getEnvironment());
 117 
 118     static {
 119         Environment.getEnvironment().initTimeout(WAIT_STATE_TIMEOUT);
 120         Environment.getEnvironment().initOutput(OUTPUT, TestOut.getNullOutput());
 121         Environment.getEnvironment().initTimeout(Mouse.CLICK);
 122         Environment.getEnvironment().initTimeout(Drag.BEFORE_DRAG_TIMEOUT);
 123         Environment.getEnvironment().initTimeout(Drag.BEFORE_DROP_TIMEOUT);
 124         Environment.getEnvironment().initTimeout(Drag.IN_DRAG_TIMEOUT);
 125         Environment.getEnvironment().initTimeout(Keyboard.PUSH);
 126     }
 127 
 128     /**
 129      *
 130      * @return
 131      */
 132     public static DefaultWrapper getWrapper() {
 133         return theWrapper;
 134     }
 135     CONTROL node;
 136     Environment env;
 137 
 138     /**
 139      * Fur null source.
 140      *
 141      * @see org.jemmy.env.Environment
 142      * @param env The environment
 143      */
 144     protected Wrap(Environment env) {
 145         this.env = env;
 146         node = null;
 147         fillTheProps(false);
 148     }
 149 
 150     /**
 151      *


 167         return env;
 168     }
 169 
 170     public void setEnvironment(Environment env) {
 171         this.env = env;
 172     }
 173 
 174     /**
 175      *
 176      * @return The encapsulated object
 177      */
 178     @Property(CONTROL_PROP_NAME)
 179     public CONTROL getControl() {
 180         return node;
 181     }
 182 
 183     /**
 184      * Return default point to click, drag. This implementation returns the
 185      * center must be overriden if something different is desired.
 186      *
 187      * @return
 188      */
 189     @Property(CLICKPOINT_PROP_NAME)
 190     public Point getClickPoint() {
 191         return new Point(getScreenBounds().width / 2, (getScreenBounds().height / 2));
 192     }
 193 
 194     /**
 195      * Returns control bounds in screen coordinates. These bounds could include
 196      * parts that are covered by other controls or clipped out by parent
 197      * components. If the control is not shown {@linkplain
 198      * JemmyException JemmyException} will be thrown.
 199      *
 200      * @return control bounds in screen coordinates.
 201      * @throws JemmyException if the control is not visible
 202      */
 203     @Property(BOUNDS_PROP_NAME)
 204     public abstract Rectangle getScreenBounds();
 205 
 206     /**
 207      * Transforms point in local control coordinate system to screen
 208      * coordinates.
 209      *
 210      * @param local
 211      * @return
 212      * @see #toLocal(org.jemmy.Point)
 213      */
 214     public Point toAbsolute(Point local) {
 215         Rectangle bounds = getScreenBounds();
 216         return local.translate(bounds.x, bounds.y);
 217     }
 218 
 219     /**
 220      * Transforms point in screen coordinates to local control coordinate
 221      * system.
 222      *
 223      * @param local
 224      * @return coordinates which should be used for mouse operations.
 225      * @see #toAbsolute(org.jemmy.Point)
 226      */
 227     public Point toLocal(Point local) {
 228         Rectangle bounds = getScreenBounds();
 229         return local.translate(-bounds.x, -bounds.y);
 230     }
 231 
 232     /**
 233      * Captures the screen area held by the component. ImageFactory performs the
 234      * actual capturing.
 235      *
 236      * @return TODO find a replacement
 237      */
 238     public Image getScreenImage() {
 239         Rectangle bounds = getScreenBounds();
 240         return getScreenImage(new Rectangle(0, 0, bounds.width, bounds.height));
 241     }
 242 
 243     /**
 244      * Captures portion of the screen area held by the component. ImageFactory
 245      * performs the actual capturing.
 246      *
 247      * @param rect Part of the control to capture
 248      * @return TODO find a replacement
 249      */
 250     public Image getScreenImage(Rectangle rect) {
 251         if (getEnvironment().getImageCapturer() == null) {
 252             throw new JemmyException("Image capturer is not specified.");
 253         }
 254         return getEnvironment().getImageCapturer().capture(this, rect);
 255     }
 256 
 257     /**
 258      * Waits for a portion of image to be exact the same as the parameter.
 259      *
 260      * @see Wrap#as(java.lang.Class)
 261      * @param golden
 262      * @param rect A portion of control to compare.
 263      * @param resID ID of a result image to save in case of failure. No image
 264      * saved if null.
 265      * @param diffID ID of a diff image to save in case of failure. No image
 266      * saved if null.
 267      */
 268     public void waitImage(final Image golden, final Rectangle rect, String resID, String diffID) {
 269         try {
 270             waitState(new State<Object>() {
 271 
 272                 public Object reached() {
 273                     return (getScreenImage(rect).compareTo(golden) == null) ? true : null;
 274                 }
 275 
 276                 @Override
 277                 public String toString() {
 278                     return "Control having expected image";
 279                 }
 280             });
 281         } catch (TimeoutExpiredException e) {
 282             if (diffID != null) {
 283                 getEnvironment().getOutput(OUTPUT).println("Saving difference to " + diffID);
 284                 getScreenImage(rect).compareTo(golden).save(diffID);
 285             }
 286             throw e;
 287         } finally {
 288             if (resID != null) {
 289                 getEnvironment().getOutput(OUTPUT).println("Saving result to " + resID);
 290                 getScreenImage(rect).save(resID);
 291             }
 292         }
 293     }
 294 
 295     /**
 296      * Waits for image to be exact the same as the parameter.
 297      *
 298      * @see Wrap#as(java.lang.Class)
 299      * @param golden
 300      * @param resID ID of a result image to save in case of failure. No image
 301      * saved if null.
 302      * @param diffID ID of a diff image to save in case of failure. No image
 303      * saved if null.
 304      */
 305     public void waitImage(final Image golden, String resID, String diffID) {
 306         Rectangle bounds = getScreenBounds();
 307         waitImage(golden, new Rectangle(0, 0, bounds.width, bounds.height), resID, diffID);
 308     }
 309 
 310     /**
 311      * TODO javadoc
 312      *
 313      * @param <V>
 314      * @param state
 315      * @param value
 316      * @return last returned State value
 317      * @throws TimeoutExpiredException in case the wait is unsuccessful.
 318      */
 319     public <V> V waitState(State<V> state, V value) {
 320         return getEnvironment().getWaiter(WAIT_STATE_TIMEOUT).ensureValue(value, state);
 321     }
 322 
 323     /**
 324      * TODO javadoc
 325      *
 326      * @param <V>
 327      * @param state
 328      * @return last returned State value
 329      * @throws TimeoutExpiredException in case the wait is unsuccessful.
 330      */
 331     public <V> V waitState(State<V> state) {
 332         return getEnvironment().getWaiter(WAIT_STATE_TIMEOUT).ensureState(state);
 333     }
 334 
 335     /**
 336      * ***********************************************************************
 337      */
 338     /*
 339      * INTERFACES
 340      */
 341     /**
 342      * ***********************************************************************
 343      */
 344     private Method findAsMethod(Class<? extends ControlInterface> interfaceClass, Class type) {
 345         while (type != null) {
 346             for (Method m : getClass().getMethods()) {
 347                 As as = m.getAnnotation(As.class);


 353                     }
 354                     return m;
 355                 }
 356             }
 357             type = type.getSuperclass();
 358         }
 359         return null;
 360     }
 361 
 362     /**
 363      * Checks if the control could be treated as a ControlInterface. If it is,
 364      * <code>Wrap#as(java.lang.Class)</code> will be called. This implementation
 365      * checks whether the class implements the necessary interface. It also
 366      * works for root interfaces such as
 367      * <code>MouseTarget</code> and
 368      * <code>KeyTarget</code>, which implementations are encapsulated. If some
 369      * other functionality is desired, must be overriden together with
 370      * <code>as(java.lang.Class)</code>
 371      *
 372      * @see Wrap#is(java.lang.Class)
 373      * @param <INTERFACE>
 374      * @param interfaceClass
 375      * @return

 376      */
 377     public <INTERFACE extends ControlInterface> boolean is(Class<INTERFACE> interfaceClass) {
 378         if (interfaceClass.isInstance(this)) {
 379             return true;
 380         }
 381         return findAsMethod(interfaceClass, Void.class) != null;
 382     }
 383 
 384     /**
 385      * Checks if the control could be treated as a parametrized
 386      * ControlInterface. If it is,
 387      * <code>Wrap#as(java.lang.Class, java.lang.Class)</code> will be called.
 388      * This implementation checks whether the class implements the necessary
 389      * interface. It also works for root interfaces such as
 390      * <code>MouseTarget</code> and
 391      * <code>KeyTarget</code>, which implementations are encapsulated. If some
 392      * other functionality is desired, must be overriden together with
 393      * <code>as(java.lang.Class)</code>
 394      *
 395      * @see Wrap#is(java.lang.Class)
 396      * @param <TYPE>
 397      * @param <INTERFACE>
 398      * @param interfaceClass
 399      * @param type The parameter class.
 400      * @return

 401      */
 402     public <TYPE, INTERFACE extends TypeControlInterface<TYPE>> boolean is(Class<INTERFACE> interfaceClass, Class<TYPE> type) {
 403         if (interfaceClass.isInstance(this)) {
 404             if (interfaceClass.cast(this).getType().isAssignableFrom(type)) {
 405                 return true;
 406             }
 407         }
 408         return findAsMethod(interfaceClass, type) != null;
 409     }
 410 
 411     private Object callAsMethod(Class<? extends ControlInterface> interfaceClass, Class type) {
 412         Method m = findAsMethod(interfaceClass, type);
 413         if (m != null) {
 414             try {
 415                 if (m.getParameterTypes().length == 0) {
 416                     return m.invoke(this);
 417                 } else if (m.getParameterTypes().length == 1) {
 418                     return m.invoke(this, !type.equals(Void.class) ? type : Object.class);
 419                 } else {
 420                     throw new InterfaceException(this, interfaceClass);
 421                 }
 422             } catch (IllegalAccessException ex) {
 423                 throw new JemmyException("Unable to call method \"" + m.getName() + "()\"", ex, this);
 424             } catch (IllegalArgumentException ex) {
 425                 throw new JemmyException("Unable to call method \"" + m.getName() + "()\"", ex, this);
 426             } catch (InvocationTargetException ex) {
 427                 throw new JemmyException("Unable to call method \"" + m.getName() + "()\"", ex, this);
 428             }
 429         }
 430         return null;
 431     }
 432 
 433     /**
 434      * Returns an implementation of interface associated with this object. First
 435      * it checks
 436      *
 437      * @see Wrap#is(java.lang.Class)
 438      * @param <INTERFACE>
 439      * @param interfaceClass
 440      * @return
 441      */
 442     public <INTERFACE extends ControlInterface> INTERFACE as(Class<INTERFACE> interfaceClass) {
 443         if (interfaceClass.isInstance(this)) {
 444             return interfaceClass.cast(this);
 445         }
 446 
 447         Object res = callAsMethod(interfaceClass, Void.class);
 448         if (res != null) {
 449             return (INTERFACE) res;
 450         }
 451 
 452         throw new InterfaceException(this, interfaceClass);
 453     }
 454 
 455     /**
 456      * Returns an implementation of interface associated with the object.
 457      *
 458      * @see Wrap#is(java.lang.Class)
 459      * @param <TYPE>
 460      * @param <INTERFACE>
 461      * @param interfaceClass
 462      * @param type The parameter class.
 463      * @return
 464      */
 465     public <TYPE, INTERFACE extends TypeControlInterface<TYPE>> INTERFACE as(Class<INTERFACE> interfaceClass, Class<TYPE> type) {
 466         if (interfaceClass.isInstance(this)) {
 467             if (interfaceClass.cast(this).getType().isAssignableFrom(type)) {
 468                 return interfaceClass.cast(this);
 469             }
 470         }
 471 
 472         Object res = callAsMethod(interfaceClass, type);
 473         if (res != null) {
 474             return (INTERFACE) res;
 475         }
 476 
 477         throw new InterfaceException(this, interfaceClass);
 478     }
 479     /**
 480      * ***********************************************************************
 481      */
 482     /*
 483      * INPUT
 484      */
 485     /**
 486      * ***********************************************************************
 487      */
 488     private Mouse mouse = null;
 489     private Drag drag = null;
 490     private Keyboard keyboard = null;
 491 
 492     /**
 493      * A shortcut to
 494      * <code>as(MouseTarget.class).mouse()</code>
 495      *
 496      * @return
 497      */
 498     @As(Mouse.class)
 499     public Mouse mouse() {
 500         if (mouse == null) {
 501             mouse = getEnvironment().getInputFactory().create(this, Mouse.class);
 502         }
 503         return mouse;
 504     }
 505 
 506     /**
 507      * A shortcut to
 508      * <code>as(MouseTarget.class).drag()</code>
 509      *
 510      * @return
 511      */
 512     @As(Drag.class)
 513     public Drag drag() {
 514         if (drag == null) {
 515             drag = getEnvironment().getInputFactory().create(this, Drag.class);
 516         }
 517         return drag;
 518     }
 519 
 520     /**
 521      * A shortcut to
 522      * <code>as(KeyTarget.class).wrap()</code>
 523      *
 524      * @return
 525      */
 526     @As(Keyboard.class)
 527     public Keyboard keyboard() {
 528         if (keyboard == null) {
 529             keyboard = getEnvironment().getInputFactory().create(this, Keyboard.class);
 530         }
 531         return keyboard;
 532     }
 533     /**
 534      * ***********************************************************************
 535      */
 536     /*
 537      * PROPERTIES
 538      */
 539     /**
 540      * ***********************************************************************
 541      */
 542     private HashMap<String, Object> properties = new HashMap<String, Object>();
 543 
 544     /**
 545      *
 546      * @return
 547      */
 548     @Property(CONTROL_CLASS_PROP_NAME)
 549     public Class<?> getControlClass() {
 550         return getControl().getClass();
 551     }
 552 
 553     private void fillTheProps(boolean quiet) {
 554         properties.clear();
 555         properties.put(WRAPPER_CLASS_PROP_NAME, getClass());
 556         readAnnotationProps(quiet);
 557         readControlProps(quiet);
 558     }
 559 
 560     private void readControlProps(boolean quiet) {
 561         Class<?> cls = getClass();
 562         do {
 563             if (cls.isAnnotationPresent(FieldProperties.class)) {
 564                 for (String s : cls.getAnnotation(FieldProperties.class).value()) {
 565                     Object value;
 566                     try {
 567                         value = getFieldProperty(s);


 650                 }
 651             }
 652         }
 653         return null;
 654     }
 655 
 656     private Object getProperty(Object object, Method m) {
 657         Property prop = m.getAnnotation(Property.class);
 658         try {
 659             return m.invoke(object);
 660         } catch (IllegalAccessException ex) {
 661             throw new JemmyException("Unable to obtain property \"" + ((prop != null) ? prop.value() : "null") + "\"", ex, this);
 662         } catch (IllegalArgumentException ex) {
 663             throw new JemmyException("Unable to obtain property \"" + ((prop != null) ? prop.value() : "null") + "\"", ex, this);
 664         } catch (InvocationTargetException ex) {
 665             throw new JemmyException("Unable to obtain property \"" + ((prop != null) ? prop.value() : "null") + "\"", ex, this);
 666         }
 667     }
 668 
 669     /**
 670      * Get property of the wrapped object. Uses first available from <nl>
 671      * <li>methods annotated by
 672      * <code>org.jemmy.control.Property</code></li> <li>wrapped object methods
 673      * listed in
 674      * <code>org.jemmy.control.MethodProperties</code></li> <li>wrapped object
 675      * fields listed in
 676      * <code>org.jemmy.control.FieldProperties</code></li> </nl>
 677      *
 678      * @param name property name
 679      * @throws JemmyException if no property found
 680      * @see Property
 681      * @see MethodProperties
 682      * @see FieldProperties
 683      * @return property value
 684      */
 685     public Object getProperty(String name) {
 686         if (WRAPPER_CLASS_PROP_NAME.equals(name)) {
 687             return getClass();
 688         }
 689         Method m = getPropertyMethod(this.getClass(), name);
 690         if (m != null) {
 691             return getProperty(this, m);
 692         }
 693         if (hasMethodProperty(name)) {
 694             return getMethodProperty(name);
 695         }
 696         if (hasFieldProperty(name)) {
 697             return getFieldProperty(name);
 698         }
 699         throw new JemmyException("No property \"" + name + "\"", this);
 700     }
 701 
 702     private Object getInterfaceProperty(Class cls, Object instance, String name) {
 703         Method m = getPropertyMethod(cls, name);
 704         if (m != null) {
 705             return getProperty(instance, m);
 706         }
 707         throw new JemmyException("No property \"" + name + "\" in interface " + cls.getName(), instance);
 708     }
 709 
 710     /**
 711      * Get property out of the control interface. Refer to the interface doc to
 712      * find out what properties are provided.
 713      *
 714      * @param <INTERFACE>
 715      * @param name
 716      * @param intrfc
 717      * @return
 718      */
 719     public <INTERFACE extends ControlInterface> Object getProperty(String name, Class<INTERFACE> intrfc) {
 720         return getInterfaceProperty(intrfc, as(intrfc), name);
 721     }
 722 
 723     /**
 724      * Get property out of the control interface. Refer to the interface doc to
 725      * find out what properties are provided.
 726      *
 727      * @param <TYPE>
 728      * @param <INTERFACE>
 729      * @param name
 730      * @param intrfc
 731      * @param type
 732      * @return
 733      */
 734     public <TYPE, INTERFACE extends TypeControlInterface<TYPE>> Object getProperty(String name, Class<INTERFACE> intrfc, Class<TYPE> type) {
 735         return getInterfaceProperty(intrfc, as(intrfc, type), name);
 736     }
 737 
 738     /**
 739      * Wait for the property
 740      * <code>property</code> to get the specified value.
 741      * <code>WAIT_STATE_TIMOUT</code> timeout is used
 742      *
 743      * @param property name of the property being waited for
 744      * @param value property value to wait
 745      */
 746     public void waitProperty(final String property, final Object value) {
 747         getEnvironment().getWaiter(WAIT_STATE_TIMEOUT).ensureValue(value, new State<Object>() {
 748 
 749             public Object reached() {
 750                 return getProperty(property);
 751             }
 752 
 753             @Override
 754             public String toString() {
 755                 return "Control having property " + property + " expected value '" + value + "' (Property = '" + getProperty(property) + "')";
 756             }
 757         });
 758     }
 759 
 760     /**
 761      * Wait for the property
 762      * <code>property</code> of control interface to get the specified value.
 763      * <code>WAIT_STATE_TIMOUT</code> timeout is used
 764      *
 765      * @param <INTERFACE>
 766      * @param property
 767      * @param intrfc
 768      * @param value
 769      */
 770     public <INTERFACE extends ControlInterface> void waitProperty(final String property, final Class<INTERFACE> intrfc, final Object value) {
 771         Object instance = as(intrfc);
 772         getEnvironment().getWaiter(WAIT_STATE_TIMEOUT).ensureValue(value, new State<Object>() {
 773 
 774             public Object reached() {
 775                 return getProperty(property, intrfc);
 776             }
 777 
 778             @Override
 779             public String toString() {
 780                 return "Interface " + intrfc.getName() + " having property " + property + " expected value '" + value + "' (Property = '" + getProperty(property, intrfc) + "')";
 781             }
 782         });
 783     }
 784 
 785     /**
 786      * Wait for the property
 787      * <code>property</code> of control interface to get the specified value.
 788      * <code>WAIT_STATE_TIMOUT</code> timeout is used
 789      *
 790      * @param <TYPE>
 791      * @param <INTERFACE>
 792      * @param property
 793      * @param intrfc
 794      * @param type
 795      * @param value
 796      */
 797     public <TYPE, INTERFACE extends TypeControlInterface<TYPE>> void waitProperty(final String property, final Class<INTERFACE> intrfc, final Class<TYPE> type, final Object value) {
 798         getEnvironment().getWaiter(WAIT_STATE_TIMEOUT).ensureValue(value, new State<Object>() {
 799 
 800             public Object reached() {
 801                 return getProperty(property, intrfc, type);
 802             }
 803 
 804             @Override
 805             public String toString() {
 806                 return "Interface " + intrfc.getName() + " having property " + property + " expected value '" + value + "' (Property = '" + getProperty(property) + "')";
 807             }
 808         });
 809     }
 810 
 811     /**
 812      *
 813      * @param name
 814      * @return
 815      */
 816     public boolean hasFieldProperty(String name) {
 817         Class<?> cls = getClass();
 818         do {
 819             if (cls.isAnnotationPresent(FieldProperties.class)) {
 820                 FieldProperties props = cls.getAnnotation(FieldProperties.class);
 821                 if (contains(props.value(), name)) {
 822                     return true;
 823                 }
 824             }
 825         } while ((cls = cls.getSuperclass()) != null);
 826         return false;
 827     }
 828 
 829     /**
 830      *
 831      * @param name
 832      * @return
 833      */
 834     public boolean hasMethodProperty(String name) {
 835         Class<?> cls = getClass();
 836         do {
 837             if (cls.isAnnotationPresent(MethodProperties.class)) {
 838                 MethodProperties props = cls.getAnnotation(MethodProperties.class);
 839                 if (contains(props.value(), name)) {
 840                     return true;
 841                 }
 842             }
 843         } while ((cls = cls.getSuperclass()) != null);
 844         return false;
 845     }
 846 
 847     private boolean contains(String[] values, String name) {
 848         for (int i = 0; i < values.length; i++) {
 849             if (name.equals(values[i])) {
 850                 return true;
 851             }
 852 
 853         }
 854         return false;
 855     }
 856 
 857     /**
 858      *
 859      * @param name
 860      * @return
 861      */
 862     public Object getFieldProperty(final String name) {
 863         if (!hasFieldProperty(name)) {
 864             throw new JemmyException("No \"" + name + "\" field property specified on " + getClass().getName());
 865         }
 866         GetAction action = new GetAction() {
 867 
 868             @Override
 869             public void run(Object... parameters) throws Exception {
 870                 setResult(getControl().getClass().getField(name).get(getControl()));
 871             }
 872         };
 873         Object result = action.dispatch(env);
 874         if (action.getThrowable() != null) {
 875             throw new JemmyException("Unable to obtain property \"" + name + "\"", action.getThrowable(), this);
 876         }
 877         return result;
 878     }
 879 
 880     /**
 881      *
 882      * @param name
 883      * @return
 884      */
 885     public Object getMethodProperty(final String name) {
 886         if (!hasMethodProperty(name)) {
 887             throw new JemmyException("No \"" + name + "\" method property specified on " + getClass().getName());
 888         }
 889         GetAction action = new GetAction() {
 890 
 891             @Override
 892             public void run(Object... parameters) throws Exception {
 893                 setResult(getControl().getClass().getMethod(name).invoke(getControl()));
 894             }
 895 
 896             @Override
 897             public String toString() {
 898                 return "Getting property \"" + name + "\" on " + getClass().getName();
 899             }
 900         };
 901         Object result = action.dispatch(env);
 902         if (action.getThrowable() != null) {
 903             throw new JemmyException("Unable to obtain property \"" + name + "\"", action.getThrowable(), this);
 904         }
 905         return result;
 906     }
 907 
 908     /**
 909      *
 910      * @param <P>
 911      * @param valueClass
 912      * @param name
 913      * @return
 914      */
 915     public <P> P getProperty(Class<P> valueClass, String name) {
 916         return valueClass.cast(getProperty(name));
 917     }
 918 
 919     /**
 920      * Returns a a map of all known controls properties including values from
 921      * methods marked by
 922      * <code>@Property</code> and values of methods/field from
 923      * <code>@MethodProperties</code>/
 924      * <code>FieldProperties</code> correspondingly.
 925      *
 926      * @return a map of properties
 927      * @throws Runtime exception should there be an exception thrown while
 928      * getting a property
 929      */
 930     public HashMap<String, Object> getProperties() {
 931         fillTheProps(false);
 932         return properties;
 933     }
 934 
 935     /**
 936      * Returns a a map of all controls properties which is possible to obtain.
 937      * Similar to
 938      * <code>getProperties()</code> only exception is swallowed should there be
 939      * an exception thrown while getting a property.
 940      *
 941      * @return a map of properties which were possible to obtain.
 942      */
 943     public HashMap<String, Object> getPropertiesQiuet() {
 944         fillTheProps(true);
 945         return properties;
 946     }
 947 }


  36 import org.jemmy.env.TestOut;
  37 import org.jemmy.env.Timeout;
  38 import org.jemmy.image.Image;
  39 import org.jemmy.interfaces.*;
  40 import org.jemmy.timing.State;
  41 
  42 /**
  43  * This is a wrap which holds reference to a control without UI hierarchy. It
  44  * also encapsulates all the logic to deal with the underlying control, in terms
  45  * of implementations of ControlInterface.
  46  *
  47  * @see Wrap#as(java.lang.Class)
  48  * @see Wrap#is(java.lang.Class)
  49  * @param <CONTROL> type of the encapsulated object.
  50  * @author shura, erikgreijus
  51  */
  52 @ControlType(Object.class)
  53 @ControlInterfaces({Mouse.class, Keyboard.class, Drag.class})
  54 public abstract class Wrap<CONTROL extends Object> {
  55 



  56     public static final String BOUNDS_PROP_NAME = "bounds";



  57     public static final String CLICKPOINT_PROP_NAME = "clickPoint";



  58     public static final String CONTROL_CLASS_PROP_NAME = "control.class";



  59     public static final String CONTROL_PROP_NAME = "control";



  60     public static final String INPUT_FACTORY_PROPERTY = "input.control.interface.factory";



  61     public static final String IMAGE_LOADER_PROPERTY = "image.loader";



  62     public static final String IMAGE_CAPTURER_PROPERTY = "image.capturer";



  63     public static final String TEXT_PROP_NAME = "text";



  64     public static final String POSITION_PROP_NAME = "position";



  65     public static final String VALUE_PROP_NAME = "value";



  66     public static final String WRAPPER_CLASS_PROP_NAME = "wrapper.class";



  67     public static final String TOOLTIP_PROP_NAME = "tooltip";



  68     public static final String NAME_PROP_NAME = "name";



  69     public static final Timeout WAIT_STATE_TIMEOUT = new Timeout("wait.state", 1000);
  70 


  71     public static final String OUTPUT = Wrap.class.getName() + ".OUTPUT";
  72     private static DefaultWrapper theWrapper = new DefaultWrapper(Environment.getEnvironment());
  73 
  74     static {
  75         Environment.getEnvironment().initTimeout(WAIT_STATE_TIMEOUT);
  76         Environment.getEnvironment().initOutput(OUTPUT, TestOut.getNullOutput());
  77         Environment.getEnvironment().initTimeout(Mouse.CLICK);
  78         Environment.getEnvironment().initTimeout(Drag.BEFORE_DRAG_TIMEOUT);
  79         Environment.getEnvironment().initTimeout(Drag.BEFORE_DROP_TIMEOUT);
  80         Environment.getEnvironment().initTimeout(Drag.IN_DRAG_TIMEOUT);
  81         Environment.getEnvironment().initTimeout(Keyboard.PUSH);
  82     }
  83 




  84     public static DefaultWrapper getWrapper() {
  85         return theWrapper;
  86     }
  87     CONTROL node;
  88     Environment env;
  89 
  90     /**
  91      * Fur null source.
  92      *
  93      * @see org.jemmy.env.Environment
  94      * @param env The environment
  95      */
  96     protected Wrap(Environment env) {
  97         this.env = env;
  98         node = null;
  99         fillTheProps(false);
 100     }
 101 
 102     /**
 103      *


 119         return env;
 120     }
 121 
 122     public void setEnvironment(Environment env) {
 123         this.env = env;
 124     }
 125 
 126     /**
 127      *
 128      * @return The encapsulated object
 129      */
 130     @Property(CONTROL_PROP_NAME)
 131     public CONTROL getControl() {
 132         return node;
 133     }
 134 
 135     /**
 136      * Return default point to click, drag. This implementation returns the
 137      * center must be overriden if something different is desired.
 138      *
 139      * @return the default click point
 140      */
 141     @Property(CLICKPOINT_PROP_NAME)
 142     public Point getClickPoint() {
 143         return new Point(getScreenBounds().width / 2, (getScreenBounds().height / 2));
 144     }
 145 
 146     /**
 147      * Returns control bounds in screen coordinates. These bounds could include
 148      * parts that are covered by other controls or clipped out by parent
 149      * components. If the control is not shown {@linkplain
 150      * JemmyException JemmyException} will be thrown.
 151      *
 152      * @return control bounds in screen coordinates.
 153      * @throws JemmyException if the control is not visible
 154      */
 155     @Property(BOUNDS_PROP_NAME)
 156     public abstract Rectangle getScreenBounds();
 157 
 158     /**
 159      * Transforms point in local control coordinate system to screen
 160      * coordinates.
 161      *
 162      * @param local the local coordinate
 163      * @return a absolute translated point
 164      * @see #toLocal(org.jemmy.Point)
 165      */
 166     public Point toAbsolute(Point local) {
 167         Rectangle bounds = getScreenBounds();
 168         return local.translate(bounds.x, bounds.y);
 169     }
 170 
 171     /**
 172      * Transforms point in screen coordinates to local control coordinate
 173      * system.
 174      *
 175      * @param local the local coordinate
 176      * @return coordinates which should be used for mouse operations.
 177      * @see #toAbsolute(org.jemmy.Point)
 178      */
 179     public Point toLocal(Point local) {
 180         Rectangle bounds = getScreenBounds();
 181         return local.translate(-bounds.x, -bounds.y);
 182     }
 183 
 184     /**
 185      * Captures the screen area held by the component. ImageFactory performs the
 186      * actual capturing.
 187      *
 188      * @return TODO find a replacement
 189      */
 190     public Image getScreenImage() {
 191         Rectangle bounds = getScreenBounds();
 192         return getScreenImage(new Rectangle(0, 0, bounds.width, bounds.height));
 193     }
 194 
 195     /**
 196      * Captures portion of the screen area held by the component. ImageFactory
 197      * performs the actual capturing.
 198      *
 199      * @param rect Part of the control to capture
 200      * @return TODO find a replacement
 201      */
 202     public Image getScreenImage(Rectangle rect) {
 203         if (getEnvironment().getImageCapturer() == null) {
 204             throw new JemmyException("Image capturer is not specified.");
 205         }
 206         return getEnvironment().getImageCapturer().capture(this, rect);
 207     }
 208 
 209     /**
 210      * Waits for a portion of image to be exact the same as the parameter.
 211      *
 212      * @see Wrap#as(java.lang.Class)
 213      * @param golden the image to match against
 214      * @param rect A portion of control to compare.
 215      * @param resID ID of a result image to save in case of failure. No image
 216      * saved if null.
 217      * @param diffID ID of a diff image to save in case of failure. No image
 218      * saved if null.
 219      */
 220     public void waitImage(final Image golden, final Rectangle rect, String resID, String diffID) {
 221         try {
 222             waitState(new State<Object>() {
 223 
 224                 public Object reached() {
 225                     return (getScreenImage(rect).compareTo(golden) == null) ? true : null;
 226                 }
 227 
 228                 @Override
 229                 public String toString() {
 230                     return "Control having expected image";
 231                 }
 232             });
 233         } catch (TimeoutExpiredException e) {
 234             if (diffID != null) {
 235                 getEnvironment().getOutput(OUTPUT).println("Saving difference to " + diffID);
 236                 getScreenImage(rect).compareTo(golden).save(diffID);
 237             }
 238             throw e;
 239         } finally {
 240             if (resID != null) {
 241                 getEnvironment().getOutput(OUTPUT).println("Saving result to " + resID);
 242                 getScreenImage(rect).save(resID);
 243             }
 244         }
 245     }
 246 
 247     /**
 248      * Waits for image to be exact the same as the parameter.
 249      *
 250      * @see Wrap#as(java.lang.Class)
 251      * @param golden the image to match against
 252      * @param resID ID of a result image to save in case of failure. No image
 253      * saved if null.
 254      * @param diffID ID of a diff image to save in case of failure. No image
 255      * saved if null.
 256      */
 257     public void waitImage(final Image golden, String resID, String diffID) {
 258         Rectangle bounds = getScreenBounds();
 259         waitImage(golden, new Rectangle(0, 0, bounds.width, bounds.height), resID, diffID);
 260     }
 261 
 262     /**
 263      * TODO javadoc
 264      *
 265      * @param <V> the states type
 266      * @param state the state
 267      * @param value the state value
 268      * @return last returned State value
 269      * @throws TimeoutExpiredException in case the wait is unsuccessful.
 270      */
 271     public <V> V waitState(State<V> state, V value) {
 272         return getEnvironment().getWaiter(WAIT_STATE_TIMEOUT).ensureValue(value, state);
 273     }
 274 
 275     /**
 276      * @param <V> the states type
 277      * @param state the state


 278      * @return last returned State value
 279      * @throws TimeoutExpiredException in case the wait is unsuccessful.
 280      */
 281     public <V> V waitState(State<V> state) {
 282         return getEnvironment().getWaiter(WAIT_STATE_TIMEOUT).ensureState(state);
 283     }
 284 
 285     /**
 286      * ***********************************************************************
 287      */
 288     /*
 289      * INTERFACES
 290      */
 291     /**
 292      * ***********************************************************************
 293      */
 294     private Method findAsMethod(Class<? extends ControlInterface> interfaceClass, Class type) {
 295         while (type != null) {
 296             for (Method m : getClass().getMethods()) {
 297                 As as = m.getAnnotation(As.class);


 303                     }
 304                     return m;
 305                 }
 306             }
 307             type = type.getSuperclass();
 308         }
 309         return null;
 310     }
 311 
 312     /**
 313      * Checks if the control could be treated as a ControlInterface. If it is,
 314      * <code>Wrap#as(java.lang.Class)</code> will be called. This implementation
 315      * checks whether the class implements the necessary interface. It also
 316      * works for root interfaces such as
 317      * <code>MouseTarget</code> and
 318      * <code>KeyTarget</code>, which implementations are encapsulated. If some
 319      * other functionality is desired, must be overriden together with
 320      * <code>as(java.lang.Class)</code>
 321      *
 322      * @see Wrap#is(java.lang.Class)
 323      * @param <INTERFACE> the control interface
 324      * @param interfaceClass the interface class
 325      * @return <code>true</code> if the control is an ControlInterface, 
 326      *         <code>false</code> otherwise
 327      */
 328     public <INTERFACE extends ControlInterface> boolean is(Class<INTERFACE> interfaceClass) {
 329         if (interfaceClass.isInstance(this)) {
 330             return true;
 331         }
 332         return findAsMethod(interfaceClass, Void.class) != null;
 333     }
 334 
 335     /**
 336      * Checks if the control could be treated as a parametrized
 337      * ControlInterface. If it is,
 338      * <code>Wrap#as(java.lang.Class, java.lang.Class)</code> will be called.
 339      * This implementation checks whether the class implements the necessary
 340      * interface. It also works for root interfaces such as
 341      * <code>MouseTarget</code> and
 342      * <code>KeyTarget</code>, which implementations are encapsulated. If some
 343      * other functionality is desired, must be overriden together with
 344      * <code>as(java.lang.Class)</code>
 345      *
 346      * @see Wrap#is(java.lang.Class)
 347      * @param <TYPE> the type interface
 348      * @param <INTERFACE> the control interface
 349      * @param interfaceClass the interface class
 350      * @param type The parameter class.
 351      * @return <code>true</code> if the control is an ControlInterface, 
 352      *         <code>false</code> otherwise
 353      */
 354     public <TYPE, INTERFACE extends TypeControlInterface<TYPE>> boolean is(Class<INTERFACE> interfaceClass, Class<TYPE> type) {
 355         if (interfaceClass.isInstance(this)) {
 356             if (interfaceClass.cast(this).getType().isAssignableFrom(type)) {
 357                 return true;
 358             }
 359         }
 360         return findAsMethod(interfaceClass, type) != null;
 361     }
 362 
 363     private Object callAsMethod(Class<? extends ControlInterface> interfaceClass, Class type) {
 364         Method m = findAsMethod(interfaceClass, type);
 365         if (m != null) {
 366             try {
 367                 if (m.getParameterTypes().length == 0) {
 368                     return m.invoke(this);
 369                 } else if (m.getParameterTypes().length == 1) {
 370                     return m.invoke(this, !type.equals(Void.class) ? type : Object.class);
 371                 } else {
 372                     throw new InterfaceException(this, interfaceClass);
 373                 }
 374             } catch (IllegalAccessException ex) {
 375                 throw new JemmyException("Unable to call method \"" + m.getName() + "()\"", ex, this);
 376             } catch (IllegalArgumentException ex) {
 377                 throw new JemmyException("Unable to call method \"" + m.getName() + "()\"", ex, this);
 378             } catch (InvocationTargetException ex) {
 379                 throw new JemmyException("Unable to call method \"" + m.getName() + "()\"", ex, this);
 380             }
 381         }
 382         return null;
 383     }
 384 
 385     /**
 386      * Returns an implementation of interface associated with this object. First
 387      * it checks
 388      *
 389      * @see Wrap#is(java.lang.Class)
 390      * @param <INTERFACE> the control interface
 391      * @param interfaceClass the interface class
 392      * @return the control interface instance
 393      */
 394     public <INTERFACE extends ControlInterface> INTERFACE as(Class<INTERFACE> interfaceClass) {
 395         if (interfaceClass.isInstance(this)) {
 396             return interfaceClass.cast(this);
 397         }
 398 
 399         Object res = callAsMethod(interfaceClass, Void.class);
 400         if (res != null) {
 401             return (INTERFACE) res;
 402         }
 403 
 404         throw new InterfaceException(this, interfaceClass);
 405     }
 406 
 407     /**
 408      * Returns an implementation of interface associated with the object.
 409      *
 410      * @see Wrap#is(java.lang.Class)
 411      * @param <TYPE> the type interface
 412      * @param <INTERFACE> the control interface
 413      * @param interfaceClass the interface class
 414      * @param type The parameter class.
 415      * @return the type control instance
 416      */
 417     public <TYPE, INTERFACE extends TypeControlInterface<TYPE>> INTERFACE as(Class<INTERFACE> interfaceClass, Class<TYPE> type) {
 418         if (interfaceClass.isInstance(this)) {
 419             if (interfaceClass.cast(this).getType().isAssignableFrom(type)) {
 420                 return interfaceClass.cast(this);
 421             }
 422         }
 423 
 424         Object res = callAsMethod(interfaceClass, type);
 425         if (res != null) {
 426             return (INTERFACE) res;
 427         }
 428 
 429         throw new InterfaceException(this, interfaceClass);
 430     }
 431     /**
 432      * ***********************************************************************
 433      */
 434     /*
 435      * INPUT
 436      */
 437     /**
 438      * ***********************************************************************
 439      */
 440     private Mouse mouse = null;
 441     private Drag drag = null;
 442     private Keyboard keyboard = null;
 443 
 444     /**
 445      * A shortcut to <code>as(MouseTarget.class).mouse()</code>

 446      *
 447      * @return the mouse target
 448      */
 449     @As(Mouse.class)
 450     public Mouse mouse() {
 451         if (mouse == null) {
 452             mouse = getEnvironment().getInputFactory().create(this, Mouse.class);
 453         }
 454         return mouse;
 455     }
 456 
 457     /**
 458      * A shortcut to <code>as(MouseTarget.class).drag()</code>

 459      *
 460      * @return the drag target
 461      */
 462     @As(Drag.class)
 463     public Drag drag() {
 464         if (drag == null) {
 465             drag = getEnvironment().getInputFactory().create(this, Drag.class);
 466         }
 467         return drag;
 468     }
 469 
 470     /**
 471      * A shortcut to <code>as(KeyTarget.class).wrap()</code>

 472      *
 473      * @return the wrap target
 474      */
 475     @As(Keyboard.class)
 476     public Keyboard keyboard() {
 477         if (keyboard == null) {
 478             keyboard = getEnvironment().getInputFactory().create(this, Keyboard.class);
 479         }
 480         return keyboard;
 481     }
 482     /**
 483      * ***********************************************************************
 484      */
 485     /*
 486      * PROPERTIES
 487      */
 488     /**
 489      * ***********************************************************************
 490      */
 491     private HashMap<String, Object> properties = new HashMap<String, Object>();
 492 




 493     @Property(CONTROL_CLASS_PROP_NAME)
 494     public Class<?> getControlClass() {
 495         return getControl().getClass();
 496     }
 497 
 498     private void fillTheProps(boolean quiet) {
 499         properties.clear();
 500         properties.put(WRAPPER_CLASS_PROP_NAME, getClass());
 501         readAnnotationProps(quiet);
 502         readControlProps(quiet);
 503     }
 504 
 505     private void readControlProps(boolean quiet) {
 506         Class<?> cls = getClass();
 507         do {
 508             if (cls.isAnnotationPresent(FieldProperties.class)) {
 509                 for (String s : cls.getAnnotation(FieldProperties.class).value()) {
 510                     Object value;
 511                     try {
 512                         value = getFieldProperty(s);


 595                 }
 596             }
 597         }
 598         return null;
 599     }
 600 
 601     private Object getProperty(Object object, Method m) {
 602         Property prop = m.getAnnotation(Property.class);
 603         try {
 604             return m.invoke(object);
 605         } catch (IllegalAccessException ex) {
 606             throw new JemmyException("Unable to obtain property \"" + ((prop != null) ? prop.value() : "null") + "\"", ex, this);
 607         } catch (IllegalArgumentException ex) {
 608             throw new JemmyException("Unable to obtain property \"" + ((prop != null) ? prop.value() : "null") + "\"", ex, this);
 609         } catch (InvocationTargetException ex) {
 610             throw new JemmyException("Unable to obtain property \"" + ((prop != null) ? prop.value() : "null") + "\"", ex, this);
 611         }
 612     }
 613 
 614     /**
 615      * Get property of the wrapped object. Uses first available from 
 616      * <ol>
 617      * <li>methods annotated by <code>org.jemmy.control.Property</code></li>
 618      * <li>wrapped object methods listed in <code>org.jemmy.control.MethodProperties</code></li>
 619      * <li>wrapped object fields listed in <code>org.jemmy.control.FieldProperties</code></li>
 620      * </ol>

 621      *
 622      * @param name property name
 623      * @throws JemmyException if no property found
 624      * @see Property
 625      * @see MethodProperties
 626      * @see FieldProperties
 627      * @return property value
 628      */
 629     public Object getProperty(String name) {
 630         if (WRAPPER_CLASS_PROP_NAME.equals(name)) {
 631             return getClass();
 632         }
 633         Method m = getPropertyMethod(this.getClass(), name);
 634         if (m != null) {
 635             return getProperty(this, m);
 636         }
 637         if (hasMethodProperty(name)) {
 638             return getMethodProperty(name);
 639         }
 640         if (hasFieldProperty(name)) {
 641             return getFieldProperty(name);
 642         }
 643         throw new JemmyException("No property \"" + name + "\"", this);
 644     }
 645 
 646     private Object getInterfaceProperty(Class cls, Object instance, String name) {
 647         Method m = getPropertyMethod(cls, name);
 648         if (m != null) {
 649             return getProperty(instance, m);
 650         }
 651         throw new JemmyException("No property \"" + name + "\" in interface " + cls.getName(), instance);
 652     }
 653 
 654     /**
 655      * Get property out of the control interface. Refer to the interface doc to
 656      * find out what properties are provided.
 657      *
 658      * @param <INTERFACE> the control interface
 659      * @param name the property name
 660      * @param intrfc the interface class
 661      * @return the control property
 662      */
 663     public <INTERFACE extends ControlInterface> Object getProperty(String name, Class<INTERFACE> intrfc) {
 664         return getInterfaceProperty(intrfc, as(intrfc), name);
 665     }
 666 
 667     /**
 668      * Get property out of the control interface. Refer to the interface doc to
 669      * find out what properties are provided.
 670      *
 671      * @param <TYPE> the type interface
 672      * @param <INTERFACE> the control interface
 673      * @param name the property name
 674      * @param intrfc the interface class
 675      * @param type The parameter class.
 676      * @return the control property
 677      */
 678     public <TYPE, INTERFACE extends TypeControlInterface<TYPE>> Object getProperty(String name, Class<INTERFACE> intrfc, Class<TYPE> type) {
 679         return getInterfaceProperty(intrfc, as(intrfc, type), name);
 680     }
 681 
 682     /**
 683      * Wait for the property
 684      * <code>property</code> to get the specified value.
 685      * <code>WAIT_STATE_TIMOUT</code> timeout is used
 686      *
 687      * @param property name of the property being waited for
 688      * @param value property value to wait
 689      */
 690     public void waitProperty(final String property, final Object value) {
 691         getEnvironment().getWaiter(WAIT_STATE_TIMEOUT).ensureValue(value, new State<Object>() {
 692 
 693             public Object reached() {
 694                 return getProperty(property);
 695             }
 696 
 697             @Override
 698             public String toString() {
 699                 return "Control having property " + property + " expected value '" + value + "' (Property = '" + getProperty(property) + "')";
 700             }
 701         });
 702     }
 703 
 704     /**
 705      * Wait for the property
 706      * <code>property</code> of control interface to get the specified value.
 707      * <code>WAIT_STATE_TIMOUT</code> timeout is used
 708      *
 709      * @param <INTERFACE> the control interface
 710      * @param property the property name
 711      * @param intrfc the interface class
 712      * @param value the new parameter value
 713      */
 714     public <INTERFACE extends ControlInterface> void waitProperty(final String property, final Class<INTERFACE> intrfc, final Object value) {
 715         Object instance = as(intrfc);
 716         getEnvironment().getWaiter(WAIT_STATE_TIMEOUT).ensureValue(value, new State<Object>() {
 717 
 718             public Object reached() {
 719                 return getProperty(property, intrfc);
 720             }
 721 
 722             @Override
 723             public String toString() {
 724                 return "Interface " + intrfc.getName() + " having property " + property + " expected value '" + value + "' (Property = '" + getProperty(property, intrfc) + "')";
 725             }
 726         });
 727     }
 728 
 729     /**
 730      * Wait for the property
 731      * <code>property</code> of control interface to get the specified value.
 732      * <code>WAIT_STATE_TIMOUT</code> timeout is used
 733      *
 734      * @param <TYPE> the type interface
 735      * @param <INTERFACE> the control interface
 736      * @param property the property name
 737      * @param intrfc the interface class
 738      * @param type the parameter class.
 739      * @param value the new parameter value
 740      */
 741     public <TYPE, INTERFACE extends TypeControlInterface<TYPE>> void waitProperty(final String property, final Class<INTERFACE> intrfc, final Class<TYPE> type, final Object value) {
 742         getEnvironment().getWaiter(WAIT_STATE_TIMEOUT).ensureValue(value, new State<Object>() {
 743 
 744             public Object reached() {
 745                 return getProperty(property, intrfc, type);
 746             }
 747 
 748             @Override
 749             public String toString() {
 750                 return "Interface " + intrfc.getName() + " having property " + property + " expected value '" + value + "' (Property = '" + getProperty(property) + "')";
 751             }
 752         });
 753     }
 754 





 755     public boolean hasFieldProperty(String name) {
 756         Class<?> cls = getClass();
 757         do {
 758             if (cls.isAnnotationPresent(FieldProperties.class)) {
 759                 FieldProperties props = cls.getAnnotation(FieldProperties.class);
 760                 if (contains(props.value(), name)) {
 761                     return true;
 762                 }
 763             }
 764         } while ((cls = cls.getSuperclass()) != null);
 765         return false;
 766     }
 767 





 768     public boolean hasMethodProperty(String name) {
 769         Class<?> cls = getClass();
 770         do {
 771             if (cls.isAnnotationPresent(MethodProperties.class)) {
 772                 MethodProperties props = cls.getAnnotation(MethodProperties.class);
 773                 if (contains(props.value(), name)) {
 774                     return true;
 775                 }
 776             }
 777         } while ((cls = cls.getSuperclass()) != null);
 778         return false;
 779     }
 780 
 781     private boolean contains(String[] values, String name) {
 782         for (int i = 0; i < values.length; i++) {
 783             if (name.equals(values[i])) {
 784                 return true;
 785             }
 786 
 787         }
 788         return false;
 789     }
 790 





 791     public Object getFieldProperty(final String name) {
 792         if (!hasFieldProperty(name)) {
 793             throw new JemmyException("No \"" + name + "\" field property specified on " + getClass().getName());
 794         }
 795         GetAction action = new GetAction() {
 796 
 797             @Override
 798             public void run(Object... parameters) throws Exception {
 799                 setResult(getControl().getClass().getField(name).get(getControl()));
 800             }
 801         };
 802         Object result = action.dispatch(env);
 803         if (action.getThrowable() != null) {
 804             throw new JemmyException("Unable to obtain property \"" + name + "\"", action.getThrowable(), this);
 805         }
 806         return result;
 807     }
 808 





 809     public Object getMethodProperty(final String name) {
 810         if (!hasMethodProperty(name)) {
 811             throw new JemmyException("No \"" + name + "\" method property specified on " + getClass().getName());
 812         }
 813         GetAction action = new GetAction() {
 814 
 815             @Override
 816             public void run(Object... parameters) throws Exception {
 817                 setResult(getControl().getClass().getMethod(name).invoke(getControl()));
 818             }
 819 
 820             @Override
 821             public String toString() {
 822                 return "Getting property \"" + name + "\" on " + getClass().getName();
 823             }
 824         };
 825         Object result = action.dispatch(env);
 826         if (action.getThrowable() != null) {
 827             throw new JemmyException("Unable to obtain property \"" + name + "\"", action.getThrowable(), this);
 828         }
 829         return result;
 830     }
 831 







 832     public <P> P getProperty(Class<P> valueClass, String name) {
 833         return valueClass.cast(getProperty(name));
 834     }
 835 
 836     /**
 837      * Returns a a map of all known controls properties including values from
 838      * methods marked by
 839      * <code>@Property</code> and values of methods/field from
 840      * <code>@MethodProperties</code>/
 841      * <code>FieldProperties</code> correspondingly.
 842      *
 843      * @return a map of properties
 844      * @throws RuntimeException should there be an exception thrown while
 845      * getting a property
 846      */
 847     public HashMap<String, Object> getProperties() {
 848         fillTheProps(false);
 849         return properties;
 850     }
 851 
 852     /**
 853      * Returns a a map of all controls properties which is possible to obtain.
 854      * Similar to
 855      * <code>getProperties()</code> only exception is swallowed should there be
 856      * an exception thrown while getting a property.
 857      *
 858      * @return a map of properties which were possible to obtain.
 859      */
 860     public HashMap<String, Object> getPropertiesQiuet() {
 861         fillTheProps(true);
 862         return properties;
 863     }
 864 }
< prev index next >