1  /*
     2   * Copyright the original author or authors.
     3   * 
     4   * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   * 
     8   *      http://www.mozilla.org/MPL/MPL-1.1.html
     9   * 
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  import org.as2lib.core.BasicClass;
    18  import org.as2lib.env.except.IllegalArgumentException;
    19  import org.as2lib.env.reflect.ReflectUtil;
    20  import org.as2lib.app.exec.ForEachExecutable;
    21  import org.as2lib.util.AccessPermission;
    22  
    23  /**
    24   * {@code Call} enables another object to call a method in another scope without
    25   * having to know the scope.
    26   * 
    27   * <p>This enables you to pass a call to another object and let the object execute
    28   * the call without losing its scope. You use the {@link #execute} method to do so.
    29   *
    30   * @author Simon Wacker
    31   * @author Martin Heidegger
    32   */
    33  class org.as2lib.app.exec.Call extends BasicClass implements ForEachExecutable {
    34  	
    35  	/** The object to execute the method on. */
    36  	private var object;
    37  	
    38  	/** The method to execute on the object. */
    39  	private var method:Function;
    40  	
    41  	/**
    42  	 * Constructs a new {@code Call} instance.
    43  	 *
    44  	 * @param object the object to execute the method on
    45  	 * @param method the method to execute
    46  	 * @throws IllegalArgumentException if either {@code object} or {@code method} is 
    47  	 * {@code null} or {@code undefined}
    48  	 */
    49  	public function Call(object, method:Function) {
    50  		if (object == null) {
    51  			throw new IllegalArgumentException("Required parameter 'object' is null or undefined.", this, arguments);
    52  		}
    53  		if (method == null) {
    54  			throw new IllegalArgumentException("Required parameter 'method' is null or undefined.", this, arguments);
    55  		}
    56  		this.object = object;
    57  		this.method = method;
    58  	}
    59  	
    60  	/**
    61  	 * Executes the method on the object passing the given {@code arguments} and returns the
    62  	 * result of the execution.
    63  	 * 
    64  	 * @return the result of the method execution
    65  	 */
    66  	public function execute() {
    67  		return method.apply(object, arguments);
    68  	}
    69  	
    70  	/**
    71  	 * Iterates over the passed-in {@code object} using the for..in loop and executes
    72  	 * this call passing the found member, its name and the passed-in {@code object}.
    73  	 * 
    74  	 * <p>Example:
    75  	 * <code>
    76  	 *   class MyClass {
    77  	 * 
    78  	 *       private var a:String;
    79  	 *       private var b:String;
    80  	 *       private var c:String;
    81  	 * 
    82  	 *       public function MyClass() {
    83  	 *           a = "1";
    84  	 *           b = "2";
    85  	 *           c = "2";
    86  	 *       }
    87  	 *      
    88  	 *       public function traceObject(value, name:String, inObject):Void {
    89  	 *           trace(name + ": " + value);
    90  	 *       }
    91  	 * 
    92  	 *       public function listAll() {
    93  	 *           new Call(this, traceObject).forEach(this);
    94  	 *       }
    95  	 *   }
    96  	 * </code>
    97  	 *
    98  	 * <p>Note that only members visible to for..in loops cause the {@link #execute}
    99  	 * method to be invoked.
   100  	 * 
   101  	 * @param object the object to iterate over
   102  	 */
   103  	public function forEach(object):Array {
   104  		var i:String;
   105  		var result:Array = new Array();
   106  		for (i in object) {
   107  			try {
   108  				result.push(execute(object[i], i, object));
   109  			} catch(e) {
   110  				
   111  			}
   112  		}
   113  		return result;
   114  	}
   115  	
   116  	/**
   117  	 * Returns the string representation of this call.
   118  	 * 
   119  	 * @return the string representation of this call
   120  	 */
   121  	public function toString():String {
   122  		// TODO: Refactor the code and outsource it.
   123  		var result:String="";
   124  		result += "[type " + ReflectUtil.getTypeNameForInstance(this) + " -> ";
   125  		AccessPermission.set(object, null, AccessPermission.ALLOW_ALL);
   126  		var methodName:String = ReflectUtil.getMethodName(method, object);
   127  		if (ReflectUtil.isMethodStatic(methodName, object)) {
   128  			result += "static ";
   129  		}
   130  		if (object == null) {
   131  			result += object.toString();
   132  		} else {
   133  			var className:String = ReflectUtil.getTypeName(object);
   134  			if (className) {
   135  				result += className;
   136  			} else {
   137  				result += object.toString();
   138  			}
   139  		}
   140  		result += "." + methodName;
   141  		result += "()]";
   142  		return result;
   143  	}
   144  	
   145  }