PageRenderTime 27ms CodeModel.GetById 8ms app.highlight 13ms RepoModel.GetById 2ms app.codeStats 0ms

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

http://ambienttalk.googlecode.com/
Java | 241 lines | 85 code | 24 blank | 132 comment | 6 complexity | 8661c43140df74781989fec1620ead8b 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.ATMethod;
 36import edu.vub.at.objects.ATObject;
 37import edu.vub.at.objects.ATTable;
 38import edu.vub.at.objects.coercion.NativeTypeTags;
 39import edu.vub.at.objects.grammar.ATSymbol;
 40import edu.vub.at.objects.natives.NATBoolean;
 41import edu.vub.at.objects.natives.NATByRef;
 42import edu.vub.at.objects.natives.NATNumber;
 43import edu.vub.at.objects.natives.NATTable;
 44import edu.vub.at.objects.natives.NATText;
 45
 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
 72public class NATIntrospectiveMirror extends NATByRef {
 73
 74	/** the object reflected on. This object is NOT a NATMirage */
 75	private final ATObject principal_;
 76	
 77	/**
 78	 * Return a mirror on the given native or custom AmbientTalk object.
 79	 * 
 80	 * @param objectRepresentation the object to reflect upon
 81	 * @return either an introspective mirror (if the passed object is native), otherwise
 82	 * a custom intercessive mirror.
 83	 */
 84	public static final ATObject atValue(ATObject objectRepresentation) throws XTypeMismatch {
 85		if (objectRepresentation.isMirage()) {
 86			return objectRepresentation.asMirage().getMirror();
 87		} else {
 88			return new NATIntrospectiveMirror(objectRepresentation);
 89		}
 90	}
 91	
 92	/**
 93	 * An introspective mirror is a wrapper which forwards a deified (upped) version of invoked 
 94	 * methods and field accesses to its principal. This principal is a Java object 
 95	 * representing an ambienttalk object. The deificiation process implies that 
 96	 * only the object's meta_level operations (implemented in Java) will be called
 97	 * directly by the mirror.
 98	 * 
 99	 * @param representation - the object to reflect upon, which is *not* a NATMirage
100	 */
101	private NATIntrospectiveMirror(ATObject representation) {
102		principal_ = representation;
103	}
104	
105	public NATIntrospectiveMirror asNativeIntrospectiveMirror() {
106		return this;
107	}
108
109	public boolean isNativeIntrospectiveMirror() {
110		return true;
111	}
112
113	/**
114	 * This method is used to allow selecting the base field of an intercessive mirror using 
115	 * the reflective selection of fields. This method is never invoked directly by the 
116	 * implementation.
117	 * @return the base-level entity this mirror reflects on
118	 */
119	public ATObject base_base() {
120		return principal_;
121	}
122	
123	public int hashCode() { return principal_.hashCode(); }
124	
125	public ATBoolean base__opeql__opeql_(ATObject other) throws InterpreterException {
126		if (other.isNativeIntrospectiveMirror()) {
127			return NATBoolean.atValue(principal_.equals(other.asNativeIntrospectiveMirror().principal_));
128		} else {
129			return NATBoolean._FALSE_;
130		}
131	}
132	
133	/* ------------------------------------------
134	 * -- Slot accessing and mutating protocol --
135	 * ------------------------------------------ */
136
137    
138    public ATMethod meta_grabMethod(ATSymbol methodName) throws InterpreterException {
139        try {
140        	// try to find a meta_ method in the principal
141			return Reflection.downMetaLevelMethod(principal_, methodName);
142		} catch (XSelectorNotFound e) {
143			e.catchOnlyIfSelectorEquals(methodName);
144			// try to find a base_ method in the mirror
145			return super.meta_grabMethod(methodName);
146		}
147    }
148
149	/**
150	 * Listing the methods of a mirror requires us to list all of the meta_ methods
151	 * of the principal + all of the base_ methods of the mirror itself
152	 */
153    public ATTable meta_listMethods() throws InterpreterException {
154   	    ATMethod[] principalMetaMethods = Reflection.downMetaLevelMethods(principal_);
155   	    ATMethod[] mirrorBaseMethods = Reflection.downBaseLevelMethods(this);
156        return NATTable.atValue(NATTable.collate(principalMetaMethods, mirrorBaseMethods));
157    }
158	
159	/* ------------------------------------
160	 * -- Extension and cloning protocol --
161	 * ------------------------------------ */
162
163	/**
164	 * This method allows re-initialise a mirror object. However, since the link from a 
165	 * mirror to its base object is immutable, this results in contacting the mirror
166	 * factory, to create a (new) mirror for the requested object.
167	 * @param initargs  an ATObject[] containing as its first element the object that needs to be reflects upon
168	 * @return <b>another</b> (possibly new) mirror object 
169	 */
170	public ATObject meta_newInstance(ATTable initargs) throws InterpreterException {
171    	int len = initargs.base_length().asNativeNumber().javaValue;
172		if (len != 1)
173			throw new XArityMismatch("init method of mirror", 1, len);
174		ATObject reflectee = initargs.base_at(NATNumber.ONE);
175		return atValue(reflectee);
176		/*ATObject[] initargs = init.asNativeTable().elements_;
177		if(initargs.length != 1) {
178			ATObject reflectee = initargs[0];
179			return atValue(reflectee);
180		} else {
181			throw new XArityMismatch("init", 1, initargs.length);
182		}*/
183	}
184	
185	/* ---------------------------------
186	 * -- Abstract Grammar Protocol   --
187	 * --------------------------------- */
188		
189	public NATText meta_print() throws InterpreterException {
190		return NATText.atValue("<mirror on:"+principal_.meta_print().javaValue+">");
191	}
192	
193    public ATTable meta_typeTags() throws InterpreterException {
194    	return NATTable.of(NativeTypeTags._MIRROR_);
195    }
196	
197	/**
198	 * OBSOLETE: introspective mirrors are now pass-by-reference.
199	 * This has the following repercussions:
200	 *  - when passing the mirror of an isolate, a remote ref to the mirror is passed instead.
201	 *    The isolate is not copied.
202	 *  - mirrors on far references can still be created, by passing the principal by ref
203	 *    and by reflecting on the obtained far reference
204	 * 
205	 * An introspective mirror is pass-by-copy.
206     * When an introspective mirror is deserialized, it will become a mirror on
207     * its deserialized principal. This means that, if the principal is passed
208     * by copy, the mirror will be a local mirror on the copy. If the principal is passed
209     * by reference, the mirror will be a local mirror on the far reference.
210	 */
211	/*public ATObject meta_resolve() throws InterpreterException {
212		if(principal_ instanceof NATMirage)
213			return ((NATMirage)principal_).getMirror();
214		else
215			return this;
216	}*/
217
218	/**
219	 * For mirrors, first try to find a <tt>meta_</tt> method in the principal.
220	 * If this fails, try to find a <tt>base_</tt> method in the introspective mirror itself.
221	 */
222	protected boolean hasLocalMethod(ATSymbol atSelector) throws InterpreterException {
223        return Reflection.upRespondsTo(principal_, Reflection.upMetaLevelSelector(atSelector)) ||
224               super.hasLocalMethod(atSelector);
225	}
226	
227	/**
228	 * For mirrors, first try to find a <tt>meta_</tt> method in the principal.
229	 * If this fails, try to find a <tt>base_</tt> method in the introspective mirror itself.
230	 */
231	protected ATMethod getLocalMethod(ATSymbol selector) throws InterpreterException {
232		try {
233			String methSelector = Reflection.upMetaLevelSelector(selector);
234			return Reflection.upMethodSelection(principal_, methSelector, selector);
235		} catch (XSelectorNotFound e) {
236			e.catchOnlyIfSelectorEquals(selector);
237			return super.getLocalMethod(selector);
238		}
239	}
240
241}