PageRenderTime 43ms CodeModel.GetById 13ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/interpreter/tags/at2dist091109/src/edu/vub/at/actors/natives/ReceptionistsSet.java

http://ambienttalk.googlecode.com/
Java | 274 lines | 139 code | 30 blank | 105 comment | 21 complexity | 82c60da402164d1a5ce689b87f8dbbad MD5 | raw file
  1/**
  2 * AmbientTalk/2 Project
  3 * ReceptionistsSet.java created on Dec 5, 2006 at 10:58:44 PM
  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.actors.natives;
 29
 30import java.lang.ref.WeakReference;
 31import java.util.HashMap;
 32import java.util.Hashtable;
 33
 34import edu.vub.at.actors.id.ATObjectID;
 35import edu.vub.at.eval.Evaluator;
 36import edu.vub.at.exceptions.InterpreterException;
 37import edu.vub.at.exceptions.XIllegalOperation;
 38import edu.vub.at.exceptions.XObjectOffline;
 39import edu.vub.at.objects.ATObject;
 40import edu.vub.at.objects.ATTable;
 41import edu.vub.at.objects.ATTypeTag;
 42import edu.vub.at.objects.mirrors.NativeClosure;
 43import edu.vub.at.objects.natives.NATObject;
 44import edu.vub.at.objects.natives.NATTable;
 45import edu.vub.at.objects.natives.NATText;
 46import edu.vub.at.objects.natives.grammar.AGSymbol;
 47
 48/**
 49 * An NATActorMirror's ReceptionistsSet keeps a mapping between identifiers and local objects
 50 * which allows resolving far objects to local ones. The ReceptionistsSet also stores
 51 * which actors refer to an object, which is the basis for a distributed garbage 
 52 * collection algorithm.
 53 *
 54 * @author smostinc
 55 */
 56public class ReceptionistsSet {
 57
 58    // TODO: these maps are not garbage-collected: obsolete entries are never removed
 59	
 60	/** object id (ATObjectID) -> local object (ATObject) */
 61	private final HashMap exportedObjectsTable_;
 62	
 63	/**
 64	 * local object (ATObject) -> object id (ATObjectID)
 65	 * under which this object is currently exported. This map
 66	 * and the previous map maintain a bi-directional mapping
 67	 * between objects and globally unique object IDs.
 68	 */
 69	private final HashMap exportedObjectIds_;
 70
 71	
 72	private final ELActor owner_;
 73	
 74	/**
 75	 * a pool of remote object references: ensures that each ATObjectID is paired
 76	 * with a unique remote object reference (and corresponding outbox)
 77	 */
 78	private final Hashtable remoteReferences_;
 79	
 80	/**
 81	 * a pool of far object references: ensures that each ATObjectID is paired
 82	 * with a unique far object reference
 83	 */
 84	private final Hashtable farReferences_;
 85	
 86	/** Create a fresh receptionist owned by a given actor */
 87	public ReceptionistsSet(ELActor forActor) {
 88		owner_ = forActor;
 89		exportedObjectsTable_ = new HashMap();
 90		exportedObjectIds_ = new HashMap();
 91		remoteReferences_ = new Hashtable();
 92		farReferences_ = new Hashtable();
 93	}
 94	
 95	private NATRemoteFarRef createRemoteFarRef(ATObjectID objectId, ATTypeTag[] types, boolean isConnected) {
 96		NATRemoteFarRef farref;
 97		WeakReference pooled = (WeakReference) remoteReferences_.get(objectId);
 98		if (pooled != null) {
 99			farref = (NATRemoteFarRef) pooled.get();
100			if (farref != null) {
101				return farref;
102			}
103		}
104		farref = new NATRemoteFarRef(objectId, owner_, types, isConnected);
105		remoteReferences_.put(objectId, new WeakReference(farref));
106		return farref;
107	}
108	
109	private NATLocalFarRef createLocalFarRef(ELActor actor, ATObjectID objectId, ATTypeTag[] types, boolean isConnected) {
110		NATLocalFarRef farref;
111		WeakReference pooled = (WeakReference) farReferences_.get(objectId);
112		if (pooled != null) {
113			farref = (NATLocalFarRef) pooled.get();
114			if (farref != null) {
115				return farref;
116			}
117		}
118
119		farref = new NATLocalFarRef(actor, objectId, types, owner_, isConnected);
120		farReferences_.put(objectId, new WeakReference(farref));
121		return farref;
122	}
123	
124	/**
125	 * Export a local object such that it now has a unique global identifier which
126	 * can be distributed to other actors. Only near references may be exported.
127	 * 
128	 * @param object - the local object to export to the outside world
129	 * @param description - a globally human-readable meaningful description of the object
130	 * @return a local remote reference denoting the local object
131	 * @throws XIllegalOperation - if object is a far reference
132	 */
133	public NATLocalFarRef exportObject(ATObject object, String description) throws InterpreterException {
134		if (object.isNativeFarReference()) {
135			throw new XIllegalOperation("Cannot export a far reference to " + object);
136		}
137		
138
139		ATObjectID objId = null;
140
141		// if this object was already exported, return a far ref with the same ID
142		// as the one already stored
143		if (exportedObjectIds_.containsKey(object)) {
144			objId = (ATObjectID) exportedObjectIds_.get(object);
145		} else {
146			// get the host VM
147			ELVirtualMachine currentVM = owner_.getHost();
148			
149			// create a new unique ID for the exported object, but make sure that the unique identity
150			// remembers the VM id and actor ID from which the object originated
151			objId = new ATObjectID(currentVM.getGUID(), owner_.getActorID(), description);
152			
153			exportedObjectsTable_.put(objId, object);
154			exportedObjectIds_.put(object, objId);
155		}
156				
157		// copy types of local object
158		ATObject[] origTypes = object.meta_typeTags().asNativeTable().elements_;
159		ATTypeTag[] types = new ATTypeTag[origTypes.length];
160		System.arraycopy(origTypes, 0, types, 0, origTypes.length);
161		return createLocalFarRef(owner_, objId, types, true);
162	}
163	
164	public NATLocalFarRef exportObject(ATObject object) throws InterpreterException {
165		return exportObject(object, object.toString());
166	}
167	
168	/**
169	 * Take offline a local object which was exported to the outside world. 
170	 *  
171	 * @param object - the local object exported to the outside world
172	 * @throws XIllegalOperation if the object was not found locally
173	 */
174	public void takeOfflineObject(ATObject object) throws XIllegalOperation {
175		if (exportedObjectIds_.containsKey(object)) {
176			ATObjectID objId = (ATObjectID) exportedObjectIds_.get(object);
177			exportedObjectsTable_.remove(objId);
178			exportedObjectIds_.remove(object);
179			//notify the rest of VM that this object was taken offline
180			owner_.getHost().event_objectTakenOffline(objId, null);
181		} else{
182			
183			//the object was not previously exported or it has already been taken offline
184			//I don't know the objectId => throw XIllegalOperation
185			throw new XIllegalOperation("Cannot take offline an object that is not online: " + object);
186		}
187	}
188	
189	/**
190	 * A disconnected object is defined as:
191	 * object: {
192	 *   def object := //disconnected object;
193	 *   def reconnect() { //reconnect & re-publish the disconnected object }
194	 * }
195	 */
196	public class NATDisconnected extends NATObject {
197		private final AGSymbol _OBJECT_ = AGSymbol.jAlloc("object");
198		private final AGSymbol _RECONNECT_ = AGSymbol.jAlloc("reconnect");
199		public NATDisconnected(final ATObject object, final ATObjectID objectId) throws InterpreterException {
200			meta_defineField(_OBJECT_, object);
201			meta_defineField(_RECONNECT_, 	new NativeClosure(this) {
202				public ATObject base_apply(ATTable args) throws InterpreterException {
203					owner_.getHost().discoveryActor_.event_reconnectPublications(object);
204					owner_.getHost().event_objectReconnected(objectId);
205					return Evaluator.getNil();
206				}
207			});
208		}
209		public NATText meta_print() throws InterpreterException {
210			return NATText.atValue("<disconnected:"+impl_invokeAccessor(this, _OBJECT_, NATTable.EMPTY)+">");
211		}
212	}
213	
214	/**
215	 * Disconnect a local object which was exported to the outside world. 
216	 *  
217	 * @param object - the local object exported to the outside world
218	 * @throws XIllegalOperation if the object was not found locally
219	 */
220	public ATObject disconnect(final ATObject object) throws InterpreterException {
221		if (exportedObjectIds_.containsKey(object)) {
222			ATObjectID objId = (ATObjectID) exportedObjectIds_.get(object);
223			NATDisconnected disco = new NATDisconnected(object, objId);
224			//notify the rest of VM that this object was taken offline
225			owner_.getHost().discoveryActor_.event_disconnectPublications(object);
226			owner_.getHost().event_objectDisconnected(objId);
227			return disco;
228		} else{
229			//check whether the object to disconnect is a far reference.
230			if(object instanceof NATFarReference) {
231				NATFarReference reference = (NATFarReference)object;
232				ATObjectID objId = reference.getObjectId();
233				NATDisconnected disco = new NATDisconnected(object, objId);
234				// notify locally the far reference, no need to broadcast the
235				// 'disconnect' event, neither disconnect publications.
236				owner_.getHost().connectionManager_.notifyObjectDisconnected(objId);
237				return disco;
238			} else{ 
239			  //the object was not previously exported or it has already been disconnected
240			  //I don't know the objectId => throw XIllegalOperation
241			  throw new XIllegalOperation("Attempt to disconnect neither a local exported object nor a far reference: "+object);
242			}
243		}
244	}
245	
246	/**
247	 * Try to resolve a remote object reference into a local (near) reference.
248	 * 
249	 * @param objectId the identifier of the remote object
250	 * @return either the local object corresponding to that identifier, or a far reference designating the id
251	 * @throws XObjectOffline if the object was not found locally
252	 */
253	public ATObject resolveObject(ATObjectID objectId, ATTypeTag[] types, boolean isConnected) throws XObjectOffline {
254		if (objectId.getActorId().equals(owner_.getActorID())) { // does objectId denote a local object?
255			
256			// object should be found in this actor
257			ATObject localObject = (ATObject) exportedObjectsTable_.get(objectId);
258			if (localObject == null) {
259				throw new XObjectOffline(objectId); // could not find the object locally
260			} else {
261				return localObject; // far ref now resolved to near ref
262			}
263			
264		} else if (objectId.isRemote()) { // the resolved object is not local
265			// the designated object does not live in this VM
266			return createRemoteFarRef(objectId, types, isConnected);
267		} else {
268			// the designated object lives in the same VM as this actor
269			ELActor localActor = owner_.getHost().getActor(objectId.getActorId());
270			return createLocalFarRef(localActor, objectId, types, isConnected);
271		}
272	}
273	
274}