/* * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package org.netbeans.jemmy.operators; import java.awt.Component; import java.awt.event.InputEvent; import java.lang.reflect.InvocationTargetException; import java.util.Hashtable; import java.util.StringTokenizer; import java.util.Vector; import org.netbeans.jemmy.Action; import org.netbeans.jemmy.ActionProducer; import org.netbeans.jemmy.CharBindingMap; import org.netbeans.jemmy.ClassReference; import org.netbeans.jemmy.ComponentChooser; import org.netbeans.jemmy.ComponentSearcher; import org.netbeans.jemmy.JemmyException; import org.netbeans.jemmy.JemmyProperties; import org.netbeans.jemmy.Outputable; import org.netbeans.jemmy.QueueTool; import org.netbeans.jemmy.TestOut; import org.netbeans.jemmy.TimeoutExpiredException; import org.netbeans.jemmy.Timeoutable; import org.netbeans.jemmy.Timeouts; import org.netbeans.jemmy.Waitable; import org.netbeans.jemmy.Waiter; import org.netbeans.jemmy.util.DefaultVisualizer; import org.netbeans.jemmy.util.MouseVisualizer; import org.netbeans.jemmy.util.Platform; /** * Keeps all environment and low-level methods. * * @author Alexandre Iline (alexandre.iline@oracle.com) */ public abstract class Operator implements Timeoutable, Outputable { /** * Identifier for a "class" property. * * @see #getDump */ public static final String CLASS_DPROP = "Class"; /** * Identifier for a "toString" property. * * @see #getDump */ public static final String TO_STRING_DPROP = "toString"; private static Vector operatorPkgs; private Timeouts timeouts; private TestOut output; private CharBindingMap map; private ComponentVisualizer visualizer; private StringComparator comparator; private PathParser parser; private QueueTool queueTool; private boolean verification = false; private JemmyProperties properties; /** * Inits environment. */ public Operator() { super(); initEnvironment(); } /** * Specifies an object to be used by default to prepare component. Each new * operator created after the method using will have defined visualizer. * Default implementation is org.netbeans.jemmy.util.DefaultVisualizer * class. * * @param visualizer ComponentVisualizer implementation * @return previous value * @see #setVisualizer(Operator.ComponentVisualizer) * @see #getDefaultComponentVisualizer() * @see org.netbeans.jemmy.util.DefaultVisualizer */ public static ComponentVisualizer setDefaultComponentVisualizer(ComponentVisualizer visualizer) { return ((ComponentVisualizer) JemmyProperties. setCurrentProperty("ComponentOperator.ComponentVisualizer", visualizer)); } /** * Returns an object to be used by default to prepare component. * * @return Object is used by default to prepare component * @see #getVisualizer() * @see #setDefaultComponentVisualizer(Operator.ComponentVisualizer) */ public static ComponentVisualizer getDefaultComponentVisualizer() { return ((ComponentVisualizer) JemmyProperties. getCurrentProperty("ComponentOperator.ComponentVisualizer")); } /** * Defines string comparator to be assigned in constructor. * * @param comparator the comparator to be used by default. * @return previous value. * @see #getDefaultStringComparator() * @see Operator.StringComparator */ public static StringComparator setDefaultStringComparator(StringComparator comparator) { return ((StringComparator) JemmyProperties. setCurrentProperty("ComponentOperator.StringComparator", comparator)); } /** * Returns string comparator used to init operators. * * @return the comparator used by default. * @see #setDefaultStringComparator(Operator.StringComparator) * @see Operator.StringComparator */ public static StringComparator getDefaultStringComparator() { return ((StringComparator) JemmyProperties. getCurrentProperty("ComponentOperator.StringComparator")); } /** * Specifies an object used for parsing of path-like strings. * * @param parser the parser. * @return a previous value. * @see Operator.PathParser * @see #getDefaultPathParser */ public static PathParser setDefaultPathParser(PathParser parser) { return ((PathParser) JemmyProperties. setCurrentProperty("ComponentOperator.PathParser", parser)); } /** * Returns an object used for parsing of path-like strings. * * @return a parser used by default. * @see Operator.PathParser * @see #setDefaultPathParser */ public static PathParser getDefaultPathParser() { return ((PathParser) JemmyProperties. getCurrentProperty("ComponentOperator.PathParser")); } /** * Defines whether newly created operators should perform operation * verifications by default. * * @param verification a verification mode to be used by default. * @return a previous value. * @see #getDefaultVerification() * @see #setVerification(boolean) */ public static boolean setDefaultVerification(boolean verification) { Boolean oldValue = (Boolean) (JemmyProperties. setCurrentProperty("Operator.Verification", verification ? Boolean.TRUE : Boolean.FALSE)); return (oldValue != null) ? oldValue : false; } /** * Says whether newly created operators perform operations verifications by * default. * * @return a verification mode used by default. * @see #setDefaultVerification(boolean) * @see #getVerification() */ public static boolean getDefaultVerification() { return ((Boolean) (JemmyProperties. getCurrentProperty("Operator.Verification"))); } /** * Compares caption (button text, window title, ...) with a sample text. * * @param caption String to be compared with match. Method returns false, if * parameter is null. * @param match Sample to compare with. Method returns true, if parameter is * null. * @param ce Compare exactly. If true, text can be a substring of caption. * @param ccs Compare case sensitively. If true, both text and caption are * converted to upper case before comparison. * @return true is the captions matched the match. * @see #isCaptionEqual * @deprecated use another methods with the same name. */ @Deprecated public static boolean isCaptionEqual(String caption, String match, boolean ce, boolean ccs) { return new DefaultStringComparator(ce, ccs).equals(caption, match); } /** * Compares caption (button text, window title, ...) with a sample text. * * @param caption String to be compared with match * @param match Sample to compare with * @param comparator StringComparator instance. * @return true is the captions matched the match. * @see #isCaptionEqual */ public static boolean isCaptionEqual(String caption, String match, StringComparator comparator) { return comparator.equals(caption, match); } /** * Returns default mouse button mask. * * @return {@code InputEvent.BUTTON*_MASK} field value */ public static int getDefaultMouseButton() { return InputEvent.BUTTON1_MASK; } /** * Returns mask of mouse button which used to popup expanding. * (InputEvent.BUTTON3_MASK) * * @return {@code InputEvent.BUTTON*_MASK} field value */ public static int getPopupMouseButton() { return InputEvent.BUTTON3_MASK; } /** * Creates operator for component. Tries to find class with "operator * package"."class name"Operator name, where "operator package" is a package * from operator packages list, and "class name" is the name of class or one * of its superclasses. * * @param comp Component to create operator for. * @return a new operator with default environment. * @see #addOperatorPackage(String) */ public static ComponentOperator createOperator(Component comp) { //hack! try { Class cclass = Class.forName("java.awt.Component"); Class compClass = comp.getClass(); ComponentOperator result; do { if ((result = createOperator(comp, compClass)) != null) { return result; } } while (cclass.isAssignableFrom(compClass = compClass.getSuperclass())); } catch (ClassNotFoundException ignored) { } return null; } /** * Adds package to the list of packages containing operators.
* "org.netbeans.jemmy.operators" is in the list by default. * * @param pkgName Package name. * @see #createOperator(Component) */ public static void addOperatorPackage(String pkgName) { operatorPkgs.add(pkgName); } /** * Returns an operator containing default environment. * * @return an empty operator (not having any component source) having * default environment. */ public static Operator getEnvironmentOperator() { return new NullOperator(); } static { //init visualizer depending on OS: //Linux - new MouseVisualizer(MouseVisualizer.TOP, 0.5, 10, false) //others - new DefaultVisualizer() if (Platform.isLinux()) { setDefaultComponentVisualizer(new MouseVisualizer(MouseVisualizer.TOP, 0.5, 10, false)); } else { setDefaultComponentVisualizer(new DefaultVisualizer()); } operatorPkgs = new Vector<>(); setDefaultStringComparator(new DefaultStringComparator(false, false)); setDefaultPathParser(new DefaultPathParser("|")); addOperatorPackage("org.netbeans.jemmy.operators"); setDefaultVerification(true); } /** * Returns object operator is used for. * * @return an instance of java.awt.Component subclass which this operator * was created for. */ public abstract Component getSource(); //////////////////////////////////////////////////////// //Environment // //////////////////////////////////////////////////////// /** * Returns QueueTool is used to work with queue. * * @return a QueueTool. */ public QueueTool getQueueTool() { return queueTool; } /** * Copies all environment (output, timeouts, visualizer) from another * operator. * * @param anotherOperator an operator to copy the environment to. */ public void copyEnvironment(Operator anotherOperator) { setTimeouts(anotherOperator.getTimeouts()); setOutput(anotherOperator.getOutput()); setVisualizer(anotherOperator.getVisualizer()); setComparator(anotherOperator.getComparator()); setVerification(anotherOperator.getVerification()); setCharBindingMap(anotherOperator.getCharBindingMap()); setProperties(anotherOperator.getProperties()); } @Override public void setTimeouts(Timeouts timeouts) { this.timeouts = timeouts; queueTool.setTimeouts(timeouts); } @Override public Timeouts getTimeouts() { return timeouts; } /** * Returns component visualizer. Visualizer is used from from * makeComponentVisible() method. * * @return a visualizer assigned to this operator. * @see #getDefaultComponentVisualizer() * @see #setVisualizer(Operator.ComponentVisualizer) */ public ComponentVisualizer getVisualizer() { return visualizer; } /** * Changes component visualizer. Visualizer is used from from * makeComponentVisible() method. * * @param vo a visualizer to assign to this operator. * @see #setDefaultComponentVisualizer(Operator.ComponentVisualizer) * @see #getVisualizer() */ public void setVisualizer(ComponentVisualizer vo) { visualizer = vo; } /** * Returns a JemmyProperty object assigned to this operator. * * @return a JemmyProperty object got from the top of property stack or from * another operator by copyuing environment. * @see #setProperties */ public JemmyProperties getProperties() { return properties; } /** * Assigns a JemmyProperty object to this operator. * * @param properties a properties to assign to this operator. * @return previously assigned properties. * @see #getProperties */ public JemmyProperties setProperties(JemmyProperties properties) { JemmyProperties oldProperties = getProperties(); this.properties = properties; return oldProperties; } /** * Defines CharBindingMap. * * @param map a CharBindingMap to use for keyboard operations. * @see org.netbeans.jemmy.CharBindingMap * @see * org.netbeans.jemmy.JemmyProperties#setCurrentCharBindingMap(CharBindingMap) * @see #getCharBindingMap */ public void setCharBindingMap(CharBindingMap map) { this.map = map; } /** * Returns CharBindingMap used for keyboard operations. * * @return a map assigned to this object. * @see #setCharBindingMap */ public CharBindingMap getCharBindingMap() { return map; } @Override public void setOutput(TestOut out) { output = out; queueTool.setOutput(output.createErrorOutput()); } @Override public TestOut getOutput() { return output; } /** * Returns object which is used for string comparison. * * @return a comparator assigned to this operator. * @see org.netbeans.jemmy.operators.Operator.StringComparator * @see org.netbeans.jemmy.operators.Operator.DefaultStringComparator * @see #setComparator */ public StringComparator getComparator() { return comparator; } /** * Defines object which is used for string comparison. * * @param comparator a comparator to use for string comparision. * @see org.netbeans.jemmy.operators.Operator.StringComparator * @see org.netbeans.jemmy.operators.Operator.DefaultStringComparator * @see #getComparator */ public void setComparator(StringComparator comparator) { this.comparator = comparator; } /** * Returns object which is used for parsing of path-like strings. * * @return a comparator assigned to this operator. * @see #setPathParser */ public PathParser getPathParser() { return parser; } /** * Specifies object which is used for parsing of path-like strings. * * @param parser a parser to use for path parsing. * @see #getPathParser */ public void setPathParser(PathParser parser) { this.parser = parser; } /** * Defines whether operator should perform operation verifications. * * @param verification new value. * @return old value * @see #setDefaultVerification(boolean) * @see #getDefaultVerification() * @see #getVerification() */ public boolean setVerification(boolean verification) { boolean oldValue = this.verification; this.verification = verification; return oldValue; } /** * Says whether operator performs operation verifications. * * @return old value * @see #setDefaultVerification(boolean) * @see #getDefaultVerification() * @see #setVerification(boolean) */ public boolean getVerification() { return verification; } //////////////////////////////////////////////////////// //Util // //////////////////////////////////////////////////////// /** * Creates new array which has all elements from first array, except last * element. * * @param path an original array * @return new array */ public String[] getParentPath(String path[]) { if (path.length > 1) { String[] ppath = new String[path.length - 1]; System.arraycopy(path, 0, ppath, 0, ppath.length); return ppath; } else { return new String[0]; } } public ComponentChooser[] getParentPath(ComponentChooser path[]) { if (path.length > 1) { ComponentChooser[] ppath = new ComponentChooser[path.length - 1]; System.arraycopy(path, 0, ppath, 0, ppath.length); return ppath; } else { return new ComponentChooser[0]; } } /** * Parses a string to a string array using a PathParser assigned to this * operator. * * @param path an original string * @return created String array. */ public String[] parseString(String path) { return getPathParser().parse(path); } /** * Parses strings like "1|2|3" into arrays {"1", "2", "3"}. * * @param path an original string * @param delim a delimiter string * @return created String array. */ public String[] parseString(String path, String delim) { return new DefaultPathParser(delim).parse(path); } /** * Returns key code to be pressed for character typing. * * @param c Character to be typed. * @return a value of one of the {@code KeyEvent.VK_*} fields. * @see org.netbeans.jemmy.CharBindingMap */ public int getCharKey(char c) { return map.getCharKey(c); } /** * Returns modifiers mask for character typing. * * @param c Character to be typed. * @return a combination of {@code InputEvent.*_MASK} fields. * @see org.netbeans.jemmy.CharBindingMap */ public int getCharModifiers(char c) { return map.getCharModifiers(c); } /** * Returns key codes to by pressed for characters typing. * * @param c Characters to be typed. * @return an array of {@code KeyEvent.VK_*} values. * @see org.netbeans.jemmy.CharBindingMap */ public int[] getCharsKeys(char[] c) { int[] result = new int[c.length]; for (int i = 0; i < c.length; i++) { result[i] = getCharKey(c[i]); } return result; } /** * Returns modifiers masks for characters typing. * * @param c Characters to be typed. * @return an array of a combination of {@code InputEvent.*_MASK} * fields. * @see org.netbeans.jemmy.CharBindingMap */ public int[] getCharsModifiers(char[] c) { int[] result = new int[c.length]; for (int i = 0; i < c.length; i++) { result[i] = getCharModifiers(c[i]); } return result; } /** * Returns key codes to by pressed for the string typing. * * @param s String to be typed. * @return an array of {@code KeyEvent.VK_*} values. * @see org.netbeans.jemmy.CharBindingMap */ public int[] getCharsKeys(String s) { return getCharsKeys(s.toCharArray()); } /** * Returns modifiers masks for the string typing. * * @param s String to be typed. * @return an array of a combination of {@code InputEvent.*_MASK} * fields. * @see org.netbeans.jemmy.CharBindingMap */ public int[] getCharsModifiers(String s) { return getCharsModifiers(s.toCharArray()); } /** * Compares string using getComparator StringComparator. * * @param caption a caption * @param match a pattern * @return true if {@code caption} and {@code match} match * @see #isCaptionEqual */ public boolean isCaptionEqual(String caption, String match) { return comparator.equals(caption, match); } /** * Prints component information into operator output. */ public void printDump() { Hashtable result = getDump(); Object[] keys = result.keySet().toArray(); for (int i = 0; i < result.size(); i++) { output.printLine(keys[i] + " = " + result.get(keys[i])); } } /** * Returns information about component. All records marked by simbolic * constants defined in public static final {@code *_DPROP} fields for * each operator type. * * @return a Hashtable containing name-value pairs. */ public Hashtable getDump() { Hashtable result = new Hashtable<>(); result.put(CLASS_DPROP, getSource().getClass().getName()); result.put(TO_STRING_DPROP, getSource().toString()); return result; } /** * Waits a state specified by a ComponentChooser instance. * * @param state a ComponentChooser defining the state criteria. * @throws TimeoutExpiredException if the state has not achieved in a value * defined by {@code "ComponentOperator.WaitStateTimeout"} */ public void waitState(final ComponentChooser state) { waitState(new Waitable() { @Override public String actionProduced(Void obj) { return state.checkComponent(getSource()) ? "" : null; } @Override public String getDescription() { return "Wait \"" + state.getDescription() + "\" state to be reached"; } @Override public String toString() { return "Operator.waitState.Waitable{description = " + getDescription() + '}'; } }); } public R waitState(Waitable waitable) { Waiter stateWaiter = new Waiter<>(waitable); stateWaiter.setTimeoutsToCloneOf(getTimeouts(), "ComponentOperator.WaitStateTimeout"); stateWaiter.setOutput(getOutput().createErrorOutput()); try { return stateWaiter.waitAction(null); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw (new JemmyException( "Waiting of \"" + waitable.getDescription() + "\" state has been interrupted!")); } } /** * Waits a state specified by a ComponentChooser instance on EDT queue. * * @param state a ComponentChooser defining the state criteria. * @throws TimeoutExpiredException if the state has not achieved in a value * defined by {@code "ComponentOperator.WaitStateTimeout"} */ public void waitStateOnQueue(final ComponentChooser state) { waitState((comp) -> { return (boolean) (queueTool.invokeSmoothly( new QueueTool.QueueAction("checkComponent") { @Override public final Object launch() throws Exception { return state.checkComponent(comp); } })); }); } //////////////////////////////////////////////////////// //Mapping // //////////////////////////////////////////////////////// /** * Performs an operation with time control. * * @param action an action to execute. * @param param an action parameters. * @param actionTimeOrigin is a timeout name to use for waiting for the * action to be finished. * @return an action result. */ protected R produceTimeRestricted(Action action, final P param, String actionTimeOrigin) { ActionProducer producer = new ActionProducer<>(action); producer.setOutput(getOutput().createErrorOutput()); producer.setTimeouts(getTimeouts().cloneThis()); producer.getTimeouts().setTimeout("ActionProducer.MaxActionTime", getTimeouts().getTimeout(actionTimeOrigin)); try { R result = producer.produceAction(param, actionTimeOrigin); Throwable exception = producer.getException(); if (exception != null) { if (exception instanceof JemmyException) { throw ((JemmyException) exception); } else { throw (new JemmyException("Exception during " + action.getDescription(), exception)); } } return result; } catch (InterruptedException e) { throw (new JemmyException("Interrupted!", e)); } } /** * Performs an operation with time control. * * @param action an action to execute. * @param actionTimeOrigin is a timeout name to use for waiting for the * action to be finished. * @return an action result. */ protected R produceTimeRestricted(Action action, String actionTimeOrigin) { return produceTimeRestricted(action, null, actionTimeOrigin); } /** * Performs an operation without time control. * * @param action an action to execute. * @param param an action parameters. */ protected void produceNoBlocking(NoBlockingAction action, P param) { try { ActionProducer noBlockingProducer = new ActionProducer<>(action, false); noBlockingProducer.setOutput(output.createErrorOutput()); noBlockingProducer.setTimeouts(timeouts); noBlockingProducer.produceAction(param, null); } catch (InterruptedException e) { throw (new JemmyException("Exception during \"" + action.getDescription() + "\" execution", e)); } if (action.exception != null) { throw (new JemmyException("Exception during nonblocking \"" + action.getDescription() + "\"", action.exception)); } } /** * Performs an operation without time control. * * @param action an action to execute. */ protected void produceNoBlocking(NoBlockingAction action) { produceNoBlocking(action, null); } /** * Equivalent to {@code getQueue().lock();}. */ protected void lockQueue() { queueTool.lock(); } /** * Equivalent to {@code getQueue().unlock();}. */ protected void unlockQueue() { queueTool.unlock(); } /** * Unlocks Queue and then throw exception. * * @param e an exception to be thrown. */ protected void unlockAndThrow(Exception e) { unlockQueue(); throw (new JemmyException("Exception during queue locking", e)); } /** * To map nonprimitive type component's method. * * @param action a mapping action. * @return an action result. * @see Operator.MapAction */ protected R runMapping(MapAction action) { return runMappingPrimitive(action); } /** * To map char component's method. * * @param action a mapping action. * @return an action result. * @see #runMapping(Operator.MapAction) * @see Operator.MapCharacterAction */ protected char runMapping(MapCharacterAction action) { return (Character) runMappingPrimitive(action); } /** * To map byte component's method. * * @param action a mapping action. * @return an action result. * @see #runMapping(Operator.MapAction) * @see Operator.MapByteAction */ protected byte runMapping(MapByteAction action) { return (Byte) runMappingPrimitive(action); } /** * To map int component's method. * * @param action a mapping action. * @return an action result. * @see #runMapping(Operator.MapAction) * @see Operator.MapIntegerAction */ protected int runMapping(MapIntegerAction action) { return (Integer) runMappingPrimitive(action); } /** * To map long component's method. * * @param action a mapping action. * @return an action result. * @see #runMapping(Operator.MapAction) * @see Operator.MapLongAction */ protected long runMapping(MapLongAction action) { return (Long) runMappingPrimitive(action); } /** * To map float component's method. * * @param action a mapping action. * @return an action result. * @see #runMapping(Operator.MapAction) * @see Operator.MapFloatAction */ protected float runMapping(MapFloatAction action) { return (Float) runMappingPrimitive(action); } /** * To map double component's method. * * @param action a mapping action. * @return an action result. * @see #runMapping(Operator.MapAction) * @see Operator.MapDoubleAction */ protected double runMapping(MapDoubleAction action) { return (Double) runMappingPrimitive(action); } /** * To map boolean component's method. * * @param action a mapping action. * @return an action result. * @see #runMapping(Operator.MapAction) * @see Operator.MapBooleanAction */ protected boolean runMapping(MapBooleanAction action) { return (Boolean) runMappingPrimitive(action); } /** * To map void component's method. * * @param action a mapping action. * @see #runMapping(Operator.MapAction) * @see Operator.MapVoidAction */ protected void runMapping(MapVoidAction action) { runMappingPrimitive(action); } /** * Adds array of objects to dump hashtable. Is used for multiple properties * such as list items and tree nodes. * * @param table a table to add properties to. * @param title property names prefix. Property names are constructed by * adding a number to the prefix: * {@code title + "_" + Iteger.toString("ordinal index")} * @param items an array of property values. * @return an array of property names (with added numbers). */ protected String[] addToDump(Hashtable table, String title, Object[] items) { String[] names = createNames(title + "_", items.length); for (int i = 0; i < items.length; i++) { table.put(names[i], items[i].toString()); } return names; } /** * Adds two dimentional array of objects to dump hashtable. Is used for * multiple properties such as table cells. * * @param table a table to add properties to. * @param title property names prefix. Property names are constructed by * adding two numbers to the prefix: * {@code title + "_" + Iteger.toString("row index") + "_" + Iteger.toString("column index")} * @param items an array of property values. * @return an array of property names (with added numbers). */ protected String[] addToDump(Hashtable table, String title, Object[][] items) { String[] names = createNames(title + "_", items.length); for (int i = 0; i < items.length; i++) { addToDump(table, names[i], items[i]); } return names; } //////////////////////////////////////////////////////// //Private // //////////////////////////////////////////////////////// private R runMappingPrimitive(QueueTool.QueueAction action) { return queueTool.invokeSmoothly(action); } private String[] createNames(String title, int count) { String[] result = new String[count]; int indexLength = Integer.toString(count).length(); StringBuilder zeroStringB = new StringBuilder(indexLength); for (int i = 0; i < indexLength; i++) { zeroStringB.append('0'); } String zeroString = zeroStringB.toString(); for (int i = 0; i < count; i++) { String indexString = Integer.toString(i); result[i] = title + zeroString.substring(0, indexLength - indexString.length()) + indexString; } return result; } private static ComponentOperator createOperator(Component comp, Class compClass) { StringTokenizer token = new StringTokenizer(compClass.getName(), "."); String className = ""; while (token.hasMoreTokens()) { className = token.nextToken(); } Object[] params = {comp}; Class[] param_classes = {compClass}; String operatorPackage; for (String operatorPkg : operatorPkgs) { operatorPackage = operatorPkg; try { return ((ComponentOperator) new ClassReference(operatorPackage + "." + className + "Operator"). newInstance(params, param_classes)); } catch (ClassNotFoundException ignored) { } catch (InvocationTargetException ignored) { } catch (NoSuchMethodException ignored) { } catch (IllegalAccessException ignored) { } catch (InstantiationException ignored) { } } return null; } private void initEnvironment() { queueTool = new QueueTool(); setTimeouts(JemmyProperties.getProperties().getTimeouts()); setOutput(JemmyProperties.getProperties().getOutput()); setCharBindingMap(JemmyProperties.getProperties().getCharBindingMap()); setVisualizer(getDefaultComponentVisualizer()); setComparator(getDefaultStringComparator()); setVerification(getDefaultVerification()); setProperties(JemmyProperties.getProperties()); setPathParser(getDefaultPathParser()); } /** * Returns toString() result from component of this operator. It calls * {@link #getSource}.toString() in dispatch thread. * * @return toString() result from component of this operator. */ public String toStringSource() { return runMapping(new MapAction("getSource().toString()") { @Override public String map() { return getSource().toString(); } }); } /** * Interface used to make component visible & ready to to make operations * with. */ public interface ComponentVisualizer { /** * Prepares component for a user input. * * @param compOper Operator asking for necessary actions. */ public void makeVisible(ComponentOperator compOper); } /** * Interface to compare string resources like labels, button text, ... with * match.
*/ public interface StringComparator { /** * Imlementation must return true if strings are equal. * * @param caption a text to compare with pattern. * @param match a pattern * @return true if text and pattern matches. */ public boolean equals(String caption, String match); } /** * Default StringComparator implementation. */ public static class DefaultStringComparator implements StringComparator { boolean ce; boolean ccs; /** * Constructs a DefaultStringComparator object. * * @param ce Compare exactly. If false, text can be a substring of * caption. * @param ccs Compare case sensitively. */ public DefaultStringComparator(boolean ce, boolean ccs) { this.ce = ce; this.ccs = ccs; } /** * Compares a caption with a match using switched passed into * constructor. * * @param caption String to be compared with match. Method returns * false, if parameter is null. * @param match Sample to compare with. Method returns true, if * parameter is null. * @return true if text and pattern matches. */ @Override public boolean equals(String caption, String match) { if (match == null) { return true; } if (caption == null) { return false; } String c, t; if (!ccs) { c = caption.toUpperCase(); t = match.toUpperCase(); } else { c = caption; t = match; } if (ce) { return c.equals(t); } else { return c.contains(t); } } } /** * Used for parsing of path-like strings. */ public interface PathParser { /** * Parses a string to a String array. * * @param path a String to parse. * @return a parsed array. */ public String[] parse(String path); } /** * Used for parsing of path-like strings where path components are separated * by a string-separator: "drive|directory|subdirectory|file". */ public static class DefaultPathParser implements PathParser { String separator; /** * Constructs a DefaultPathParser object. * * @param separator a string used as separator. */ public DefaultPathParser(String separator) { this.separator = separator; } @Override public String[] parse(String path) { if (path.length() > 0) { Vector parsed = new Vector<>(); int position = 0; int sepIndex = 0; while ((sepIndex = path.indexOf(separator, position)) != -1) { parsed.add(path.substring(position, sepIndex)); position = sepIndex + separator.length(); } parsed.add(path.substring(position)); String[] result = new String[parsed.size()]; for (int i = 0; i < parsed.size(); i++) { result[i] = parsed.get(i); } return result; } else { return new String[0]; } } } /** * Allows to bind a component by a component type. */ public static class Finder implements ComponentChooser { Class clz; ComponentChooser subchooser; /** * Constructs Finder. * * @param clz a component class. * @param subchooser other searching criteria. */ public Finder(Class clz, ComponentChooser subchooser) { this.clz = clz; this.subchooser = subchooser; } /** * Constructs Finder. * * @param clz a component class. */ public Finder(Class clz) { this(clz, ComponentSearcher.getTrueChooser("Any " + clz.getName())); } @Override public boolean checkComponent(Component comp) { if (clz.isInstance(comp)) { return subchooser.checkComponent(comp); } return false; } @Override public String getDescription() { return subchooser.getDescription(); } @Override public String toString() { return "Finder{" + "clz=" + clz + ", subchooser=" + subchooser + '}'; } } /** * Can be used to make nonblocking operation implementation. Typical * scenario is:
* produceNoBlocking(new NoBlockingAction("Button pushing") {
* public Object doAction(Object param) {
* push();
* return null;
* }
* });
*/ protected abstract class NoBlockingAction implements Action { String description; Exception exception; /** * Constructs a NoBlockingAction object. * * @param description an action description. */ public NoBlockingAction(String description) { this.description = description; exception = null; } @Override public final R launch(P param) { R result = null; try { result = doAction(param); } catch (Exception e) { exception = e; } return result; } /** * Performs a mapping action. * * @param param an action parameter. * @return an action result. */ public abstract R doAction(P param); @Override public String getDescription() { return description; } @Override public String toString() { return "NoBlockingAction{" + "description=" + description + ", exception=" + exception + '}'; } /** * Specifies the exception. * * @param e an exception. * @see #getException */ protected void setException(Exception e) { exception = e; } /** * Returns an exception occurred during the action execution. * * @return an exception. * @see #setException */ public Exception getException() { return exception; } } /** * Can be used to simplify non-primitive type component's methods mapping. * Like this:
* public Color getBackground() {
* return((Color)runMapping(new MapAction("getBackground") {
* public Object map() {
* return ((Component)getSource()).getBackground();
* }
* }));
* }
* * @see #runMapping(Operator.MapAction) */ protected abstract class MapAction extends QueueTool.QueueAction { /** * Constructs a MapAction object. * * @param description an action description. */ public MapAction(String description) { super(description); } @Override public final R launch() throws Exception { return map(); } /** * Executes a map action. * * @return an action result. * @throws Exception */ public abstract R map() throws Exception; } /** * Can be used to simplify char component's methods mapping. * * @see #runMapping(Operator.MapCharacterAction) */ protected abstract class MapCharacterAction extends QueueTool.QueueAction { /** * Constructs a MapCharacterAction object. * * @param description an action description. */ public MapCharacterAction(String description) { super(description); } @Override public final Object launch() throws Exception { return map(); } /** * Executes a map action. * * @return an action result. * @throws Exception */ public abstract char map() throws Exception; } /** * Can be used to simplify byte component's methods mapping. * * @see #runMapping(Operator.MapByteAction) */ protected abstract class MapByteAction extends QueueTool.QueueAction { /** * Constructs a MapByteAction object. * * @param description an action description. */ public MapByteAction(String description) { super(description); } @Override public final Object launch() throws Exception { return map(); } /** * Executes a map action. * * @return an action result. * @throws Exception */ public abstract byte map() throws Exception; } /** * Can be used to simplify int component's methods mapping. * * @see #runMapping(Operator.MapIntegerAction) */ protected abstract class MapIntegerAction extends QueueTool.QueueAction { /** * Constructs a MapIntegerAction object. * * @param description an action description. */ public MapIntegerAction(String description) { super(description); } @Override public final Object launch() throws Exception { return map(); } /** * Executes a map action. * * @return an action result. * @throws Exception */ public abstract int map() throws Exception; } /** * Can be used to simplify long component's methods mapping. * * @see #runMapping(Operator.MapLongAction) */ protected abstract class MapLongAction extends QueueTool.QueueAction { /** * Constructs a MapLongAction object. * * @param description an action description. */ public MapLongAction(String description) { super(description); } @Override public final Object launch() throws Exception { return map(); } /** * Executes a map action. * * @return an action result. * @throws Exception */ public abstract long map() throws Exception; } /** * Can be used to simplify float component's methods mapping. * * @see #runMapping(Operator.MapFloatAction) */ protected abstract class MapFloatAction extends QueueTool.QueueAction { /** * Constructs a MapFloatAction object. * * @param description an action description. */ public MapFloatAction(String description) { super(description); } @Override public final Object launch() throws Exception { return map(); } /** * Executes a map action. * * @return an action result. * @throws Exception */ public abstract float map() throws Exception; } /** * Can be used to simplify double component's methods mapping. * * @see #runMapping(Operator.MapDoubleAction) */ protected abstract class MapDoubleAction extends QueueTool.QueueAction { /** * Constructs a MapDoubleAction object. * * @param description an action description. */ public MapDoubleAction(String description) { super(description); } @Override public final Object launch() throws Exception { return map(); } /** * Executes a map action. * * @return an action result. * @throws Exception */ public abstract double map() throws Exception; } /** * Can be used to simplify boolean component's methods mapping. * * @see #runMapping(Operator.MapBooleanAction) */ protected abstract class MapBooleanAction extends QueueTool.QueueAction { /** * Constructs a MapBooleanAction object. * * @param description an action description. */ public MapBooleanAction(String description) { super(description); } @Override public final Object launch() throws Exception { return map() ? Boolean.TRUE : Boolean.FALSE; } /** * Executes a map action. * * @return an action result. * @throws Exception */ public abstract boolean map() throws Exception; } /** * Can be used to simplify void component's methods mapping. * * @see #runMapping(Operator.MapVoidAction) */ protected abstract class MapVoidAction extends QueueTool.QueueAction { /** * Constructs a MapVoidAction object. * * @param description an action description. */ public MapVoidAction(String description) { super(description); } @Override public final Object launch() throws Exception { map(); return null; } /** * Executes a map action. * * @throws Exception */ public abstract void map() throws Exception; } private static class NullOperator extends Operator { public NullOperator() { super(); } @Override public Component getSource() { return null; } } }