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