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.aop.advice.DynamicAdviceFactory; 19 import org.as2lib.env.overload.Overload; 20 import org.as2lib.app.exec.Call; 21 import org.as2lib.aop.Advice; 22 import org.as2lib.aop.Pointcut; 23 import org.as2lib.aop.advice.AbstractAdvice; 24 import org.as2lib.aop.advice.AdviceFactory; 25 import org.as2lib.aop.advice.SimpleAdviceFactory; 26 import org.as2lib.aop.advice.DynamicBeforeAdvice; 27 import org.as2lib.aop.advice.DynamicAroundAdvice; 28 import org.as2lib.aop.advice.DynamicAfterAdvice; 29 import org.as2lib.aop.advice.DynamicAfterReturningAdvice; 30 import org.as2lib.aop.advice.DynamicAfterThrowingAdvice; 31 import org.as2lib.env.except.IllegalArgumentException; 32 33 /** 34 * {@code SimpleDynamicAdviceFactory} manages the creation of advices for different 35 * advice types in a simple manner. 36 * 37 * @author Simon Wacker 38 */ 39 class org.as2lib.aop.advice.SimpleDynamicAdviceFactory extends BasicClass implements DynamicAdviceFactory { 40 41 /** All registered advices. */ 42 private var registry:Array; 43 44 /** 45 * Constructs a new {@code SimpleDynamicAdviceFactory} instance. 46 */ 47 public function SimpleDynamicAdviceFactory(Void) { 48 registry = new Array(); 49 bindAdviceFactoryByAdviceClass(AbstractAdvice.BEFORE, DynamicBeforeAdvice); 50 bindAdviceFactoryByAdviceClass(AbstractAdvice.AROUND, DynamicAroundAdvice); 51 bindAdviceFactoryByAdviceClass(AbstractAdvice.AFTER, DynamicAfterAdvice); 52 bindAdviceFactoryByAdviceClass(AbstractAdvice.AFTER_RETURNING, DynamicAfterReturningAdvice); 53 bindAdviceFactoryByAdviceClass(AbstractAdvice.AFTER_THROWING, DynamicAfterThrowingAdvice); 54 } 55 56 /** 57 * @overload #bindAdviceFactoryByAdviceFactory 58 * @overload #bindAdviceFactoryByAdviceClass 59 */ 60 public function bindAdviceFactory() { 61 var o:Overload = new Overload(this); 62 o.addHandler(bindAdviceFactoryByAdviceFactory, [Number, AdviceFactory]); 63 o.addHandler(bindAdviceFactoryByAdviceClass, [Number, Function]); 64 return o.forward(arguments); 65 } 66 67 /** 68 * Binds the given {@code adviceFactory} to the {@code adviceType}. If a request is 69 * made with the given {@code adviceType} as type, the bound {@code adviceFactory} 70 * will be used to create the advice that gets returned. 71 * 72 * <p>If there is already an advice factory bound to the given {@code adviceType} 73 * the old binding gets overwritten. 74 * 75 * <p>If you want to remove a binding pass an {@code adviceFactory} of value 76 * {@code null} or {@code undefined} 77 * 78 * @param adviceType the type to bind the {@code adviceFactory} to 79 * @param adviceFactory the advice factory to bind to the given {@code adviceType} 80 * @throws IllegalArgumentException if argument {@code adviceType} is {@code null} 81 * or {@code undefined} 82 */ 83 public function bindAdviceFactoryByAdviceFactory(adviceType:Number, adviceFactory:AdviceFactory):Void { 84 if (adviceType == null) throw new IllegalArgumentException("Argument 'adviceType' must not be 'null' nor 'undefined'.", this, arguments); 85 registry[adviceType] = adviceFactory; 86 } 87 88 /** 89 * Creates a new {@link SimpleAdviceFactory} instance for the given 90 * {@code adviceClass}, binds the created advice factory to the given 91 * {@code adviceType} and returns the factory. 92 * 93 * <p>If there is already an advice factory bound to the given {@code adviceType} 94 * the old binding gets overwritten. 95 * 96 * @param adviceType the type to bind the {@code adviceFactory} to 97 * @param adviceClass the class of the advice to create instances of if a advice 98 * request for the given {@code adviceType} is made 99 * @return an advice factory configured for the given {@code adviceClass} 100 * @throws IllegalArgumentException if argument {@code adviceType} is {@code null} 101 * or {@code undefined} 102 * @throws IllegalArgumentException if argument {@code adviceClass} is {@code null} 103 * or {@code undefined} 104 */ 105 public function bindAdviceFactoryByAdviceClass(adviceType:Number, adviceClass:Function):AdviceFactory { 106 var factory:AdviceFactory = new SimpleAdviceFactory(adviceClass); 107 bindAdviceFactoryByAdviceFactory(adviceType, factory); 108 return factory; 109 } 110 111 /** 112 * @overload #getAdviceByTypeAndStringAndCall 113 * @overload #getAdviceByTypeAndPointcutAndCall 114 */ 115 public function getAdvice():Advice { 116 var o:Overload = new Overload(this); 117 o.addHandler([Number, String, Call], getAdviceByTypeAndStringAndCall); 118 o.addHandler([Number, Pointcut, Call], getAdviceByTypeAndPointcutAndCall); 119 return o.forward(arguments); 120 } 121 122 /** 123 * Returns the advice corresponding to the given {@code type}. The returned advice 124 * uses the passed-in {@code pointcut} and {@code callback}. 125 * 126 * <p>The {@code callback} is invoked if the {@code execute} method of the returned 127 * advice is executed. 128 * 129 * <p>Commonly supported types are defined as constants in the 130 * {@link AbstractAdvice} class. 131 * 132 * @param type the type of the advice to return 133 * @param pointcut the string representation of a pointcut used by the returned advice 134 * @param callback the callback that is executed if you invoke the {@code execute} 135 * method on the returned advice 136 * @return the advice corresponding to the type and configured with the given 137 * {@code pointcut} and {@code callback} 138 * @throws IllegalArgumentException if argument {@code type} is {@code null} or 139 * {@code undefined} 140 */ 141 public function getAdviceByTypeAndStringAndCall(type:Number, pointcut:String, callback:Call):Advice { 142 if (type == null) throw new IllegalArgumentException("Argument 'type' must not be 'null' nor 'undefined'.", this, arguments); 143 return AdviceFactory(registry[type]).getAdvice(pointcut, callback); 144 } 145 146 /** 147 * Returns the advice corresponding to the given {@code type}. The returned advice 148 * uses the passed-in {@code pointcut} and {@code callback}. 149 * 150 * <p>The {@code callback} is invoked if the {@code execute} method of the returned 151 * advice is executed. 152 * 153 * <p>Commonly supported types are defined as constants in the 154 * {@link AbstractAdvice} class. 155 * 156 * @param type the type of the advice to return 157 * @param pointcut the pointcut used by the returned advice 158 * @param callback the callback that is executed if you invoke the {@code execute} 159 * method on the returned advice 160 * @return the advice corresponding to the type and configured with the given 161 * {@code pointcut} and {@code callback} 162 * @throws IllegalArgumentException if argument {@code type} is {@code null} or 163 * {@code undefined} 164 */ 165 public function getAdviceByTypeAndPointcutAndCall(type:Number, pointcut:Pointcut, callback:Call):Advice { 166 if (type == null) throw new IllegalArgumentException("Argument 'type' must not be 'null' nor 'undefined'.", this, arguments); 167 return AdviceFactory(registry[type]).getAdvice(pointcut, callback); 168 } 169 170 }