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  * @author shura, mrkam, erikgreijus
  47  */
  48 public class Environment {
  49     public static final String JEMMY_PROPERTIES_FILE_PROPERTY = "jemmy.properties";
  50     public static final String TIMEOUTS_FILE_PROPERTY = "timeouts";
  51     /**
  52      * Information output for Environment class
  53      */
  54     public static final String OUTPUT = Environment.class.getName() + ".OUTPUT";
  55     private final static Environment env = new Environment(null);
  56 
  57     public static Environment getEnvironment() {
  58         return env;
  59     }
  60 
  61     static {
  62         env.setOutput(new TestOut(System.in, System.out, System.err));
  63         env.setExecutor(new DefaultExecutor());
  64     }
  65     private HashMap<PropertyKey, Object> environment = new HashMap<PropertyKey, Object>();
  66     private Environment parent;
  67 
  68     public Environment(Environment parent) {
  69         this.parent = parent;
  70         environment = new HashMap<PropertyKey, Object>();
  71         if (parent == null) {
  72             loadProperties(System.getProperty(JEMMY_PROPERTIES_FILE_PROPERTY));
  73         }
  74     }
  75 
  76     public Environment() {
  77         this(getEnvironment());
  78     }
  79 
  80     public Environment getParentEnvironment() {
  81         return parent;
  82     }
  83 
  84     public void setParentEnvironment(Environment parent) {
  85         this.parent = parent;
  86     }
  87 
  88     public void loadProperties(String propFileName) {
  89         if (propFileName == null || propFileName.length() == 0) {
  90             propFileName = System.getProperty("user.home") + File.separator + ".jemmy.properties";
  91         }
  92         File propFile = new File(propFileName);
  93         System.out.println("Loading jemmy properties from " + propFile);
  94         if (propFile.exists()) {
  95             Properties props = new Properties();
  96             try {
  97                 props.load(new FileInputStream(propFile));
  98             } catch (IOException ex) {
  99                 throw new JemmyException("Unable to load properties", ex, propFileName);
 100             }
 101             for (String k : props.stringPropertyNames()) {
 102                 if (k.equals(TIMEOUTS_FILE_PROPERTY)) {
 103                     loadTimeouts(propFile.getParentFile(), props.getProperty(k));
 104                 } else {
 105                     setProperty(k, props.getProperty(k));
 106                 }
 107             }
 108         } else {
 109             System.out.println("Property file " + propFile + " does not exists. Ignoring.");
 110         }
 111     }
 112 
 113     private void loadTimeouts(File propDir, String file) {
 114         File timeoutsFile = new File(file);
 115         if (!timeoutsFile.isAbsolute()) {
 116             timeoutsFile = new File(propDir.getAbsolutePath() + File.separator + file);
 117         }
 118         System.out.println("Loading timeouts from " + timeoutsFile.getAbsolutePath());
 119         try {
 120             Properties timeouts = new Properties();
 121             timeouts.load(new FileInputStream(timeoutsFile));
 122             for (String k : timeouts.stringPropertyNames()) {
 123                 setTimeout(k, Long.parseLong(timeouts.getProperty(k)));
 124             }
 125         } catch (IOException ex) {
 126             throw new JemmyException("Unable to load timeouts", ex, timeoutsFile.getAbsolutePath());
 127         }
 128     }
 129 
 130     public List<?> get(Class cls) {
 131         Set<PropertyKey> all = environment.keySet();
 132         ArrayList<Object> result = new ArrayList<Object>();
 133         for (PropertyKey key : all) {
 134             if (key.getCls().equals(cls)) {
 135                 result.add(environment.get(key));
 136             }
 137         }
 138         return result;
 139     }
 140 
 141     public ActionExecutor setExecutor(ActionExecutor defaultExecutor) {
 142         return (ActionExecutor) setProperty(ActionExecutor.class, defaultExecutor);
 143     }
 144 
 145     public ActionExecutor getExecutor() {
 146         ActionExecutor res = (ActionExecutor) getProperty(ActionExecutor.class);
 147         if (res == null) {
 148             String executorClassName = (String) getProperty(ActionExecutor.ACTION_EXECUTOR_PROPERTY);
 149             try {
 150                 res = ActionExecutor.class.cast(Class.forName(executorClassName).newInstance());
 151                 setExecutor(res);
 152             } catch (InstantiationException ex) {
 153                 throw new JemmyException("Unable to instantiate executor ", ex, executorClassName);
 154             } catch (IllegalAccessException ex) {
 155                 throw new JemmyException("Unable to instantiate executor ", ex, executorClassName);
 156             } catch (ClassNotFoundException ex) {
 157                 throw new JemmyException("No executorclass ", ex, executorClassName);
 158             }
 159         }
 160         return res;
 161     }
 162 
 163     public <T> T setProperty(Class<T> cls, Object ref, T obj) {
 164         return setProperty(new PropertyKey<T>(cls, ref), obj);
 165     }
 166 
 167     private <T> T setPropertyIfNotSet(Class<T> cls, Object ref, T obj) {
 168         return setPropertyIfNotSet(new PropertyKey<T>(cls, ref), obj);
 169     }
 170 
 171     private <T> T getProperty(Class<T> cls, Object ref) {
 172         return getProperty(cls, ref, null);
 173     }
 174 
 175     @SuppressWarnings("unchecked")
 176     public <T> T getProperty(Class cls, Object ref, T defaultValue) {
 177         for (PropertyKey pk : environment.keySet()) {
 178             if (pk.equals(new PropertyKey(cls, ref))) {
 179                 return (T) environment.get(pk);
 180             }
 181         }
 182         if (getParentEnvironment() != null) {
 183             return getParentEnvironment().getProperty(cls, ref, defaultValue);
 184         } else {
 185             return defaultValue;
 186         }
 187     }
 188 
 189     /**
 190      * @param <T> todo document
 191      * @param cls todo document
 192      * @param obj if null then property is removed
 193      * @return todo document
 194      */
 195     public <T> T setProperty(Class<T> cls, T obj) {
 196         return setProperty(cls, null, obj);
 197     }
 198 
 199     /**
 200      * @param <T> todo document
 201      * @param cls todo document
 202      * @param obj if null then property is removed
 203      * @return todo document
 204      */
 205     public <T> T setPropertyIfNotSet(Class<T> cls, T obj) {
 206         return setPropertyIfNotSet(cls, null, obj);
 207     }
 208 
 209     public <T> T getProperty(Class<T> cls) {
 210         return getProperty(cls, null);
 211     }
 212 
 213     /**
 214      * @param name todo document
 215      * @param obj if null then property is removed
 216      * @return todo document
 217      */
 218     public Object setProperty(String name, Object obj) {
 219         return setProperty(Object.class, name, obj);
 220     }
 221 
 222     public Object setPropertyIfNotSet(String name, Object obj) {
 223         return setPropertyIfNotSet(Object.class, name, obj);
 224     }
 225 
 226     public Object getProperty(String name) {
 227         return getProperty(Object.class, name);
 228     }
 229 
 230     public Object getProperty(String name, Object defaultValue) {
 231         return getProperty(Environment.class, name, defaultValue);
 232     }
 233 
 234     private <T> T setProperty(PropertyKey<T> key, Object value) {
 235         if (value == null) {
 236             return key.cls.cast(environment.remove(key));
 237         } else {
 238             return key.cls.cast(environment.put(key, value));
 239         }
 240     }
 241 
 242     private <T> T setPropertyIfNotSet(PropertyKey<T> key, T value) {
 243         if (getParentEnvironment() != null) {
 244             T res = key.cls.cast(getParentEnvironment().getProperty(key));
 245             if (res != null) {
 246                 return res;
 247             }
 248         }
 249         T res = key.cls.cast(environment.get(key));
 250         if (res == null) {
 251             return key.cls.cast(environment.put(key, value));
 252         } else {
 253             return res;
 254         }
 255     }
 256 
 257     private Object getProperty(PropertyKey key) {
 258         return environment.get(key);
 259     }
 260 
 261     public TestOut setOutput(TestOut out) {
 262         return (TestOut) setProperty(TestOut.class, out);
 263     }
 264 
 265     public TestOut getOutput() {
 266         return (TestOut) getProperty(TestOut.class);
 267     }
 268 
 269     /**
 270      * Set some specific output. All classes which provide output should use
 271      * some specific outputs. Please consult javadoc for a class in question.
 272      * Use <code>null</code> to unset the property.
 273      *
 274      * @param outputName todo document
 275      * @param out todo document
 276      * @return todo document
 277      */
 278     public TestOut setOutput(String outputName, TestOut out) {
 279         return (TestOut) setProperty(TestOut.class, outputName, out);
 280     }
 281 
 282     /**
 283      * Initializes some specific output only if it is not yet set.
 284      *
 285      * @param outputName todo document
 286      * @param out todo document
 287      * @return todo document
 288      */
 289     public TestOut initOutput(String outputName, TestOut out) {
 290         TestOut res = (TestOut) getProperty(TestOut.class, outputName);
 291         if (res == null) {
 292             return setOutput(outputName, out);
 293         } else {
 294             return res;
 295         }
 296     }
 297 
 298     /**
 299      * Get's a specific output. If nothing assigned, returns
 300      * <code>getOutput()</code>
 301      *
 302      * @param outputName todo document
 303      * @return todo document
 304      */
 305     public TestOut getOutput(String outputName) {
 306         TestOut res = (TestOut) getProperty(TestOut.class, outputName);
 307         return (res != null) ? res : getOutput();
 308     }
 309 
 310     public Waiter getWaiter(Timeout timeout) {
 311         return getWaiter(timeout.getName());
 312     }
 313 
 314     public Waiter getWaiter(String timeoutName) {
 315         return new Waiter(getTimeout(timeoutName));
 316     }
 317 
 318     public Timeout getTimeout(Timeout timeout) {
 319         return getTimeout(timeout.getName());
 320     }
 321 
 322     public Timeout getTimeout(String name) {
 323         return (Timeout) getProperty(Timeout.class, name);
 324     }
 325 
 326     /**
 327      * Sets timeout.
 328      *
 329      * @param timeout Timeout to set.
 330      * @return replaced timeout if it was already set.
 331      */
 332     public Timeout setTimeout(Timeout timeout) {
 333         return (Timeout) setProperty(Timeout.class, timeout.getName(), timeout);
 334     }
 335 
 336     /**
 337      * Initializes timeout only if it is not set.
 338      *
 339      * @param timeout Timeout to set.
 340      * @return replaced timeout if it was already set.
 341      */
 342     public Timeout initTimeout(Timeout timeout) {
 343         if (getProperty(Timeout.class, timeout.getName()) == null) {
 344             return setTimeout(timeout);
 345         }
 346         return getTimeout(timeout);
 347     }
 348 
 349     /**
 350      * Sets new value for the timeout specified by Timeout object instance.
 351      *
 352      * @param timeout Timeout object instance which identifies the name of the
 353      * timeout to set.
 354      * @param value new value for the timout.
 355      * @return replaced timeout if it was already set.
 356      */
 357     public Timeout setTimeout(Timeout timeout, long value) {
 358         return setTimeout(timeout.getName(), value);
 359     }
 360 
 361     /**
 362      * Sets new value for the timeout.
 363      *
 364      * @param name Name of the timeout.
 365      * @param value Value of the timeout.
 366      * @return replaced timeout if it was already set.
 367      */
 368     public Timeout setTimeout(String name, long value) {
 369         return setTimeout(new Timeout(name, value));
 370     }
 371 
 372     public CharBindingMap getBindingMap() {
 373         return (CharBindingMap) getProperty(CharBindingMap.class);
 374     }
 375 
 376     public CharBindingMap setBindingMap(CharBindingMap map) {
 377         return (CharBindingMap) setProperty(CharBindingMap.class, map);
 378     }
 379 
 380     public ImageLoader getImageLoader() {
 381         ImageLoader res = (ImageLoader) getProperty(ImageLoader.class);
 382         if (res == null) {
 383             String loaderClass = (String) getProperty(Wrap.IMAGE_LOADER_PROPERTY);
 384             if (loaderClass == null) {
 385                 throw new IllegalStateException("No image loader provided!");
 386             }
 387             try {
 388                 res = ImageLoader.class.cast(Class.forName(String.class.cast(loaderClass)).newInstance());
 389                 setImageLoader(res);
 390             } catch (InstantiationException ex) {
 391                 throw new JemmyException("Unable to instantiate image loader ", ex, loaderClass);
 392             } catch (IllegalAccessException ex) {
 393                 throw new JemmyException("Unable to instantiate image loader ", ex, loaderClass);
 394             } catch (ClassNotFoundException ex) {
 395                 throw new JemmyException("No image loader class ", ex, loaderClass);
 396             }
 397         }
 398         return res;
 399     }
 400 
 401     public ImageCapturer getImageCapturer() {
 402         ImageCapturer res = (ImageCapturer) getProperty(ImageCapturer.class);
 403         if (res == null) {
 404             String capturerClass = (String) getProperty(Wrap.IMAGE_CAPTURER_PROPERTY);
 405             if (capturerClass == null) {
 406                 throw new IllegalStateException("No image capturer provided!");
 407             }
 408             try {
 409                 res = ImageCapturer.class.cast(Class.forName(String.class.cast(capturerClass)).newInstance());
 410                 setImageCapturer(res);
 411             } catch (InstantiationException ex) {
 412                 throw new JemmyException("Unable to instantiate image capturer ", ex, capturerClass);
 413             } catch (IllegalAccessException ex) {
 414                 throw new JemmyException("Unable to instantiate image capturer ", ex, capturerClass);
 415             } catch (ClassNotFoundException ex) {
 416                 throw new JemmyException("No image capturer class ", ex, capturerClass);
 417             }
 418         }
 419         return res;
 420     }
 421 
 422     public ImageLoader setImageLoader(ImageLoader imageLoader) {
 423         return (ImageLoader) setProperty(ImageLoader.class, imageLoader);
 424     }
 425 
 426     public ImageCapturer setImageCapturer(ImageCapturer imageCapturer) {
 427         getOutput(OUTPUT).println("ImageCapturer set to " + imageCapturer);
 428         return (ImageCapturer) setProperty(ImageCapturer.class, imageCapturer);
 429     }
 430 
 431     public ControlInterfaceFactory getInputFactory() {
 432         ControlInterfaceFactory res = (ControlInterfaceFactory) getProperty(ControlInterfaceFactory.class);
 433         if (res == null) {
 434             String factoryClass = (String) getProperty(Wrap.INPUT_FACTORY_PROPERTY);
 435             if (factoryClass != null) {
 436                 try {
 437                     res = ControlInterfaceFactory.class.cast(Class.forName(String.class.cast(factoryClass)).newInstance());
 438                     setInputFactory(res);
 439                 } catch (InstantiationException ex) {
 440                     throw new JemmyException("Unable to instantiate input factory", ex, factoryClass);
 441                 } catch (IllegalAccessException ex) {
 442                     throw new JemmyException("Unable to instantiate input factory", ex, factoryClass);
 443                 } catch (ClassNotFoundException ex) {
 444                     throw new JemmyException("Unable to load input factory", ex, factoryClass);
 445                 }
 446             }
 447         }
 448         return res;
 449     }
 450 
 451     public ControlInterfaceFactory setInputFactory(ControlInterfaceFactory factory) {
 452         getOutput(OUTPUT).println("Input factory set to " + factory);
 453         return (ControlInterfaceFactory) setProperty(ControlInterfaceFactory.class, factory);
 454     }
 455 
 456     private static class PropertyKey<TYPE> {
 457 
 458         private Class<TYPE> cls;
 459         private Object ref;
 460 
 461         public PropertyKey(Class<TYPE> cls, Object ref) {
 462             this.cls = cls;
 463             this.ref = ref;
 464         }
 465 
 466         private PropertyKey(Class<TYPE> cls) {
 467             this(cls, null);
 468         }
 469 
 470         public Class<TYPE> getCls() {
 471             return cls;
 472         }
 473 
 474         public Object getRef() {
 475             return ref;
 476         }
 477 
 478         @Override
 479         public boolean equals(Object obj) {
 480             if (obj == null) {
 481                 return false;
 482             }
 483             if (getClass() != obj.getClass()) {
 484                 return false;
 485             }
 486             final PropertyKey other = (PropertyKey) obj;
 487             if (this.cls != other.cls && (this.cls == null || !this.cls.equals(other.cls))) {
 488                 return false;
 489             }
 490             if (this.ref != other.ref && (this.ref == null || !this.ref.equals(other.ref))) {
 491                 return false;
 492             }
 493             return true;
 494         }
 495 
 496         @Override
 497         public int hashCode() {
 498             int hash = 7;
 499             hash = 41 * hash + (this.cls != null ? this.cls.hashCode() : 0);
 500             hash = 41 * hash + (this.ref != null ? this.ref.hashCode() : 0);
 501             return hash;
 502         }
 503     }
 504 }