/interpreter/tags/at_build150307/src/edu/vub/at/objects/mirrors/NATIntrospectiveMirror.java

http://ambienttalk.googlecode.com/ · Java · 340 lines · 124 code · 29 blank · 187 comment · 6 complexity · 0771a4434cf2e05f7aec1e76bb992173 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. */
  28. package edu.vub.at.objects.mirrors;
  29. import edu.vub.at.exceptions.InterpreterException;
  30. import edu.vub.at.exceptions.XArityMismatch;
  31. import edu.vub.at.exceptions.XSelectorNotFound;
  32. import edu.vub.at.exceptions.XTypeMismatch;
  33. import edu.vub.at.objects.ATBoolean;
  34. import edu.vub.at.objects.ATField;
  35. import edu.vub.at.objects.ATMethod;
  36. import edu.vub.at.objects.ATNil;
  37. import edu.vub.at.objects.ATObject;
  38. import edu.vub.at.objects.ATTable;
  39. import edu.vub.at.objects.coercion.NativeStripes;
  40. import edu.vub.at.objects.grammar.ATSymbol;
  41. import edu.vub.at.objects.natives.NATBoolean;
  42. import edu.vub.at.objects.natives.NATByRef;
  43. import edu.vub.at.objects.natives.NATNil;
  44. import edu.vub.at.objects.natives.NATTable;
  45. import edu.vub.at.objects.natives.NATText;
  46. /**
  47. * <p>NATIntrospectiveMirror is a default mirror to represent an ambienttalk object
  48. * which is capable of offering the java meta-interface of any language value at the
  49. * ambienttalk level. This allows introspection into the language value's internals
  50. * as well as invoking some meta-level operations on it. Technically, NATMirror is
  51. * simply a wrapper object around an ambienttalk object which deifies (ups) methods
  52. * invoked upon it.</p>
  53. *
  54. * <p>Note that whereas the mirror can offer e.g. an apply method when reifying a
  55. * closure, this does not affect its own meta-interface. A NATMirror is always an
  56. * object and can thus not be applied at the ambienttalk level.</p>
  57. *
  58. * Example:
  59. * <pre>
  60. * def clo := { | x | x * 2 };
  61. * def m := at.mirrors.Factory.createMirror(clo);
  62. *
  63. * clo( 5 ) <i> => 10 (legal) </i>
  64. * m.apply([5]) <i> => 10 (legal) </i>
  65. * m( 5 ) <i> => error (Application expected a closure, given a mirror) </i>
  66. * </pre>
  67. *
  68. * @author smostinc
  69. * @author tvcutsem
  70. */
  71. public class NATIntrospectiveMirror extends NATByRef {
  72. /** the object reflected on. This object is NOT a NATMirage */
  73. private final ATObject principal_;
  74. /**
  75. * Return a mirror on the given native or custom AmbientTalk object.
  76. *
  77. * @param objectRepresentation the object to reflect upon
  78. * @return either an introspective mirror (if the passed object is native), otherwise
  79. * a custom intercessive mirror.
  80. */
  81. public static final ATObject atValue(ATObject objectRepresentation) throws XTypeMismatch {
  82. if(objectRepresentation instanceof NATMirage)
  83. return objectRepresentation.asMirage().getMirror();
  84. else
  85. return new NATIntrospectiveMirror(objectRepresentation);
  86. }
  87. /**
  88. * An introspective mirror is a wrapper which forwards a deified (upped) version of invoked
  89. * methods and field accesses to its principal. This principal is a Java object
  90. * representing an ambienttalk object. The deificiation process implies that
  91. * only the object's meta_level operations (implemented in Java) will be called
  92. * directly by the mirror.
  93. *
  94. * @param representation - the object to reflect upon, which is *not* a NATMirage
  95. */
  96. private NATIntrospectiveMirror(ATObject representation) {
  97. principal_ = representation;
  98. }
  99. /**
  100. * This method is used to allow selecting the base field of an intercessive mirror using
  101. * the reflective selection of fields. This method is never invoked directly by the
  102. * implementation.
  103. * @return the base-level entity this mirror reflects on
  104. */
  105. public ATObject base_getBase() {
  106. return principal_;
  107. }
  108. /* ------------------------------
  109. * -- Message Sending Protocol --
  110. * ------------------------------ */
  111. /**
  112. * <p>The effect of invoking methods on a mirror (through meta_invoke) consists of
  113. * checking whether the requested functionality is provided as a meta-operation
  114. * by the principal that is wrapped by this mirror. This implies the requested
  115. * selector is sought for at the java-level, albeit prefixed with 'meta_'.</p>
  116. *
  117. * <p>Because an explicit AmbientTalk method invocation must be converted into an
  118. * implicit Java method invocation, the invocation must be deified ('upped').
  119. * To uphold stratification of the mirror architecture, the result of this
  120. * operation should be a mirror on the result of the Java method invocation.</p>
  121. *
  122. * <p>Note that only when the principal does not have a matching meta_level method
  123. * the mirror itself will be tested for a corresponding base_level method (e.g.
  124. * used for operators such as ==). In the latter case, stratification is not
  125. * enforced. This is due to the fact that these operations are not active at the
  126. * mirror level, they are base-level operations which happen to be applied on a
  127. * mirror. An added advantage of this technique is that it permits a mirror to
  128. * give out a reference to its principal.</p>
  129. */
  130. public ATObject meta_invoke(ATObject receiver, ATSymbol atSelector, ATTable arguments) throws InterpreterException {
  131. String jSelector = Reflection.upMetaLevelSelector(atSelector);
  132. try {
  133. return Reflection.upInvocation(
  134. principal_, // implementor and self
  135. jSelector,
  136. atSelector,
  137. arguments);
  138. } catch (XSelectorNotFound e) {
  139. e.catchOnlyIfSelectorEquals(atSelector);
  140. // Principal does not have a corresponding meta_level method
  141. // try for a base_level method of the mirror itself.
  142. return super.meta_invoke(receiver, atSelector, arguments);
  143. }
  144. }
  145. /* ------------------------------------------
  146. * -- Slot accessing and mutating protocol --
  147. * ------------------------------------------ */
  148. /**
  149. * <p>The effect of selecting fields or methods on a mirror (through meta_select)
  150. * consists of checking whether the requested selector matches a field of the
  151. * principal wrapped by this mirror. If this is the case, the principal's
  152. * ('meta_get' + selector) method will be invoked. Else the selector might
  153. * identify one of the principal's meta-operations. If this is the case, then
  154. * an AmbientTalk representation of the Java method ('meta_' + selector) will
  155. * be returned. </p>
  156. *
  157. * <p>Because an explicit AmbientTalk method invocation must be converted into
  158. * an implicit Java method invocation, the invocation must be deified ('upped').
  159. * To uphold stratification of the mirror architecture, the result of this
  160. * operation should be a mirror on the result of the Java method invocation.</p>
  161. *
  162. * <p>Note that only when the principal does not have a matching meta_level field
  163. * or method the mirror itself will be tested for a corresponding base_level
  164. * behaviour (e.g. for its base field or for operators such as ==). In the
  165. * latter case, stratification is not enforced. This is due to the fact that
  166. * the said fields and methods are not meta-level behaviour, rather they are
  167. * base-level operations which happen to be applicable on a mirror. An added
  168. * advantage of this technique is that it permits a mirror to have a field
  169. * referring to its principal.</p>
  170. */
  171. public ATObject meta_select(ATObject receiver, ATSymbol atSelector) throws InterpreterException {
  172. String jSelector = Reflection.upMetaFieldAccessSelector(atSelector);
  173. try {
  174. return Reflection.upFieldSelection(principal_, jSelector, atSelector);
  175. } catch (XSelectorNotFound e) {
  176. e.catchOnlyIfSelectorEquals(atSelector);
  177. try {
  178. jSelector = Reflection.upMetaLevelSelector(atSelector);
  179. return Reflection.upMethodSelection(
  180. principal_,
  181. jSelector,
  182. atSelector);
  183. } catch (XSelectorNotFound e2) {
  184. e2.catchOnlyIfSelectorEquals(atSelector);
  185. // Principal does not have a corresponding meta_level field nor
  186. // method try for a base_level field or method of the mirror itself.
  187. return super.meta_select(receiver, atSelector);
  188. }
  189. }
  190. }
  191. /**
  192. * A mirror responds to a message m if and only if:
  193. * - either its principal has a method named meta_m
  194. * - or the mirror itself implements a method named base_m
  195. */
  196. public ATBoolean meta_respondsTo(ATSymbol atSelector) throws InterpreterException {
  197. String jSelector = Reflection.upMetaLevelSelector(atSelector);
  198. boolean metaResponds = Reflection.upRespondsTo(principal_, jSelector);
  199. if (metaResponds) {
  200. return NATBoolean._TRUE_;
  201. } else {
  202. return super.meta_respondsTo(atSelector);
  203. }
  204. }
  205. /**
  206. * The effect of assigning a field on a mirror can be twofold. Either a meta_field
  207. * of the reflectee is altered (in this case, the passed value must be a mirror to
  208. * uphold stratification). Otherwise it is possible that a base field of the mirror
  209. * itself is changed.
  210. */
  211. public ATNil meta_assignField(ATObject receiver, ATSymbol name, ATObject value) throws InterpreterException {
  212. String jSelector = Reflection.upMetaFieldMutationSelector(name);
  213. try{
  214. Reflection.upFieldAssignment(principal_, jSelector, name, value);
  215. } catch (XSelectorNotFound e) {
  216. e.catchOnlyIfSelectorEquals(name);
  217. // Principal does not have a corresponding meta_level method
  218. // OR the passed value is not a mirror object
  219. // try for a base_level method of the mirror itself.
  220. return super.meta_assignField(receiver, name, value);
  221. }
  222. return NATNil._INSTANCE_;
  223. }
  224. public ATField meta_grabField(ATSymbol fieldName) throws InterpreterException {
  225. try {
  226. // try to find a meta_get / meta_set field in the principal_
  227. return Reflection.downMetaLevelField(principal_, fieldName);
  228. } catch (XSelectorNotFound e) {
  229. e.catchOnlyIfSelectorEquals(fieldName);
  230. // try to find a base_get / base_set field in the mirror
  231. return super.meta_grabField(fieldName);
  232. }
  233. }
  234. public ATMethod meta_grabMethod(ATSymbol methodName) throws InterpreterException {
  235. try {
  236. // try to find a meta_ method in the principal
  237. return Reflection.downMetaLevelMethod(principal_, methodName);
  238. } catch (XSelectorNotFound e) {
  239. e.catchOnlyIfSelectorEquals(methodName);
  240. // try to find a base_ method in the mirror
  241. return super.meta_grabMethod(methodName);
  242. }
  243. }
  244. /**
  245. * Listing the fields of a mirror requires us to list all of the meta_get methods
  246. * of the principal + all of the base_get methods of the mirror itself
  247. */
  248. public ATTable meta_listFields() throws InterpreterException {
  249. ATField[] principalMetaFields = Reflection.downMetaLevelFields(principal_);
  250. ATField[] mirrorBaseFields = Reflection.downBaseLevelFields(this);
  251. return NATTable.atValue(NATTable.collate(principalMetaFields, mirrorBaseFields));
  252. }
  253. /**
  254. * Listing the methods of a mirror requires us to list all of the meta_ methods
  255. * of the principal (excluding meta_get/set methods) + all of the base_ methods
  256. * (excluding base_get/set methods) of the mirror itself
  257. */
  258. public ATTable meta_listMethods() throws InterpreterException {
  259. ATMethod[] principalMetaMethods = Reflection.downMetaLevelMethods(principal_);
  260. ATMethod[] mirrorBaseMethods = Reflection.downBaseLevelMethods(this);
  261. return NATTable.atValue(NATTable.collate(principalMetaMethods, mirrorBaseMethods));
  262. }
  263. /* ------------------------------------
  264. * -- Extension and cloning protocol --
  265. * ------------------------------------ */
  266. /**
  267. * This method allows re-initialise a mirror object. However, since the link from a
  268. * mirror to its base object is immutable, this results in contacting the mirror
  269. * factory, to create a (new) mirror for the requested object.
  270. * @param initargs - an ATObject[] containing as its first element the object that needs to be reflects upon
  271. * @return <b>another</b> (possibly new) mirror object
  272. */
  273. public ATObject meta_newInstance(ATTable init) throws XArityMismatch, XTypeMismatch {
  274. ATObject[] initargs = init.asNativeTable().elements_;
  275. if(initargs.length != 1) {
  276. ATObject reflectee = initargs[0];
  277. return atValue(reflectee);
  278. } else {
  279. throw new XArityMismatch("init", 1, initargs.length);
  280. }
  281. }
  282. /* ---------------------------------
  283. * -- Abstract Grammar Protocol --
  284. * --------------------------------- */
  285. public NATText meta_print() throws InterpreterException {
  286. return NATText.atValue("<mirror on:"+principal_.meta_print().javaValue+">");
  287. }
  288. public ATTable meta_getStripes() throws InterpreterException {
  289. return NATTable.of(NativeStripes._MIRROR_);
  290. }
  291. /**
  292. * OBSOLETE: introspective mirrors are now pass-by-reference.
  293. * This has the following repercussions:
  294. * - when passing the mirror of an isolate, a remote ref to the mirror is passed instead.
  295. * The isolate is not copied.
  296. * - mirrors on far references can still be created, by passing the principal by ref
  297. * and by reflecting on the obtained far reference
  298. *
  299. * An introspective mirror is pass-by-copy.
  300. * When an introspective mirror is deserialized, it will become a mirror on
  301. * its deserialized principal. This means that, if the principal is passed
  302. * by copy, the mirror will be a local mirror on the copy. If the principal is passed
  303. * by reference, the mirror will be a local mirror on the far reference.
  304. */
  305. /*public ATObject meta_resolve() throws InterpreterException {
  306. if(principal_ instanceof NATMirage)
  307. return ((NATMirage)principal_).getMirror();
  308. else
  309. return this;
  310. }*/
  311. }