diff --git a/src/as/com/threerings/presents/client/Client.as b/src/as/com/threerings/presents/client/Client.as index 4b5540022..c84713c3c 100644 --- a/src/as/com/threerings/presents/client/Client.as +++ b/src/as/com/threerings/presents/client/Client.as @@ -4,6 +4,8 @@ import flash.events.EventDispatcher; import flash.events.TimerEvent; import flash.util.Timer; +import com.threerings.util.TypedArray; + import com.threerings.presents.data.ClientObject; import com.threerings.presents.dobj.DObjectManager; @@ -296,5 +298,7 @@ public class Client extends EventDispatcher /** Ticks. */ protected var _tickInterval :Timer; + + protected var _stringArray :TypedArray = new TypedArray(String); } } diff --git a/src/as/com/threerings/presents/client/ConfirmListener.as b/src/as/com/threerings/presents/client/ConfirmListener.as new file mode 100644 index 000000000..f28e9ddec --- /dev/null +++ b/src/as/com/threerings/presents/client/ConfirmListener.as @@ -0,0 +1,7 @@ +package com.threerings.presents.client { + +public interface ConfirmListener extends InvocationListener +{ + function requestProcessed () :void; +} +} diff --git a/src/as/com/threerings/presents/client/InvocationDirector.as b/src/as/com/threerings/presents/client/InvocationDirector.as index 228b6cdd6..5f25a0b0a 100644 --- a/src/as/com/threerings/presents/client/InvocationDirector.as +++ b/src/as/com/threerings/presents/client/InvocationDirector.as @@ -1,10 +1,18 @@ package com.threerings.presents.client { +import mx.collections.IViewCursor; +import mx.collections.ListCollectionView; + +import com.threerings.util.SimpleMap; + +import com.threerings.presents.data.ListenerMarshaller; + import com.threerings.presents.dobj.DEvent; import com.threerings.presents.dobj.DObject; import com.threerings.presents.dobj.DObjectManager; import com.threerings.presents.dobj.DSet; import com.threerings.presents.dobj.EventListener; +import com.threerings.presents.dobj.InvocationRequestEvent; import com.threerings.presents.dobj.ObjectAccessError; import com.threerings.presents.dobj.Subscriber; @@ -31,9 +39,12 @@ public class InvocationDirector public function cleanup () :void { + // wipe our client object, receiver mappings and listener mappings _clobj = null; - // TODO: lots more + // also reset our counters + _requestId = 0; + _receiverId = 0; } /** @@ -42,7 +53,7 @@ public class InvocationDirector */ public function registerReceiver (decoder :InvocationDecoder) :void { - _reclist.push(decoder); + _reclist.addItem(decoder); // if we're already online, assign a recevier id now if (_clobj != null) { @@ -50,10 +61,36 @@ public class InvocationDirector } } - // documentation inherited from interface EventListener - public function eventReceived (event :DEvent) :void + /** + * Removes a receiver registration. + */ + public function unregisterReceiver (receiverCode :String) :void { - // TODO + // remove the receiver from the list + for (var iter :IViewCursor = _reclist.getCursor(); iter.moveNext(); ) { + var decoder :InvocationDecoder = + (iter.current as InvocationDecoder); + if (decoder.getReceiverCode() === receiverCode) { + iter.remove(); + } + } + + // if we're logged on, clear out any receiver id mapping + if (_clobj != null) { + var rreg :InvocationRegistration = + (_clobj.receivers.getByKey(receiverCode) + as InvocationRegistration); + if (rreg == null) { + Log.warning("Receiver unregistered for which we have no " + + "id to code mapping [code=" + receiverCode + "]."); + } else { + var decoder :Object = _receivers.remove(rreg.receiverId); +// Log.info("Cleared receiver " + +// StringUtil.shortClassName(decoder) + +// " " + rreg + "."); + } + _clobj.removeFromReceivers(receiverCode); + } } /** @@ -62,7 +99,10 @@ public class InvocationDirector */ internal function assignReceiverId (decoder :InvocationDecoder) :void { - // TODO + var reg :InvocationRegistration = new InvocationRegistration( + decoder.getReceiverCode(), nextReceiverId()); + _clobj.addToReceivers(reg); + _receivers[reg.receiverId] = decoder; } /** @@ -81,6 +121,63 @@ public class InvocationDirector } } + /** + * Requests that the specified invocation request be packaged up and + * sent to the supplied invocation oid. + */ + public function sendRequest ( + invOid :int, invCode :int, methodId :int, args :Array) :void + { + // configure any invocation listener marshallers among the args + for each (var arg :Object in args) { + if (arg is ListenerMarshaller) { + var lm :ListenerMarshaller = (arg as ListenerMarshaller); + lm.callerOid = _clobj.getOid(); + lm.requestId = nextRequestId(); + lm.mapStamp = new Date().getTime(); + + // create a mapping for this marshaller so that we can + // properly dispatch responses sent to it + _listeners[lm.requestId] = lm; + } + } + + // create an invocation request event + var event :InvocationRequestEvent = + new InvocationRequestEvent(invOid, invCode, methodId, args); + + // because invocation directors are used on the server, we set the + // source oid here so that invocation requests are properly + // attributed to the right client object when created by + // server-side entities only sort of pretending to be a client + event.setSourceOid(_clobj.getOid()); + + // now, dispatch the event + _omgr.postEvent(event); + } + + // documentation inherited from interface EventListener + public function eventReceived (event :DEvent) :void + { + // TODO + } + + /** + * Used to generate monotonically increasing invocation request ids. + */ + protected function nextRequestId () :int + { + return _requestId++; + } + + /** + * Used to generate monotonically increasing invocation receiver ids. + */ + protected function nextReceiverId () :int + { + return _receiverId++; + } + /** * Called by the ClientSubscriber helper class when the client object * has been returned by the server. @@ -106,15 +203,32 @@ public class InvocationDirector _client.getClientObjectFailed(cause); } + /** The distributed object manager with which we interact. */ internal var _omgr :DObjectManager; + /** The client for whom we're working. */ internal var _client :Client; + /** Our client object; invocation responses and notifications are + * received on this object. */ internal var _clobj :ClientObject; + /** Used to generate monotonically increasing request ids. */ + protected var _requestId :int; + + /** Used to generate monotonically increasing receiver ids. */ + protected var _receiverId :int; + + /** Used to keep track of invocation service listeners which will + * receive responses from invocation service requests. */ + protected var _listeners :SimpleMap = new SimpleMap(); + + /** Used to keep track of invocation notification receivers. */ + protected var _receivers :SimpleMap = new SimpleMap(); + /** All registered receivers are maintained in a list so that we can * assign receiver ids to them when we go online. */ - internal var _reclist :Array = new Array(); + internal var _reclist :ListCollectionView = new ListCollectionView(); } } diff --git a/src/as/com/threerings/presents/client/InvocationListener.as b/src/as/com/threerings/presents/client/InvocationListener.as new file mode 100644 index 000000000..9ef7e0f67 --- /dev/null +++ b/src/as/com/threerings/presents/client/InvocationListener.as @@ -0,0 +1,7 @@ +package com.threerings.presents.client { + +public interface InvocationListener +{ + function requestFailed (cause :String) :void; +} +} diff --git a/src/as/com/threerings/presents/client/ResultListener.as b/src/as/com/threerings/presents/client/ResultListener.as new file mode 100644 index 000000000..a0be0a892 --- /dev/null +++ b/src/as/com/threerings/presents/client/ResultListener.as @@ -0,0 +1,7 @@ +package com.threerings.presents.client { + +public interface ResultListener extends InvocationListener +{ + function requestProcessed (result :Object) :void; +} +} diff --git a/src/as/com/threerings/presents/data/ClientObject.as b/src/as/com/threerings/presents/data/ClientObject.as index fe33415dd..e8790c26b 100644 --- a/src/as/com/threerings/presents/data/ClientObject.as +++ b/src/as/com/threerings/presents/data/ClientObject.as @@ -67,6 +67,21 @@ public class ClientObject extends DObject } // AUTO-GENERATED: METHODS START + public function addToReceivers (elem :DSetEntry) :void + { + requestEntryAdd(RECEIVERS, elem); + } + + public function removeFromReceivers (key :Object) :void + { + requestEntryRemove(RECEIVERS, key); + } + + public function updateReceivers (elem :DSetEntry) :void + { + requestEntryUpdate(RECEIVERS, elem); + } + public function setReceivers (value :DSet) :void { requestAttributeChange(RECEIVERS, value, this.receivers); diff --git a/src/as/com/threerings/presents/data/InvocationMarshaller.as b/src/as/com/threerings/presents/data/InvocationMarshaller.as new file mode 100644 index 000000000..9347fbf84 --- /dev/null +++ b/src/as/com/threerings/presents/data/InvocationMarshaller.as @@ -0,0 +1,117 @@ +// +// $Id: InvocationMarshaller.java 3832 2006-02-04 03:49:53Z ray $ +// +// Narya library - tools for developing networked games +// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/narya/ +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.threerings.presents.data { + +import com.threerings.util.ClassUtil; + +import com.threerings.io.Streamable; + +import com.threerings.presents.Log; + +import com.threerings.presents.client.Client; +import com.threerings.presents.client.ConfirmListener; +import com.threerings.presents.client.ResultListener; +import com.threerings.presents.client.InvocationService; + +import com.threerings.presents.dobj.DObjectManager; +import com.threerings.presents.dobj.InvocationResponseEvent; + +/** + * Provides a base from which all invocation service marshallers extend. + * Handles functionality common to all marshallers. + */ +public class InvocationMarshaller + implements Streamable, InvocationService +{ + /** + * Initializes this invocation marshaller instance with the requisite + * information to allow it to operate in the wide world. This is + * called by the invocation manager when an invocation provider is + * registered and should not be called otherwise. + */ + public function init (invOid :int, invCode :int) :void + { + _invOid = invOid; + _invCode = invCode; + } + + /** + * Sets the invocation oid to which this marshaller should send its + * invocation service requests. This is called by the invocation + * manager in certain initialization circumstances. + */ + public function setInvocationOid (invOid :int) :void + { + _invOid = invOid; + } + + /** + * Returns the code assigned to this marshaller. + */ + public function getInvocationCode () :int + { + return _invCode; + } + + /** + * Called by generated invocation marshaller code; packages up and + * sends the specified invocation service request. + */ + protected function sendRequest ( + client :Client, methodId :int, args :Array) :void + { + client.getInvocationDirector().sendRequest( + _invOid, _invCode, methodId, args); + } + + /** + * Generates a string representation of this instance. + */ + public function toString () :String + { + return "[invOid=" + _invOid + ", code=" + _invCode + + ", type=" + ClassUtil.getClassName(this) + "]"; + } + + // documentation inherited from interface Streamable + public function writeObject (out :ObjectOutputStream) :void + { + out.writeInt(_invOid); + out.writeInt(_invCode); + } + + // documentation inherited from interface Streamable + public function readObject (ins :ObjectInputStream) :void + { + _invOid = ins.readInt(); + _invCode = ins.readInt(); + } + + /** The oid of the invocation object, where invocation service + * requests are sent. */ + protected var _invOid :int; + + /** The invocation service code assigned to this service when it was + * registered on the server. */ + protected var _invCode :int; +} +} diff --git a/src/as/com/threerings/presents/data/ListenerMarshaller.as b/src/as/com/threerings/presents/data/ListenerMarshaller.as new file mode 100644 index 000000000..5cf82a169 --- /dev/null +++ b/src/as/com/threerings/presents/data/ListenerMarshaller.as @@ -0,0 +1,87 @@ +package com.threerings.presents.data { + +import com.threerings.util.ClassUtil; + +import com.threerings.io.ObjectInputStream; +import com.threerings.io.ObjectOutputStream; +import com.threerings.io.Streamable; + +import com.threerings.presents.client.InvocationListener; + +import com.threerings.presents.dobj.DObjectManager; +import com.threerings.presents.dobj.InvocationResponseEvent; + +import com.threerings.presents.Log; + +public class ListenerMarshaller + implements Streamable, InvocationListener +{ + /** The method id used to dispatch a requestFailed response. */ + public const REQUEST_FAILED_RSPID :int = 0; + + /** The oid of the invocation service requester. */ + public var callerOid :int; + + /** The request id associated with this listener. */ + public var requestId :int; + + /** The actual invocation listener associated with this + * marshalling listener. This is only valid on the client. */ + public var listener :InvocationListener; + + /** The time at which this listener marshaller was registered. + * This is only valid on the client. */ + public var mapStamp :Number; + + /** The distributed object manager to use when dispatching proxied + * responses. This is only valid on the server. */ + public var omgr :DObjectManager; + + // documentation inherited from interface + public function requestFailed (cause :String) :void + { + omgr.postEvent(new InvocationResponseEvent( + callerOid, requestId, REQUEST_FAILED_RSPID, + [ cause ])); + } + /** + * Called to dispatch an invocation response to our target + * listener. + */ + public function dispatchResponse (methodId :int, args :Array) :void + { + if (methodId == REQUEST_FAILED_RSPID) { + listener.requestFailed((args[0] as String)); + + } else { + Log.warning("Requested to dispatch unknown invocation " + + "response [listener=" + listener + + ", methodId=" + methodId + + ", args=" + args + "]."); + } + } + + /** + * Generates a string representation of this instance. + */ + public function toString () :String + { + return "[callerOid=" + callerOid + ", reqId=" + requestId + + ", type=" + ClassUtil.getClassName(this) + "]"; + } + + // documentation inherited from interface Streamable + public function writeObject (out :ObjectOutputStream) :void + { + out.writeInt(callerOid); + out.writeShort(requestId); + } + + // documentation inherited from interface Streamable + public function readObject (ins :ObjectInputStream) :void + { + callerOid = ins.readInt(); + requestId = ins.readShort(); + } +} +} diff --git a/src/as/com/threerings/presents/dobj/AttributeChangedEvent.as b/src/as/com/threerings/presents/dobj/AttributeChangedEvent.as index e4f5005cb..acd800b9b 100644 --- a/src/as/com/threerings/presents/dobj/AttributeChangedEvent.as +++ b/src/as/com/threerings/presents/dobj/AttributeChangedEvent.as @@ -68,7 +68,7 @@ public class AttributeChangedEvent extends NamedEvent } // documentation inherited - internal override function notifyListener (listener :Object) :void + protected override function notifyListener (listener :Object) :void { if (listener is AttributeChangeListener) { listener.attributeChanged(this); diff --git a/src/as/com/threerings/presents/dobj/DEvent.as b/src/as/com/threerings/presents/dobj/DEvent.as index cdf11c161..9672ad752 100644 --- a/src/as/com/threerings/presents/dobj/DEvent.as +++ b/src/as/com/threerings/presents/dobj/DEvent.as @@ -40,6 +40,36 @@ public /* abstract */ class DEvent return false; } + /** + * Returns the object id of the client that generated this event. If + * the event was generated by the server, the value returned will be + * -1. This is not valid on the client, it will return -1 for all + * events there (it is primarily provided to allow for event-level + * access control). + */ + public function getSourceOid () :int + { + return _soid; + } + + /** + * Do not call this method. Sets the source oid of the client that + * generated this event. It is automatically called by the client + * management code when a client forwards an event to the server. + */ + public function setSourceOid (sourceOid :int) :void + { + _soid = sourceOid; + } + + /** + * We want to make the notifyListener method visible to DObject. + */ + internal function friendNotifyListener (listener :Object) :void + { + notifyListener(listener); + } + /** * Events with associated listener interfaces should implement this * function and notify the supplied listener if it implements their @@ -47,7 +77,7 @@ public /* abstract */ class DEvent * AttributeChangedEvent} will notify listeners that implement {@link * AttributeChangeListener}. */ - internal function notifyListener (listener :Object) :void + protected function notifyListener (listener :Object) :void { // the default is to do nothing } @@ -89,6 +119,9 @@ public /* abstract */ class DEvent /** The oid of the object that is the target of this event. */ protected var _toid :int; + /** The oid of the client that generated this event. */ + protected var _soid :int = -1; + protected static const UNSET_OLD_ENTRY :DSetEntry = new DummyEntry(); } } diff --git a/src/as/com/threerings/presents/dobj/DObject.as b/src/as/com/threerings/presents/dobj/DObject.as index 25b58ae36..bd3f96003 100644 --- a/src/as/com/threerings/presents/dobj/DObject.as +++ b/src/as/com/threerings/presents/dobj/DObject.as @@ -83,7 +83,7 @@ public class DObject // extends EventDispatcher for (var ii :int = 0; ii < _listeners.length; ii++) { var listener :Object = _listeners.getItemAt(ii); try { - event.notifyListener(listener); + event.friendNotifyListener(listener); if (listener is EventListener) { listener.eventReceived(event); diff --git a/src/as/com/threerings/presents/dobj/ElementUpdatedEvent.as b/src/as/com/threerings/presents/dobj/ElementUpdatedEvent.as index c640081df..fb769f961 100644 --- a/src/as/com/threerings/presents/dobj/ElementUpdatedEvent.as +++ b/src/as/com/threerings/presents/dobj/ElementUpdatedEvent.as @@ -95,7 +95,7 @@ public class ElementUpdatedEvent extends NamedEvent } // documentation inherited - internal override function notifyListener (listener :Object) :void + protected override function notifyListener (listener :Object) :void { if (listener is ElementUpdateListener) { listener.elementUpdated(this); diff --git a/src/as/com/threerings/presents/dobj/EntryAddedEvent.as b/src/as/com/threerings/presents/dobj/EntryAddedEvent.as index 10babd20c..d3ba227e4 100644 --- a/src/as/com/threerings/presents/dobj/EntryAddedEvent.as +++ b/src/as/com/threerings/presents/dobj/EntryAddedEvent.as @@ -55,7 +55,7 @@ public class EntryAddedEvent extends NamedEvent } // documentation inherited - internal override function notifyListener (listener :Object) :void + protected override function notifyListener (listener :Object) :void { if (listener is SetListener) { listener.entryAdded(this); diff --git a/src/as/com/threerings/presents/dobj/EntryRemovedEvent.as b/src/as/com/threerings/presents/dobj/EntryRemovedEvent.as index 711c23464..765f711c7 100644 --- a/src/as/com/threerings/presents/dobj/EntryRemovedEvent.as +++ b/src/as/com/threerings/presents/dobj/EntryRemovedEvent.as @@ -75,7 +75,7 @@ public class EntryRemovedEvent extends NamedEvent } // documentation inherited - internal override function notifyListener (listener :Object) :void + protected override function notifyListener (listener :Object) :void { if (listener is SetListener) { listener.entryRemoved(this); diff --git a/src/as/com/threerings/presents/dobj/EntryUpdatedEvent.as b/src/as/com/threerings/presents/dobj/EntryUpdatedEvent.as index e11d78cb6..496276f0d 100644 --- a/src/as/com/threerings/presents/dobj/EntryUpdatedEvent.as +++ b/src/as/com/threerings/presents/dobj/EntryUpdatedEvent.as @@ -73,7 +73,7 @@ public class EntryUpdatedEvent extends NamedEvent } // documentation inherited - internal override function notifyListener (listener :Object) :void + protected override function notifyListener (listener :Object) :void { if (listener is SetListener) { listener.entryUpdated(this); diff --git a/src/as/com/threerings/presents/dobj/InvocationRequestEvent.as b/src/as/com/threerings/presents/dobj/InvocationRequestEvent.as new file mode 100644 index 000000000..27949c49e --- /dev/null +++ b/src/as/com/threerings/presents/dobj/InvocationRequestEvent.as @@ -0,0 +1,134 @@ +// +// $Id: InvocationRequestEvent.java 3099 2004-08-27 02:21:06Z mdb $ +// +// Narya library - tools for developing networked games +// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/narya/ +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.threerings.presents.dobj { + +import flash.util.StringBuilder; + +import com.threerings.io.ObjectInputStream; +import com.threerings.io.ObjectOutputStream; + +/** + * Used to dispatch an invocation request from the client to the server. + * + * @see DObjectManager#postEvent + */ +public class InvocationRequestEvent extends DEvent +{ + /** + * Constructs a new invocation request event on the specified target + * object with the supplied code, method and arguments. + * + * @param targetOid the object id of the object on which the event is + * to be dispatched. + * @param invCode the invocation provider identification code. + * @param methodId the id of the method to be invoked. + * @param args the arguments for the method. This array should contain + * only values of valid distributed object types. + */ + public function InvocationRequestEvent ( + targetOid :int, invCode :int, methodId :int, args :Array) + { + super(targetOid); + _invCode = invCode; + _methodId = methodId; + _args = args; + } + + /** + * Returns the invocation code associated with this request. + */ + public function getInvCode () :int + { + return _invCode; + } + + /** + * Returns the id of the method associated with this request. + */ + public function getMethodId () :int + { + return _methodId; + } + + /** + * Returns the arguments associated with this request. + */ + public function getArgs () :Array + { + return _args; + } + + /** + * Applies this attribute change to the object. + */ + public override function applyToObject (target :DObject) :Boolean + //throws ObjectAccessException + { + // nothing to do here + return true; + } + + // documentation inherited + protected override function notifyListener (listener :Object) :void + { + // nothing to do here + } + + // documentation inherited + protected override function toStringBuf (buf :StringBuilder) :void + { + buf.append("IREQ:"); + super.toStringBuf(buf); + buf.append(", code=", _invCode); + buf.append(", methodId=", _methodId); + buf.append(", args=", _args); + } + + // documentation inherited from interface Streamable + public override function writeObject (out :ObjectOutputStream) :void + { + super.writeObject(out); + out.writeInt(_invCode); + out.writeByte(_methodId); + out.writeObject(_args); + } + + // documentation inherited from interface Streamable + public override function readObject (ins :ObjectInputStream) :void + { + super.readObject(ins); + _invCode = ins.readInt(); + _methodId = ins.readByte(); + _args = (ins.readObject() as Array); + } + + /** The code identifying which invocation provider to which this + * request is directed. */ + protected var _invCode :int; + + /** The id of the method being invoked. */ + protected var _methodId :int; + + /** The arguments to the method being invoked. */ + protected var _args :Array; +} +} diff --git a/src/as/com/threerings/presents/dobj/InvocationResponseEvent.as b/src/as/com/threerings/presents/dobj/InvocationResponseEvent.as new file mode 100644 index 000000000..274e9784c --- /dev/null +++ b/src/as/com/threerings/presents/dobj/InvocationResponseEvent.as @@ -0,0 +1,133 @@ +// +// $Id: InvocationResponseEvent.java 3099 2004-08-27 02:21:06Z mdb $ +// +// Narya library - tools for developing networked games +// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/narya/ +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.threerings.presents.dobj { + +import flash.util.StringBuilder; + +import com.threerings.io.ObjectInputStream; +import com.threerings.io.ObjectOutputStream; + +/** + * Used to dispatch an invocation response from the server to the client. + * + * @see DObjectManager#postEvent + */ +public class InvocationResponseEvent extends DEvent +{ + /** + * Constructs a new invocation response event on the specified target + * object with the supplied code, method and arguments. + * + * @param targetOid the object id of the object on which the event is + * to be dispatched. + * @param requestId the id of the request to which we are responding. + * @param methodId the method to be invoked. + * @param args the arguments for the method. This array should contain + * only values of valid distributed object types. + */ + public function InvocationResponseEvent ( + targetOid :int, requestId :int, methodId :int, args :Array) + { + super(targetOid); + _requestId = requestId; + _methodId = methodId; + _args = args; + } + + /** + * Returns the invocation request id associated with this response. + */ + public function getRequestId () :int + { + return _requestId; + } + + /** + * Returns the method associated with this response. + */ + public function getMethodId () :int + { + return _methodId; + } + + /** + * Returns the arguments associated with this response. + */ + public function getArgs () :Array + { + return _args; + } + + /** + * Applies this attribute change to the object. + */ + public override function applyToObject (target :DObject) :Boolean + //throws ObjectAccessException + { + // nothing to do here + return true; + } + + // documentation inherited + protected override function notifyListener (listener :Object) :void + { + // nothing to do here + } + + // documentation inherited + protected override function toStringBuf (buf :StringBuilder) :void + { + buf.append("IRSP:"); + super.toStringBuf(buf); + buf.append(", reqid=", _requestId); + buf.append(", methodId=", _methodId); + buf.append(", args=", _args); + } + + // documentation inherited + public override function writeObject (out :ObjectOutputStream) :void + { + super.writeObject(out); + out.writeShort(_requestId); + out.writeByte(_methodId); + out.writeObject(_args); + } + + // documentation inherited + public override function readObject (ins :ObjectInputStream) :void + { + super.readObject(ins); + _requestId = ins.readShort(); + _methodId = ins.readByte(); + _args = (ins.readObject() as Array); + } + + /** The id of the request with which this response is associated. */ + protected var _requestId :int; + + /** The id of the method being invoked. */ + protected var _methodId :int; + + /** The arguments to the method being invoked. */ + protected var _args :Array; +} +} diff --git a/src/as/com/threerings/presents/dobj/MessageEvent.as b/src/as/com/threerings/presents/dobj/MessageEvent.as index 8d2a634fa..b66071f0d 100644 --- a/src/as/com/threerings/presents/dobj/MessageEvent.as +++ b/src/as/com/threerings/presents/dobj/MessageEvent.as @@ -61,7 +61,7 @@ public class MessageEvent extends NamedEvent } // documentation inherited - internal override function notifyListener (listener :Object) :void + protected override function notifyListener (listener :Object) :void { if (listener is MessageListener) { listener.messageReceived(this); diff --git a/src/as/com/threerings/presents/dobj/ObjectAddedEvent.as b/src/as/com/threerings/presents/dobj/ObjectAddedEvent.as index cbb2be321..36f02728a 100644 --- a/src/as/com/threerings/presents/dobj/ObjectAddedEvent.as +++ b/src/as/com/threerings/presents/dobj/ObjectAddedEvent.as @@ -51,7 +51,7 @@ public class ObjectAddedEvent extends NamedEvent } // documentation inherited - internal override function notifyListener (listener :Object) :void + protected override function notifyListener (listener :Object) :void { if (listener is OidListListener) { listener.objectAdded(this); diff --git a/src/as/com/threerings/presents/dobj/ObjectDestroyedEvent.as b/src/as/com/threerings/presents/dobj/ObjectDestroyedEvent.as index 1157bc806..bbc3b8825 100644 --- a/src/as/com/threerings/presents/dobj/ObjectDestroyedEvent.as +++ b/src/as/com/threerings/presents/dobj/ObjectDestroyedEvent.as @@ -53,7 +53,7 @@ public class ObjectDestroyedEvent extends DEvent } // documentation inherited - internal override function notifyListener (listener :Object) :void + protected override function notifyListener (listener :Object) :void { if (listener is ObjectDeathListener) { listener.objectDestroyed(this); diff --git a/src/as/com/threerings/presents/dobj/ObjectRemovedEvent.as b/src/as/com/threerings/presents/dobj/ObjectRemovedEvent.as index 30ee7e386..3a20343b2 100644 --- a/src/as/com/threerings/presents/dobj/ObjectRemovedEvent.as +++ b/src/as/com/threerings/presents/dobj/ObjectRemovedEvent.as @@ -74,7 +74,7 @@ public class ObjectRemovedEvent extends NamedEvent } // documentation inherited - internal override function notifyListener (listener :Object) :void + protected override function notifyListener (listener :Object) :void { if (listener is OidListListener) { listener.objectRemoved(this); diff --git a/src/as/com/threerings/util/SimpleMap.as b/src/as/com/threerings/util/SimpleMap.as index 8ee795d5e..60fa7a55e 100644 --- a/src/as/com/threerings/util/SimpleMap.as +++ b/src/as/com/threerings/util/SimpleMap.as @@ -6,6 +6,13 @@ package com.threerings.util { */ public dynamic class SimpleMap extends Object { - // nada + public function remove (key :Object) :Object + { + // I'm not sure this really works + var skey :String = key.toString(); + var value :Object = this[skey]; + this[skey] = undefined; + return value; + } } }