PageRenderTime 48ms CodeModel.GetById 8ms app.highlight 32ms RepoModel.GetById 2ms app.codeStats 0ms

/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 */
 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.NativeStripes;
 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_getStripes() throws InterpreterException {
316    	return NATTable.of(NativeStripes._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}