I decided to go hog wild and clean up all the type use in Presents which

required some serious bending and folding of the generic type system, but for
the most part we managed to avoid any mutilating. The gendobj task now
generates properly typed "addToXXX" and "updateXXX" DSet methods based on the
parameterized type of the DSet. This might cause unrecompiled code to break,
but I don't think there are many cases in the base toolkit where people call
DSet adders or updaters. We'll see and I'll add backwards compatibility
versions for cases where we need them to support GG games (everything else we
can just recompile).


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4245 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2006-07-05 00:55:05 +00:00
parent 94b79826d4
commit 8afd0316ec
27 changed files with 269 additions and 212 deletions
@@ -32,6 +32,7 @@ import com.samskivert.util.DebugChords;
import com.samskivert.util.HashIntMap; import com.samskivert.util.HashIntMap;
import com.samskivert.util.Queue; import com.samskivert.util.Queue;
import com.samskivert.util.StringUtil; import com.samskivert.util.StringUtil;
import com.samskivert.util.IntMap;
import com.samskivert.util.Interval; import com.samskivert.util.Interval;
import com.threerings.presents.Log; import com.threerings.presents.Log;
@@ -82,14 +83,16 @@ public class ClientDObjectMgr
} }
// inherit documentation from the interface // inherit documentation from the interface
public void createObject (Class dclass, Subscriber target) public <T extends DObject> void createObject (
Class<T> dclass, Subscriber<T> target)
{ {
// not presently supported // not presently supported
throw new RuntimeException("createObject() not supported"); throw new RuntimeException("createObject() not supported");
} }
// inherit documentation from the interface // inherit documentation from the interface
public void subscribeToObject (int oid, Subscriber target) public <T extends DObject> void subscribeToObject (
int oid, Subscriber<T> target)
{ {
if (oid <= 0) { if (oid <= 0) {
target.requestFailed( target.requestFailed(
@@ -100,15 +103,17 @@ public class ClientDObjectMgr
} }
// inherit documentation from the interface // inherit documentation from the interface
public void unsubscribeFromObject (int oid, Subscriber target) public <T extends DObject> void unsubscribeFromObject (
int oid, Subscriber<T> target)
{ {
queueAction(oid, target, false); queueAction(oid, target, false);
} }
protected void queueAction (int oid, Subscriber target, boolean subscribe) protected <T extends DObject> void queueAction (
int oid, Subscriber<T> target, boolean subscribe)
{ {
// queue up an action // queue up an action
_actions.append(new ObjectAction(oid, target, subscribe)); _actions.append(new ObjectAction<T>(oid, target, subscribe));
// and queue up the omgr to get invoked on the invoker thread // and queue up the omgr to get invoked on the invoker thread
_client.getRunQueue().postRunnable(this); _client.getRunQueue().postRunnable(this);
} }
@@ -130,14 +135,13 @@ public class ClientDObjectMgr
// inherit documentation from the interface // inherit documentation from the interface
public void removedLastSubscriber (DObject obj, boolean deathWish) public void removedLastSubscriber (DObject obj, boolean deathWish)
{ {
// if this object has a registered flush delay, don't can it just // if this object has a registered flush delay, don't can it just yet,
// yet, just slip it onto the flush queue // just slip it onto the flush queue
Class oclass = obj.getClass(); Class<?> oclass = obj.getClass();
for (Iterator iter = _delays.keySet().iterator(); iter.hasNext(); ) { for (Class<?> dclass : _delays.keySet()) {
Class dclass = (Class)iter.next();
if (dclass.isAssignableFrom(oclass)) { if (dclass.isAssignableFrom(oclass)) {
long expire = System.currentTimeMillis() + long expire = System.currentTimeMillis() +
((Long)_delays.get(dclass)).longValue(); _delays.get(dclass).longValue();
_flushes.put(obj.getOid(), new FlushRecord(obj, expire)); _flushes.put(obj.getOid(), new FlushRecord(obj, expire));
// Log.info("Flushing " + obj.getOid() + " at " + // Log.info("Flushing " + obj.getOid() + " at " +
// new java.util.Date(expire)); // new java.util.Date(expire));
@@ -154,7 +158,7 @@ public class ClientDObjectMgr
* *
* @see Client#registerFlushDelay * @see Client#registerFlushDelay
*/ */
public void registerFlushDelay (Class objclass, long delay) public void registerFlushDelay (Class<?> objclass, long delay)
{ {
_delays.put(objclass, Long.valueOf(delay)); _delays.put(objclass, Long.valueOf(delay));
} }
@@ -191,8 +195,8 @@ public class ClientDObjectMgr
// Log.info("Dispatch event: " + evt); // Log.info("Dispatch event: " + evt);
dispatchEvent(evt); dispatchEvent(evt);
} else if (obj instanceof ObjectResponse) { } else if (obj instanceof ObjectResponse<?>) {
registerObjectAndNotify(((ObjectResponse)obj).getObject()); registerObjectAndNotify((ObjectResponse<?>)obj);
} else if (obj instanceof UnsubscribeResponse) { } else if (obj instanceof UnsubscribeResponse) {
int oid = ((UnsubscribeResponse)obj).getOid(); int oid = ((UnsubscribeResponse)obj).getOid();
@@ -208,10 +212,10 @@ public class ClientDObjectMgr
} else if (obj instanceof PongResponse) { } else if (obj instanceof PongResponse) {
_client.gotPong((PongResponse)obj); _client.gotPong((PongResponse)obj);
} else if (obj instanceof ObjectAction) { } else if (obj instanceof ObjectAction<?>) {
ObjectAction act = (ObjectAction)obj; ObjectAction<?> act = (ObjectAction<?>)obj;
if (act.subscribe) { if (act.subscribe) {
doSubscribe(act.oid, act.target); doSubscribe(act);
} else { } else {
doUnsubscribe(act.oid, act.target); doUnsubscribe(act.oid, act.target);
} }
@@ -228,17 +232,17 @@ public class ClientDObjectMgr
// if this is a compound event, we need to process its contained // if this is a compound event, we need to process its contained
// events in order // events in order
if (event instanceof CompoundEvent) { if (event instanceof CompoundEvent) {
List events = ((CompoundEvent)event).getEvents(); List<DEvent> events = ((CompoundEvent)event).getEvents();
int ecount = events.size(); int ecount = events.size();
for (int i = 0; i < ecount; i++) { for (int i = 0; i < ecount; i++) {
dispatchEvent((DEvent)events.get(i)); dispatchEvent(events.get(i));
} }
return; return;
} }
// look up the object on which we're dispatching this event // look up the object on which we're dispatching this event
int toid = event.getTargetOid(); int toid = event.getTargetOid();
DObject target = (DObject)_ocache.get(toid); DObject target = _ocache.get(toid);
if (target == null) { if (target == null) {
if (!_dead.containsKey(toid)) { if (!_dead.containsKey(toid)) {
Log.warning("Unable to dispatch event on non-proxied " + Log.warning("Unable to dispatch event on non-proxied " +
@@ -276,16 +280,18 @@ public class ClientDObjectMgr
* Registers this object in our proxy cache and notifies the * Registers this object in our proxy cache and notifies the
* subscribers that were waiting for subscription to this object. * subscribers that were waiting for subscription to this object.
*/ */
protected void registerObjectAndNotify (DObject obj) protected <T extends DObject> void registerObjectAndNotify (
ObjectResponse<T> orsp)
{ {
// let the object know that we'll be managing it // let the object know that we'll be managing it
T obj = orsp.getObject();
obj.setManager(this); obj.setManager(this);
// stick the object into the proxy object table // stick the object into the proxy object table
_ocache.put(obj.getOid(), obj); _ocache.put(obj.getOid(), obj);
// let the penders know that the object is available // let the penders know that the object is available
PendingRequest req = (PendingRequest)_penders.remove(obj.getOid()); PendingRequest<?> req = _penders.remove(obj.getOid());
if (req == null) { if (req == null) {
Log.warning("Got object, but no one cares?! " + Log.warning("Got object, but no one cares?! " +
"[oid=" + obj.getOid() + ", obj=" + obj + "]."); "[oid=" + obj.getOid() + ", obj=" + obj + "].");
@@ -293,7 +299,8 @@ public class ClientDObjectMgr
} }
for (int i = 0; i < req.targets.size(); i++) { for (int i = 0; i < req.targets.size(); i++) {
Subscriber target = (Subscriber)req.targets.get(i); @SuppressWarnings("unchecked") Subscriber<T> target =
(Subscriber<T>)req.targets.get(i);
// add them as a subscriber // add them as a subscriber
obj.addSubscriber(target); obj.addSubscriber(target);
// and let them know that the object is in // and let them know that the object is in
@@ -308,7 +315,7 @@ public class ClientDObjectMgr
protected void notifyFailure (int oid) protected void notifyFailure (int oid)
{ {
// let the penders know that the object is not available // let the penders know that the object is not available
PendingRequest req = (PendingRequest)_penders.remove(oid); PendingRequest<?> req = _penders.remove(oid);
if (req == null) { if (req == null) {
Log.warning("Failed to get object, but no one cares?! " + Log.warning("Failed to get object, but no one cares?! " +
"[oid=" + oid + "]."); "[oid=" + oid + "].");
@@ -316,9 +323,8 @@ public class ClientDObjectMgr
} }
for (int i = 0; i < req.targets.size(); i++) { for (int i = 0; i < req.targets.size(); i++) {
Subscriber target = (Subscriber)req.targets.get(i);
// and let them know that the object is in // and let them know that the object is in
target.requestFailed(oid, null); req.targets.get(i).requestFailed(oid, null);
} }
} }
@@ -326,12 +332,15 @@ public class ClientDObjectMgr
* This is guaranteed to be invoked via the invoker and can safely do * This is guaranteed to be invoked via the invoker and can safely do
* main thread type things like call back to the subscriber. * main thread type things like call back to the subscriber.
*/ */
protected void doSubscribe (int oid, Subscriber target) protected <T extends DObject> void doSubscribe (ObjectAction<T> action)
{ {
// Log.info("doSubscribe: " + oid + ": " + target); // Log.info("doSubscribe: " + oid + ": " + target);
int oid = action.oid;
Subscriber<T> target = action.target;
// first see if we've already got the object in our table // first see if we've already got the object in our table
DObject obj = (DObject)_ocache.get(oid); @SuppressWarnings("unchecked") T obj = (T)_ocache.get(oid);
if (obj != null) { if (obj != null) {
// clear the object out of the flush table if it's in there // clear the object out of the flush table if it's in there
if (_flushes.remove(oid) != null) { if (_flushes.remove(oid) != null) {
@@ -344,7 +353,8 @@ public class ClientDObjectMgr
} }
// see if we've already got an outstanding request for this object // see if we've already got an outstanding request for this object
PendingRequest req = (PendingRequest)_penders.get(oid); @SuppressWarnings("unchecked") PendingRequest<T> req =
(PendingRequest<T>)_penders.get(oid);
if (req != null) { if (req != null) {
// add this subscriber to the list of subscribers to be // add this subscriber to the list of subscribers to be
// notified when the request is satisfied // notified when the request is satisfied
@@ -353,7 +363,7 @@ public class ClientDObjectMgr
} }
// otherwise we need to create a new request // otherwise we need to create a new request
req = new PendingRequest(oid); req = new PendingRequest<T>(oid);
req.addTarget(target); req.addTarget(target);
_penders.put(oid, req); _penders.put(oid, req);
// Log.info("Registering pending request [oid=" + oid + "]."); // Log.info("Registering pending request [oid=" + oid + "].");
@@ -368,7 +378,7 @@ public class ClientDObjectMgr
*/ */
protected void doUnsubscribe (int oid, Subscriber target) protected void doUnsubscribe (int oid, Subscriber target)
{ {
DObject dobj = (DObject)_ocache.get(oid); DObject dobj = _ocache.get(oid);
if (dobj != null) { if (dobj != null) {
dobj.removeSubscriber(target); dobj.removeSubscriber(target);
@@ -404,9 +414,11 @@ public class ClientDObjectMgr
protected void flushObjects () protected void flushObjects ()
{ {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
for (Iterator iter = _flushes.keySet().iterator(); iter.hasNext(); ) { for (Iterator<IntMap.IntEntry<FlushRecord>> iter =
int oid = ((Integer)iter.next()).intValue(); _flushes.intEntrySet().iterator(); iter.hasNext(); ) {
FlushRecord rec = (FlushRecord)_flushes.get(oid); IntMap.IntEntry<FlushRecord> entry = iter.next();
int oid = entry.getIntKey();
FlushRecord rec = entry.getValue();
if (rec.expire <= now) { if (rec.expire <= now) {
iter.remove(); iter.remove();
flushObject(rec.object); flushObject(rec.object);
@@ -419,13 +431,13 @@ public class ClientDObjectMgr
* The object action is used to queue up a subscribe or unsubscribe * The object action is used to queue up a subscribe or unsubscribe
* request. * request.
*/ */
protected static final class ObjectAction protected static final class ObjectAction<T extends DObject>
{ {
public int oid; public int oid;
public Subscriber target; public Subscriber<T> target;
public boolean subscribe; public boolean subscribe;
public ObjectAction (int oid, Subscriber target, boolean subscribe) public ObjectAction (int oid, Subscriber<T> target, boolean subscribe)
{ {
this.oid = oid; this.oid = oid;
this.target = target; this.target = target;
@@ -438,17 +450,18 @@ public class ClientDObjectMgr
} }
} }
protected static final class PendingRequest protected static final class PendingRequest<T extends DObject>
{ {
public int oid; public int oid;
public ArrayList targets = new ArrayList(); public ArrayList<Subscriber<T>> targets =
new ArrayList<Subscriber<T>>();
public PendingRequest (int oid) public PendingRequest (int oid)
{ {
this.oid = oid; this.oid = oid;
} }
public void addTarget (Subscriber target) public void addTarget (Subscriber<T> target)
{ {
targets.add(target); targets.add(target);
} }
@@ -478,31 +491,30 @@ public class ClientDObjectMgr
protected Client _client; protected Client _client;
/** Our primary dispatch queue. */ /** Our primary dispatch queue. */
protected Queue _actions = new Queue(); protected Queue<Object> _actions = new Queue<Object>();
/** All of the distributed objects that are active on this client. */ /** All of the distributed objects that are active on this client. */
protected HashIntMap _ocache = new HashIntMap(); protected HashIntMap<DObject> _ocache = new HashIntMap<DObject>();
/** Objects that have been marked for death. */ /** Objects that have been marked for death. */
protected HashIntMap _dead = new HashIntMap(); protected HashIntMap<DObject> _dead = new HashIntMap<DObject>();
/** Pending object subscriptions. */ /** Pending object subscriptions. */
protected HashIntMap _penders = new HashIntMap(); protected HashIntMap<PendingRequest<?>> _penders =
new HashIntMap<PendingRequest<?>>();
/** A mapping from distributed object class to flush delay. */ /** A mapping from distributed object class to flush delay. */
protected HashMap _delays = new HashMap(); protected HashMap<Class<?>,Long> _delays = new HashMap<Class<?>,Long>();
/** A set of objects waiting to be flushed. */ /** A set of objects waiting to be flushed. */
protected HashIntMap _flushes = new HashIntMap(); protected HashIntMap<FlushRecord> _flushes = new HashIntMap<FlushRecord>();
/** A debug hook that allows the dumping of all objects in the object /** A debug hook that allows the dumping of all objects in the object
* table out to the log. */ * table out to the log. */
protected DebugChords.Hook DUMP_OTABLE_HOOK = new DebugChords.Hook() { protected DebugChords.Hook DUMP_OTABLE_HOOK = new DebugChords.Hook() {
public void invoke () { public void invoke () {
Log.info("Dumping " + _ocache.size() + " objects:"); Log.info("Dumping " + _ocache.size() + " objects:");
Iterator iter = _ocache.values().iterator(); for (DObject obj : _ocache.values()) {
while (iter.hasNext()) {
DObject obj = (DObject)iter.next();
Log.info(obj.getClass().getName() + " " + obj); Log.info(obj.getClass().getName() + " " + obj);
} }
} }
@@ -597,7 +597,7 @@ public class Communicator
protected void iterate () protected void iterate ()
{ {
// fetch the next message from the queue // fetch the next message from the queue
UpstreamMessage msg = (UpstreamMessage)_msgq.get(); UpstreamMessage msg = _msgq.get();
// if this is a termination message, we're being // if this is a termination message, we're being
// requested to exit, so we want to bail now rather // requested to exit, so we want to bail now rather
@@ -675,7 +675,7 @@ public class Communicator
protected Writer _writer; protected Writer _writer;
protected SocketChannel _channel; protected SocketChannel _channel;
protected Queue _msgq = new Queue(); protected Queue<UpstreamMessage> _msgq = new Queue<UpstreamMessage>();
protected long _lastWrite; protected long _lastWrite;
protected Exception _logonError; protected Exception _logonError;
@@ -81,7 +81,7 @@ public class InvocationDirector
clobj.addListener(InvocationDirector.this); clobj.addListener(InvocationDirector.this);
// clear out our previous registrations // clear out our previous registrations
clobj.setReceivers(new DSet()); clobj.setReceivers(new DSet<Registration>());
// keep a handle on this bad boy // keep a handle on this bad boy
_clobj = clobj; _clobj = clobj;
@@ -348,7 +348,7 @@ public class InvocationDirector
_omgr.subscribeToObject(newCloid, new Subscriber<ClientObject>() { _omgr.subscribeToObject(newCloid, new Subscriber<ClientObject>() {
public void objectAvailable (ClientObject clobj) { public void objectAvailable (ClientObject clobj) {
// grab a reference to our old receiver registrations // grab a reference to our old receiver registrations
DSet receivers = _clobj.receivers; DSet<Registration> receivers = _clobj.receivers;
// replace the client object // replace the client object
_clobj = clobj; _clobj = clobj;
@@ -359,10 +359,9 @@ public class InvocationDirector
// reregister our receivers // reregister our receivers
_clobj.startTransaction(); _clobj.startTransaction();
try { try {
_clobj.setReceivers(new DSet()); _clobj.setReceivers(new DSet<Registration>());
Iterator iter = receivers.iterator(); for (Registration reg : receivers) {
while (iter.hasNext()) { _clobj.addToReceivers(reg);
_clobj.addToReceivers((Registration)iter.next());
} }
} finally { } finally {
_clobj.commitTransaction(); _clobj.commitTransaction();
@@ -21,6 +21,8 @@
package com.threerings.presents.data; package com.threerings.presents.data;
import com.threerings.presents.client.InvocationReceiver;
import com.threerings.presents.dobj.DObject; import com.threerings.presents.dobj.DObject;
import com.threerings.presents.dobj.DSet; import com.threerings.presents.dobj.DSet;
@@ -43,7 +45,8 @@ public class ClientObject extends DObject
/** Used to publish all invocation service receivers registered on /** Used to publish all invocation service receivers registered on
* this client. */ * this client. */
public DSet receivers = new DSet(); public DSet<InvocationReceiver.Registration> receivers =
new DSet<InvocationReceiver.Registration>();
/** /**
* Returns a short string identifying this client. * Returns a short string identifying this client.
@@ -87,7 +90,7 @@ public class ClientObject extends DObject
* <code>receivers</code> set. The set will not change until the event is * <code>receivers</code> set. The set will not change until the event is
* actually propagated through the system. * actually propagated through the system.
*/ */
public void addToReceivers (DSet.Entry elem) public void addToReceivers (InvocationReceiver.Registration elem)
{ {
requestEntryAdd(RECEIVERS, receivers, elem); requestEntryAdd(RECEIVERS, receivers, elem);
} }
@@ -107,7 +110,7 @@ public class ClientObject extends DObject
* <code>receivers</code> set. The set will not change until the event is * <code>receivers</code> set. The set will not change until the event is
* actually propagated through the system. * actually propagated through the system.
*/ */
public void updateReceivers (DSet.Entry elem) public void updateReceivers (InvocationReceiver.Registration elem)
{ {
requestEntryUpdate(RECEIVERS, receivers, elem); requestEntryUpdate(RECEIVERS, receivers, elem);
} }
@@ -122,7 +125,7 @@ public class ClientObject extends DObject
* change. Proxied copies of this object (on clients) will apply the * change. Proxied copies of this object (on clients) will apply the
* value change when they received the attribute changed notification. * value change when they received the attribute changed notification.
*/ */
public void setReceivers (DSet value) public void setReceivers (DSet<com.threerings.presents.client.InvocationReceiver.Registration> value)
{ {
requestAttributeChange(RECEIVERS, value, this.receivers); requestAttributeChange(RECEIVERS, value, this.receivers);
this.receivers = (value == null) ? null : value.typedClone(); this.receivers = (value == null) ? null : value.typedClone();
@@ -56,7 +56,7 @@ public class CompoundEvent extends DEvent
_omgr = omgr; _omgr = omgr;
_target = target; _target = target;
_events = new StreamableArrayList(); _events = new StreamableArrayList<DEvent>();
} }
/** /**
@@ -73,7 +73,7 @@ public class CompoundEvent extends DEvent
* Returns the list of events contained within this compound event. * Returns the list of events contained within this compound event.
* Don't mess with it. * Don't mess with it.
*/ */
public List getEvents () public List<DEvent> getEvents ()
{ {
return _events; return _events;
} }
@@ -95,7 +95,7 @@ public class CompoundEvent extends DEvent
case 0: // nothing doing case 0: // nothing doing
break; break;
case 1: // no point in being compound case 1: // no point in being compound
_omgr.postEvent((DEvent)_events.get(0)); _omgr.postEvent(_events.get(0));
break; break;
default: // now we're talking default: // now we're talking
_omgr.postEvent(this); _omgr.postEvent(this);
@@ -124,7 +124,7 @@ public class CompoundEvent extends DEvent
int ecount = _events.size(); int ecount = _events.size();
for (int i = 0; i < ecount; i++) { for (int i = 0; i < ecount; i++) {
((DEvent)_events.get(i)).setSourceOid(sourceOid); _events.get(i).setSourceOid(sourceOid);
} }
} }
@@ -166,5 +166,5 @@ public class CompoundEvent extends DEvent
protected transient DObject _target; protected transient DObject _target;
/** A list of the events associated with this compound event. */ /** A list of the events associated with this compound event. */
protected StreamableArrayList _events; protected StreamableArrayList<DEvent> _events;
} }
@@ -127,7 +127,7 @@ public class DObject
{ {
public DObject () public DObject ()
{ {
_fields = (Field[])_ftable.get(getClass()); _fields = _ftable.get(getClass());
if (_fields == null) { if (_fields == null) {
_fields = getClass().getFields(); _fields = getClass().getFields();
Arrays.sort(_fields, FIELD_COMP); Arrays.sort(_fields, FIELD_COMP);
@@ -280,10 +280,12 @@ public class DObject
/** /**
* Get the DSet with the specified name. * Get the DSet with the specified name.
*/ */
public final DSet getSet (String setName) public final <T extends DSet.Entry> DSet<T> getSet (String setName)
{ {
try { try {
return (DSet) getField(setName).get(this); @SuppressWarnings("unchecked") DSet<T> casted =
(DSet<T>)getField(setName).get(this);
return casted;
} catch (Exception e) { } catch (Exception e) {
throw new IllegalArgumentException("No such set: " + setName); throw new IllegalArgumentException("No such set: " + setName);
} }
@@ -292,7 +294,7 @@ public class DObject
/** /**
* Request to have the specified item added to the specified DSet. * Request to have the specified item added to the specified DSet.
*/ */
public void addToSet (String setName, DSet.Entry entry) public <T extends DSet.Entry> void addToSet (String setName, T entry)
{ {
requestEntryAdd(setName, getSet(setName), entry); requestEntryAdd(setName, getSet(setName), entry);
} }
@@ -844,7 +846,8 @@ public class DObject
/** /**
* Calls by derived instances when a set adder method was called. * Calls by derived instances when a set adder method was called.
*/ */
protected void requestEntryAdd (String name, DSet set, DSet.Entry entry) protected <T extends DSet.Entry> void requestEntryAdd (
String name, DSet<T> set, T entry)
{ {
// if we're on the authoritative server, we update the set immediately // if we're on the authoritative server, we update the set immediately
boolean alreadyApplied = false; boolean alreadyApplied = false;
@@ -855,16 +858,17 @@ public class DObject
alreadyApplied = true; alreadyApplied = true;
} }
// dispatch an entry added event // dispatch an entry added event
postEvent(new EntryAddedEvent(_oid, name, entry, alreadyApplied)); postEvent(new EntryAddedEvent<T>(_oid, name, entry, alreadyApplied));
} }
/** /**
* Calls by derived instances when a set remover method was called. * Calls by derived instances when a set remover method was called.
*/ */
protected void requestEntryRemove (String name, DSet set, Comparable key) protected <T extends DSet.Entry> void requestEntryRemove (
String name, DSet<T> set, Comparable key)
{ {
// if we're on the authoritative server, we update the set immediately // if we're on the authoritative server, we update the set immediately
DSet.Entry oldEntry = null; T oldEntry = null;
if (_omgr != null && _omgr.isManager(this)) { if (_omgr != null && _omgr.isManager(this)) {
oldEntry = set.removeKey(key); oldEntry = set.removeKey(key);
if (oldEntry == null) { if (oldEntry == null) {
@@ -872,16 +876,17 @@ public class DObject
} }
} }
// dispatch an entry removed event // dispatch an entry removed event
postEvent(new EntryRemovedEvent(_oid, name, key, oldEntry)); postEvent(new EntryRemovedEvent<T>(_oid, name, key, oldEntry));
} }
/** /**
* Calls by derived instances when a set updater method was called. * Calls by derived instances when a set updater method was called.
*/ */
protected void requestEntryUpdate (String name, DSet set, DSet.Entry entry) protected <T extends DSet.Entry> void requestEntryUpdate (
String name, DSet<T> set, T entry)
{ {
// if we're on the authoritative server, we update the set immediately // if we're on the authoritative server, we update the set immediately
DSet.Entry oldEntry = null; T oldEntry = null;
if (_omgr != null && _omgr.isManager(this)) { if (_omgr != null && _omgr.isManager(this)) {
oldEntry = set.update(entry); oldEntry = set.update(entry);
if (oldEntry == null) { if (oldEntry == null) {
@@ -889,7 +894,7 @@ public class DObject
} }
} }
// dispatch an entry updated event // dispatch an entry updated event
postEvent(new EntryUpdatedEvent(_oid, name, entry, oldEntry)); postEvent(new EntryUpdatedEvent<T>(_oid, name, entry, oldEntry));
} }
/** /**
@@ -955,12 +960,14 @@ public class DObject
/** Maintains a mapping of sorted field arrays for each distributed /** Maintains a mapping of sorted field arrays for each distributed
* object class. */ * object class. */
protected static HashMap _ftable = new HashMap(); protected static HashMap<Class,Field[]> _ftable =
new HashMap<Class,Field[]>();
/** Used to sort and search {@link #_fields}. */ /** Used to sort and search {@link #_fields}. */
protected static final Comparator FIELD_COMP = new Comparator() { protected static final Comparator<Field> FIELD_COMP =
public int compare (Object o1, Object o2) { new Comparator<Field>() {
return ((Field)o1).getName().compareTo(((Field)o2).getName()); public int compare (Field f1, Field f2) {
return f1.getName().compareTo(f2.getName());
} }
}; };
} }
@@ -239,7 +239,8 @@ public class DSet<E extends DSet.Entry>
*/ */
public Object[] toArray (Object[] array) public Object[] toArray (Object[] array)
{ {
return toArray((E[])array); @SuppressWarnings("unchecked") E[] casted = (E[])array;
return toArray(casted);
} }
/** /**
@@ -32,7 +32,7 @@ import com.threerings.presents.Log;
* *
* @see DObjectManager#postEvent * @see DObjectManager#postEvent
*/ */
public class EntryAddedEvent extends NamedEvent public class EntryAddedEvent<T extends DSet.Entry> extends NamedEvent
{ {
/** /**
* Constructs a new entry added event on the specified target object * Constructs a new entry added event on the specified target object
@@ -44,7 +44,7 @@ public class EntryAddedEvent extends NamedEvent
* entry. * entry.
* @param entry the entry to add to the set attribute. * @param entry the entry to add to the set attribute.
*/ */
public EntryAddedEvent (int targetOid, String name, DSet.Entry entry) public EntryAddedEvent (int targetOid, String name, T entry)
{ {
this(targetOid, name, entry, false); this(targetOid, name, entry, false);
} }
@@ -53,7 +53,7 @@ public class EntryAddedEvent extends NamedEvent
* Used when the distributed object already added the entry before * Used when the distributed object already added the entry before
* generating the event. * generating the event.
*/ */
public EntryAddedEvent (int targetOid, String name, DSet.Entry entry, public EntryAddedEvent (int targetOid, String name, T entry,
boolean alreadyApplied) boolean alreadyApplied)
{ {
super(targetOid, name); super(targetOid, name);
@@ -72,7 +72,7 @@ public class EntryAddedEvent extends NamedEvent
/** /**
* Returns the entry that has been added. * Returns the entry that has been added.
*/ */
public DSet.Entry getEntry () public T getEntry ()
{ {
return _entry; return _entry;
} }
@@ -84,7 +84,7 @@ public class EntryAddedEvent extends NamedEvent
throws ObjectAccessException throws ObjectAccessException
{ {
if (!_alreadyApplied) { if (!_alreadyApplied) {
boolean added = ((DSet)target.getAttribute(_name)).add(_entry); boolean added = target.getSet(_name).add(_entry);
if (!added) { if (!added) {
Log.warning("Duplicate entry found [event=" + this + "]."); Log.warning("Duplicate entry found [event=" + this + "].");
} }
@@ -109,7 +109,7 @@ public class EntryAddedEvent extends NamedEvent
StringUtil.toString(buf, _entry); StringUtil.toString(buf, _entry);
} }
protected DSet.Entry _entry; protected T _entry;
/** Used when this event is generated on the authoritative server /** Used when this event is generated on the authoritative server
* where object changes are made immediately. This lets us know not to * where object changes are made immediately. This lets us know not to
@@ -31,7 +31,7 @@ import com.threerings.presents.Log;
* *
* @see DObjectManager#postEvent * @see DObjectManager#postEvent
*/ */
public class EntryRemovedEvent extends NamedEvent public class EntryRemovedEvent<T extends DSet.Entry> extends NamedEvent
{ {
/** /**
* Constructs a new entry removed event on the specified target object * Constructs a new entry removed event on the specified target object
@@ -45,7 +45,7 @@ public class EntryRemovedEvent extends NamedEvent
* @param oldEntry the previous value of the entry. * @param oldEntry the previous value of the entry.
*/ */
public EntryRemovedEvent (int targetOid, String name, Comparable key, public EntryRemovedEvent (int targetOid, String name, Comparable key,
DSet.Entry oldEntry) T oldEntry)
{ {
super(targetOid, name); super(targetOid, name);
_key = key; _key = key;
@@ -65,13 +65,13 @@ public class EntryRemovedEvent extends NamedEvent
*/ */
public Comparable getKey () public Comparable getKey ()
{ {
return (Comparable)_key; return _key;
} }
/** /**
* Returns the entry that was in the set prior to being updated. * Returns the entry that was in the set prior to being updated.
*/ */
public DSet.Entry getOldEntry () public T getOldEntry ()
{ {
return _oldEntry; return _oldEntry;
} }
@@ -83,7 +83,7 @@ public class EntryRemovedEvent extends NamedEvent
throws ObjectAccessException throws ObjectAccessException
{ {
if (_oldEntry == UNSET_OLD_ENTRY) { if (_oldEntry == UNSET_OLD_ENTRY) {
DSet set = (DSet)target.getAttribute(_name); DSet<T> set = target.getSet(_name);
// remove, fetch the previous value for interested callers // remove, fetch the previous value for interested callers
_oldEntry = set.removeKey(_key); _oldEntry = set.removeKey(_key);
if (_oldEntry == null) { if (_oldEntry == null) {
@@ -113,5 +113,6 @@ public class EntryRemovedEvent extends NamedEvent
} }
protected Comparable _key; protected Comparable _key;
protected transient DSet.Entry _oldEntry = UNSET_OLD_ENTRY; @SuppressWarnings("unchecked")
protected transient T _oldEntry = (T)UNSET_OLD_ENTRY;
} }
@@ -32,7 +32,7 @@ import com.threerings.presents.Log;
* *
* @see DObjectManager#postEvent * @see DObjectManager#postEvent
*/ */
public class EntryUpdatedEvent extends NamedEvent public class EntryUpdatedEvent<T extends DSet.Entry> extends NamedEvent
{ {
/** /**
* Constructs a new entry updated event on the specified target object * Constructs a new entry updated event on the specified target object
@@ -45,8 +45,7 @@ public class EntryUpdatedEvent extends NamedEvent
* @param entry the entry to update. * @param entry the entry to update.
* @param oldEntry the previous value of the entry. * @param oldEntry the previous value of the entry.
*/ */
public EntryUpdatedEvent (int targetOid, String name, DSet.Entry entry, public EntryUpdatedEvent (int targetOid, String name, T entry, T oldEntry)
DSet.Entry oldEntry)
{ {
super(targetOid, name); super(targetOid, name);
_entry = entry; _entry = entry;
@@ -64,7 +63,7 @@ public class EntryUpdatedEvent extends NamedEvent
/** /**
* Returns the entry that has been updated. * Returns the entry that has been updated.
*/ */
public DSet.Entry getEntry () public T getEntry ()
{ {
return _entry; return _entry;
} }
@@ -72,7 +71,7 @@ public class EntryUpdatedEvent extends NamedEvent
/** /**
* Returns the entry that was in the set prior to being updated. * Returns the entry that was in the set prior to being updated.
*/ */
public DSet.Entry getOldEntry () public T getOldEntry ()
{ {
return _oldEntry; return _oldEntry;
} }
@@ -85,7 +84,7 @@ public class EntryUpdatedEvent extends NamedEvent
{ {
// only apply the change if we haven't already // only apply the change if we haven't already
if (_oldEntry == UNSET_OLD_ENTRY) { if (_oldEntry == UNSET_OLD_ENTRY) {
DSet set = (DSet)target.getAttribute(_name); DSet<T> set = target.getSet(_name);
// fetch the previous value for interested callers // fetch the previous value for interested callers
_oldEntry = set.update(_entry); _oldEntry = set.update(_entry);
if (_oldEntry == null) { if (_oldEntry == null) {
@@ -115,6 +114,7 @@ public class EntryUpdatedEvent extends NamedEvent
StringUtil.toString(buf, _entry); StringUtil.toString(buf, _entry);
} }
protected DSet.Entry _entry; protected T _entry;
protected transient DSet.Entry _oldEntry = UNSET_OLD_ENTRY; @SuppressWarnings("unchecked")
protected transient T _oldEntry = (T)UNSET_OLD_ENTRY;
} }
@@ -23,7 +23,8 @@ package com.threerings.presents.net;
import com.threerings.presents.dobj.DObject; import com.threerings.presents.dobj.DObject;
public class ObjectResponse extends DownstreamMessage public class ObjectResponse<T extends DObject>
extends DownstreamMessage
{ {
/** /**
* Zero argument constructor used when unserializing an instance. * Zero argument constructor used when unserializing an instance.
@@ -36,12 +37,12 @@ public class ObjectResponse extends DownstreamMessage
/** /**
* Constructs an object response with the supplied distributed object. * Constructs an object response with the supplied distributed object.
*/ */
public ObjectResponse (DObject dobj) public ObjectResponse (T dobj)
{ {
_dobj = dobj; _dobj = dobj;
} }
public DObject getObject () public T getObject ()
{ {
return _dobj; return _dobj;
} }
@@ -52,5 +53,5 @@ public class ObjectResponse extends DownstreamMessage
} }
/** The object which is associated with this response. */ /** The object which is associated with this response. */
protected DObject _dobj; protected T _dobj;
} }
@@ -43,7 +43,7 @@ public class NodeObject extends DObject
* <code>clients</code> set. The set will not change until the event is * <code>clients</code> set. The set will not change until the event is
* actually propagated through the system. * actually propagated through the system.
*/ */
public void addToClients (DSet.Entry elem) public void addToClients (ClientInfo elem)
{ {
requestEntryAdd(CLIENTS, clients, elem); requestEntryAdd(CLIENTS, clients, elem);
} }
@@ -63,7 +63,7 @@ public class NodeObject extends DObject
* <code>clients</code> set. The set will not change until the event is * <code>clients</code> set. The set will not change until the event is
* actually propagated through the system. * actually propagated through the system.
*/ */
public void updateClients (DSet.Entry elem) public void updateClients (ClientInfo elem)
{ {
requestEntryUpdate(CLIENTS, clients, elem); requestEntryUpdate(CLIENTS, clients, elem);
} }
@@ -229,7 +229,9 @@ public class ClientManager
// request that the appropriate client object be created by the // request that the appropriate client object be created by the
// dobject manager which starts the whole business off // dobject manager which starts the whole business off
PresentsServer.omgr.createObject(clr.getClientObjectClass(), clr); @SuppressWarnings("unchecked") Class<ClientObject> cclass =
(Class<ClientObject>)clr.getClientObjectClass();
PresentsServer.omgr.createObject(cclass, clr);
} catch (Exception e) { } catch (Exception e) {
// let the listener know that we're hosed // let the listener know that we're hosed
@@ -64,7 +64,7 @@ public class ClientResolver extends Invoker.Unit
* Returns the {@link ClientObject} derived class that should be * Returns the {@link ClientObject} derived class that should be
* created to kick off the resolution process. * created to kick off the resolution process.
*/ */
public Class getClientObjectClass () public Class<? extends ClientObject> getClientObjectClass ()
{ {
return ClientObject.class; return ClientObject.class;
} }
@@ -65,11 +65,12 @@ import com.threerings.presents.dobj.Subscriber;
* the client. * the client.
*/ */
public class InvocationManager public class InvocationManager
implements Subscriber, EventListener implements Subscriber<DObject>, EventListener
{ {
/** The list of services that are to be provided to clients at boot /** The list of services that are to be provided to clients at boot
* time. Don't mess with this list! */ * time. Don't mess with this list! */
public StreamableArrayList bootlist = new StreamableArrayList(); public StreamableArrayList<InvocationMarshaller> bootlist =
new StreamableArrayList<InvocationMarshaller>();
/** /**
* Constructs an invocation manager which will use the supplied * Constructs an invocation manager which will use the supplied
@@ -174,8 +175,7 @@ public class InvocationManager
// let any early registered marshallers know about our invoid // let any early registered marshallers know about our invoid
while (_lateInitQueue.size() > 0) { while (_lateInitQueue.size() > 0) {
InvocationMarshaller marsh = (InvocationMarshaller) InvocationMarshaller marsh = _lateInitQueue.remove(0);
_lateInitQueue.remove(0);
marsh.setInvocationOid(_invoid); marsh.setInvocationOid(_invoid);
} }
@@ -222,8 +222,7 @@ public class InvocationManager
} }
// look up the dispatcher // look up the dispatcher
InvocationDispatcher disp = (InvocationDispatcher) InvocationDispatcher disp = _dispatchers.get(invCode);
_dispatchers.get(invCode);
if (disp == null) { if (disp == null) {
Log.info("Received invocation request but dispatcher " + Log.info("Received invocation request but dispatcher " +
"registration was already cleared [code=" + invCode + "registration was already cleared [code=" + invCode +
@@ -298,8 +297,8 @@ public class InvocationManager
} }
// debugging action... // debugging action...
protected static final LRUHashMap _recentRegServices = protected static final LRUHashMap<Integer,String> _recentRegServices =
new LRUHashMap(10000); new LRUHashMap<Integer,String>(10000);
/** The distributed object manager with which we're working. */ /** The distributed object manager with which we're working. */
protected RootDObjectManager _omgr; protected RootDObjectManager _omgr;
@@ -312,12 +311,14 @@ public class InvocationManager
protected int _invCode; protected int _invCode;
/** A table of invocation dispatchers each mapped by a unique code. */ /** A table of invocation dispatchers each mapped by a unique code. */
protected HashIntMap _dispatchers = new HashIntMap(); protected HashIntMap<InvocationDispatcher> _dispatchers =
new HashIntMap<InvocationDispatcher>();
/** Used to keep track of marshallers registered before we had our /** Used to keep track of marshallers registered before we had our
* invocation object so that we can fill their invocation id in * invocation object so that we can fill their invocation id in
* belatedly. */ * belatedly. */
protected ArrayList _lateInitQueue = new ArrayList(); protected ArrayList<InvocationMarshaller> _lateInitQueue =
new ArrayList<InvocationMarshaller>();
/** The text that is appended to the procedure name when automatically /** The text that is appended to the procedure name when automatically
* generating a failure response. */ * generating a failure response. */
@@ -764,7 +764,7 @@ public class PresentsClient
// documentation inherited from interface // documentation inherited from interface
public void objectAvailable (DObject object) public void objectAvailable (DObject object)
{ {
if (postMessage(new ObjectResponse(object))) { if (postMessage(new ObjectResponse<DObject>(object))) {
// make a note of this new subscription // make a note of this new subscription
mapSubscrip(object); mapSubscrip(object);
} else { } else {
@@ -196,7 +196,7 @@ public class PresentsDObjectMgr
*/ */
public DObject getObject (int oid) public DObject getObject (int oid)
{ {
return (DObject)_objects.get(oid); return _objects.get(oid);
} }
/** /**
@@ -324,7 +324,7 @@ public class PresentsDObjectMgr
int ecount = events.size(); int ecount = events.size();
// look up the target object // look up the target object
DObject target = (DObject)_objects.get(event.getTargetOid()); DObject target = _objects.get(event.getTargetOid());
if (target == null) { if (target == null) {
Log.debug("Compound event target no longer exists " + Log.debug("Compound event target no longer exists " +
"[event=" + event + "]."); "[event=" + event + "].");
@@ -357,7 +357,7 @@ public class PresentsDObjectMgr
protected void processEvent (DEvent event) protected void processEvent (DEvent event)
{ {
// look up the target object // look up the target object
DObject target = (DObject)_objects.get(event.getTargetOid()); DObject target = _objects.get(event.getTargetOid());
if (target == null) { if (target == null) {
Log.debug("Event target no longer exists " + Log.debug("Event target no longer exists " +
"[event=" + event + "]."); "[event=" + event + "].");
@@ -491,7 +491,7 @@ public class PresentsDObjectMgr
} }
Reference ref = refs[i]; Reference ref = refs[i];
DObject reffer = (DObject)_objects.get(ref.reffingOid); DObject reffer = _objects.get(ref.reffingOid);
// ensure that the referencing object is still around // ensure that the referencing object is still around
if (reffer != null) { if (reffer != null) {
@@ -857,7 +857,7 @@ public class PresentsDObjectMgr
throws ObjectAccessException throws ObjectAccessException
{ {
// look up the target object // look up the target object
T obj = (T)_objects.get(_oid); @SuppressWarnings("unchecked") T obj = (T)_objects.get(_oid);
// if we're unsubscribing, take care of that and get on out // if we're unsubscribing, take care of that and get on out
if (_action == UNSUBSCRIBE) { if (_action == UNSUBSCRIBE) {
@@ -985,7 +985,7 @@ public class PresentsDObjectMgr
protected boolean _running = true; protected boolean _running = true;
/** The event queue via which all events are processed. */ /** The event queue via which all events are processed. */
protected Queue _evqueue = new Queue(); protected Queue<Object> _evqueue = new Queue<Object>();
/** The managed distributed objects table. */ /** The managed distributed objects table. */
protected HashIntMap<DObject> _objects = new HashIntMap<DObject>(); protected HashIntMap<DObject> _objects = new HashIntMap<DObject>();
@@ -112,7 +112,8 @@ public class PresentsServer
SignalManager.registerSignalHandler(SignalManager.SIGHUP, this); SignalManager.registerSignalHandler(SignalManager.SIGHUP, this);
// create our list of shutdowners // create our list of shutdowners
_downers = new ObserverList(ObserverList.SAFE_IN_ORDER_NOTIFY); _downers = new ObserverList<Shutdowner>(
ObserverList.SAFE_IN_ORDER_NOTIFY);
// create our distributed object manager // create our distributed object manager
omgr = createDObjectManager(); omgr = createDObjectManager();
@@ -258,7 +259,7 @@ public class PresentsServer
report.append(max/1024).append("k max\n"); report.append(max/1024).append("k max\n");
for (int ii = 0; ii < _reporters.size(); ii++) { for (int ii = 0; ii < _reporters.size(); ii++) {
Reporter rptr = (Reporter)_reporters.get(ii); Reporter rptr = _reporters.get(ii);
try { try {
rptr.appendReport(report, now, sinceLast, reset); rptr.appendReport(report, now, sinceLast, reset);
} catch (Throwable t) { } catch (Throwable t) {
@@ -308,7 +309,7 @@ public class PresentsServer
*/ */
public void shutdown () public void shutdown ()
{ {
ObserverList downers = _downers; ObserverList<Shutdowner> downers = _downers;
if (downers == null) { if (downers == null) {
Log.warning("Refusing repeat shutdown request."); Log.warning("Refusing repeat shutdown request.");
return; return;
@@ -322,9 +323,9 @@ public class PresentsServer
} }
// shut down all shutdown participants // shut down all shutdown participants
downers.apply(new ObserverList.ObserverOp() { downers.apply(new ObserverList.ObserverOp<Shutdowner>() {
public boolean apply (Object observer) { public boolean apply (Shutdowner downer) {
((Shutdowner)observer).shutdown(); downer.shutdown();
return true; return true;
} }
}); });
@@ -399,10 +400,10 @@ public class PresentsServer
protected static long _lastReportStamp = _serverStartTime; protected static long _lastReportStamp = _serverStartTime;
/** Used to generate "state of server" reports. */ /** Used to generate "state of server" reports. */
protected static ArrayList _reporters = new ArrayList(); protected static ArrayList<Reporter> _reporters = new ArrayList<Reporter>();
/** A list of shutdown participants. */ /** A list of shutdown participants. */
protected static ObserverList _downers;; protected static ObserverList<Shutdowner> _downers;;
/** The frequency with which we generate "state of server" reports. */ /** The frequency with which we generate "state of server" reports. */
protected static final long REPORT_INTERVAL = 15 * 60 * 1000L; protected static final long REPORT_INTERVAL = 15 * 60 * 1000L;
@@ -69,10 +69,11 @@ public class TimeBaseProvider
* base object is created or if the creation fails. * base object is created or if the creation fails.
*/ */
public static void createTimeBase ( public static void createTimeBase (
final String timeBase, final ResultListener resl) final String timeBase, final ResultListener<TimeBaseObject> resl)
{ {
_omgr.createObject(TimeBaseObject.class, new Subscriber () { _omgr.createObject(TimeBaseObject.class,
public void objectAvailable (DObject object) { new Subscriber<TimeBaseObject> () {
public void objectAvailable (TimeBaseObject object) {
// stuff it into our table // stuff it into our table
_timeBases.put(timeBase, object); _timeBases.put(timeBase, object);
// and notify the listener // and notify the listener
@@ -95,7 +96,7 @@ public class TimeBaseProvider
*/ */
public static TimeBaseObject getTimeBase (String timeBase) public static TimeBaseObject getTimeBase (String timeBase)
{ {
return (TimeBaseObject)_timeBases.get(timeBase); return _timeBases.get(timeBase);
} }
/** /**
@@ -116,7 +117,8 @@ public class TimeBaseProvider
} }
/** Used to keep track of our time base objects. */ /** Used to keep track of our time base objects. */
protected static HashMap _timeBases = new HashMap(); protected static HashMap<String,TimeBaseObject> _timeBases =
new HashMap<String,TimeBaseObject>();
/** The invocation manager with which we interoperate. */ /** The invocation manager with which we interoperate. */
protected static InvocationManager _invmgr; protected static InvocationManager _invmgr;
@@ -194,7 +194,7 @@ public class ConnectionManager extends LoopingThread
* Called by the authenticator to indicate that a connection was * Called by the authenticator to indicate that a connection was
* successfully authenticated. * successfully authenticated.
*/ */
public void connectionDidAuthenticate (Connection conn) public void connectionDidAuthenticate (AuthingConnection conn)
{ {
// slap this sucker onto the authenticated connections queue // slap this sucker onto the authenticated connections queue
_authq.append(conn); _authq.append(conn);
@@ -360,7 +360,7 @@ public class ConnectionManager extends LoopingThread
// close any connections that have been queued up to die // close any connections that have been queued up to die
Connection dconn; Connection dconn;
while ((dconn = (Connection)_deathq.getNonBlocking()) != null) { while ((dconn = _deathq.getNonBlocking()) != null) {
// it's possible that we caught an EOF trying to read from // it's possible that we caught an EOF trying to read from
// this connection even after it was queued up for death, so // this connection even after it was queued up for death, so
// let's avoid trying to close it twice // let's avoid trying to close it twice
@@ -396,10 +396,8 @@ public class ConnectionManager extends LoopingThread
} }
// send any messages that are waiting on the outgoing queue // send any messages that are waiting on the outgoing queue
Object obj; Tuple<Connection,byte[]> tup;
while ((obj = _outq.getNonBlocking()) != null) { while ((tup = _outq.getNonBlocking()) != null) {
@SuppressWarnings("unchecked") Tuple<Connection,byte[]> tup =
(Tuple<Connection,byte[]>)obj;
Connection conn = tup.left; Connection conn = tup.left;
// if an overflow queue exists for this client, go ahead and // if an overflow queue exists for this client, go ahead and
@@ -423,7 +421,7 @@ public class ConnectionManager extends LoopingThread
// check for connections that have completed authentication // check for connections that have completed authentication
AuthingConnection conn; AuthingConnection conn;
while ((conn = (AuthingConnection)_authq.getNonBlocking()) != null) { while ((conn = _authq.getNonBlocking()) != null) {
try { try {
// construct a new running connection to handle this // construct a new running connection to handle this
// connections network traffic from here on out // connections network traffic from here on out
@@ -893,10 +891,11 @@ public class ConnectionManager extends LoopingThread
protected HashMap<SelectionKey,NetEventHandler> _handlers = protected HashMap<SelectionKey,NetEventHandler> _handlers =
new HashMap<SelectionKey,NetEventHandler>(); new HashMap<SelectionKey,NetEventHandler>();
protected Queue _deathq = new Queue(); protected Queue<Connection> _deathq = new Queue<Connection>();
protected Queue _authq = new Queue(); protected Queue<AuthingConnection> _authq = new Queue<AuthingConnection>();
protected Queue _outq = new Queue(); protected Queue<Tuple<Connection,byte[]>> _outq =
new Queue<Tuple<Connection,byte[]>>();
protected FramingOutputStream _framer; protected FramingOutputStream _framer;
protected ByteBuffer _outbuf = ByteBuffer.allocateDirect(64 * 1024); protected ByteBuffer _outbuf = ByteBuffer.allocateDirect(64 * 1024);
@@ -31,6 +31,8 @@ import java.io.StringWriter;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -109,9 +111,7 @@ public class GenDObjectTask extends Task
throw new BuildException("Can't resolve InvocationListener", e); throw new BuildException("Can't resolve InvocationListener", e);
} }
ArrayList files = new ArrayList(); for (FileSet fs : _filesets) {
for (Iterator iter = _filesets.iterator(); iter.hasNext(); ) {
FileSet fs = (FileSet)iter.next();
DirectoryScanner ds = fs.getDirectoryScanner(getProject()); DirectoryScanner ds = fs.getDirectoryScanner(getProject());
File fromDir = fs.getDir(getProject()); File fromDir = fs.getDir(getProject());
String[] srcFiles = ds.getIncludedFiles(); String[] srcFiles = ds.getIncludedFiles();
@@ -158,7 +158,7 @@ public class GenDObjectTask extends Task
} }
// determine which fields we need to deal with // determine which fields we need to deal with
ArrayList flist = new ArrayList(); ArrayList<Field> flist = new ArrayList<Field>();
Field[] fields = oclass.getDeclaredFields(); Field[] fields = oclass.getDeclaredFields();
for (int ii = 0; ii < fields.length; ii++) { for (int ii = 0; ii < fields.length; ii++) {
Field f = fields[ii]; Field f = fields[ii];
@@ -175,12 +175,12 @@ public class GenDObjectTask extends Task
String[] lines = null; String[] lines = null;
try { try {
BufferedReader bin = new BufferedReader(new FileReader(source)); BufferedReader bin = new BufferedReader(new FileReader(source));
ArrayList llist = new ArrayList(); ArrayList<String> llist = new ArrayList<String>();
String line = null; String line = null;
while ((line = bin.readLine()) != null) { while ((line = bin.readLine()) != null) {
llist.add(line); llist.add(line);
} }
lines = (String[])llist.toArray(new String[llist.size()]); lines = llist.toArray(new String[llist.size()]);
bin.close(); bin.close();
} catch (IOException ioe) { } catch (IOException ioe) {
System.err.println("Error reading '" + source + "': " + ioe); System.err.println("Error reading '" + source + "': " + ioe);
@@ -249,8 +249,8 @@ public class GenDObjectTask extends Task
StringBuilder fsection = new StringBuilder(); StringBuilder fsection = new StringBuilder();
StringBuilder msection = new StringBuilder(); StringBuilder msection = new StringBuilder();
for (int ii = 0; ii < flist.size(); ii++) { for (int ii = 0; ii < flist.size(); ii++) {
Field f = (Field)flist.get(ii); Field f = flist.get(ii);
Class ftype = f.getType(); Class<?> ftype = f.getType();
String fname = f.getName(); String fname = f.getName();
// create our velocity context // create our velocity context
@@ -262,13 +262,34 @@ public class GenDObjectTask extends Task
ctx.put("clonefield", GenUtil.cloneArgument(_dsclass, f, "value")); ctx.put("clonefield", GenUtil.cloneArgument(_dsclass, f, "value"));
ctx.put("capfield", StringUtil.unStudlyName(fname).toUpperCase()); ctx.put("capfield", StringUtil.unStudlyName(fname).toUpperCase());
ctx.put("upfield", StringUtils.capitalize(fname)); ctx.put("upfield", StringUtils.capitalize(fname));
// if this field is an array, we need its component types
if (ftype.isArray()) { if (ftype.isArray()) {
Class etype = ftype.getComponentType(); Class<?> etype = ftype.getComponentType();
ctx.put("elemtype", GenUtil.simpleName(etype)); ctx.put("elemtype", GenUtil.simpleName(etype));
ctx.put("wrapelem", GenUtil.boxArgument(etype, "value")); ctx.put("wrapelem", GenUtil.boxArgument(etype, "value"));
ctx.put("wrapoelem", GenUtil.boxArgument(etype, "ovalue")); ctx.put("wrapoelem", GenUtil.boxArgument(etype, "ovalue"));
} }
// if this field is a generic DSet, we need its bound type
if (_dsclass.isAssignableFrom(ftype)) {
Type t = f.getGenericType();
// we need to walk up the heirarchy until we get to the
// parameterized DSet
while (t instanceof Class<?>) {
t = ((Class<?>)t).getGenericSuperclass();
}
if (t instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType)t;
if (pt.getActualTypeArguments().length > 0) {
ctx.put("etype", GenUtil.simpleName(
(Class<?>)pt.getActualTypeArguments()[0]));
}
} else {
ctx.put("etype", "DSet.Entry");
}
}
// now figure out which template to use // now figure out which template to use
String tname = "field.tmpl"; String tname = "field.tmpl";
if (_dsclass.isAssignableFrom(ftype)) { if (_dsclass.isAssignableFrom(ftype)) {
@@ -370,7 +391,7 @@ public class GenDObjectTask extends Task
} }
/** A list of filesets that contain tile images. */ /** A list of filesets that contain tile images. */
protected ArrayList _filesets = new ArrayList(); protected ArrayList<FileSet> _filesets = new ArrayList<FileSet>();
/** Used to do our own classpath business. */ /** Used to do our own classpath business. */
protected ClassLoader _cloader; protected ClassLoader _cloader;
@@ -380,15 +401,15 @@ public class GenDObjectTask extends Task
/** {@link DObject} resolved with the proper classloader so that we /** {@link DObject} resolved with the proper classloader so that we
* can compare it to loaded derived classes. */ * can compare it to loaded derived classes. */
protected Class _doclass; protected Class<?> _doclass;
/** {@link DSet} resolved with the proper classloader so that we can /** {@link DSet} resolved with the proper classloader so that we can
* compare it to loaded derived classes. */ * compare it to loaded derived classes. */
protected Class _dsclass; protected Class<?> _dsclass;
/** {@link OidList} resolved with the proper classloader so that we /** {@link OidList} resolved with the proper classloader so that we
* can compare it to loaded derived classes. */ * can compare it to loaded derived classes. */
protected Class _olclass; protected Class<?> _olclass;
/** Specifies the start of the path to our various templates. */ /** Specifies the start of the path to our various templates. */
protected static final String BASE_TMPL = protected static final String BASE_TMPL =
@@ -68,8 +68,9 @@ public class GenReceiverTask extends InvocationTask
return; return;
} }
HashMap imports = new HashMap(); HashMap<String,Boolean> imports = new HashMap<String,Boolean>();
ComparableArrayList methods = new ComparableArrayList(); ComparableArrayList<ServiceMethod> methods =
new ComparableArrayList<ServiceMethod>();
// we need to import the receiver itself // we need to import the receiver itself
imports.put(importify(receiver.getName()), Boolean.TRUE); imports.put(importify(receiver.getName()), Boolean.TRUE);
@@ -94,14 +95,14 @@ public class GenReceiverTask extends InvocationTask
} }
protected void generateSender (File source, String rname, String rpackage, protected void generateSender (File source, String rname, String rpackage,
List methods, Iterator imports) List methods, Iterator<String> imports)
{ {
String name = StringUtil.replace(rname, "Receiver", ""); String name = StringUtil.replace(rname, "Receiver", "");
String sname = StringUtil.replace(rname, "Receiver", "Sender"); String sname = StringUtil.replace(rname, "Receiver", "Sender");
String spackage = StringUtil.replace(rpackage, ".client", ".server"); String spackage = StringUtil.replace(rpackage, ".client", ".server");
// construct our imports list // construct our imports list
ComparableArrayList implist = new ComparableArrayList(); ComparableArrayList<String> implist = new ComparableArrayList<String>();
CollectionUtil.addAll(implist, imports); CollectionUtil.addAll(implist, imports);
checkedAdd(implist, ClientObject.class.getName()); checkedAdd(implist, ClientObject.class.getName());
checkedAdd(implist, InvocationSender.class.getName()); checkedAdd(implist, InvocationSender.class.getName());
@@ -134,13 +135,13 @@ public class GenReceiverTask extends InvocationTask
protected void generateDecoder ( protected void generateDecoder (
File source, String rname, String rpackage, List methods, File source, String rname, String rpackage, List methods,
Iterator imports) Iterator<String> imports)
{ {
String name = StringUtil.replace(rname, "Receiver", ""); String name = StringUtil.replace(rname, "Receiver", "");
String dname = StringUtil.replace(rname, "Receiver", "Decoder"); String dname = StringUtil.replace(rname, "Receiver", "Decoder");
// construct our imports list // construct our imports list
ComparableArrayList implist = new ComparableArrayList(); ComparableArrayList<String> implist = new ComparableArrayList<String>();
CollectionUtil.addAll(implist, imports); CollectionUtil.addAll(implist, imports);
checkedAdd(implist, InvocationDecoder.class.getName()); checkedAdd(implist, InvocationDecoder.class.getName());
implist.sort(); implist.sort();
@@ -37,13 +37,15 @@ import com.threerings.presents.server.InvocationProvider;
public class GenServiceTask extends InvocationTask public class GenServiceTask extends InvocationTask
{ {
/** Used to keep track of custom InvocationListener derivations. */ /** Used to keep track of custom InvocationListener derivations. */
public class ServiceListener implements Comparable public class ServiceListener implements Comparable<ServiceListener>
{ {
public Class listener; public Class listener;
public ComparableArrayList methods = new ComparableArrayList(); public ComparableArrayList<ServiceMethod> methods =
new ComparableArrayList<ServiceMethod>();
public ServiceListener (Class service, Class listener, HashMap imports) public ServiceListener (Class service, Class listener,
HashMap<String,Boolean> imports)
{ {
this.listener = listener; this.listener = listener;
Method[] methdecls = listener.getDeclaredMethods(); Method[] methdecls = listener.getDeclaredMethods();
@@ -59,9 +61,9 @@ public class GenServiceTask extends InvocationTask
methods.sort(); methods.sort();
} }
public int compareTo (Object other) public int compareTo (ServiceListener other)
{ {
return getName().compareTo(((ServiceListener)other).getName()); return getName().compareTo(other.getName());
} }
public boolean equals (Object other) public boolean equals (Object other)
@@ -115,9 +117,11 @@ public class GenServiceTask extends InvocationTask
return; return;
} }
HashMap imports = new HashMap(); HashMap<String,Boolean> imports = new HashMap<String,Boolean>();
ComparableArrayList methods = new ComparableArrayList(); ComparableArrayList<ServiceMethod> methods =
ComparableArrayList listeners = new ComparableArrayList(); new ComparableArrayList<ServiceMethod>();
ComparableArrayList<ServiceListener> listeners =
new ComparableArrayList<ServiceListener>();
// we need to import the service itself // we need to import the service itself
imports.put(importify(service.getName()), Boolean.TRUE); imports.put(importify(service.getName()), Boolean.TRUE);
@@ -158,14 +162,14 @@ public class GenServiceTask extends InvocationTask
protected void generateMarshaller ( protected void generateMarshaller (
File source, String sname, String spackage, List methods, File source, String sname, String spackage, List methods,
List listeners, Iterator imports) List listeners, Iterator<String> imports)
{ {
String name = StringUtil.replace(sname, "Service", ""); String name = StringUtil.replace(sname, "Service", "");
String mname = StringUtil.replace(sname, "Service", "Marshaller"); String mname = StringUtil.replace(sname, "Service", "Marshaller");
String mpackage = StringUtil.replace(spackage, ".client", ".data"); String mpackage = StringUtil.replace(spackage, ".client", ".data");
// construct our imports list // construct our imports list
ComparableArrayList implist = new ComparableArrayList(); ComparableArrayList<String> implist = new ComparableArrayList<String>();
CollectionUtil.addAll(implist, imports); CollectionUtil.addAll(implist, imports);
checkedAdd(implist, Client.class.getName()); checkedAdd(implist, Client.class.getName());
checkedAdd(implist, InvocationMarshaller.class.getName()); checkedAdd(implist, InvocationMarshaller.class.getName());
@@ -198,14 +202,14 @@ public class GenServiceTask extends InvocationTask
protected void generateDispatcher ( protected void generateDispatcher (
File source, String sname, String spackage, List methods, File source, String sname, String spackage, List methods,
Iterator imports) Iterator<String> imports)
{ {
String name = StringUtil.replace(sname, "Service", ""); String name = StringUtil.replace(sname, "Service", "");
String dname = StringUtil.replace(sname, "Service", "Dispatcher"); String dname = StringUtil.replace(sname, "Service", "Dispatcher");
String dpackage = StringUtil.replace(spackage, ".client", ".server"); String dpackage = StringUtil.replace(spackage, ".client", ".server");
// construct our imports list // construct our imports list
ComparableArrayList implist = new ComparableArrayList(); ComparableArrayList<String> implist = new ComparableArrayList<String>();
CollectionUtil.addAll(implist, imports); CollectionUtil.addAll(implist, imports);
checkedAdd(implist, ClientObject.class.getName()); checkedAdd(implist, ClientObject.class.getName());
checkedAdd(implist, InvocationMarshaller.class.getName()); checkedAdd(implist, InvocationMarshaller.class.getName());
@@ -241,14 +245,14 @@ public class GenServiceTask extends InvocationTask
protected void generateProvider ( protected void generateProvider (
File source, String sname, String spackage, List methods, File source, String sname, String spackage, List methods,
List listeners, Iterator imports) List listeners, Iterator<String> imports)
{ {
String name = StringUtil.replace(sname, "Service", ""); String name = StringUtil.replace(sname, "Service", "");
String mname = StringUtil.replace(sname, "Service", "Provider"); String mname = StringUtil.replace(sname, "Service", "Provider");
String mpackage = StringUtil.replace(spackage, ".client", ".server"); String mpackage = StringUtil.replace(spackage, ".client", ".server");
// construct our imports list // construct our imports list
ComparableArrayList implist = new ComparableArrayList(); ComparableArrayList<String> implist = new ComparableArrayList<String>();
CollectionUtil.addAll(implist, imports); CollectionUtil.addAll(implist, imports);
checkedAdd(implist, ClientObject.class.getName()); checkedAdd(implist, ClientObject.class.getName());
checkedAdd(implist, InvocationProvider.class.getName()); checkedAdd(implist, InvocationProvider.class.getName());
@@ -280,7 +284,7 @@ public class GenServiceTask extends InvocationTask
} }
/** Services for which we should not generate provider interfaces. */ /** Services for which we should not generate provider interfaces. */
protected HashSet _providerless = new HashSet(); protected HashSet<String> _providerless = new HashSet<String>();
/** Specifies the path to the marshaller template. */ /** Specifies the path to the marshaller template. */
protected static final String MARSHALLER_TMPL = protected static final String MARSHALLER_TMPL =
@@ -46,7 +46,7 @@ public abstract class InvocationTask extends Task
public Class listener; public Class listener;
public ListenerArgument (int index, Class listener) public ListenerArgument (int index, Class<?> listener)
{ {
this.index = index+1; this.index = index+1;
this.listener = listener; this.listener = listener;
@@ -65,21 +65,23 @@ public abstract class InvocationTask extends Task
} }
/** Used to keep track of invocation service methods. */ /** Used to keep track of invocation service methods. */
public class ServiceMethod implements Comparable public class ServiceMethod implements Comparable<ServiceMethod>
{ {
public Method method; public Method method;
public ArrayList listenerArgs = new ArrayList(); public ArrayList<ListenerArgument> listenerArgs =
new ArrayList<ListenerArgument>();
public ServiceMethod (Class service, Method method, HashMap imports) public ServiceMethod (Class<?> service, Method method,
HashMap<String,Boolean> imports)
{ {
this.method = method; this.method = method;
// we need to look through our arguments and note any needed // we need to look through our arguments and note any needed
// imports in the supplied table // imports in the supplied table
Class[] args = method.getParameterTypes(); Class<?>[] args = method.getParameterTypes();
for (int ii = 0; ii < args.length; ii++) { for (int ii = 0; ii < args.length; ii++) {
Class arg = args[ii]; Class<?> arg = args[ii];
while (arg.isArray()) { while (arg.isArray()) {
arg = arg.getComponentType(); arg = arg.getComponentType();
} }
@@ -132,7 +134,7 @@ public abstract class InvocationTask extends Task
public String getArgList (boolean skipFirst) public String getArgList (boolean skipFirst)
{ {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
Class[] args = method.getParameterTypes(); Class<?>[] args = method.getParameterTypes();
for (int ii = skipFirst ? 1 : 0; ii < args.length; ii++) { for (int ii = skipFirst ? 1 : 0; ii < args.length; ii++) {
if (buf.length() > 0) { if (buf.length() > 0) {
buf.append(", "); buf.append(", ");
@@ -146,7 +148,7 @@ public abstract class InvocationTask extends Task
public String getWrappedArgList (boolean skipFirst) public String getWrappedArgList (boolean skipFirst)
{ {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
Class[] args = method.getParameterTypes(); Class<?>[] args = method.getParameterTypes();
for (int ii = (skipFirst ? 1 : 0); ii < args.length; ii++) { for (int ii = (skipFirst ? 1 : 0); ii < args.length; ii++) {
if (buf.length() > 0) { if (buf.length() > 0) {
buf.append(", "); buf.append(", ");
@@ -161,15 +163,15 @@ public abstract class InvocationTask extends Task
return (method.getParameterTypes().length > (skipFirst ? 1 : 0)); return (method.getParameterTypes().length > (skipFirst ? 1 : 0));
} }
public int compareTo (Object other) public int compareTo (ServiceMethod other)
{ {
return getCode().compareTo(((ServiceMethod)other).getCode()); return getCode().compareTo(other.getCode());
} }
public String getUnwrappedArgList (boolean listenerMode) public String getUnwrappedArgList (boolean listenerMode)
{ {
StringBuilder buf = new StringBuilder(); StringBuilder buf = new StringBuilder();
Class[] args = method.getParameterTypes(); Class<?>[] args = method.getParameterTypes();
for (int ii = (listenerMode ? 0 : 1); ii < args.length; ii++) { for (int ii = (listenerMode ? 0 : 1); ii < args.length; ii++) {
if (buf.length() > 0) { if (buf.length() > 0) {
buf.append(", "); buf.append(", ");
@@ -180,7 +182,7 @@ public abstract class InvocationTask extends Task
return buf.toString(); return buf.toString();
} }
protected String boxArgument (Class clazz, int index) protected String boxArgument (Class<?> clazz, int index)
{ {
if (_ilistener.isAssignableFrom(clazz)) { if (_ilistener.isAssignableFrom(clazz)) {
return GenUtil.boxArgument(clazz, "listener" + index); return GenUtil.boxArgument(clazz, "listener" + index);
@@ -190,7 +192,7 @@ public abstract class InvocationTask extends Task
} }
protected String unboxArgument ( protected String unboxArgument (
Class clazz, int index, boolean listenerMode) Class<?> clazz, int index, boolean listenerMode)
{ {
if (listenerMode && _ilistener.isAssignableFrom(clazz)) { if (listenerMode && _ilistener.isAssignableFrom(clazz)) {
return "listener" + index; return "listener" + index;
@@ -252,8 +254,7 @@ public abstract class InvocationTask extends Task
throw new BuildException("Can't resolve InvocationListener", e); throw new BuildException("Can't resolve InvocationListener", e);
} }
for (Iterator iter = _filesets.iterator(); iter.hasNext(); ) { for (FileSet fs : _filesets) {
FileSet fs = (FileSet)iter.next();
DirectoryScanner ds = fs.getDirectoryScanner(getProject()); DirectoryScanner ds = fs.getDirectoryScanner(getProject());
File fromDir = fs.getDir(getProject()); File fromDir = fs.getDir(getProject());
String[] srcFiles = ds.getIncludedFiles(); String[] srcFiles = ds.getIncludedFiles();
@@ -302,7 +303,7 @@ public abstract class InvocationTask extends Task
FileUtils.writeStringToFile(new File(path), data, "UTF-8"); FileUtils.writeStringToFile(new File(path), data, "UTF-8");
} }
protected static void checkedAdd (List list, Object value) protected static <T> void checkedAdd (List<T> list, T value)
{ {
if (!list.contains(value)) { if (!list.contains(value)) {
list.add(value); list.add(value);
@@ -324,7 +325,7 @@ public abstract class InvocationTask extends Task
} }
/** A list of filesets that contain tile images. */ /** A list of filesets that contain tile images. */
protected ArrayList _filesets = new ArrayList(); protected ArrayList<FileSet> _filesets = new ArrayList<FileSet>();
/** A header to put on all generated source files. */ /** A header to put on all generated source files. */
protected String _header; protected String _header;
@@ -337,5 +338,5 @@ public abstract class InvocationTask extends Task
/** {@link InvocationListener} resolved with the proper classloader so /** {@link InvocationListener} resolved with the proper classloader so
* that we can compare it to loaded derived classes. */ * that we can compare it to loaded derived classes. */
protected Class _ilistener; protected Class<?> _ilistener;
} }
@@ -3,7 +3,7 @@
* <code>$field</code> set. The set will not change until the event is * <code>$field</code> set. The set will not change until the event is
* actually propagated through the system. * actually propagated through the system.
*/ */
public void addTo$upfield (DSet.Entry elem) public void addTo$upfield ($etype elem)
{ {
requestEntryAdd($capfield, $field, elem); requestEntryAdd($capfield, $field, elem);
} }
@@ -23,7 +23,7 @@
* <code>$field</code> set. The set will not change until the event is * <code>$field</code> set. The set will not change until the event is
* actually propagated through the system. * actually propagated through the system.
*/ */
public void update$upfield (DSet.Entry elem) public void update$upfield ($etype elem)
{ {
requestEntryUpdate($capfield, $field, elem); requestEntryUpdate($capfield, $field, elem);
} }
@@ -44,7 +44,8 @@ public class ClassUtil
* @return the method with the specified name or null if no method * @return the method with the specified name or null if no method
* with that name could be found. * with that name could be found.
*/ */
public static Method getMethod (String name, Object target, HashMap cache) public static Method getMethod (
String name, Object target, HashMap<String,Method> cache)
{ {
Class tclass = target.getClass(); Class tclass = target.getClass();
String key = tclass.getName() + ":" + name; String key = tclass.getName() + ":" + name;
@@ -35,14 +35,14 @@ import com.threerings.presents.dobj.Subscriber;
* complete before the subscriber decides they no longer wish to be * complete before the subscriber decides they no longer wish to be
* subscribed. * subscribed.
*/ */
public class SafeSubscriber public class SafeSubscriber<T extends DObject>
implements Subscriber implements Subscriber<T>
{ {
/** /**
* Creates a safe subscriber for the specified distributed object * Creates a safe subscriber for the specified distributed object
* which will interact with the specified subscriber. * which will interact with the specified subscriber.
*/ */
public SafeSubscriber (int oid, Subscriber subscriber) public SafeSubscriber (int oid, Subscriber<T> subscriber)
{ {
// make sure they're not fucking us around // make sure they're not fucking us around
if (oid <= 0) { if (oid <= 0) {
@@ -157,7 +157,7 @@ public class SafeSubscriber
} }
// documentation inherited from interface // documentation inherited from interface
public void objectAvailable (DObject object) public void objectAvailable (T object)
{ {
// make sure life is not too cruel // make sure life is not too cruel
if (_object != null) { if (_object != null) {
@@ -224,8 +224,8 @@ public class SafeSubscriber
} }
protected int _oid; protected int _oid;
protected Subscriber _subscriber; protected Subscriber<T> _subscriber;
protected DObject _object; protected T _object;
protected boolean _active; protected boolean _active;
protected boolean _pending; protected boolean _pending;
} }