1 /*
2  * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation. Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 package org.netbeans.jemmy.util;
26 
27 import java.awt.Component;
28 import java.lang.reflect.InvocationTargetException;
29 
30 import org.netbeans.jemmy.ClassReference;
31 import org.netbeans.jemmy.ComponentChooser;
32 import org.netbeans.jemmy.JemmyProperties;
33 import org.netbeans.jemmy.Outputable;
34 import org.netbeans.jemmy.TestOut;
35 
36 /**
37  *
38  * Implementation of org.netbeans.jemmy.ComponentChooser interface. Class can be
39  * used to find component by its field/methods values. <br>
40  * Example:
41  * <pre>
42  *            String[] methods = {"getClientProperty"};
43  *            Object[][] params = {{"classname"}};
44  *            Class<?>[][] classes = {{Object.class}};
45  *            Object[] results = {"javax.swing.JCheckBox"};
46  *
47  *            JCheckBox box = JCheckBoxOperator.findJCheckBox(frm0, new PropChooser(methods, params, classes, results));
48  * </pre> Or:
49  * <pre>
50  *            String[] methods = {"getText"};
51  *            Object[] results = {"Open"};
52  *
53  *            JButtonOperator box = new JButtonOperator(containerOperator, new PropChooser(fields, results));
54  * </pre>
55  *
56  * @author Alexandre Iline (alexandre.iline@oracle.com)
57  */
58 public class PropChooser implements ComponentChooser, Outputable {
59 
60     /**
61      * Names of methods to check.
62      */
63     protected String[] propNames;
64 
65     /**
66      * Methods parameters.
67      */
68     protected Object[][] params;
69 
70     /**
71      * Classes of parameters.
72      */
73     protected Class<?>[][] classes;
74 
75     /**
76      * Expected results of methods.
77      */
78     protected Object[] results;
79 
80     private TestOut output;
81 
82     /**
83      * Constructs a PropChooser object.
84      *
85      * @param propNames Names of methods/fields
86      * @param params Parameters values for methods. <BR>
87      * params[0] is an array of parameters for propNames[0] methods. <BR>
88      * If propNames[0] is a field, params[0] is ignored.
89      * @param classes Parameters classes.
90      * @param results Objects to compare method/field values to. <BR>
91      * A value of propNames[0] method/field should be equal to results[0]
92      * object.
93      */
PropChooser(String[] propNames, Object[][] params, Class<?>[][] classes, Object[] results)94     public PropChooser(String[] propNames,
95             Object[][] params,
96             Class<?>[][] classes,
97             Object[] results) {
98         this.propNames = propNames;
99         this.results = results;
100         if (params != null) {
101             this.params = params;
102         } else {
103             this.params = new Object[propNames.length][0];
104         }
105         if (classes != null) {
106             this.classes = classes;
107         } else {
108             this.classes = new Class<?>[this.params.length][0];
109             for (int i = 0; i < this.params.length; i++) {
110                 Class<?>[] clsss = new Class<?>[this.params[i].length];
111                 for (int j = 0; j < this.params[i].length; j++) {
112                     clsss[j] = this.params[i][j].getClass();
113                 }
114                 this.classes[i] = clsss;
115             }
116         }
117         setOutput(JemmyProperties.getCurrentOutput());
118     }
119 
120     /**
121      * Constructs a PropChooser object for checking of methods with no
122      * parameters.
123      *
124      * @param propNames Names of methods/fields
125      * @param results Objects to compare method/field values to.
126      */
PropChooser(String[] propNames, Object[] results)127     public PropChooser(String[] propNames,
128             Object[] results) {
129         this(propNames, null, null, results);
130     }
131 
132     @Override
setOutput(TestOut output)133     public void setOutput(TestOut output) {
134         this.output = output;
135     }
136 
137     @Override
getOutput()138     public TestOut getOutput() {
139         return output;
140     }
141 
142     @Override
checkComponent(Component comp)143     public boolean checkComponent(Component comp) {
144         try {
145             String propName = null;
146             Object value;
147             ClassReference disp = new ClassReference(comp);
148             for (int i = 0; i < propNames.length; i++) {
149                 propName = propNames[i];
150                 if (propName != null) {
151                     if (isField(comp, propName, classes[i])) {
152                         try {
153                             value = disp.getField(propName);
154                         } catch (IllegalStateException e) {
155                             output.printStackTrace(e);
156                             return false;
157                         } catch (NoSuchFieldException e) {
158                             output.printStackTrace(e);
159                             return false;
160                         } catch (IllegalAccessException e) {
161                             output.printStackTrace(e);
162                             return false;
163                         }
164                     } else {
165                         try {
166                             value = disp.invokeMethod(propName, params[i], classes[i]);
167                         } catch (InvocationTargetException e) {
168                             output.printStackTrace(e);
169                             return false;
170                         } catch (IllegalStateException e) {
171                             output.printStackTrace(e);
172                             return false;
173                         } catch (NoSuchMethodException e) {
174                             output.printStackTrace(e);
175                             return false;
176                         } catch (IllegalAccessException e) {
177                             output.printStackTrace(e);
178                             return false;
179                         }
180                     }
181                     if (!checkProperty(value, results[i])) {
182                         return false;
183                     }
184                 }
185             }
186             return true;
187         } catch (SecurityException e) {
188             output.printStackTrace(e);
189             return false;
190         }
191     }
192 
193     @Override
getDescription()194     public String getDescription() {
195         StringBuilder result = new StringBuilder();
196         for (String propName : propNames) {
197             result.append(' ').append(propName);
198         }
199         return "Component by properties array\n    :" + result.toString();
200     }
201 
202     @Override
toString()203     public String toString() {
204         return "PropChooser{" + "description=" + getDescription() + '}';
205     }
206 
207     /**
208      * Method to check one method result with an etalon. Can be overrided by a
209      * subclass.
210      *
211      * @param value Method/field value
212      * @param etalon Object to compare to.
213      * @return true if the value matches the etalon.
214      */
checkProperty(Object value, Object etalon)215     protected boolean checkProperty(Object value, Object etalon) {
216         return value.equals(etalon);
217     }
218 
219     /* try to define if propName is a field or method*/
isField(Component comp, String propName, Class<?>[] params)220     private boolean isField(Component comp, String propName, Class<?>[] params)
221             throws SecurityException {
222         try {
223             comp.getClass().getField(propName);
224             comp.getClass().getMethod(propName, params);
225         } catch (NoSuchMethodException e) {
226             return true;
227         } catch (NoSuchFieldException e) {
228             return false;
229         }
230         return true;
231     }
232 }
233