/* * Copyright (c) 2007, 2017 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.jemmy.lookup; import java.io.PrintStream; import java.util.List; import org.jemmy.interfaces.*; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.jemmy.control.Wrap; import org.jemmy.control.Wrapper; import org.jemmy.env.Environment; import org.jemmy.env.TestOut; import org.jemmy.timing.State; /** * Default implementation of Lookup. Regularly, it is enough just override this * implementation and allow it to handle sub-lookups creation. * @see AbstractLookup#lookup(org.jemmy.lookup.LookupCriteria) * @see AbstractLookup#lookup(java.lang.Class, org.jemmy.lookup.LookupCriteria) * @param * @author shura */ public abstract class AbstractLookup extends AbstractParent implements Lookup { static final String PREFIX_DELTA = "| "; private ArrayList found; Environment env; private Class clss; private LookupCriteria criteria = null; private Wrapper wrapper; /** * Identifies output where lookup progress is printed. * @see Environment#getOutput(java.lang.String) * @see AbstractLookup#wait(int) * @see AbstractLookup#size() */ public static final String OUTPUT = AbstractLookup.class.getName() + ".OUTPUT"; static { Environment.getEnvironment().initTimeout(WAIT_CONTROL_TIMEOUT); Environment.getEnvironment().initOutput(OUTPUT, TestOut.getNullOutput()); } /** * This actual lookup logic is delegated to getCildren(java.lang.Object) * method * @see AbstractLookup#getChildren(java.lang.Object) * @param env * @param controlClass * @param criteria * @param wrapper */ public AbstractLookup(Environment env, Class controlClass, LookupCriteria criteria, Wrapper wrapper) { this.env = env; found = new ArrayList(); this.clss = controlClass; this.criteria = criteria; this.wrapper = wrapper; } Wrapper getWrapper() { return wrapper; } /** * * @return */ LookupCriteria getCriteria() { return criteria; } /** * * @return */ Environment getEnvironment() { return env; } /** * * @return The class of the sount controls. */ Class getControlClass() { return clss; } public Lookup lookup(Class controlClass, LookupCriteria criteria) { return new ClassLookupImpl(env, this, controlClass, criteria, wrapper); } public Lookup lookup(LookupCriteria criteria) { return new ClassLookupImpl(env, this, clss, criteria, wrapper); } /** * Waits for certain number of controls to fit criteria. * Depending on how outputs set, prints out info about the lookup. * @param count * @return this, after the count of found number of found controls * exceeds the required. * @see AbstractLookup#OUTPUT */ public Lookup wait(final int count) { getEnvironment().getOutput(OUTPUT).println("Waiting for " + count + " controls of " + clss.getName() + " class fitting criteria " + criteria); env.getWaiter(Lookup.WAIT_CONTROL_TIMEOUT.getName()).ensureState(new State() { public Integer reached() { if(found.size() < count) refresh(); return (found.size() >= count) ? found.size() : null; } @Override public String toString() { return "Waiting for " + count + " " + clss.getName() + " controls to be found adhering to " + criteria; } }); return this; } /** * Gets the number of controls which fit criteria. * Depending on how outputs set, prints out info about the lookup. * @see AbstractLookup#OUTPUT * @return */ public int size() { getEnvironment().getOutput(OUTPUT).println("Getting number of controls of " + clss.getName() + " class fitting criteria " + criteria); refresh(); return found.size(); } /** * */ void refresh() { found.clear(); List childen = getChildren(null); if (childen != null) { for (Object c : childen) { add(c); } } } @SuppressWarnings("element-type-mismatch") private void add(Object subparent) { if (subparent != null/* && !found.contains(subparent)*/) { if (clss.isInstance(subparent) && check(clss.cast(subparent))) { found.add(clss.cast(subparent)); } List childen = getChildren(subparent); if (childen != null) { for (Object child : childen) { add(child); } } } } /** * * @param control * @return */ protected boolean check(CONTROL control) { return control != null && criteria.check(control); } /** * Returns Wrap of the control with specified index * @param index * @return Wrap */ public Wrap wrap(int index) { return instantiate(get(index)); } /** * * @return */ public Wrap wrap() { return wrap(0); } /** * @{inheritDoc} */ public INTERFACE as(int index, Class interfaceClass) { return wrap(index).as(interfaceClass); } /** * @{inheritDoc} */ public INTERFACE as(Class interfaceClass) { return as(0, interfaceClass); } /** * @{inheritDoc} */ public > INTERFACE as(int index, Class interfaceClass, Class type) { return wrap(index).as(interfaceClass, type); } /** * @{inheritDoc} */ public > INTERFACE as(Class interfaceClass, Class type) { return as(0, interfaceClass, type); } public CONTROL get(int index) { wait(index + 1); return found.get(index); } /** * @{inheritDoc} */ public CONTROL get() { return get(0); } /** * * @return */ List getFound() { return found; } /** * * @return */ public Class getType() { return getControlClass(); } /** * Override this to get subchildren of the controls in the hierarchy. * List could contain any type of objects - not just CONTROL. * @param subParent - one of the elements in the hierarchy reflected by this lookup. * If null passed - first level children are expected. * @return */ abstract List getChildren(Object subParent); private String buildClassChain(Class cls) { StringBuilder sb = new StringBuilder(cls.getName()); if (getType().isInterface()) { sb.append(" implements ").append(getType().getName()); } else { do { cls = cls.getSuperclass(); sb.append(" <- ").append(cls.getName()); } while (!cls.equals(getType()) && !cls.equals(Object.class)); } return sb.toString(); } /** * Wraps the control with a Wrap class. * @see Wrap * @param wrap * @return Wrap */ private Wrap instantiate(CONTROL control) { return wrapper.wrap(clss, control); } /** * * @param out * @param obj * @param prefix */ protected void dumpOne(PrintStream out, CONTROL obj, String prefix) { Map data = getWrapper().wrap(getControlClass(), getControlClass().cast(obj)).getPropertiesQiuet(); out.println(prefix + "+-" + buildClassChain(obj.getClass())); for (String key : data.keySet()) { out.print(prefix + PREFIX_DELTA + " " + key + "="); if (data.get(key) == null) { out.println("null"); } else { out.println(data.get(key)); } } } /** * * @param out * @param lookup */ protected abstract void dump(PrintStream out, Lookup lookup); public void dump(PrintStream out) { dump(out, this); } /* static class LookupImpl extends AbstractLookup { AbstractLookup parent; public LookupImpl(Environment env, AbstractLookup parent, Class clss, LookupCriteria criteria) { super(env, clss, criteria); this.parent = parent; } @Override public List getChildren(T subParent) { return getFound(); } @Override public Wrap instantiate(T control) { return parent.instantiate(control); } @Override protected void refresh() { parent.refresh(); super.refresh(); } } */ static class ClassLookupImpl extends AbstractLookup { AbstractLookup parent; Class cls; public ClassLookupImpl(Environment env, AbstractLookup parent, Class cls, LookupCriteria criteria, Wrapper wrapper) { super(env, cls, criteria, wrapper); this.cls = cls; this.parent = parent; } @Override protected boolean check(ST control) { return getControlClass().isInstance(control) && super.check(control); } @Override public List getChildren(Object subParent) { return getFound(); } @Override protected void refresh() { parent.refresh(); for (T next : parent.found) { if (cls.isInstance(next) && check(cls.cast(next))) { super.found.add(cls.cast(next)); } } } @Override protected void dump(PrintStream out, Lookup lookup) { parent.dump(out, lookup); } } /* static class ClassLookupImpl extends AbstractLookup { AbstractLookup parent; public ClassLookupImpl(Environment env, AbstractLookup parent, Class cls, LookupCriteria criteria) { super(env, cls, criteria); this.parent = parent; } @Override protected boolean check(ST wrap) { return getControlClass().isInstance(wrap) && super.check(wrap); } @Override public List getChildren(Object subParent) { return getFound(); } @Override public Wrap instantiate(ST wrap) { return parent.instantiate(wrap); } @Override protected void refresh() { parent.refresh(); super.refresh(); } } */ /* class ClassParent implements Parent { Class clss; ClassParent(Class clss) { this.clss = clss; } public Wrap instantiate(T wrap) { return (Wrap) AbstractLookup.this.instantiate((CONTROL) wrap); } public Lookup lookup(final LookupCriteria criteria) { return new LookupImpl(env, this, new TypedLookup(clss) { @Override public boolean checkControl(T wrap) { return criteria.check(wrap); } }); } } */ }