001 /* 002 Copyright (C) 2001-2002 Renaud Pawlak <renaud@aopsys.com> 003 004 This program is free software; you can redistribute it and/or modify 005 it under the terms of the GNU Lesser General Public License as 006 published by the Free Software Foundation; either version 2 of the 007 License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, but 010 WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 Lesser General Public License for more details. 013 014 You should have received a copy of the GNU Lesser General Public 015 License along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 017 USA */ 018 019 package org.objectweb.jac.core; 020 021 022 import java.io.Serializable; 023 import java.lang.reflect.Method; 024 import java.util.Vector; 025 import org.aopalliance.intercept.ConstructorInterceptor; 026 import org.aopalliance.intercept.ConstructorInvocation; 027 import org.aopalliance.intercept.Invocation; 028 import org.aopalliance.intercept.MethodInterceptor; 029 import org.aopalliance.intercept.MethodInvocation; 030 import org.objectweb.jac.core.rtti.ClassRepository; 031 032 /** 033 * This class is the root class for all the wrappers. A wrapper is 034 * part of a collaboration point when one or several of its methods 035 * wrap a base program object (a wrappee). The set of wrappers 036 * (methods) that wrap a wrappee (method) it called a wrapping 037 * (method) chain. 038 * 039 * <p>When a method call occurs on a wrappee, the system creates a new 040 * collaboration point in the current collaboration and all the 041 * wrappers are sequentially called. 042 * 043 * <p>A given wrapper passes the hand to the next wrapper (or to the 044 * wrappee if last) by explicitly calling the <code>proceed()</code> 045 * method. 046 * 047 * <p>For futher details about wrapping semantics, see the 048 * <code>Wrapper.proceed()</code> method and the 049 * <code>Wrappee.wrap()</code> methods. 050 * 051 * @author <a href="http://cedric.cnam.fr/~pawlak/index-english.html">Renaud Pawlak</a> */ 052 053 public abstract class Wrapper 054 implements Serializable, MethodInterceptor, ConstructorInterceptor 055 { 056 057 protected static final ClassRepository cr = ClassRepository.get(); 058 059 /** 060 * The constructor sets the aspect component that owns the wrapper 061 * from the context. */ 062 063 public Wrapper(AspectComponent ac) { 064 // this.ac = ACManager.get().getName(ac); 065 this.ac = ac; 066 if (ac != null) { 067 //Log.trace("wrapper","new wrapper for "+ac); 068 ac.addWrapper(this); 069 //Log.trace("wrapper","wrappers= "+ac.getWrappers()); 070 } 071 } 072 073 /** The AC of the wrapper. */ 074 // protected transient String acName; 075 protected final transient AspectComponent ac; 076 077 /** 078 * Returns true if the method is defined in the wrapper class. 079 * 080 * @param methodName the method to test 081 * @return true if wrapper method 082 */ 083 084 public static boolean defines(String methodName) { 085 if (ClassRepository.getDirectMethodAccess(Wrapper.class, methodName)[0] 086 != null) 087 return true; 088 return false; 089 } 090 091 /** 092 * Returns the exception handlers of the given wrapper class. Are 093 * considered as exception handlers all methods whose first 094 * argument is an Exception. 095 * 096 * @param wrapperClass the wrapper class 097 * @return a vector containing the methods names */ 098 099 public static Vector getExceptionHandlers(Class wrapperClass) { 100 Method[] methods = wrapperClass.getMethods(); 101 Vector ret = new Vector(); 102 for (int i = 0; i < methods.length; i++) { 103 Class[] pts = methods[i].getParameterTypes(); 104 if (pts.length > 0) { 105 Class cl = pts[0]; 106 boolean ok = false; 107 if (cl != null) { 108 while (cl != null 109 && (!cl.isPrimitive()) 110 && cl != Object.class) { 111 if (cl == Exception.class) { 112 ok = true; 113 } 114 cl = cl.getSuperclass(); 115 } 116 } 117 if (ok) { 118 ret.add(methods[i].getName()); 119 } 120 } 121 } 122 return ret; 123 } 124 125 /** 126 * Returns the Aspect Component the wrapper belongs to by resolving 127 * the name. 128 * 129 * @see #getAspectComponentName() */ 130 131 public AspectComponent getAspectComponent() { 132 return ac; 133 /* 134 if (ac==null) return null; 135 return (AspectComponent)ACManager.get().getObject(ac); 136 */ 137 } 138 139 /** 140 * Returns the Aspect Component name the wrapper belongs to. By 141 * default, this name is set by the system when an aspect component 142 * wraps a given wrappee. 143 * 144 * @see Wrappee */ 145 146 public String getAspectComponentName() { 147 return ACManager.get().getName(ac); 148 } 149 150 /** 151 * Set the aspect component name that owns the wrapper. The name of 152 * the aspect component is the one registered in 153 * <code>ACManager</code> (see <code>ACManager.get()</code>). This 154 * method should not be called directly since the aspect component 155 * is automatically set by the system when the wrap method is 156 * called on a wrappee. 157 * 158 * @param ac the name of the aspect component 159 * @see Wrappee 160 */ 161 /* 162 public void setAspectComponent(AspectComponent ac) { 163 this.ac = ac; 164 } 165 */ 166 /** 167 * String representation of a wrapper (eg <code>{wrapper 168 * className owned by aspectComponentName}</code>). */ 169 170 public String toString() { 171 if (ac == null) { 172 return super.toString() + "(nobody)"; 173 } 174 return super.toString() + "(" + getAspectComponentName() + ")"; 175 } 176 177 /** 178 * Run the next wrapper of the collaboration point. 179 * 180 * <p>A new collaboration point is initiated by the system when a 181 * method call occurs on a base program object (a wrappee). If the 182 * called method is wrapped by one or several wrapping methods 183 * (wrappers methods - see <code>Wrappee.wrap()</code>), then the 184 * system first upcalls all the wrapping methods. 185 * 186 * <p>A wrapping method is a regular Java method that takes no 187 * argument and returns an object. It can access the currently 188 * called method runtime caracteristics by using the 189 * <code>CollaborationParticipant</code> interface methods 190 * implemented by the wrapper (see <code>method()</code> or 191 * <code>args</code>). 192 * 193 * <p>The set of wrapping methods that wraps a wrappee method is 194 * called a wrapping method chain. The wrapping methods of a 195 * wrapping chain are sequentially called. A given wrapping method 196 * of the wrapping chain passes the hand to the next wrapping 197 * method of this chain by calling <code>proceed()</code>. 198 * 199 * <p>A wrapper should ALWAYS call the proceed method except if it 200 * delibaratly wants to replace all the upcoming wrappers and base 201 * method functionalities (e.g. the 202 * <code>org.objectweb.jac.aspects.binding.ForwardingWrapper</code>). 203 * 204 * <p>The wrapping methods are called in a well-defined order. A 205 * wrapper cannot change this order by himself since it is the 206 * composition aspect that is responsible for setting this order 207 * (see <code>Wrappee.wrap()</code> and 208 * <code>CompositionAspect.getWeaveTimeRank()</code>). 209 * 210 * <p>Within a clean aspect-oriented design, the wrapper can be 211 * shortcutted by its aspect component if needed (see 212 * <code>AspectComponent.beforeRunningWrapper()</code>). 213 * 214 * <p>In a wrapping method, proceed returns the value returned by 215 * the wrappee method. A wrapper can modify this return value if 216 * needed. The wrapping method code that is placed before the 217 * <code>proceed()</code> call is called <i>before</i> code (since 218 * it is executed before the wrapped method execution), and the 219 * code that is placed after the proceed call is called 220 * <i>after</i> code (since it is executed after). 221 * 222 * <p>A typical wrapping method looks like the following: 223 * 224 * <ul><pre> 225 * public class MyWrapper extends Wrapper { 226 * public MyWrapper(AspectComponent ac) { super(ac); } 227 * public Object invoke(MethodInvocation mi) { 228 * // before code (can access the called method infos) 229 * ... 230 * Object result = proceed(mi); 231 * // after code (can modify the returned value) 232 * ... 233 * // must return a value (most of the time the proceed() value) 234 * return result; 235 * } 236 * public Object construct(ConstructorInvocation ci) { 237 * return proceed(ci); 238 * } 239 * } 240 * </pre></ul> 241 * 242 * @return the final value returned by the current method call 243 * @see Wrapping#wrap(Wrappee,Wrapper,AbstractMethodItem) 244 * @see CollaborationParticipant 245 * @see CompositionAspect#getWeaveTimeRank(WrappingChain,Wrapper) 246 * @see AspectComponent#beforeRunningWrapper(Wrapper,String) 247 */ 248 public final Object proceed(Invocation invocation) { 249 // The AOP Alliance Invocation interface is implemented by the Interaction class 250 Interaction interaction = (Interaction) invocation; 251 interaction.rank += 1; 252 return Wrapping.nextWrapper(interaction); 253 } 254 255 // following methods implement the CollaborationParticipant interface 256 257 public final void attrdef(String name, Object value) { 258 Collaboration.get().addAttribute(name, value); 259 } 260 261 public final Object attr(String name) { 262 return Collaboration.get().getAttribute(name); 263 } 264 265 public Object invoke(MethodInvocation invocation) throws Throwable { 266 throw new Exception("Wrapper "+this+" does not support method interception."); 267 } 268 269 public Object construct(ConstructorInvocation invocation) throws Throwable 270 { 271 throw new Exception("Wrapper "+this+" does not support construction interception."); 272 } 273 274 }