24 */ 25 package org.jemmy.lookup; 26 27 import java.io.PrintStream; 28 import java.util.List; 29 import org.jemmy.interfaces.*; 30 import java.util.ArrayList; 31 import java.util.HashMap; 32 import java.util.Map; 33 import org.jemmy.control.Wrap; 34 import org.jemmy.control.Wrapper; 35 import org.jemmy.env.Environment; 36 import org.jemmy.env.TestOut; 37 import org.jemmy.timing.State; 38 39 /** 40 * Default implementation of Lookup. Regularly, it is enough just override this 41 * implementation and allow it to handle sub-lookups creation. 42 * @see AbstractLookup#lookup(org.jemmy.lookup.LookupCriteria) 43 * @see AbstractLookup#lookup(java.lang.Class, org.jemmy.lookup.LookupCriteria) 44 * @param <CONTROL> 45 * @author shura 46 */ 47 public abstract class AbstractLookup<CONTROL> extends AbstractParent<CONTROL> implements Lookup<CONTROL> { 48 49 static final String PREFIX_DELTA = "| "; 50 private ArrayList<CONTROL> found; 51 Environment env; 52 private Class<CONTROL> clss; 53 private LookupCriteria<CONTROL> criteria = null; 54 private Wrapper wrapper; 55 56 /** 57 * Identifies output where lookup progress is printed. 58 * @see Environment#getOutput(java.lang.String) 59 * @see AbstractLookup#wait(int) 60 * @see AbstractLookup#size() 61 */ 62 public static final String OUTPUT = AbstractLookup.class.getName() + ".OUTPUT"; 63 64 65 static { 66 Environment.getEnvironment().initTimeout(WAIT_CONTROL_TIMEOUT); 67 Environment.getEnvironment().initOutput(OUTPUT, TestOut.getNullOutput()); 68 } 69 70 /** 71 * This actual lookup logic is delegated to <code>getCildren(java.lang.Object)</code> 72 * method 73 * @see AbstractLookup#getChildren(java.lang.Object) 74 * @param env 75 * @param controlClass 76 * @param criteria 77 * @param wrapper 78 */ 79 public AbstractLookup(Environment env, Class<CONTROL> controlClass, LookupCriteria<CONTROL> criteria, Wrapper wrapper) { 80 this.env = env; 81 found = new ArrayList<CONTROL>(); 82 this.clss = controlClass; 83 this.criteria = criteria; 84 this.wrapper = wrapper; 85 } 86 87 Wrapper getWrapper() { 88 return wrapper; 89 } 90 91 /** 92 * 93 * @return 94 */ 95 LookupCriteria<CONTROL> getCriteria() { 96 return criteria; 97 } 98 99 /** 100 * 101 * @return 102 */ 103 Environment getEnvironment() { 104 return env; 105 } 106 107 /** 108 * 109 * @return The class of the sount controls. 110 */ 111 Class<CONTROL> getControlClass() { 112 return clss; 113 } 114 115 public <T extends CONTROL> Lookup<T> lookup(Class<T> controlClass, LookupCriteria<T> criteria) { 116 return new ClassLookupImpl<CONTROL, T>(env, this, controlClass, criteria, wrapper); 117 } 118 119 public Lookup<CONTROL> lookup(LookupCriteria<CONTROL> criteria) { 120 return new ClassLookupImpl<CONTROL, CONTROL>(env, this, clss, criteria, wrapper); 121 } 122 123 /** 124 * Waits for certain number of controls to fit criteria. 125 * Depending on how outputs set, prints out info about the lookup. 126 * @param count 127 * @return this, after the count of found number of found controls 128 * exceeds the required. 129 * @see AbstractLookup#OUTPUT 130 */ 131 public Lookup<? extends CONTROL> wait(final int count) { 132 getEnvironment().getOutput(OUTPUT).println("Waiting for " + count + " controls of " + clss.getName() + " class fitting criteria " + criteria); 133 env.getWaiter(Lookup.WAIT_CONTROL_TIMEOUT.getName()).ensureState(new State<Integer>() { 134 135 public Integer reached() { 136 if(found.size() < count) 137 refresh(); 138 return (found.size() >= count) ? found.size() : null; 139 } 140 141 @Override 142 public String toString() { 143 return "Waiting for " + count + " " + clss.getName() + " controls to be found adhering to " 144 + criteria; 145 } 146 147 }); 148 return this; 149 } 150 151 /** 152 * Gets the number of controls which fit criteria. 153 * Depending on how outputs set, prints out info about the lookup. 154 * @see AbstractLookup#OUTPUT 155 * @return 156 */ 157 public int size() { 158 getEnvironment().getOutput(OUTPUT).println("Getting number of controls of " + clss.getName() + " class fitting criteria " + criteria); 159 refresh(); 160 return found.size(); 161 } 162 163 /** 164 * 165 */ 166 void refresh() { 167 found.clear(); 168 List childen = getChildren(null); 169 if (childen != null) { 170 for (Object c : childen) { 171 add(c); 172 } 173 } 174 } 175 176 @SuppressWarnings("element-type-mismatch") 177 private void add(Object subparent) { 178 if (subparent != null/* && !found.contains(subparent)*/) { 179 if (clss.isInstance(subparent) && check(clss.cast(subparent))) { 180 found.add(clss.cast(subparent)); 181 } 182 List childen = getChildren(subparent); 183 if (childen != null) { 184 for (Object child : childen) { 185 add(child); 186 } 187 } 188 } 189 } 190 191 /** 192 * 193 * @param control 194 * @return 195 */ 196 protected boolean check(CONTROL control) { 197 return control != null && criteria.check(control); 198 } 199 200 /** 201 * Returns Wrap of the control with specified index 202 * @param index 203 * @return Wrap 204 */ 205 public Wrap<? extends CONTROL> wrap(int index) { 206 return instantiate(get(index)); 207 } 208 209 /** 210 * 211 * @return 212 */ 213 public Wrap<? extends CONTROL> wrap() { 214 return wrap(0); 215 } 216 217 /** 218 * @{inheritDoc} 219 */ 220 public <INTERFACE extends ControlInterface> INTERFACE as(int index, Class<INTERFACE> interfaceClass) { 221 return wrap(index).as(interfaceClass); 222 } 223 224 /** 225 * @{inheritDoc} 226 */ 227 public <INTERFACE extends ControlInterface> INTERFACE as(Class<INTERFACE> interfaceClass) { 228 return as(0, interfaceClass); 229 } 230 231 /** 232 * @{inheritDoc} 233 */ 234 public <TYPE, INTERFACE extends TypeControlInterface<TYPE>> INTERFACE as(int index, Class<INTERFACE> interfaceClass, Class<TYPE> type) { 235 return wrap(index).as(interfaceClass, type); 236 } 237 238 /** 239 * @{inheritDoc} 240 */ 241 public <TYPE, INTERFACE extends TypeControlInterface<TYPE>> INTERFACE as(Class<INTERFACE> interfaceClass, Class<TYPE> type) { 242 return as(0, interfaceClass, type); 243 } 244 245 public CONTROL get(int index) { 246 wait(index + 1); 247 return found.get(index); 248 } 249 250 /** 251 * @{inheritDoc} 252 */ 253 public CONTROL get() { 254 return get(0); 255 } 256 257 /** 258 * 259 * @return 260 */ 261 List<CONTROL> getFound() { 262 return found; 263 } 264 265 /** 266 * 267 * @return 268 */ 269 public Class<CONTROL> getType() { 270 return getControlClass(); 271 } 272 273 /** 274 * Override this to get subchildren of the controls in the hierarchy. 275 * List could contain any type of objects - not just <code>CONTROL</code>. 276 * @param subParent - one of the elements in the hierarchy reflected by this lookup. 277 * If null passed - first level children are expected. 278 * @return 279 */ 280 abstract List getChildren(Object subParent); 281 282 private String buildClassChain(Class cls) { 283 StringBuilder sb = new StringBuilder(cls.getName()); 284 if (getType().isInterface()) { 285 sb.append(" implements ").append(getType().getName()); 286 } else { 287 do { 288 cls = cls.getSuperclass(); 289 sb.append(" <- ").append(cls.getName()); 290 } while (!cls.equals(getType()) && !cls.equals(Object.class)); 291 } 292 return sb.toString(); 293 } 294 295 /** 296 * Wraps the control with a <code>Wrap</code> class. 297 * @see Wrap 298 * @param wrap 299 * @return Wrap 300 */ 301 private Wrap<? extends CONTROL> instantiate(CONTROL control) { 302 return wrapper.wrap(clss, control); 303 } 304 305 /** 306 * 307 * @param out 308 * @param obj 309 * @param prefix 310 */ 311 protected void dumpOne(PrintStream out, CONTROL obj, String prefix) { 312 Map<String, Object> data = getWrapper().wrap(getControlClass(), getControlClass().cast(obj)).getPropertiesQiuet(); 313 out.println(prefix + "+-" + buildClassChain(obj.getClass())); 314 for (String key : data.keySet()) { 315 out.print(prefix + PREFIX_DELTA + " " + key + "="); 316 if (data.get(key) == null) { 317 out.println("null"); 318 } else { 319 out.println(data.get(key)); 320 } 321 } 322 } 323 324 /** 325 * 326 * @param out 327 * @param lookup 328 */ 329 protected abstract void dump(PrintStream out, Lookup<? extends CONTROL> lookup); 330 331 public void dump(PrintStream out) { 332 dump(out, this); 333 } 334 /* 335 static class LookupImpl<T> extends AbstractLookup<T> { 336 337 AbstractLookup<T> parent; 338 339 public LookupImpl(Environment env, AbstractLookup<T> parent, Class<T> clss, LookupCriteria<T> criteria) { 340 super(env, clss, criteria); 341 this.parent = parent; 342 } 343 344 @Override 345 public List<T> getChildren(T subParent) { 346 return getFound(); 347 } 348 | 24 */ 25 package org.jemmy.lookup; 26 27 import java.io.PrintStream; 28 import java.util.List; 29 import org.jemmy.interfaces.*; 30 import java.util.ArrayList; 31 import java.util.HashMap; 32 import java.util.Map; 33 import org.jemmy.control.Wrap; 34 import org.jemmy.control.Wrapper; 35 import org.jemmy.env.Environment; 36 import org.jemmy.env.TestOut; 37 import org.jemmy.timing.State; 38 39 /** 40 * Default implementation of Lookup. Regularly, it is enough just override this 41 * implementation and allow it to handle sub-lookups creation. 42 * @see AbstractLookup#lookup(org.jemmy.lookup.LookupCriteria) 43 * @see AbstractLookup#lookup(java.lang.Class, org.jemmy.lookup.LookupCriteria) 44 * @param <CONTROL> todo document 45 * @author shura 46 */ 47 public abstract class AbstractLookup<CONTROL> extends AbstractParent<CONTROL> implements Lookup<CONTROL> { 48 49 static final String PREFIX_DELTA = "| "; 50 private ArrayList<CONTROL> found; 51 Environment env; 52 private Class<CONTROL> clss; 53 private LookupCriteria<CONTROL> criteria = null; 54 private Wrapper wrapper; 55 56 /** 57 * Identifies output where lookup progress is printed. 58 * @see Environment#getOutput(java.lang.String) 59 * @see AbstractLookup#wait(int) 60 * @see AbstractLookup#size() 61 */ 62 public static final String OUTPUT = AbstractLookup.class.getName() + ".OUTPUT"; 63 64 65 static { 66 Environment.getEnvironment().initTimeout(WAIT_CONTROL_TIMEOUT); 67 Environment.getEnvironment().initOutput(OUTPUT, TestOut.getNullOutput()); 68 } 69 70 /** 71 * This actual lookup logic is delegated to <code>getCildren(java.lang.Object)</code> 72 * method 73 * @see AbstractLookup#getChildren(java.lang.Object) 74 * @param env todo document 75 * @param controlClass todo document 76 * @param criteria todo document 77 * @param wrapper todo document 78 */ 79 public AbstractLookup(Environment env, Class<CONTROL> controlClass, LookupCriteria<CONTROL> criteria, Wrapper wrapper) { 80 this.env = env; 81 found = new ArrayList<CONTROL>(); 82 this.clss = controlClass; 83 this.criteria = criteria; 84 this.wrapper = wrapper; 85 } 86 87 Wrapper getWrapper() { 88 return wrapper; 89 } 90 91 LookupCriteria<CONTROL> getCriteria() { 92 return criteria; 93 } 94 95 Environment getEnvironment() { 96 return env; 97 } 98 99 /** 100 * @return The class of the sount controls. 101 */ 102 Class<CONTROL> getControlClass() { 103 return clss; 104 } 105 106 public <T extends CONTROL> Lookup<T> lookup(Class<T> controlClass, LookupCriteria<T> criteria) { 107 return new ClassLookupImpl<CONTROL, T>(env, this, controlClass, criteria, wrapper); 108 } 109 110 public Lookup<CONTROL> lookup(LookupCriteria<CONTROL> criteria) { 111 return new ClassLookupImpl<CONTROL, CONTROL>(env, this, clss, criteria, wrapper); 112 } 113 114 /** 115 * Waits for certain number of controls to fit criteria. 116 * Depending on how outputs set, prints out info about the lookup. 117 * @param count todo document 118 * @return this, after the count of found number of found controls 119 * exceeds the required. 120 * @see AbstractLookup#OUTPUT 121 */ 122 public Lookup<? extends CONTROL> wait(final int count) { 123 getEnvironment().getOutput(OUTPUT).println("Waiting for " + count + " controls of " + clss.getName() + " class fitting criteria " + criteria); 124 env.getWaiter(Lookup.WAIT_CONTROL_TIMEOUT.getName()).ensureState(new State<Integer>() { 125 126 public Integer reached() { 127 if(found.size() < count) 128 refresh(); 129 return (found.size() >= count) ? found.size() : null; 130 } 131 132 @Override 133 public String toString() { 134 return "Waiting for " + count + " " + clss.getName() + " controls to be found adhering to " 135 + criteria; 136 } 137 138 }); 139 return this; 140 } 141 142 /** 143 * Gets the number of controls which fit criteria. 144 * Depending on how outputs set, prints out info about the lookup. 145 * @see AbstractLookup#OUTPUT 146 * @return todo document 147 */ 148 public int size() { 149 getEnvironment().getOutput(OUTPUT).println("Getting number of controls of " + clss.getName() + " class fitting criteria " + criteria); 150 refresh(); 151 return found.size(); 152 } 153 154 void refresh() { 155 found.clear(); 156 List childen = getChildren(null); 157 if (childen != null) { 158 for (Object c : childen) { 159 add(c); 160 } 161 } 162 } 163 164 @SuppressWarnings("element-type-mismatch") 165 private void add(Object subparent) { 166 if (subparent != null/* && !found.contains(subparent)*/) { 167 if (clss.isInstance(subparent) && check(clss.cast(subparent))) { 168 found.add(clss.cast(subparent)); 169 } 170 List childen = getChildren(subparent); 171 if (childen != null) { 172 for (Object child : childen) { 173 add(child); 174 } 175 } 176 } 177 } 178 179 protected boolean check(CONTROL control) { 180 return control != null && criteria.check(control); 181 } 182 183 /** 184 * Returns Wrap of the control with specified index 185 * @param index todo document 186 * @return Wrap 187 */ 188 public Wrap<? extends CONTROL> wrap(int index) { 189 return instantiate(get(index)); 190 } 191 192 public Wrap<? extends CONTROL> wrap() { 193 return wrap(0); 194 } 195 196 /** 197 * {@inheritDoc} 198 */ 199 public <INTERFACE extends ControlInterface> INTERFACE as(int index, Class<INTERFACE> interfaceClass) { 200 return wrap(index).as(interfaceClass); 201 } 202 203 /** 204 * {@inheritDoc} 205 */ 206 public <INTERFACE extends ControlInterface> INTERFACE as(Class<INTERFACE> interfaceClass) { 207 return as(0, interfaceClass); 208 } 209 210 /** 211 * {@inheritDoc} 212 */ 213 public <TYPE, INTERFACE extends TypeControlInterface<TYPE>> INTERFACE as(int index, Class<INTERFACE> interfaceClass, Class<TYPE> type) { 214 return wrap(index).as(interfaceClass, type); 215 } 216 217 /** 218 * {@inheritDoc} 219 */ 220 public <TYPE, INTERFACE extends TypeControlInterface<TYPE>> INTERFACE as(Class<INTERFACE> interfaceClass, Class<TYPE> type) { 221 return as(0, interfaceClass, type); 222 } 223 224 public CONTROL get(int index) { 225 wait(index + 1); 226 return found.get(index); 227 } 228 229 /** 230 * {@inheritDoc} 231 */ 232 public CONTROL get() { 233 return get(0); 234 } 235 236 List<CONTROL> getFound() { 237 return found; 238 } 239 240 public Class<CONTROL> getType() { 241 return getControlClass(); 242 } 243 244 /** 245 * Override this to get subchildren of the controls in the hierarchy. 246 * List could contain any type of objects - not just <code>CONTROL</code>. 247 * @param subParent - one of the elements in the hierarchy reflected by this lookup. 248 * If null passed - first level children are expected. 249 * @return todo document 250 */ 251 abstract List getChildren(Object subParent); 252 253 private String buildClassChain(Class cls) { 254 StringBuilder sb = new StringBuilder(cls.getName()); 255 if (getType().isInterface()) { 256 sb.append(" implements ").append(getType().getName()); 257 } else { 258 do { 259 cls = cls.getSuperclass(); 260 sb.append(" <- ").append(cls.getName()); 261 } while (!cls.equals(getType()) && !cls.equals(Object.class)); 262 } 263 return sb.toString(); 264 } 265 266 /** 267 * Wraps the control with a <code>Wrap</code> class. 268 * @see Wrap 269 * @param control todo document 270 * @return Wrap 271 */ 272 private Wrap<? extends CONTROL> instantiate(CONTROL control) { 273 return wrapper.wrap(clss, control); 274 } 275 276 protected void dumpOne(PrintStream out, CONTROL obj, String prefix) { 277 Map<String, Object> data = getWrapper().wrap(getControlClass(), getControlClass().cast(obj)).getPropertiesQiuet(); 278 out.println(prefix + "+-" + buildClassChain(obj.getClass())); 279 for (String key : data.keySet()) { 280 out.print(prefix + PREFIX_DELTA + " " + key + "="); 281 if (data.get(key) == null) { 282 out.println("null"); 283 } else { 284 out.println(data.get(key)); 285 } 286 } 287 } 288 289 protected abstract void dump(PrintStream out, Lookup<? extends CONTROL> lookup); 290 291 public void dump(PrintStream out) { 292 dump(out, this); 293 } 294 /* 295 static class LookupImpl<T> extends AbstractLookup<T> { 296 297 AbstractLookup<T> parent; 298 299 public LookupImpl(Environment env, AbstractLookup<T> parent, Class<T> clss, LookupCriteria<T> criteria) { 300 super(env, clss, criteria); 301 this.parent = parent; 302 } 303 304 @Override 305 public List<T> getChildren(T subParent) { 306 return getFound(); 307 } 308 |