001: package abbot.script;
002:
003: import java.awt.Component;
004: import java.lang.reflect.Method;
005: import java.util.Map;
006:
007: import abbot.tester.ComponentTester;
008:
009: /** Provides support for using property-like methods, including select
010: * non-static method access to Components. Specifically, allows specification
011: * of a ComponentReference to be used as the method invocation target. If a
012: * ComponentReference is given, then the class of the component reference is
013: * used as the target class.<p>
014: */
015:
016: public abstract class PropertyCall extends Call {
017:
018: private String componentID = null;
019:
020: /** Create a PropertyCall based on loaded XML attributes. */
021: public PropertyCall(Resolver resolver, Map attributes) {
022: super (resolver, patchAttributes(resolver, attributes));
023: componentID = (String) attributes.get(TAG_COMPONENT);
024: }
025:
026: /** Create a PropertyCall based on a static invocation on an
027: arbitrary class.
028: */
029: public PropertyCall(Resolver resolver, String description,
030: String className, String methodName, String[] args) {
031: super (resolver, description, className, methodName, args);
032: componentID = null;
033: }
034:
035: /** Create a PropertyCall with a Component target. The target
036: class name is derived from the given component reference ID. */
037: public PropertyCall(Resolver resolver, String description,
038: String methodName, String id) {
039: super (resolver, description, getRefClass(resolver, id),
040: methodName, null);
041: componentID = id;
042: }
043:
044: /** Return the component reference ID used by this method invocation. */
045: public String getComponentID() {
046: return componentID;
047: }
048:
049: /** Set the component reference ID used by method invocation. The class
050: * of the component referenced by the component reference will replace the
051: * current target class.
052: */
053: public void setComponentID(String id) {
054: if (id == null) {
055: componentID = null;
056: } else {
057: ComponentReference ref = getResolver()
058: .getComponentReference(id);
059: if (ref != null) {
060: componentID = id;
061: setTargetClassName(ref.getRefClassName());
062: } else
063: throw new NoSuchReferenceException(id);
064: }
065: }
066:
067: /** Save attributes specific to this Step class. */
068: public Map getAttributes() {
069: Map map = super .getAttributes();
070: if (componentID != null) {
071: map.remove(TAG_CLASS);
072: map.put(TAG_COMPONENT, componentID);
073: }
074: return map;
075: }
076:
077: /** Return the target of the method invocation. */
078: protected Object getTarget(Method m) throws Throwable {
079: if (componentID != null) {
080: return ArgumentParser.eval(getResolver(), componentID,
081: Component.class);
082: }
083: return super .getTarget(m);
084: }
085:
086: /** Insert default values if necessary. */
087: private static Map patchAttributes(Resolver resolver, Map map) {
088: String id = (String) map.get(TAG_COMPONENT);
089: if (id != null) {
090: map.put(TAG_CLASS, getRefClass(resolver, id));
091: }
092: return map;
093: }
094:
095: private final static String[] prefixes = { "is", "has", "get" };
096: private final static Class[] returnTypes = { boolean.class,
097: boolean.class, null, };
098:
099: /** Returns whether the given method is a property accessor. In addition
100: * to standard is/get/has property accessors, this includes
101: * pseudo-property methods on ComponentTester objects.
102: */
103: public static boolean isPropertyMethod(Method m) {
104: String name = m.getName();
105: Class rt = m.getReturnType();
106: Class[] params = m.getParameterTypes();
107: Class dc = m.getDeclaringClass();
108: for (int i = 0; i < prefixes.length; i++) {
109: if (name.startsWith(prefixes[i])
110: && name.length() > prefixes[i].length()
111: && Character.isUpperCase(name.charAt(prefixes[i]
112: .length()))
113: && ((ComponentTester.class.isAssignableFrom(dc)
114: && params.length == 1 && Component.class
115: .isAssignableFrom(params[0])) || params.length == 0)
116: && (returnTypes[i] == null || returnTypes[i]
117: .equals(rt))) {
118: return true;
119: }
120: }
121: return false;
122: }
123:
124: public String getDefaultDescription() {
125: String desc = super .getDefaultDescription();
126: if (getComponentID() != null) {
127: desc = getComponentID() + "." + desc;
128: }
129: return desc;
130: }
131:
132: /** Obtain the class of the given reference's component, or return
133: * java.awt.Component if not found.
134: */
135: private static String getRefClass(Resolver r, String id) {
136: ComponentReference ref = r.getComponentReference(id);
137: return ref == null ? Component.class.getName() : ref
138: .getRefClassName();
139: }
140: }
|