0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s): Alexandre Iline.
0025: *
0026: * The Original Software is the Jemmy library.
0027: * The Initial Developer of the Original Software is Alexandre Iline.
0028: * All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: *
0041: *
0042: *
0043: * $Id$ $Revision$ $Date$
0044: *
0045: */
0046:
0047: package org.netbeans.jemmy.operators;
0048:
0049: import org.netbeans.jemmy.Action;
0050: import org.netbeans.jemmy.ActionProducer;
0051: import org.netbeans.jemmy.CharBindingMap;
0052: import org.netbeans.jemmy.ClassReference;
0053: import org.netbeans.jemmy.ComponentChooser;
0054: import org.netbeans.jemmy.ComponentSearcher;
0055: import org.netbeans.jemmy.JemmyException;
0056: import org.netbeans.jemmy.JemmyProperties;
0057: import org.netbeans.jemmy.Outputable;
0058: import org.netbeans.jemmy.QueueTool;
0059: import org.netbeans.jemmy.QueueTool.QueueAction;
0060: import org.netbeans.jemmy.TestOut;
0061: import org.netbeans.jemmy.Timeoutable;
0062: import org.netbeans.jemmy.Timeouts;
0063: import org.netbeans.jemmy.Waitable;
0064: import org.netbeans.jemmy.Waiter;
0065:
0066: import org.netbeans.jemmy.util.DefaultVisualizer;
0067: import org.netbeans.jemmy.util.MouseVisualizer;
0068:
0069: import java.awt.Component;
0070:
0071: import java.awt.event.InputEvent;
0072: import java.awt.event.KeyEvent;
0073:
0074: import java.lang.reflect.InvocationTargetException;
0075:
0076: import java.util.Hashtable;
0077: import java.util.StringTokenizer;
0078: import java.util.Vector;
0079:
0080: /**
0081: * Keeps all environment and low-level methods.
0082: *
0083: * @author Alexandre Iline (alexandre.iline@sun.com)
0084: */
0085:
0086: public abstract class Operator extends Object implements Timeoutable,
0087: Outputable {
0088:
0089: /**
0090: * Identifier for a "class" property.
0091: * @see #getDump
0092: */
0093: public static final String CLASS_DPROP = "Class";
0094:
0095: /**
0096: * Identifier for a "toString" property.
0097: * @see #getDump
0098: */
0099: public static final String TO_STRING_DPROP = "toString";
0100:
0101: private static Vector operatorPkgs;
0102:
0103: private Timeouts timeouts;
0104: private TestOut output;
0105: private ClassReference codeDefiner;
0106: private int model;
0107: private CharBindingMap map;
0108: private ComponentVisualizer visualizer;
0109: private StringComparator comparator;
0110: private PathParser parser;
0111: private QueueTool queueTool;
0112: private boolean verification = false;
0113: private JemmyProperties properties;
0114:
0115: /**
0116: * Inits environment.
0117: */
0118: public Operator() {
0119: super ();
0120: initEnvironment();
0121: }
0122:
0123: /**
0124: * Specifies an object to be used by default to prepare component.
0125: * Each new operator created after the method using will have
0126: * defined visualizer.
0127: * Default implementation is org.netbeans.jemmy.util.DefaultVisualizer class.
0128: * @param visualizer ComponentVisualizer implementation
0129: * @return previous value
0130: * @see #setVisualizer(Operator.ComponentVisualizer)
0131: * @see #getDefaultComponentVisualizer()
0132: * @see org.netbeans.jemmy.util.DefaultVisualizer
0133: */
0134: public static ComponentVisualizer setDefaultComponentVisualizer(
0135: ComponentVisualizer visualizer) {
0136: return ((ComponentVisualizer) JemmyProperties
0137: .setCurrentProperty(
0138: "ComponentOperator.ComponentVisualizer",
0139: visualizer));
0140: }
0141:
0142: /**
0143: * Returns an object to be used by default to prepare component.
0144: * @return Object is used by default to prepare component
0145: * @see #getVisualizer()
0146: * @see #setDefaultComponentVisualizer(Operator.ComponentVisualizer)
0147: */
0148: public static ComponentVisualizer getDefaultComponentVisualizer() {
0149: return ((ComponentVisualizer) JemmyProperties
0150: .getCurrentProperty("ComponentOperator.ComponentVisualizer"));
0151: }
0152:
0153: /**
0154: * Defines string comparator to be assigned in constructor.
0155: * @param comparator the comparator to be used by default.
0156: * @return previous value.
0157: * @see #getDefaultStringComparator()
0158: * @see Operator.StringComparator
0159: */
0160: public static StringComparator setDefaultStringComparator(
0161: StringComparator comparator) {
0162: return ((StringComparator) JemmyProperties.setCurrentProperty(
0163: "ComponentOperator.StringComparator", comparator));
0164: }
0165:
0166: /**
0167: * Returns string comparator used to init operators.
0168: * @return the comparator used by default.
0169: * @see #setDefaultStringComparator(Operator.StringComparator)
0170: * @see Operator.StringComparator
0171: */
0172: public static StringComparator getDefaultStringComparator() {
0173: return ((StringComparator) JemmyProperties
0174: .getCurrentProperty("ComponentOperator.StringComparator"));
0175: }
0176:
0177: /**
0178: * Specifies an object used for parsing of path-like strings.
0179: * @param parser the parser.
0180: * @return a previous value.
0181: * @see Operator.PathParser
0182: * @see #getDefaultPathParser
0183: */
0184: public static PathParser setDefaultPathParser(PathParser parser) {
0185: return ((PathParser) JemmyProperties.setCurrentProperty(
0186: "ComponentOperator.PathParser", parser));
0187: }
0188:
0189: /**
0190: * Returns an object used for parsing of path-like strings.
0191: * @return a parser used by default.
0192: * @see Operator.PathParser
0193: * @see #setDefaultPathParser
0194: */
0195: public static PathParser getDefaultPathParser() {
0196: return ((PathParser) JemmyProperties
0197: .getCurrentProperty("ComponentOperator.PathParser"));
0198: }
0199:
0200: /**
0201: * Defines weither newly created operators should perform operation verifications by default.
0202: * @param verification a verification mode to be used by default.
0203: * @return a prevoius value.
0204: * @see #getDefaultVerification()
0205: * @see #setVerification(boolean)
0206: */
0207: public static boolean setDefaultVerification(boolean verification) {
0208: Boolean oldValue = (Boolean) (JemmyProperties
0209: .setCurrentProperty("Operator.Verification",
0210: verification ? Boolean.TRUE : Boolean.FALSE));
0211: return ((oldValue != null) ? oldValue.booleanValue() : false);
0212: }
0213:
0214: /**
0215: * Says weither newly created operators perform operations verifications by default.
0216: * @return a verification mode used by default.
0217: * @see #setDefaultVerification(boolean)
0218: * @see #getVerification()
0219: */
0220: public static boolean getDefaultVerification() {
0221: return (((Boolean) (JemmyProperties
0222: .getCurrentProperty("Operator.Verification")))
0223: .booleanValue());
0224: }
0225:
0226: /**
0227: * Compares caption (button text, window title, ...) with a sample text.
0228: * @param caption String to be compared with match. Method returns false, if parameter is null.
0229: * @param match Sample to compare with. Method returns true, if parameter is null.
0230: * @param ce Compare exactly. If true, text can be a substring of caption.
0231: * @param ccs Compare case sensitively. If true, both text and caption are
0232: * converted to upper case before comparison.
0233: * @return true is the captions matched the match.
0234: * @see #isCaptionEqual
0235: * @deprecated use another methods with the same name.
0236: */
0237: public static boolean isCaptionEqual(String caption, String match,
0238: boolean ce, boolean ccs) {
0239: return (new DefaultStringComparator(ce, ccs).equals(caption,
0240: match));
0241: }
0242:
0243: /**
0244: * Compares caption (button text, window title, ...) with a sample text.
0245: * @param caption String to be compared with match
0246: * @param match Sample to compare with
0247: * @param comparator StringComparator instance.
0248: * @return true is the captions matched the match.
0249: * @see #isCaptionEqual
0250: */
0251: public static boolean isCaptionEqual(String caption, String match,
0252: StringComparator comparator) {
0253: return (comparator.equals(caption, match));
0254: }
0255:
0256: /**
0257: * Returns default mouse button mask.
0258: * @return <code>InputEvent.BUTTON*_MASK</code> field value
0259: */
0260: public static int getDefaultMouseButton() {
0261: return (InputEvent.BUTTON1_MASK);
0262: }
0263:
0264: /**
0265: * Returns mask of mouse button which used to popup expanding. (InputEvent.BUTTON3_MASK)
0266: * @return <code>InputEvent.BUTTON*_MASK</code> field value
0267: */
0268: public static int getPopupMouseButton() {
0269: return (InputEvent.BUTTON3_MASK);
0270: }
0271:
0272: /**
0273: * Creates operator for component.
0274: * Tries to find class with "operator package"."class name"Operator name,
0275: * where "operator package" is a package from operator packages list,
0276: * and "class name" is the name of class or one of its superclasses.
0277: * @param comp Component to create operator for.
0278: * @return a new operator with default environment.
0279: * @see #addOperatorPackage(String)
0280: */
0281: public static ComponentOperator createOperator(Component comp) {
0282: //hack!
0283: try {
0284: Class cclass = Class.forName("java.awt.Component");
0285: Class compClass = comp.getClass();
0286: ComponentOperator result;
0287: do {
0288: if ((result = createOperator(comp, compClass)) != null) {
0289: return (result);
0290: }
0291: } while (cclass.isAssignableFrom(compClass = compClass
0292: .getSuperclass()));
0293: } catch (ClassNotFoundException e) {
0294: }
0295: return (null);
0296: }
0297:
0298: /**
0299: * Adds package to the list of packages containing operators. <BR>
0300: * "org.netbeans.jemmy.operators" is in the list by default.
0301: * @param pkgName Package name.
0302: * @see #createOperator(Component)
0303: */
0304: public static void addOperatorPackage(String pkgName) {
0305: operatorPkgs.add(pkgName);
0306: }
0307:
0308: /**
0309: * Returns an operator containing default environment.
0310: * @return an empty operator (not having any component source)
0311: * having default environment.
0312: */
0313: public static Operator getEnvironmentOperator() {
0314: return (new NullOperator());
0315: }
0316:
0317: static {
0318: //init visualizer depending on OS:
0319: //Linux - new MouseVisualizer(MouseVisualizer.TOP, 0.5, 10, false)
0320: //solaris - new MouseVisualizer()
0321: //others - new DefaultVisualizer()
0322: String os = System.getProperty("os.name").toUpperCase();
0323: if (os.startsWith("LINUX")) {
0324: setDefaultComponentVisualizer(new MouseVisualizer(
0325: MouseVisualizer.TOP, 0.5, 10, false));
0326: } else if (os.startsWith("SUNOS")) {
0327: setDefaultComponentVisualizer(new MouseVisualizer());
0328: } else {
0329: setDefaultComponentVisualizer(new DefaultVisualizer());
0330: }
0331: operatorPkgs = new Vector();
0332: setDefaultStringComparator(new DefaultStringComparator(false,
0333: false));
0334: setDefaultPathParser(new DefaultPathParser("|"));
0335: addOperatorPackage("org.netbeans.jemmy.operators");
0336: setDefaultVerification(true);
0337: }
0338:
0339: /**
0340: * Returns object operator is used for.
0341: * @return an instance of java.awt.Component subclass
0342: * which this operator was created for.
0343: */
0344: public abstract Component getSource();
0345:
0346: ////////////////////////////////////////////////////////
0347: //Environment //
0348: ////////////////////////////////////////////////////////
0349:
0350: /**
0351: * Returns QueueTool is used to work with queue.
0352: * @return a QueueTool.
0353: */
0354: public QueueTool getQueueTool() {
0355: return (queueTool);
0356: }
0357:
0358: /**
0359: * Copies all environment (output, timeouts,
0360: * visualizer) from another operator.
0361: * @param anotherOperator an operator to copy the environment to.
0362: */
0363: public void copyEnvironment(Operator anotherOperator) {
0364: setTimeouts(anotherOperator.getTimeouts());
0365: setOutput(anotherOperator.getOutput());
0366: setVisualizer(anotherOperator.getVisualizer());
0367: setComparator(anotherOperator.getComparator());
0368: setVerification(anotherOperator.getVerification());
0369: setCharBindingMap(anotherOperator.getCharBindingMap());
0370: setProperties(anotherOperator.getProperties());
0371: }
0372:
0373: public void setTimeouts(Timeouts timeouts) {
0374: this .timeouts = timeouts;
0375: queueTool.setTimeouts(timeouts);
0376: }
0377:
0378: public Timeouts getTimeouts() {
0379: return (timeouts);
0380: }
0381:
0382: /**
0383: * Returns component visualizer.
0384: * Visualizer is used from from makeComponentVisible() method.
0385: * @return a visualizer assigned to this operator.
0386: * @see #getDefaultComponentVisualizer()
0387: * @see #setVisualizer(Operator.ComponentVisualizer)
0388: */
0389: public ComponentVisualizer getVisualizer() {
0390: return (visualizer);
0391: }
0392:
0393: /**
0394: * Changes component visualizer.
0395: * Visualizer is used from from makeComponentVisible() method.
0396: * @param vo a visualizer to assign to this operator.
0397: * @see #setDefaultComponentVisualizer(Operator.ComponentVisualizer)
0398: * @see #getVisualizer()
0399: */
0400: public void setVisualizer(ComponentVisualizer vo) {
0401: visualizer = vo;
0402: }
0403:
0404: /**
0405: * Returns a JemmyProperty object assigned to this operator.
0406: * @return a JemmyProperty object got from the top of property stack
0407: * or from another operator by copyuing environment.
0408: * @see #setProperties
0409: */
0410: public JemmyProperties getProperties() {
0411: return (properties);
0412: }
0413:
0414: /**
0415: * Assigns a JemmyProperty object to this operator.
0416: * @param properties a properties to assign to this operator.
0417: * @return previously assigned properties.
0418: * @see #getProperties
0419: */
0420: public JemmyProperties setProperties(JemmyProperties properties) {
0421: JemmyProperties oldProperties = getProperties();
0422: this .properties = properties;
0423: return (oldProperties);
0424: }
0425:
0426: /**
0427: * Defines CharBindingMap.
0428: * @param map a CharBindingMap to use for keyboard operations.
0429: * @see org.netbeans.jemmy.CharBindingMap
0430: * @see org.netbeans.jemmy.JemmyProperties#setCurrentCharBindingMap(CharBindingMap)
0431: * @see #getCharBindingMap
0432: */
0433: public void setCharBindingMap(CharBindingMap map) {
0434: this .map = map;
0435: }
0436:
0437: /**
0438: * Returns CharBindingMap used for keyboard operations.
0439: * @return a map assigned to this object.
0440: * @see #setCharBindingMap
0441: */
0442: public CharBindingMap getCharBindingMap() {
0443: return (map);
0444: }
0445:
0446: public void setOutput(TestOut out) {
0447: output = out;
0448: queueTool.setOutput(output.createErrorOutput());
0449: }
0450:
0451: public TestOut getOutput() {
0452: return (output);
0453: }
0454:
0455: /**
0456: * Returns object which is used for string comparison.
0457: * @return a comparator assigned to this operator.
0458: * @see org.netbeans.jemmy.operators.Operator.StringComparator
0459: * @see org.netbeans.jemmy.operators.Operator.DefaultStringComparator
0460: * @see #setComparator
0461: */
0462: public StringComparator getComparator() {
0463: return (comparator);
0464: }
0465:
0466: /**
0467: * Defines object which is used for string comparison.
0468: * @param comparator a comparator to use for string comparision.
0469: * @see org.netbeans.jemmy.operators.Operator.StringComparator
0470: * @see org.netbeans.jemmy.operators.Operator.DefaultStringComparator
0471: * @see #getComparator
0472: */
0473: public void setComparator(StringComparator comparator) {
0474: this .comparator = comparator;
0475: }
0476:
0477: /**
0478: * Returns object which is used for parsing of path-like strings.
0479: * @return a comparator assigned to this operator.
0480: * @see #setPathParser
0481: */
0482: public PathParser getPathParser() {
0483: return (parser);
0484: }
0485:
0486: /**
0487: * Specifies object which is used for parsing of path-like strings.
0488: * @param parser a parser to use for path parsing.
0489: * @see #getPathParser
0490: */
0491: public void setPathParser(PathParser parser) {
0492: this .parser = parser;
0493: }
0494:
0495: /**
0496: * Defines weither operator should perform operation verifications.
0497: * @param verification new value.
0498: * @return old value
0499: * @see #setDefaultVerification(boolean)
0500: * @see #getDefaultVerification()
0501: * @see #getVerification()
0502: */
0503: public boolean setVerification(boolean verification) {
0504: boolean oldValue = this .verification;
0505: this .verification = verification;
0506: return (oldValue);
0507: }
0508:
0509: /**
0510: * Says weither operator performs operation verifications.
0511: * @return old value
0512: * @see #setDefaultVerification(boolean)
0513: * @see #getDefaultVerification()
0514: * @see #setVerification(boolean)
0515: */
0516: public boolean getVerification() {
0517: return (verification);
0518: }
0519:
0520: ////////////////////////////////////////////////////////
0521: //Util //
0522: ////////////////////////////////////////////////////////
0523:
0524: /**
0525: * Creates new array which has all elements from
0526: * first array, except last element.
0527: * @param path an original array
0528: * @return new array
0529: */
0530: public String[] getParentPath(String path[]) {
0531: if (path.length > 1) {
0532: String[] ppath = new String[path.length - 1];
0533: for (int i = 0; i < ppath.length; i++) {
0534: ppath[i] = path[i];
0535: }
0536: return (ppath);
0537: } else {
0538: return (new String[0]);
0539: }
0540: }
0541:
0542: public ComponentChooser[] getParentPath(ComponentChooser path[]) {
0543: if (path.length > 1) {
0544: ComponentChooser[] ppath = new ComponentChooser[path.length - 1];
0545: for (int i = 0; i < ppath.length; i++) {
0546: ppath[i] = path[i];
0547: }
0548: return (ppath);
0549: } else {
0550: return (new ComponentChooser[0]);
0551: }
0552: }
0553:
0554: /**
0555: * Parses a string to a string array
0556: * using a PathParser assigned to this operator.
0557: * @param path an original string
0558: * @return created String array.
0559: */
0560: public String[] parseString(String path) {
0561: return (getPathParser().parse(path));
0562: }
0563:
0564: /**
0565: * Parses strings like "1|2|3" into arrays {"1", "2", "3"}.
0566: * @param path an original string
0567: * @param delim a delimiter string
0568: * @return created String array.
0569: */
0570: public String[] parseString(String path, String delim) {
0571: return (new DefaultPathParser(delim).parse(path));
0572: }
0573:
0574: /**
0575: * Returns key code to be pressed for character typing.
0576: * @param c Character to be typed.
0577: * @return a value of one of the <code>KeyEvent.VK_*</code> fields.
0578: * @see org.netbeans.jemmy.CharBindingMap
0579: */
0580: public int getCharKey(char c) {
0581: return (map.getCharKey(c));
0582: }
0583:
0584: /**
0585: * Returns modifiers mask for character typing.
0586: * @param c Character to be typed.
0587: * @return a combination of <code>InputEvent.*_MASK</code> fields.
0588: * @see org.netbeans.jemmy.CharBindingMap
0589: */
0590: public int getCharModifiers(char c) {
0591: return (map.getCharModifiers(c));
0592: }
0593:
0594: /**
0595: * Returns key codes to by pressed for characters typing.
0596: * @param c Characters to be typed.
0597: * @return an array of <code>KeyEvent.VK_*</code> values.
0598: * @see org.netbeans.jemmy.CharBindingMap
0599: */
0600: public int[] getCharsKeys(char[] c) {
0601: int[] result = new int[c.length];
0602: for (int i = 0; i < c.length; i++) {
0603: result[i] = getCharKey(c[i]);
0604: }
0605: return (result);
0606: }
0607:
0608: /**
0609: * Returns modifiers masks for characters typing.
0610: * @param c Characters to be typed.
0611: * @return an array of a combination of <code>InputEvent.*_MASK</code> fields.
0612: * @see org.netbeans.jemmy.CharBindingMap
0613: */
0614: public int[] getCharsModifiers(char[] c) {
0615: int[] result = new int[c.length];
0616: for (int i = 0; i < c.length; i++) {
0617: result[i] = getCharModifiers(c[i]);
0618: }
0619: return (result);
0620: }
0621:
0622: /**
0623: * Returns key codes to by pressed for the string typing.
0624: * @param s String to be typed.
0625: * @return an array of <code>KeyEvent.VK_*</code> values.
0626: * @see org.netbeans.jemmy.CharBindingMap
0627: */
0628: public int[] getCharsKeys(String s) {
0629: return (getCharsKeys(s.toCharArray()));
0630: }
0631:
0632: /**
0633: * Returns modifiers masks for the string typing.
0634: * @param s String to be typed.
0635: * @return an array of a combination of <code>InputEvent.*_MASK</code> fields.
0636: * @see org.netbeans.jemmy.CharBindingMap
0637: */
0638: public int[] getCharsModifiers(String s) {
0639: return (getCharsModifiers(s.toCharArray()));
0640: }
0641:
0642: /**
0643: * Compares string using getComparator StringComparator.
0644: * @param caption a caption
0645: * @param match a pattern
0646: * @return true if <code>caption</code> and <code>match</code> match
0647: * @see #isCaptionEqual
0648: */
0649: public boolean isCaptionEqual(String caption, String match) {
0650: return (comparator.equals(caption, match));
0651: }
0652:
0653: /**
0654: * Prints component information into operator output.
0655: */
0656: public void printDump() {
0657: Hashtable result = getDump();
0658: Object[] keys = result.keySet().toArray();
0659: for (int i = 0; i < result.size(); i++) {
0660: output.printLine((String) keys[i] + " = "
0661: + (String) result.get(keys[i]));
0662: }
0663: }
0664:
0665: /**
0666: * Returns information about component.
0667: * All records marked by simbolic constants defined in
0668: * public static final <code>*_DPROP</code> fields for
0669: * each operator type.
0670: * @return a Hashtable containing name-value pairs.
0671: */
0672: public Hashtable getDump() {
0673: Hashtable result = new Hashtable();
0674: result.put(CLASS_DPROP, getSource().getClass().getName());
0675: result.put(TO_STRING_DPROP, getSource().toString());
0676: return (result);
0677: }
0678:
0679: /**
0680: * Waits a state specified by a ComponentChooser instance.
0681: * @param state a ComponentChooser defining the state criteria.
0682: * @throws TimeoutExpiredException if the state has not
0683: * achieved in a value defined by <code>"ComponentOperator.WaitStateTimeout"</code>
0684: */
0685: public void waitState(final ComponentChooser state) {
0686: Waiter stateWaiter = new Waiter(new Waitable() {
0687: public Object actionProduced(Object obj) {
0688: return (state.checkComponent(getSource()) ? "" : null);
0689: }
0690:
0691: public String getDescription() {
0692: return ("Wait \"" + state.getDescription() + "\" state to be reached");
0693: }
0694: });
0695: stateWaiter.setTimeouts(getTimeouts().cloneThis());
0696: stateWaiter.getTimeouts().setTimeout(
0697: "Waiter.WaitingTime",
0698: getTimeouts().getTimeout(
0699: "ComponentOperator.WaitStateTimeout"));
0700: stateWaiter.setOutput(getOutput().createErrorOutput());
0701: try {
0702: stateWaiter.waitAction(null);
0703: } catch (InterruptedException e) {
0704: throw (new JemmyException("Waiting of \""
0705: + state.getDescription()
0706: + "\" state has been interrupted!"));
0707: }
0708: }
0709:
0710: ////////////////////////////////////////////////////////
0711: //Mapping //
0712: ////////////////////////////////////////////////////////
0713:
0714: /**
0715: * Performs an operation with time control.
0716: * @param action an action to execute.
0717: * @param param an action parameters.
0718: * @param wholeTime a time for the action to be finished.
0719: * @return an action result.
0720: */
0721: protected Object produceTimeRestricted(Action action,
0722: final Object param, long wholeTime) {
0723: ActionProducer producer = new ActionProducer(action);
0724: producer.setOutput(getOutput().createErrorOutput());
0725: producer.setTimeouts(getTimeouts().cloneThis());
0726: producer.getTimeouts().setTimeout(
0727: "ActionProducer.MaxActionTime", wholeTime);
0728: try {
0729: Object result = producer.produceAction(param);
0730: Throwable exception = producer.getException();
0731: if (exception != null) {
0732: if (exception instanceof JemmyException) {
0733: throw ((JemmyException) exception);
0734: } else {
0735: throw (new JemmyException("Exception during "
0736: + action.getDescription(), exception));
0737: }
0738: }
0739: return (result);
0740: } catch (InterruptedException e) {
0741: throw (new JemmyException("Interrupted!", e));
0742: }
0743: }
0744:
0745: /**
0746: * Performs an operation with time control.
0747: * @param action an action to execute.
0748: * @param wholeTime a time for the action to be finished.
0749: * @return an action result.
0750: */
0751: protected Object produceTimeRestricted(Action action, long wholeTime) {
0752: return (produceTimeRestricted(action, null, wholeTime));
0753: }
0754:
0755: /**
0756: * Performs an operation without time control.
0757: * @param action an action to execute.
0758: * @param param an action parameters.
0759: */
0760: protected void produceNoBlocking(NoBlockingAction action,
0761: Object param) {
0762: try {
0763: ActionProducer noBlockingProducer = new ActionProducer(
0764: action, false);
0765: noBlockingProducer.setOutput(output.createErrorOutput());
0766: noBlockingProducer.setTimeouts(timeouts);
0767: noBlockingProducer.produceAction(param);
0768: } catch (InterruptedException e) {
0769: throw (new JemmyException("Exception during \""
0770: + action.getDescription() + "\" execution", e));
0771: }
0772: if (action.exception != null) {
0773: throw (new JemmyException("Exception during nonblocking \""
0774: + action.getDescription() + "\"", action.exception));
0775: }
0776: }
0777:
0778: /**
0779: * Performs an operation without time control.
0780: * @param action an action to execute.
0781: */
0782: protected void produceNoBlocking(NoBlockingAction action) {
0783: produceNoBlocking(action, null);
0784: }
0785:
0786: /**
0787: * Equivalent to <code>getQueue().lock();</code>.
0788: */
0789: protected void lockQueue() {
0790: queueTool.lock();
0791: }
0792:
0793: /**
0794: * Equivalent to <code>getQueue().unlock();</code>.
0795: */
0796: protected void unlockQueue() {
0797: queueTool.unlock();
0798: }
0799:
0800: /**
0801: * Unlocks Queue and then throw exception.
0802: * @param e an exception to be thrown.
0803: */
0804: protected void unlockAndThrow(Exception e) {
0805: unlockQueue();
0806: throw (new JemmyException("Exception during queue locking", e));
0807: }
0808:
0809: /**
0810: * To map nonprimitive type component's method.
0811: * @param action a mapping action.
0812: * @return an action result.
0813: * @see Operator.MapAction
0814: */
0815: protected Object runMapping(MapAction action) {
0816: return (runMappingPrimitive(action));
0817: }
0818:
0819: /**
0820: * To map char component's method.
0821: * @param action a mapping action.
0822: * @return an action result.
0823: * @see #runMapping(Operator.MapAction)
0824: * @see Operator.MapCharacterAction
0825: */
0826: protected char runMapping(MapCharacterAction action) {
0827: return (((Character) runMappingPrimitive(action)).charValue());
0828: }
0829:
0830: /**
0831: * To map byte component's method.
0832: * @param action a mapping action.
0833: * @return an action result.
0834: * @see #runMapping(Operator.MapAction)
0835: * @see Operator.MapByteAction
0836: */
0837: protected byte runMapping(MapByteAction action) {
0838: return (((Byte) runMappingPrimitive(action)).byteValue());
0839: }
0840:
0841: /**
0842: * To map int component's method.
0843: * @param action a mapping action.
0844: * @return an action result.
0845: * @see #runMapping(Operator.MapAction)
0846: * @see Operator.MapIntegerAction
0847: */
0848: protected int runMapping(MapIntegerAction action) {
0849: return (((Integer) runMappingPrimitive(action)).intValue());
0850: }
0851:
0852: /**
0853: * To map long component's method.
0854: * @param action a mapping action.
0855: * @return an action result.
0856: * @see #runMapping(Operator.MapAction)
0857: * @see Operator.MapLongAction
0858: */
0859: protected long runMapping(MapLongAction action) {
0860: return (((Long) runMappingPrimitive(action)).longValue());
0861: }
0862:
0863: /**
0864: * To map float component's method.
0865: * @param action a mapping action.
0866: * @return an action result.
0867: * @see #runMapping(Operator.MapAction)
0868: * @see Operator.MapFloatAction
0869: */
0870: protected float runMapping(MapFloatAction action) {
0871: return (((Float) runMappingPrimitive(action)).floatValue());
0872: }
0873:
0874: /**
0875: * To map double component's method.
0876: * @param action a mapping action.
0877: * @return an action result.
0878: * @see #runMapping(Operator.MapAction)
0879: * @see Operator.MapDoubleAction
0880: */
0881: protected double runMapping(MapDoubleAction action) {
0882: return (((Double) runMappingPrimitive(action)).doubleValue());
0883: }
0884:
0885: /**
0886: * To map boolean component's method.
0887: * @param action a mapping action.
0888: * @return an action result.
0889: * @see #runMapping(Operator.MapAction)
0890: * @see Operator.MapBooleanAction
0891: */
0892: protected boolean runMapping(MapBooleanAction action) {
0893: return (((Boolean) runMappingPrimitive(action)).booleanValue());
0894: }
0895:
0896: /**
0897: * To map void component's method.
0898: * @param action a mapping action.
0899: * @see #runMapping(Operator.MapAction)
0900: * @see Operator.MapVoidAction
0901: */
0902: protected void runMapping(MapVoidAction action) {
0903: runMappingPrimitive(action);
0904: }
0905:
0906: /**
0907: * Adds array of objects to dump hashtable.
0908: * Is used for multiple properties such as list items and tree nodes.
0909: * @param table a table to add properties to.
0910: * @param title property names prefix. Property names are constructed by
0911: * adding a number to the prefix:
0912: * <code>title + "_" + Iteger.toString("ordinal index")</code>
0913: * @param items an array of property values.
0914: * @return an array of property names (with added numbers).
0915: */
0916: protected String[] addToDump(Hashtable table, String title,
0917: Object[] items) {
0918: String[] names = createNames(title + "_", items.length);
0919: for (int i = 0; i < items.length; i++) {
0920: table.put(names[i], items[i].toString());
0921: }
0922: return (names);
0923: }
0924:
0925: /**
0926: * Adds two dimentional array of objects to dump hashtable.
0927: * Is used for multiple properties such as table cells.
0928: * @param table a table to add properties to.
0929: * @param title property names prefix. Property names are constructed by
0930: * adding two numbers to the prefix:
0931: * <code>title + "_" + Iteger.toString("row index") + "_" + Iteger.toString("column index")</code>
0932: * @param items an array of property values.
0933: * @return an array of property names (with added numbers).
0934: */
0935: protected String[] addToDump(Hashtable table, String title,
0936: Object[][] items) {
0937: String[] names = createNames(title + "_", items.length);
0938: for (int i = 0; i < items.length; i++) {
0939: addToDump(table, names[i], items[i]);
0940: }
0941: return (names);
0942: }
0943:
0944: ////////////////////////////////////////////////////////
0945: //Private //
0946: ////////////////////////////////////////////////////////
0947:
0948: private Object runMappingPrimitive(QueueTool.QueueAction action) {
0949: return (queueTool.invokeSmoothly(action));
0950: }
0951:
0952: private String[] createNames(String title, int count) {
0953: String[] result = new String[count];
0954: int indexLength = Integer.toString(count).length();
0955: String zeroString = "";
0956: for (int i = 0; i < indexLength; i++) {
0957: zeroString = zeroString + "0";
0958: }
0959: String indexString;
0960: for (int i = 0; i < count; i++) {
0961: indexString = Integer.toString(i);
0962: result[i] = title
0963: + zeroString.substring(0, indexLength
0964: - indexString.length()) + indexString;
0965: }
0966: return (result);
0967: }
0968:
0969: private static ComponentOperator createOperator(Component comp,
0970: Class compClass) {
0971: StringTokenizer token = new StringTokenizer(
0972: compClass.getName(), ".");
0973: String className = "";
0974: while (token.hasMoreTokens()) {
0975: className = token.nextToken();
0976: }
0977: Object[] params = { comp };
0978: Class[] param_classes = { compClass };
0979: String operatorPackage;
0980: for (int i = 0; i < operatorPkgs.size(); i++) {
0981: operatorPackage = (String) operatorPkgs.get(i);
0982: try {
0983: return ((ComponentOperator) new ClassReference(
0984: operatorPackage + "." + className + "Operator")
0985: .newInstance(params, param_classes));
0986: } catch (ClassNotFoundException e) {
0987: } catch (InvocationTargetException e) {
0988: } catch (NoSuchMethodException e) {
0989: } catch (IllegalAccessException e) {
0990: } catch (InstantiationException e) {
0991: }
0992: }
0993: return (null);
0994: }
0995:
0996: private void initEnvironment() {
0997: try {
0998: codeDefiner = new ClassReference("java.awt.event.KeyEvent");
0999: } catch (ClassNotFoundException e) {
1000: }
1001: queueTool = new QueueTool();
1002: setTimeouts(JemmyProperties.getProperties().getTimeouts());
1003: setOutput(JemmyProperties.getProperties().getOutput());
1004: setCharBindingMap(JemmyProperties.getProperties()
1005: .getCharBindingMap());
1006: setVisualizer(getDefaultComponentVisualizer());
1007: setComparator(getDefaultStringComparator());
1008: setVerification(getDefaultVerification());
1009: setProperties(JemmyProperties.getProperties());
1010: setPathParser(getDefaultPathParser());
1011: }
1012:
1013: private int nextDelimIndex(String path, String delim) {
1014: String restPath = path;
1015: int ind = 0;
1016: while ((ind = restPath.indexOf(delim)) != -1) {
1017: if (ind == 0 || restPath.substring(ind - 1, ind) != "\\") {
1018: return (ind);
1019: }
1020: }
1021: return (-1);
1022: }
1023:
1024: /**
1025: * Returns toString() result from component of this operator. It calls
1026: * {@link #getSource}.toString() in dispatch thread.
1027: * @return toString() result from component of this operator.
1028: */
1029: public String toStringSource() {
1030: return (String) runMapping(new MapAction(
1031: "getSource().toString()") {
1032: public Object map() {
1033: return getSource().toString();
1034: }
1035: });
1036: }
1037:
1038: /**
1039: * Interface used to make component visible & ready to to make operations with.
1040: */
1041: public interface ComponentVisualizer {
1042: /**
1043: * Prepares component for a user input.
1044: * @param compOper Operator asking for necessary actions.
1045: */
1046: public void makeVisible(ComponentOperator compOper);
1047: }
1048:
1049: /**
1050: * Interface to compare string resources like labels, button text, ...
1051: * with match. <BR>
1052: */
1053: public interface StringComparator {
1054: /**
1055: * Imlementation must return true if strings are equal.
1056: * @param caption a text to compare with pattern.
1057: * @param match a pattern
1058: * @return true if text and pattern matches.
1059: */
1060: public boolean equals(String caption, String match);
1061: }
1062:
1063: /**
1064: * Default StringComparator implementation.
1065: */
1066: public static class DefaultStringComparator implements
1067: StringComparator {
1068: boolean ce;
1069: boolean ccs;
1070:
1071: /**
1072: * Constructs a DefaultStringComparator object.
1073: * @param ce Compare exactly. If true, text can be a substring of caption.
1074: * @param ccs Compare case sensitively. If true, both text and caption are
1075: */
1076: public DefaultStringComparator(boolean ce, boolean ccs) {
1077: this .ce = ce;
1078: this .ccs = ccs;
1079: }
1080:
1081: /**
1082: * Compares a caption with a match using switched passed into constructor.
1083: * @param caption String to be compared with match. Method returns false, if parameter is null.
1084: * @param match Sample to compare with. Method returns true, if parameter is null.
1085: * @return true if text and pattern matches.
1086: */
1087: public boolean equals(String caption, String match) {
1088: if (match == null) {
1089: return (true);
1090: }
1091: if (caption == null) {
1092: return (false);
1093: }
1094: String c, t;
1095: if (!ccs) {
1096: c = caption.toUpperCase();
1097: t = match.toUpperCase();
1098: } else {
1099: c = caption;
1100: t = match;
1101: }
1102: if (ce) {
1103: return (c.equals(t));
1104: } else {
1105: return (c.indexOf(t) != -1);
1106: }
1107: }
1108: }
1109:
1110: /**
1111: * Used for parsing of path-like strings.
1112: */
1113: public interface PathParser {
1114: /**
1115: * Parses a string to a String array.
1116: * @param path a String to parse.
1117: * @return a parsed array.
1118: */
1119: public String[] parse(String path);
1120: }
1121:
1122: /**
1123: * Used for parsing of path-like strings where path components are
1124: * separated by a string-separator: "drive|directory|subdirectory|file".
1125: */
1126: public static class DefaultPathParser implements PathParser {
1127: String separator;
1128:
1129: /**
1130: * Constructs a DefaultPathParser object.
1131: * @param separator a string used as separator.
1132: */
1133: public DefaultPathParser(String separator) {
1134: this .separator = separator;
1135: }
1136:
1137: public String[] parse(String path) {
1138: if (path.length() > 0) {
1139: Vector parsed = new Vector();
1140: int position = 0;
1141: int sepIndex = 0;
1142: while ((sepIndex = path.indexOf(separator, position)) != -1) {
1143: parsed.add(path.substring(position, sepIndex));
1144: position = sepIndex + separator.length();
1145: }
1146: parsed.add(path.substring(position));
1147: String[] result = new String[parsed.size()];
1148: for (int i = 0; i < parsed.size(); i++) {
1149: result[i] = (String) parsed.get(i);
1150: }
1151: return (result);
1152: } else {
1153: return (new String[0]);
1154: }
1155: }
1156: }
1157:
1158: /**
1159: * Allows to bind a compponent by a component type.
1160: */
1161: public static class Finder implements ComponentChooser {
1162: Class clz;
1163: ComponentChooser subchooser;
1164:
1165: /**
1166: * Constructs Finder.
1167: * @param clz a component class.
1168: * @param subchooser other searching criteria.
1169: */
1170: public Finder(Class clz, ComponentChooser subchooser) {
1171: this .clz = clz;
1172: this .subchooser = subchooser;
1173: }
1174:
1175: /**
1176: * Constructs Finder.
1177: * @param clz a component class.
1178: */
1179: public Finder(Class clz) {
1180: this (clz, ComponentSearcher.getTrueChooser("Any "
1181: + clz.getName()));
1182: }
1183:
1184: public boolean checkComponent(Component comp) {
1185: if (clz.isInstance(comp)) {
1186: return (subchooser.checkComponent(comp));
1187: }
1188: return (false);
1189: }
1190:
1191: public String getDescription() {
1192: return (subchooser.getDescription());
1193: }
1194: }
1195:
1196: /**
1197: * Can be used to make nonblocking operation implementation.
1198: * Typical scenario is: <BR>
1199: * produceNoBlocking(new NoBlockingAction("Button pushing") {<BR>
1200: * public Object doAction(Object param) {<BR>
1201: * push();<BR>
1202: * return(null);<BR>
1203: * }<BR>
1204: * });<BR>
1205: */
1206: protected abstract class NoBlockingAction implements Action {
1207: String description;
1208: Exception exception;
1209: boolean finished;
1210:
1211: /**
1212: * Constructs a NoBlockingAction object.
1213: * @param description an action description.
1214: */
1215: public NoBlockingAction(String description) {
1216: this .description = description;
1217: exception = null;
1218: finished = false;
1219: }
1220:
1221: public final Object launch(Object param) {
1222: Object result = null;
1223: try {
1224: result = doAction(param);
1225: } catch (Exception e) {
1226: exception = e;
1227: }
1228: finished = true;
1229: return (result);
1230: }
1231:
1232: /**
1233: * Performs a mapping action.
1234: * @param param an action parameter.
1235: * @return an action result.
1236: */
1237: public abstract Object doAction(Object param);
1238:
1239: public String getDescription() {
1240: return (description);
1241: }
1242:
1243: /**
1244: * Specifies the exception.
1245: * @param e an exception.
1246: * @see #getException
1247: */
1248: protected void setException(Exception e) {
1249: exception = e;
1250: }
1251:
1252: /**
1253: * Returns an exception occured diring the action execution.
1254: * @return an exception.
1255: * @see #setException
1256: */
1257: public Exception getException() {
1258: return (exception);
1259: }
1260: }
1261:
1262: /**
1263: * Can be used to simplify nonprimitive type component's methods mapping.
1264: * Like this: <BR>
1265: * public Color getBackground() { <BR>
1266: * return((Color)runMapping(new MapAction("getBackground") { <BR>
1267: * public Object map() { <BR>
1268: * return(((Component)getSource()).getBackground()); <BR>
1269: * } <BR>
1270: * })); <BR>
1271: * } <BR>
1272: * @see #runMapping(Operator.MapAction)
1273: */
1274: protected abstract class MapAction extends QueueTool.QueueAction {
1275: /**
1276: * Constructs a MapAction object.
1277: * @param description an action description.
1278: */
1279: public MapAction(String description) {
1280: super (description);
1281: }
1282:
1283: public final Object launch() throws Exception {
1284: return (map());
1285: }
1286:
1287: /**
1288: * Executes a map action.
1289: * @return an action result.
1290: * @throws Exception
1291: */
1292: public abstract Object map() throws Exception;
1293: }
1294:
1295: /**
1296: * Can be used to simplify char component's methods mapping.
1297: * @see #runMapping(Operator.MapCharacterAction)
1298: */
1299: protected abstract class MapCharacterAction extends
1300: QueueTool.QueueAction {
1301: /**
1302: * Constructs a MapCharacterAction object.
1303: * @param description an action description.
1304: */
1305: public MapCharacterAction(String description) {
1306: super (description);
1307: }
1308:
1309: public final Object launch() throws Exception {
1310: return (new Character(map()));
1311: }
1312:
1313: /**
1314: * Executes a map action.
1315: * @return an action result.
1316: * @throws Exception
1317: */
1318: public abstract char map() throws Exception;
1319: }
1320:
1321: /**
1322: * Can be used to simplify byte component's methods mapping.
1323: * @see #runMapping(Operator.MapByteAction)
1324: */
1325: protected abstract class MapByteAction extends
1326: QueueTool.QueueAction {
1327: /**
1328: * Constructs a MapByteAction object.
1329: * @param description an action description.
1330: */
1331: public MapByteAction(String description) {
1332: super (description);
1333: }
1334:
1335: public final Object launch() throws Exception {
1336: return (new Byte(map()));
1337: }
1338:
1339: /**
1340: * Executes a map action.
1341: * @return an action result.
1342: * @throws Exception
1343: */
1344: public abstract byte map() throws Exception;
1345: }
1346:
1347: /**
1348: * Can be used to simplify int component's methods mapping.
1349: * @see #runMapping(Operator.MapIntegerAction)
1350: */
1351: protected abstract class MapIntegerAction extends
1352: QueueTool.QueueAction {
1353: /**
1354: * Constructs a MapIntegerAction object.
1355: * @param description an action description.
1356: */
1357: public MapIntegerAction(String description) {
1358: super (description);
1359: }
1360:
1361: public final Object launch() throws Exception {
1362: return (new Integer(map()));
1363: }
1364:
1365: /**
1366: * Executes a map action.
1367: * @return an action result.
1368: * @throws Exception
1369: */
1370: public abstract int map() throws Exception;
1371: }
1372:
1373: /**
1374: * Can be used to simplify long component's methods mapping.
1375: * @see #runMapping(Operator.MapLongAction)
1376: */
1377: protected abstract class MapLongAction extends
1378: QueueTool.QueueAction {
1379: /**
1380: * Constructs a MapLongAction object.
1381: * @param description an action description.
1382: */
1383: public MapLongAction(String description) {
1384: super (description);
1385: }
1386:
1387: public final Object launch() throws Exception {
1388: return (new Long(map()));
1389: }
1390:
1391: /**
1392: * Executes a map action.
1393: * @return an action result.
1394: * @throws Exception
1395: */
1396: public abstract long map() throws Exception;
1397: }
1398:
1399: /**
1400: * Can be used to simplify float component's methods mapping.
1401: * @see #runMapping(Operator.MapFloatAction)
1402: */
1403: protected abstract class MapFloatAction extends
1404: QueueTool.QueueAction {
1405: /**
1406: * Constructs a MapFloatAction object.
1407: * @param description an action description.
1408: */
1409: public MapFloatAction(String description) {
1410: super (description);
1411: }
1412:
1413: public final Object launch() throws Exception {
1414: return (new Float(map()));
1415: }
1416:
1417: /**
1418: * Executes a map action.
1419: * @return an action result.
1420: * @throws Exception
1421: */
1422: public abstract float map() throws Exception;
1423: }
1424:
1425: /**
1426: * Can be used to simplify double component's methods mapping.
1427: * @see #runMapping(Operator.MapDoubleAction)
1428: */
1429: protected abstract class MapDoubleAction extends
1430: QueueTool.QueueAction {
1431: /**
1432: * Constructs a MapDoubleAction object.
1433: * @param description an action description.
1434: */
1435: public MapDoubleAction(String description) {
1436: super (description);
1437: }
1438:
1439: public final Object launch() throws Exception {
1440: return (new Double(map()));
1441: }
1442:
1443: /**
1444: * Executes a map action.
1445: * @return an action result.
1446: * @throws Exception
1447: */
1448: public abstract double map() throws Exception;
1449: }
1450:
1451: /**
1452: * Can be used to simplify boolean component's methods mapping.
1453: * @see #runMapping(Operator.MapBooleanAction)
1454: */
1455: protected abstract class MapBooleanAction extends
1456: QueueTool.QueueAction {
1457: /**
1458: * Constructs a MapBooleanAction object.
1459: * @param description an action description.
1460: */
1461: public MapBooleanAction(String description) {
1462: super (description);
1463: }
1464:
1465: public final Object launch() throws Exception {
1466: return (map() ? Boolean.TRUE : Boolean.FALSE);
1467: }
1468:
1469: /**
1470: * Executes a map action.
1471: * @return an action result.
1472: * @throws Exception
1473: */
1474: public abstract boolean map() throws Exception;
1475: }
1476:
1477: /**
1478: * Can be used to simplify void component's methods mapping.
1479: * @see #runMapping(Operator.MapVoidAction)
1480: */
1481: protected abstract class MapVoidAction extends
1482: QueueTool.QueueAction {
1483: /**
1484: * Constructs a MapVoidAction object.
1485: * @param description an action description.
1486: */
1487: public MapVoidAction(String description) {
1488: super (description);
1489: }
1490:
1491: public final Object launch() throws Exception {
1492: map();
1493: return (null);
1494: }
1495:
1496: /**
1497: * Executes a map action.
1498: * @throws Exception
1499: */
1500: public abstract void map() throws Exception;
1501: }
1502:
1503: private static class NullOperator extends Operator {
1504: public NullOperator() {
1505: super ();
1506: }
1507:
1508: public Component getSource() {
1509: return (null);
1510: }
1511: }
1512: }
|