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