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.env.except.AbstractOperationException; 18 import org.as2lib.env.event.TypeSafeEventListenerSource; 19 20 /** 21 * {@code AbstractEventDistributorControl} offers default implementations of 22 * methods needed when implementing the {@link EventDistributorControl} interface 23 * or any sub-interface. 24 * 25 * @author Simon Wacker 26 */ 27 class org.as2lib.env.event.distributor.AbstractEventDistributorControl extends TypeSafeEventListenerSource { 28 29 /** The distributor to distribute events. */ 30 private var d; 31 32 /** 33 * Constructs a new {@code AbstractEventDistributorControl} instance. 34 * 35 * <p>{@code checkListenerType} is by default set to {@code true}. 36 * 37 * @param listenerType the expected type of listeners 38 * @param checkListenerType determines whether to check that passed-in listeners 39 * are of the expected type 40 * @throws IllegalArgumentException if the passed-in {@code listenerType} is 41 * {@code null} or {@code undefined} 42 */ 43 public function AbstractEventDistributorControl(listenerType:Function, checkListenerType:Boolean) { 44 super (listenerType, checkListenerType); 45 } 46 47 /** 48 * Returns the type of listeners this distributor expects. This is also the type of 49 * the distributor returned by the {@link #getDistributor} method. 50 * 51 * @return the type of the distributor and listeners 52 */ 53 public function getType(Void):Function { 54 return t; 55 } 56 57 /** 58 * Returns the distributor to distribute the event to all added listeners. 59 * 60 * <p>The returned distributor can be casted to the type specified on construction. 61 * You can then invoke the event method on it to distribute it to all added 62 * listeners. This event distribution approach has the advantage of proper 63 * compile-time type-checking. 64 * 65 * <p>The returned distributor throws an {@link EventExecutionException} on 66 * distribution if an event method of a listener threw an exception. 67 * 68 * <p>This method does always return the same distributor. 69 * 70 * @return the distributor to distribute the event 71 */ 72 public function getDistributor(Void) { 73 if (!this.d) this.d = createDistributor(); 74 return this.d; 75 } 76 77 /** 78 * Creates a new distributor based on the listener type specified on construction. 79 * 80 * <p>The catching of methods called on the returned distributor takes place using 81 * {@code __resolve}. This method then invokes the {@link #distribute} method with 82 * the name of the called method and the arguments used for the method call. 83 * 84 * @return the new distributor 85 */ 86 private function createDistributor(Void) { 87 var result = new Object(); 88 var t:Function = getListenerType(); 89 result.__proto__ = t.prototype; 90 result.__constructor__ = t; 91 var e:AbstractEventDistributorControl = this; 92 //var d:Function = e["distribute"]; 93 result.__resolve = function(n:String):Function { 94 return (function():Void { 95 //d.apply(e, n, arguments); causes 255 recursion error 96 // e.distribute is not MTASC compatible because "distribute" is private 97 e["distribute"](n, arguments); 98 }); 99 }; 100 var p:Object = t.prototype; 101 while (p != Object.prototype) { 102 for (var i:String in p) { 103 result[i] = function():Void { 104 // e.distribute is not MTASC compatible because "distribute" is private 105 e["distribute"](arguments.callee.n, arguments); 106 }; 107 result[i].n = i; 108 } 109 p = p.__proto__; 110 } 111 return result; 112 } 113 114 /** 115 * Executes the event with the given {@code eventName} on all added listeners, using 116 * the arguments after {@code eventName} as parameters. 117 * 118 * @param eventName the name of the event method to execute on the added listeners 119 * @param args any number of arguments that are used as parameters on execution of 120 * the event on the listeners 121 * @throws EventExecutionException if an event method on a listener threw an 122 * exception 123 */ 124 private function distribute(eventName:String, args:Array):Void { 125 throw new AbstractOperationException("This method is marked as abstract and must be overwritten.", this, arguments); 126 } 127 128 }