diff --git a/src/java/com/threerings/presents/peer/server/NodeRequestsListener.java b/src/java/com/threerings/presents/peer/server/NodeRequestsListener.java new file mode 100644 index 000000000..a398657bf --- /dev/null +++ b/src/java/com/threerings/presents/peer/server/NodeRequestsListener.java @@ -0,0 +1,32 @@ +package com.threerings.presents.peer.server; + +import java.util.Map; + +import com.threerings.presents.client.InvocationService; + +/** + * Communicates the {@link NodeRequestsResult} of a {@link PeerManager.NodeRequest} sent to one + * or more peer nodes. + */ +public interface + NodeRequestsListener extends InvocationService.InvocationListener +{ + /** + * Called upon the successful completion of {@link PeerManager#invokeNodeRequest}, regardless + * of how many nodes were contacted or applicable. + */ + public void requestsProcessed (NodeRequestsResult result); + + /** + * Contains the result of a {@link PeerManager.NodeRequest} sent to one or more peer nodes. + * Any node that returned true for {@link PeerManager.NodeRequest#isApplicable} will appear + * in either {@link #getNodeResults()} or {@link #getNodeErrors()}. The wasDropped() method + * will return true iff both mappings are empty. + */ + public interface NodeRequestsResult + { + public Map getNodeResults (); + public Map getNodeErrors (); + boolean wasDropped (); + } +} diff --git a/src/java/com/threerings/presents/peer/server/PeerManager.java b/src/java/com/threerings/presents/peer/server/PeerManager.java index 9b32ca59c..d06396628 100644 --- a/src/java/com/threerings/presents/peer/server/PeerManager.java +++ b/src/java/com/threerings/presents/peer/server/PeerManager.java @@ -471,15 +471,13 @@ public abstract class PeerManager * If any one node reports failure, this function reports failure. If all nodes report success, * this function will report success. */ - public void invokeNodeRequest ( - final NodeRequest request, final InvocationService.ConfirmListener listener, - final Runnable onDropped) + public void invokeNodeRequest (final NodeRequest request, final NodeRequestsListener listener) { // if we're not on the dobjmgr thread, get there if (!_omgr.isDispatchThread()) { _omgr.postRunnable(new Runnable() { public void run () { - invokeNodeRequest(request, listener, onDropped); + invokeNodeRequest(request, listener); } }); return; @@ -498,24 +496,32 @@ public abstract class PeerManager nodes.add(peer.getNodeName()); } } - if (nodes.isEmpty() && onDropped != null) { - onDropped.run(); + if (nodes.isEmpty()) { + listener.requestsProcessed(new NodeRequestsResultImpl()); return; } + final Map results = Maps.newHashMap(); + final Map failures = Maps.newHashMap(); for (final String node : nodes) { invokeNodeRequest(node, requestBytes, new InvocationService.ResultListener() { public void requestProcessed (Object result) { // check off this node's successful response - nodes.remove(node); - if (nodes.isEmpty()) { - // if all nodes have responded in the affirmative, let caller know - listener.requestProcessed(); - } + @SuppressWarnings("unchecked") + T castResult = (T) result; + results.put(node, castResult); + nodeDone(node); } public void requestFailed (String cause) { - // let the caller know a node failed - listener.requestFailed(cause); + failures.put(node, cause); + nodeDone(node); + } + protected void nodeDone (String node) { + nodes.remove(node); + if (nodes.isEmpty()) { + // if all nodes have responded, let caller know + listener.requestsProcessed(new NodeRequestsResultImpl(results, failures)); + } } }); } @@ -1520,6 +1526,42 @@ public abstract class PeerManager protected long _startStamp = System.currentTimeMillis(); } + protected static class NodeRequestsResultImpl + implements NodeRequestsListener.NodeRequestsResult + { + public NodeRequestsResultImpl (Map results, Map errors) + { + _results = Maps.newHashMap(results); + _errors = Maps.newHashMap(errors); + } + + public NodeRequestsResultImpl () + { + this(Collections.EMPTY_MAP, Collections.EMPTY_MAP); + } + + @Override public Map getNodeResults () + { + return _results; + } + + @Override + public Map getNodeErrors () + { + return _errors; + } + + @Override + public boolean wasDropped () + { + return _results.isEmpty() && _errors.isEmpty(); + } + + protected Map _results; + protected Map _errors; + } + + /** Extracts the node object from the supplied peer. */ protected static final Function GET_NODE_OBJECT = new Function() {