![JAR search and dependency download from the Maven repository](/logo.png)
com.threerings.nexus.net.Connection Maven / Gradle / Ivy
The newest version!
//
// Nexus Core - a framework for developing distributed applications
// http://github.com/threerings/nexus/blob/master/LICENSE
package com.threerings.nexus.net;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import react.Signal;
import com.threerings.nexus.distrib.Address;
import com.threerings.nexus.distrib.DistribUtil;
import com.threerings.nexus.distrib.EventSink;
import com.threerings.nexus.distrib.NexusEvent;
import com.threerings.nexus.distrib.NexusException;
import com.threerings.nexus.distrib.NexusObject;
import com.threerings.nexus.distrib.NexusService;
import com.threerings.nexus.util.Callback;
import com.threerings.nexus.util.Util;
import static com.threerings.nexus.util.Log.log;
/**
* Manages a connection to a particular server.
*/
public abstract class Connection
implements Downstream.Handler, EventSink
{
/** A signal emitted when this connection is closed. The payload will be non-null if the
* connection was closed in error, null if it was closed in an orderly manner. */
public final Signal onClose = Signal.create();
/**
* Requests to subscribe to the specified Nexus object. Success (i.e. the object) or failure
* will be communicated via the supplied callback.
*/
public void subscribe (Address addr, Callback cb) {
if (!_penders.addPender(addr, cb)) {
send(new Upstream.Subscribe(addr));
}
}
/**
* Requests to unsubscribe from the specified Nexus object.
*/
public void unsubscribe (NexusObject object) {
int id = object.getId();
if (_objects.remove(id) == null) {
log.warning("Requested to unsubscribe from unknown object", "id", id);
return;
}
// TODO: make a note that we just unsubscribed, and so not to warn about events that arrive
// for this object in the near future (the server doesn't yet know that we've unsubscribed)
send(new Upstream.Unsubscribe(id));
}
/**
* Closes this connection in an orderly fashion. Any messages currently queued up should be
* delivered prior to closure.
*/
public abstract void close ();
// from interface EventSink
public String getHost () {
return _host;
}
// from interface EventSink
public void postEvent (NexusObject source, NexusEvent event) {
send(new Upstream.PostEvent(event));
}
// from interface EventSink
public void postCall (NexusObject source, short attrIndex, short methodId, Object[] args) {
// determine whether we have a callback (which the service generator code will enforce is
// always the final argument of the method)
int callId, lastIdx = args.length-1;
if (lastIdx > -1 && args[lastIdx] instanceof Callback>) {
callId = 1;
for (Integer key : _calls.keySet()) {
callId = Math.max(callId, key+1);
}
_calls.put(callId, (Callback>)args[lastIdx]);
args[lastIdx] = null; // we don't send the Callback over the wire
} else {
callId = 0; // no callback, no call id
}
// finally send the service call
send(new Upstream.ServiceCall(callId, source.getId(), attrIndex,
methodId, Arrays.asList(args)));
}
// from interface Downstream.Handler
public void onSubscribe (Downstream.Subscribe msg) {
// let this object know that we are its event sink
DistribUtil.init(msg.object, msg.object.getId(), this);
// the above must precede this call, as obtaining the object's address requires that the
// event sink be configured
Address> addr = msg.object.getAddress();
List> penders = _penders.getPenders(addr);
if (penders == null) {
log.warning("Missing pender list", "addr", addr);
send(new Upstream.Unsubscribe(msg.object.getId())); // clear our subscription
return;
}
// store the object in our local table
_objects.put(msg.object.getId(), msg.object);
// notify the pending listeners that the object has arrived
for (Callback> pender : penders) {
@SuppressWarnings("unchecked") Callback cb =
(Callback)pender;
Util.notifySuccess(cb, msg.object);
}
}
// from interface Downstream.Handler
public void onSubscribeFailure (Downstream.SubscribeFailure msg) {
List> penders = _penders.getPenders(msg.addr);
if (penders == null) {
log.warning("Missing pender list", "addr", msg.addr);
} else {
Exception cause = new Exception(msg.cause);
for (Callback> pender : penders) Util.notifyFailure(pender, cause);
}
}
// from interface Downstream.Handler
public void onDispatchEvent (final Downstream.DispatchEvent msg) {
final NexusObject target = _objects.get(msg.event.targetId);
if (target == null) {
log.warning("Missing target of event", "event", msg.event);
return;
}
msg.event.applyTo(target);
}
// from interface Downstream.Handler
public void onServiceResponse (Downstream.ServiceResponse msg) {
Callback> callback = _calls.remove(msg.callId);
if (callback == null) {
log.warning("Received service response for unknown call", "msg", msg);
return;
}
// if the result contains NexusObjects, they must be initialized
if (msg.result instanceof NexusService.ObjectResponse) {
for (NexusObject obj : ((NexusService.ObjectResponse)msg.result).getObjects()) {
DistribUtil.init(obj, obj.getId(), this);
_objects.put(obj.getId(), obj); // store the object in our local table
}
}
@SuppressWarnings("unchecked") Callback
© 2015 - 2025 Weber Informatics LLC | Privacy Policy