/interpreter/tags/at2-build190607/src/edu/vub/at/objects/mirrors/NATIntrospectiveMirror.java
Java | 340 lines | 124 code | 29 blank | 187 comment | 6 complexity | d9675175542896d76485024ee4bc2de1 MD5 | raw file
1/** 2 * AmbientTalk/2 Project 3 * NATMirror.java created on Aug 13, 2006 at 10:09:29 AM 4 * (c) Programming Technology Lab, 2006 - 2007 5 * Authors: Tom Van Cutsem & Stijn Mostinckx 6 * 7 * Permission is hereby granted, free of charge, to any person 8 * obtaining a copy of this software and associated documentation 9 * files (the "Software"), to deal in the Software without 10 * restriction, including without limitation the rights to use, 11 * copy, modify, merge, publish, distribute, sublicense, and/or 12 * sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following 14 * conditions: 15 * 16 * The above copyright notice and this permission notice shall be 17 * included in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 * OTHER DEALINGS IN THE SOFTWARE. 27 */ 28package edu.vub.at.objects.mirrors; 29 30import edu.vub.at.exceptions.InterpreterException; 31import edu.vub.at.exceptions.XArityMismatch; 32import edu.vub.at.exceptions.XSelectorNotFound; 33import edu.vub.at.exceptions.XTypeMismatch; 34import edu.vub.at.objects.ATBoolean; 35import edu.vub.at.objects.ATField; 36import edu.vub.at.objects.ATMethod; 37import edu.vub.at.objects.ATNil; 38import edu.vub.at.objects.ATObject; 39import edu.vub.at.objects.ATTable; 40import edu.vub.at.objects.coercion.NativeTypeTags; 41import edu.vub.at.objects.grammar.ATSymbol; 42import edu.vub.at.objects.natives.NATBoolean; 43import edu.vub.at.objects.natives.NATByRef; 44import edu.vub.at.objects.natives.NATNil; 45import edu.vub.at.objects.natives.NATTable; 46import edu.vub.at.objects.natives.NATText; 47 48/** 49 * <p>NATIntrospectiveMirror is a default mirror to represent an ambienttalk object 50 * which is capable of offering the java meta-interface of any language value at the 51 * ambienttalk level. This allows introspection into the language value's internals 52 * as well as invoking some meta-level operations on it. Technically, NATMirror is 53 * simply a wrapper object around an ambienttalk object which deifies (ups) methods 54 * invoked upon it.</p> 55 * 56 * <p>Note that whereas the mirror can offer e.g. an apply method when reifying a 57 * closure, this does not affect its own meta-interface. A NATMirror is always an 58 * object and can thus not be applied at the ambienttalk level.</p> 59 * 60 * Example: 61 * <pre> 62 * def clo := { | x | x * 2 }; 63 * def m := at.mirrors.Factory.createMirror(clo); 64 * 65 * clo( 5 ) <i> => 10 (legal) </i> 66 * m.apply([5]) <i> => 10 (legal) </i> 67 * m( 5 ) <i> => error (Application expected a closure, given a mirror) </i> 68 * </pre> 69 * 70 * @author smostinc 71 * @author tvcutsem 72 */ 73 74public class NATIntrospectiveMirror extends NATByRef { 75 76 /** the object reflected on. This object is NOT a NATMirage */ 77 private final ATObject principal_; 78 79 /** 80 * Return a mirror on the given native or custom AmbientTalk object. 81 * 82 * @param objectRepresentation the object to reflect upon 83 * @return either an introspective mirror (if the passed object is native), otherwise 84 * a custom intercessive mirror. 85 */ 86 public static final ATObject atValue(ATObject objectRepresentation) throws XTypeMismatch { 87 if(objectRepresentation instanceof NATMirage) 88 return objectRepresentation.asMirage().getMirror(); 89 else 90 return new NATIntrospectiveMirror(objectRepresentation); 91 } 92 93 /** 94 * An introspective mirror is a wrapper which forwards a deified (upped) version of invoked 95 * methods and field accesses to its principal. This principal is a Java object 96 * representing an ambienttalk object. The deificiation process implies that 97 * only the object's meta_level operations (implemented in Java) will be called 98 * directly by the mirror. 99 * 100 * @param representation - the object to reflect upon, which is *not* a NATMirage 101 */ 102 private NATIntrospectiveMirror(ATObject representation) { 103 principal_ = representation; 104 } 105 106 /** 107 * This method is used to allow selecting the base field of an intercessive mirror using 108 * the reflective selection of fields. This method is never invoked directly by the 109 * implementation. 110 * @return the base-level entity this mirror reflects on 111 */ 112 public ATObject base_getBase() { 113 return principal_; 114 } 115 116 /* ------------------------------ 117 * -- Message Sending Protocol -- 118 * ------------------------------ */ 119 120 /** 121 * <p>The effect of invoking methods on a mirror (through meta_invoke) consists of 122 * checking whether the requested functionality is provided as a meta-operation 123 * by the principal that is wrapped by this mirror. This implies the requested 124 * selector is sought for at the java-level, albeit prefixed with 'meta_'.</p> 125 * 126 * <p>Because an explicit AmbientTalk method invocation must be converted into an 127 * implicit Java method invocation, the invocation must be deified ('upped'). 128 * To uphold stratification of the mirror architecture, the result of this 129 * operation should be a mirror on the result of the Java method invocation.</p> 130 * 131 * <p>Note that only when the principal does not have a matching meta_level method 132 * the mirror itself will be tested for a corresponding base_level method (e.g. 133 * used for operators such as ==). In the latter case, stratification is not 134 * enforced. This is due to the fact that these operations are not active at the 135 * mirror level, they are base-level operations which happen to be applied on a 136 * mirror. An added advantage of this technique is that it permits a mirror to 137 * give out a reference to its principal.</p> 138 */ 139 public ATObject meta_invoke(ATObject receiver, ATSymbol atSelector, ATTable arguments) throws InterpreterException { 140 String jSelector = Reflection.upMetaLevelSelector(atSelector); 141 142 try { 143 return Reflection.upInvocation( 144 principal_, // implementor and self 145 jSelector, 146 atSelector, 147 arguments); 148 } catch (XSelectorNotFound e) { 149 e.catchOnlyIfSelectorEquals(atSelector); 150 // Principal does not have a corresponding meta_level method 151 // try for a base_level method of the mirror itself. 152 return super.meta_invoke(receiver, atSelector, arguments); 153 } 154 } 155 156 /* ------------------------------------------ 157 * -- Slot accessing and mutating protocol -- 158 * ------------------------------------------ */ 159 160 /** 161 * <p>The effect of selecting fields or methods on a mirror (through meta_select) 162 * consists of checking whether the requested selector matches a field of the 163 * principal wrapped by this mirror. If this is the case, the principal's 164 * ('meta_get' + selector) method will be invoked. Else the selector might 165 * identify one of the principal's meta-operations. If this is the case, then 166 * an AmbientTalk representation of the Java method ('meta_' + selector) will 167 * be returned. </p> 168 * 169 * <p>Because an explicit AmbientTalk method invocation must be converted into 170 * an implicit Java method invocation, the invocation must be deified ('upped'). 171 * To uphold stratification of the mirror architecture, the result of this 172 * operation should be a mirror on the result of the Java method invocation.</p> 173 * 174 * <p>Note that only when the principal does not have a matching meta_level field 175 * or method the mirror itself will be tested for a corresponding base_level 176 * behaviour (e.g. for its base field or for operators such as ==). In the 177 * latter case, stratification is not enforced. This is due to the fact that 178 * the said fields and methods are not meta-level behaviour, rather they are 179 * base-level operations which happen to be applicable on a mirror. An added 180 * advantage of this technique is that it permits a mirror to have a field 181 * referring to its principal.</p> 182 */ 183 public ATObject meta_select(ATObject receiver, ATSymbol atSelector) throws InterpreterException { 184 String jSelector = Reflection.upMetaFieldAccessSelector(atSelector); 185 186 try { 187 return Reflection.upFieldSelection(principal_, jSelector, atSelector); 188 } catch (XSelectorNotFound e) { 189 e.catchOnlyIfSelectorEquals(atSelector); 190 try { 191 jSelector = Reflection.upMetaLevelSelector(atSelector); 192 193 return Reflection.upMethodSelection( 194 principal_, 195 jSelector, 196 atSelector); 197 } catch (XSelectorNotFound e2) { 198 e2.catchOnlyIfSelectorEquals(atSelector); 199 // Principal does not have a corresponding meta_level field nor 200 // method try for a base_level field or method of the mirror itself. 201 return super.meta_select(receiver, atSelector); 202 } 203 } 204 } 205 206 /** 207 * A mirror responds to a message m if and only if: 208 * - either its principal has a method named meta_m 209 * - or the mirror itself implements a method named base_m 210 */ 211 public ATBoolean meta_respondsTo(ATSymbol atSelector) throws InterpreterException { 212 String jSelector = Reflection.upMetaLevelSelector(atSelector); 213 boolean metaResponds = Reflection.upRespondsTo(principal_, jSelector); 214 if (metaResponds) { 215 return NATBoolean._TRUE_; 216 } else { 217 return super.meta_respondsTo(atSelector); 218 } 219 } 220 221 /** 222 * The effect of assigning a field on a mirror can be twofold. Either a meta_field 223 * of the reflectee is altered (in this case, the passed value must be a mirror to 224 * uphold stratification). Otherwise it is possible that a base field of the mirror 225 * itself is changed. 226 */ 227 public ATNil meta_assignField(ATObject receiver, ATSymbol name, ATObject value) throws InterpreterException { 228 String jSelector = Reflection.upMetaFieldMutationSelector(name); 229 try{ 230 Reflection.upFieldAssignment(principal_, jSelector, name, value); 231 } catch (XSelectorNotFound e) { 232 e.catchOnlyIfSelectorEquals(name); 233 // Principal does not have a corresponding meta_level method 234 // OR the passed value is not a mirror object 235 // try for a base_level method of the mirror itself. 236 return super.meta_assignField(receiver, name, value); 237 } 238 239 return NATNil._INSTANCE_; 240 } 241 242 public ATField meta_grabField(ATSymbol fieldName) throws InterpreterException { 243 try { 244 // try to find a meta_get / meta_set field in the principal_ 245 return Reflection.downMetaLevelField(principal_, fieldName); 246 } catch (XSelectorNotFound e) { 247 e.catchOnlyIfSelectorEquals(fieldName); 248 // try to find a base_get / base_set field in the mirror 249 return super.meta_grabField(fieldName); 250 } 251 } 252 253 public ATMethod meta_grabMethod(ATSymbol methodName) throws InterpreterException { 254 try { 255 // try to find a meta_ method in the principal 256 return Reflection.downMetaLevelMethod(principal_, methodName); 257 } catch (XSelectorNotFound e) { 258 e.catchOnlyIfSelectorEquals(methodName); 259 // try to find a base_ method in the mirror 260 return super.meta_grabMethod(methodName); 261 } 262 } 263 264 /** 265 * Listing the fields of a mirror requires us to list all of the meta_get methods 266 * of the principal + all of the base_get methods of the mirror itself 267 */ 268 public ATTable meta_listFields() throws InterpreterException { 269 ATField[] principalMetaFields = Reflection.downMetaLevelFields(principal_); 270 ATField[] mirrorBaseFields = Reflection.downBaseLevelFields(this); 271 return NATTable.atValue(NATTable.collate(principalMetaFields, mirrorBaseFields)); 272 } 273 274 /** 275 * Listing the methods of a mirror requires us to list all of the meta_ methods 276 * of the principal (excluding meta_get/set methods) + all of the base_ methods 277 * (excluding base_get/set methods) of the mirror itself 278 */ 279 public ATTable meta_listMethods() throws InterpreterException { 280 ATMethod[] principalMetaMethods = Reflection.downMetaLevelMethods(principal_); 281 ATMethod[] mirrorBaseMethods = Reflection.downBaseLevelMethods(this); 282 return NATTable.atValue(NATTable.collate(principalMetaMethods, mirrorBaseMethods)); 283 } 284 285 /* ------------------------------------ 286 * -- Extension and cloning protocol -- 287 * ------------------------------------ */ 288 289 /** 290 * This method allows re-initialise a mirror object. However, since the link from a 291 * mirror to its base object is immutable, this results in contacting the mirror 292 * factory, to create a (new) mirror for the requested object. 293 * @param initargs - an ATObject[] containing as its first element the object that needs to be reflects upon 294 * @return <b>another</b> (possibly new) mirror object 295 */ 296 public ATObject meta_newInstance(ATTable init) throws XArityMismatch, XTypeMismatch { 297 ATObject[] initargs = init.asNativeTable().elements_; 298 if(initargs.length != 1) { 299 ATObject reflectee = initargs[0]; 300 return atValue(reflectee); 301 } else { 302 throw new XArityMismatch("init", 1, initargs.length); 303 } 304 305 } 306 307 /* --------------------------------- 308 * -- Abstract Grammar Protocol -- 309 * --------------------------------- */ 310 311 public NATText meta_print() throws InterpreterException { 312 return NATText.atValue("<mirror on:"+principal_.meta_print().javaValue+">"); 313 } 314 315 public ATTable meta_getTypeTags() throws InterpreterException { 316 return NATTable.of(NativeTypeTags._MIRROR_); 317 } 318 319 /** 320 * OBSOLETE: introspective mirrors are now pass-by-reference. 321 * This has the following repercussions: 322 * - when passing the mirror of an isolate, a remote ref to the mirror is passed instead. 323 * The isolate is not copied. 324 * - mirrors on far references can still be created, by passing the principal by ref 325 * and by reflecting on the obtained far reference 326 * 327 * An introspective mirror is pass-by-copy. 328 * When an introspective mirror is deserialized, it will become a mirror on 329 * its deserialized principal. This means that, if the principal is passed 330 * by copy, the mirror will be a local mirror on the copy. If the principal is passed 331 * by reference, the mirror will be a local mirror on the far reference. 332 */ 333 /*public ATObject meta_resolve() throws InterpreterException { 334 if(principal_ instanceof NATMirage) 335 return ((NATMirage)principal_).getMirror(); 336 else 337 return this; 338 }*/ 339 340}