blob: 68ba836b333afa0a63a62d4a2379216c1bbaf3cf [file] [log] [blame]
/*
* 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<String> 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. <BR>
* "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)
//solaris - new MouseVisualizer()
//others - new DefaultVisualizer()
if (Platform.isLinux()) {
setDefaultComponentVisualizer(new MouseVisualizer(MouseVisualizer.TOP, 0.5, 10, false));
} else if (Platform.isSolaris()) {
setDefaultComponentVisualizer(new MouseVisualizer());
} 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<String, Object> 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<String, Object> getDump() {
Hashtable<String, Object> 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<String, Void>() {
@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> R waitState(Waitable<R, Void> waitable) {
Waiter<R, Void> 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<Object>("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, P> R produceTimeRestricted(Action<R, P> action, final P param,
String actionTimeOrigin) {
ActionProducer<R, P> 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, P> R produceTimeRestricted(Action<R, P> 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 <R, P> void produceNoBlocking(NoBlockingAction<R, P> action, P param) {
try {
ActionProducer<R, P> 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> R runMapping(MapAction<R> 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<String, Object> 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<String, Object> 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> R runMappingPrimitive(QueueTool.QueueAction<R> 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<String>("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. <BR>
*/
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<String> 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: <BR>
* produceNoBlocking(new NoBlockingAction("Button pushing") {<BR>
* public Object doAction(Object param) {<BR>
* push();<BR>
* return null;<BR>
* }<BR>
* });<BR>
*/
protected abstract class NoBlockingAction<R, P> implements Action<R, P> {
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: <BR>
* public Color getBackground() { <BR>
* return((Color)runMapping(new MapAction("getBackground") { <BR>
* public Object map() { <BR>
* return ((Component)getSource()).getBackground(); <BR>
* } <BR>
* })); <BR>
* } <BR>
*
* @see #runMapping(Operator.MapAction)
*/
protected abstract class MapAction<R> extends QueueTool.QueueAction<R> {
/**
* 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<Object> {
/**
* 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<Object> {
/**
* 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<Object> {
/**
* 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<Object> {
/**
* 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<Object> {
/**
* 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<Object> {
/**
* 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<Object> {
/**
* 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<Object> {
/**
* 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;
}
}
}