1 /*
   2  * Copyright (c) 2007, 2017 Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.jemmy.env;
  24 
  25 import java.io.File;
  26 import java.io.FileInputStream;
  27 import java.io.IOException;
  28 import java.util.ArrayList;
  29 import java.util.HashMap;
  30 import java.util.List;
  31 import java.util.Properties;
  32 import java.util.Set;
  33 import org.jemmy.JemmyException;
  34 import org.jemmy.action.ActionExecutor;
  35 import org.jemmy.action.DefaultExecutor;
  36 import org.jemmy.control.Wrap;
  37 import org.jemmy.image.ImageCapturer;
  38 import org.jemmy.image.ImageLoader;
  39 import org.jemmy.input.CharBindingMap;
  40 import org.jemmy.interfaces.ControlInterfaceFactory;
  41 import org.jemmy.timing.Waiter;
  42 
  43 /**
  44  *
  45  * @author shura, mrkam, erikgreijus
  46  */
  47 public class Environment {
  48 
  49     /**
  50      *
  51      */
  52     public static final String JEMMY_PROPERTIES_FILE_PROPERTY = "jemmy.properties";
  53     public static final String TIMEOUTS_FILE_PROPERTY = "timeouts";
  54     /**
  55      * Information output for Environment class
  56      */
  57     public static final String OUTPUT = Environment.class.getName() + ".OUTPUT";
  58     private final static Environment env = new Environment(null);
  59 
  60     /**
  61      *
  62      * @return
  63      */
  64     public static Environment getEnvironment() {
  65         return env;
  66     }
  67 
  68     static {
  69         env.setOutput(new TestOut(System.in, System.out, System.err));
  70         env.setExecutor(new DefaultExecutor());
  71     }
  72     private HashMap<PropertyKey, Object> environment = new HashMap<PropertyKey, Object>();
  73     private Environment parent;
  74 
  75     /**
  76      *
  77      * @param parent
  78      */
  79     public Environment(Environment parent) {
  80         this.parent = parent;
  81         environment = new HashMap<PropertyKey, Object>();
  82         if (parent == null) {
  83             loadProperties(System.getProperty(JEMMY_PROPERTIES_FILE_PROPERTY));
  84         }
  85     }
  86 
  87     /**
  88      *
  89      */
  90     public Environment() {
  91         this(getEnvironment());
  92     }
  93 
  94     /**
  95      *
  96      * @return
  97      */
  98     public Environment getParentEnvironment() {
  99         return parent;
 100     }
 101 
 102     /**
 103      *
 104      * @param parent
 105      */
 106     public void setParentEnvironment(Environment parent) {
 107         this.parent = parent;
 108     }
 109 
 110     public void loadProperties(String propFileName) {
 111         if (propFileName == null || propFileName.length() == 0) {
 112             propFileName = System.getProperty("user.home") + File.separator + ".jemmy.properties";
 113         }
 114         File propFile = new File(propFileName);
 115         System.out.println("Loading jemmy properties from " + propFile);
 116         if (propFile.exists()) {
 117             Properties props = new Properties();
 118             try {
 119                 props.load(new FileInputStream(propFile));
 120             } catch (IOException ex) {
 121                 throw new JemmyException("Unable to load properties", ex, propFileName);
 122             }
 123             for (String k : props.stringPropertyNames()) {
 124                 if (k.equals(TIMEOUTS_FILE_PROPERTY)) {
 125                     loadTimeouts(propFile.getParentFile(), props.getProperty(k));
 126                 } else {
 127                     setProperty(k, props.getProperty(k));
 128                 }
 129             }
 130         } else {
 131             System.out.println("Property file " + propFile + " does not exists. Ignoring.");
 132         }
 133     }
 134 
 135     private void loadTimeouts(File propDir, String file) {
 136         File timeoutsFile = new File(file);
 137         if (!timeoutsFile.isAbsolute()) {
 138             timeoutsFile = new File(propDir.getAbsolutePath() + File.separator + file);
 139         }
 140         System.out.println("Loading timeouts from " + timeoutsFile.getAbsolutePath());
 141         try {
 142             Properties timeouts = new Properties();
 143             timeouts.load(new FileInputStream(timeoutsFile));
 144             for (String k : timeouts.stringPropertyNames()) {
 145                 setTimeout(k, Long.parseLong(timeouts.getProperty(k)));
 146             }
 147         } catch (IOException ex) {
 148             throw new JemmyException("Unable to load timeouts", ex, timeoutsFile.getAbsolutePath());
 149         }
 150     }
 151 
 152     /**
 153      *
 154      * @param cls
 155      * @return
 156      */
 157     public List<?> get(Class cls) {
 158         Set<PropertyKey> all = environment.keySet();
 159         ArrayList<Object> result = new ArrayList<Object>();
 160         for (PropertyKey key : all) {
 161             if (key.getCls().equals(cls)) {
 162                 result.add(environment.get(key));
 163             }
 164         }
 165         return result;
 166     }
 167 
 168     /**
 169      *
 170      * @param defaultExecutor
 171      * @return
 172      */
 173     public ActionExecutor setExecutor(ActionExecutor defaultExecutor) {
 174         return (ActionExecutor) setProperty(ActionExecutor.class, defaultExecutor);
 175     }
 176 
 177     /**
 178      *
 179      * @return
 180      */
 181     public ActionExecutor getExecutor() {
 182         ActionExecutor res = (ActionExecutor) getProperty(ActionExecutor.class);
 183         if (res == null) {
 184             String executorClassName = (String) getProperty(ActionExecutor.ACTION_EXECUTOR_PROPERTY);
 185             try {
 186                 res = ActionExecutor.class.cast(Class.forName(executorClassName).newInstance());
 187                 setExecutor(res);
 188             } catch (InstantiationException ex) {
 189                 throw new JemmyException("Unable to instantiate executor ", ex, executorClassName);
 190             } catch (IllegalAccessException ex) {
 191                 throw new JemmyException("Unable to instantiate executor ", ex, executorClassName);
 192             } catch (ClassNotFoundException ex) {
 193                 throw new JemmyException("No executorclass ", ex, executorClassName);
 194             }
 195         }
 196         return res;
 197     }
 198 
 199     public <T> T setProperty(Class<T> cls, Object ref, T obj) {
 200         return setProperty(new PropertyKey<T>(cls, ref), obj);
 201     }
 202 
 203     private <T> T setPropertyIfNotSet(Class<T> cls, Object ref, T obj) {
 204         return setPropertyIfNotSet(new PropertyKey<T>(cls, ref), obj);
 205     }
 206 
 207     private <T> T getProperty(Class<T> cls, Object ref) {
 208         return getProperty(cls, ref, null);
 209     }
 210 
 211     @SuppressWarnings("unchecked")
 212     public <T> T getProperty(Class cls, Object ref, T defaultValue) {
 213         for (PropertyKey pk : environment.keySet()) {
 214             if (pk.equals(new PropertyKey(cls, ref))) {
 215                 return (T) environment.get(pk);
 216             }
 217         }
 218         if (getParentEnvironment() != null) {
 219             return getParentEnvironment().getProperty(cls, ref, defaultValue);
 220         } else {
 221             return defaultValue;
 222         }
 223     }
 224 
 225     /**
 226      *
 227      * @param <T>
 228      * @param cls
 229      * @param obj if null then property is removed
 230      * @return
 231      */
 232     public <T> T setProperty(Class<T> cls, T obj) {
 233         return setProperty(cls, null, obj);
 234     }
 235 
 236     /**
 237      *
 238      * @param <T>
 239      * @param cls
 240      * @param obj if null then property is removed
 241      * @return
 242      */
 243     public <T> T setPropertyIfNotSet(Class<T> cls, T obj) {
 244         return setPropertyIfNotSet(cls, null, obj);
 245     }
 246 
 247     /**
 248      *
 249      * @param <T>
 250      * @param cls
 251      * @return
 252      */
 253     public <T> T getProperty(Class<T> cls) {
 254         return getProperty(cls, null);
 255     }
 256 
 257     /**
 258      *
 259      * @param name
 260      * @param obj if null then property is removed
 261      * @return
 262      */
 263     public Object setProperty(String name, Object obj) {
 264         return setProperty(Object.class, name, obj);
 265     }
 266 
 267     /**
 268      *
 269      * @param name
 270      * @param obj
 271      * @return
 272      */
 273     public Object setPropertyIfNotSet(String name, Object obj) {
 274         return setPropertyIfNotSet(Object.class, name, obj);
 275     }
 276 
 277     /**
 278      *
 279      * @param name
 280      * @return
 281      */
 282     public Object getProperty(String name) {
 283         return getProperty(Object.class, name);
 284     }
 285 
 286     /**
 287      *
 288      * @param name
 289      * @param defaultValue
 290      * @return
 291      */
 292     public Object getProperty(String name, Object defaultValue) {
 293         return getProperty(Environment.class, name, defaultValue);
 294     }
 295 
 296     private <T> T setProperty(PropertyKey<T> key, Object value) {
 297         if (value == null) {
 298             return key.cls.cast(environment.remove(key));
 299         } else {
 300             return key.cls.cast(environment.put(key, value));
 301         }
 302     }
 303 
 304     private <T> T setPropertyIfNotSet(PropertyKey<T> key, T value) {
 305         if (getParentEnvironment() != null) {
 306             T res = key.cls.cast(getParentEnvironment().getProperty(key));
 307             if (res != null) {
 308                 return res;
 309             }
 310         }
 311         T res = key.cls.cast(environment.get(key));
 312         if (res == null) {
 313             return key.cls.cast(environment.put(key, value));
 314         } else {
 315             return res;
 316         }
 317     }
 318 
 319     private Object getProperty(PropertyKey key) {
 320         return environment.get(key);
 321     }
 322 
 323     /**
 324      *
 325      * @param out
 326      * @return
 327      */
 328     public TestOut setOutput(TestOut out) {
 329         return (TestOut) setProperty(TestOut.class, out);
 330     }
 331 
 332     /**
 333      *
 334      * @return
 335      */
 336     public TestOut getOutput() {
 337         return (TestOut) getProperty(TestOut.class);
 338     }
 339 
 340     /**
 341      * Set some specific output. All classes which provide output should use
 342      * some specific outputs. Please consult javadoc for a class in question.
 343      * Use <code>null</code> to unset the property.
 344      *
 345      * @param outputName
 346      * @param out
 347      * @return
 348      */
 349     public TestOut setOutput(String outputName, TestOut out) {
 350         return (TestOut) setProperty(TestOut.class, outputName, out);
 351     }
 352 
 353     /**
 354      * Initializes some specific output only if it is not yet set.
 355      *
 356      * @param outputName
 357      * @param out
 358      * @return
 359      */
 360     public TestOut initOutput(String outputName, TestOut out) {
 361         TestOut res = (TestOut) getProperty(TestOut.class, outputName);
 362         if (res == null) {
 363             return setOutput(outputName, out);
 364         } else {
 365             return res;
 366         }
 367     }
 368 
 369     /**
 370      * Get's a specific output. If nothing assigned, returns
 371      * <code>getOutput()</code>
 372      *
 373      * @param outputName
 374      * @return
 375      */
 376     public TestOut getOutput(String outputName) {
 377         TestOut res = (TestOut) getProperty(TestOut.class, outputName);
 378         return (res != null) ? res : getOutput();
 379     }
 380 
 381     /**
 382      *
 383      * @param timeout
 384      * @return
 385      */
 386     public Waiter getWaiter(Timeout timeout) {
 387         return getWaiter(timeout.getName());
 388     }
 389 
 390     /**
 391      *
 392      * @param timeoutName
 393      * @return
 394      */
 395     public Waiter getWaiter(String timeoutName) {
 396         return new Waiter(getTimeout(timeoutName));
 397     }
 398 
 399     /**
 400      *
 401      * @param timeout
 402      * @return
 403      */
 404     public Timeout getTimeout(Timeout timeout) {
 405         return getTimeout(timeout.getName());
 406     }
 407 
 408     /**
 409      *
 410      * @param name
 411      * @return
 412      */
 413     public Timeout getTimeout(String name) {
 414         return (Timeout) getProperty(Timeout.class, name);
 415     }
 416 
 417     /**
 418      * Sets timeout.
 419      *
 420      * @param timeout Timeout to set.
 421      * @return replaced timeout if it was already set.
 422      */
 423     public Timeout setTimeout(Timeout timeout) {
 424         return (Timeout) setProperty(Timeout.class, timeout.getName(), timeout);
 425     }
 426 
 427     /**
 428      * Initializes timeout only if it is not set.
 429      *
 430      * @param timeout Timeout to set.
 431      * @return replaced timeout if it was already set.
 432      */
 433     public Timeout initTimeout(Timeout timeout) {
 434         if (getProperty(Timeout.class, timeout.getName()) == null) {
 435             return setTimeout(timeout);
 436         }
 437         return getTimeout(timeout);
 438     }
 439 
 440     /**
 441      * Sets new value for the timeout specified by Timeout object instance.
 442      *
 443      * @param timeout Timeout object instance which identifies the name of the
 444      * timeout to set.
 445      * @param value new value for the timout.
 446      * @return replaced timeout if it was already set.
 447      */
 448     public Timeout setTimeout(Timeout timeout, long value) {
 449         return setTimeout(timeout.getName(), value);
 450     }
 451 
 452     /**
 453      * Sets new value for the timeout.
 454      *
 455      * @param name Name of the timeout.
 456      * @param value Value of the timeout.
 457      * @return replaced timeout if it was already set.
 458      */
 459     public Timeout setTimeout(String name, long value) {
 460         return setTimeout(new Timeout(name, value));
 461     }
 462 
 463     /**
 464      *
 465      * @return
 466      */
 467     public CharBindingMap getBindingMap() {
 468         return (CharBindingMap) getProperty(CharBindingMap.class);
 469     }
 470 
 471     /**
 472      *
 473      * @param map
 474      * @return
 475      */
 476     public CharBindingMap setBindingMap(CharBindingMap map) {
 477         return (CharBindingMap) setProperty(CharBindingMap.class, map);
 478     }
 479 
 480     /**
 481      *
 482      * @return
 483      */
 484     public ImageLoader getImageLoader() {
 485         ImageLoader res = (ImageLoader) getProperty(ImageLoader.class);
 486         if (res == null) {
 487             String loaderClass = (String) getProperty(Wrap.IMAGE_LOADER_PROPERTY);
 488             if (loaderClass == null) {
 489                 throw new IllegalStateException("No image loader provided!");
 490             }
 491             try {
 492                 res = ImageLoader.class.cast(Class.forName(String.class.cast(loaderClass)).newInstance());
 493                 setImageLoader(res);
 494             } catch (InstantiationException ex) {
 495                 throw new JemmyException("Unable to instantiate image loader ", ex, loaderClass);
 496             } catch (IllegalAccessException ex) {
 497                 throw new JemmyException("Unable to instantiate image loader ", ex, loaderClass);
 498             } catch (ClassNotFoundException ex) {
 499                 throw new JemmyException("No image loader class ", ex, loaderClass);
 500             }
 501         }
 502         return res;
 503     }
 504 
 505     /**
 506      *
 507      * @return
 508      */
 509     public ImageCapturer getImageCapturer() {
 510         ImageCapturer res = (ImageCapturer) getProperty(ImageCapturer.class);
 511         if (res == null) {
 512             String capturerClass = (String) getProperty(Wrap.IMAGE_CAPTURER_PROPERTY);
 513             if (capturerClass == null) {
 514                 throw new IllegalStateException("No image capturer provided!");
 515             }
 516             try {
 517                 res = ImageCapturer.class.cast(Class.forName(String.class.cast(capturerClass)).newInstance());
 518                 setImageCapturer(res);
 519             } catch (InstantiationException ex) {
 520                 throw new JemmyException("Unable to instantiate image capturer ", ex, capturerClass);
 521             } catch (IllegalAccessException ex) {
 522                 throw new JemmyException("Unable to instantiate image capturer ", ex, capturerClass);
 523             } catch (ClassNotFoundException ex) {
 524                 throw new JemmyException("No image capturer class ", ex, capturerClass);
 525             }
 526         }
 527         return res;
 528     }
 529 
 530     /**
 531      *
 532      * @param imageLoader
 533      * @return
 534      */
 535     public ImageLoader setImageLoader(ImageLoader imageLoader) {
 536         return (ImageLoader) setProperty(ImageLoader.class, imageLoader);
 537     }
 538 
 539     /**
 540      *
 541      * @param imageCapturer
 542      * @return
 543      */
 544     public ImageCapturer setImageCapturer(ImageCapturer imageCapturer) {
 545         getOutput(OUTPUT).println("ImageCapturer set to " + imageCapturer);
 546         return (ImageCapturer) setProperty(ImageCapturer.class, imageCapturer);
 547     }
 548 
 549     /**
 550      *
 551      * @return
 552      */
 553     public ControlInterfaceFactory getInputFactory() {
 554         ControlInterfaceFactory res = (ControlInterfaceFactory) getProperty(ControlInterfaceFactory.class);
 555         if (res == null) {
 556             String factoryClass = (String) getProperty(Wrap.INPUT_FACTORY_PROPERTY);
 557             if (factoryClass != null) {
 558                 try {
 559                     res = ControlInterfaceFactory.class.cast(Class.forName(String.class.cast(factoryClass)).newInstance());
 560                     setInputFactory(res);
 561                 } catch (InstantiationException ex) {
 562                     throw new JemmyException("Unable to instantiate input factory", ex, factoryClass);
 563                 } catch (IllegalAccessException ex) {
 564                     throw new JemmyException("Unable to instantiate input factory", ex, factoryClass);
 565                 } catch (ClassNotFoundException ex) {
 566                     throw new JemmyException("Unable to load input factory", ex, factoryClass);
 567                 }
 568             }
 569         }
 570         return res;
 571     }
 572 
 573     /**
 574      *
 575      * @param factory
 576      * @return
 577      */
 578     public ControlInterfaceFactory setInputFactory(ControlInterfaceFactory factory) {
 579         getOutput(OUTPUT).println("Input factory set to " + factory);
 580         return (ControlInterfaceFactory) setProperty(ControlInterfaceFactory.class, factory);
 581     }
 582 
 583     private static class PropertyKey<TYPE> {
 584 
 585         private Class<TYPE> cls;
 586         private Object ref;
 587 
 588         public PropertyKey(Class<TYPE> cls, Object ref) {
 589             this.cls = cls;
 590             this.ref = ref;
 591         }
 592 
 593         private PropertyKey(Class<TYPE> cls) {
 594             this(cls, null);
 595         }
 596 
 597         public Class<TYPE> getCls() {
 598             return cls;
 599         }
 600 
 601         public Object getRef() {
 602             return ref;
 603         }
 604 
 605         @Override
 606         public boolean equals(Object obj) {
 607             if (obj == null) {
 608                 return false;
 609             }
 610             if (getClass() != obj.getClass()) {
 611                 return false;
 612             }
 613             final PropertyKey other = (PropertyKey) obj;
 614             if (this.cls != other.cls && (this.cls == null || !this.cls.equals(other.cls))) {
 615                 return false;
 616             }
 617             if (this.ref != other.ref && (this.ref == null || !this.ref.equals(other.ref))) {
 618                 return false;
 619             }
 620             return true;
 621         }
 622 
 623         @Override
 624         public int hashCode() {
 625             int hash = 7;
 626             hash = 41 * hash + (this.cls != null ? this.cls.hashCode() : 0);
 627             hash = 41 * hash + (this.ref != null ? this.ref.hashCode() : 0);
 628             return hash;
 629         }
 630     }
 631 }