public synchronized RspList<Object> getResponseList() throws Exception { long expectedEndTime = timeService.expectedEndTime(timeout, MILLISECONDS); long waitingTime; while (expectedResponses > 0 && retval == null && (waitingTime = timeService.remainingTime(expectedEndTime, MILLISECONDS)) > 0) { try { this.wait(waitingTime); } catch (InterruptedException e) { // reset interruption flag Thread.currentThread().interrupt(); expectedResponses = -1; } } // Now we either have the response we need or aren't expecting any more responses - or have // run out of time. if (retval != null) return retval; else if (exception != null) throw exception; else if (expectedResponses == 0) throw new RpcException( format( "No more valid responses. Received invalid responses from all of %s", futures.values())); else throw new TimeoutException( format( "Timed out waiting for %s for valid responses from any of %s.", Util.prettyPrintTime(timeout), futures.values())); }
@Override @SuppressWarnings("unchecked") public synchronized void futureDone(Future<Object> objectFuture) { SenderContainer sc = futures.get(objectFuture); if (sc.processed) { // This can happen - it is a race condition in JGroups' NotifyingFuture.setListener() where // a listener // could be notified twice. if (trace) log.tracef( "Not processing callback; already processed callback for sender %s", sc.address); } else { sc.processed = true; Address sender = sc.address; boolean done = false; try { if (retval == null) { Object response = objectFuture.get(); if (trace) log.tracef("Received response: %s from %s", response, sender); filter.isAcceptable(response, sender); if (!filter.needMoreResponses()) { retval = new RspList(Collections.singleton(new Rsp(sender, response))); done = true; // TODO cancel other tasks? } } else { if (trace) log.tracef( "Skipping response from %s since a valid response for this request has already been received", sender); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } catch (ExecutionException e) { Throwable cause = e.getCause(); if (cause instanceof org.jgroups.SuspectedException) { // Do not set the exception field, RpcException should be thrown if there is no other // valid response return; } else if (cause instanceof org.jgroups.TimeoutException) { exception = new TimeoutException("Timeout!", e); } else if (cause instanceof Exception) { exception = (Exception) cause; } else { exception = new CacheException("Caught a throwable", cause); } if (log.isDebugEnabled()) log.debugf("Caught exception from sender %s: %s", sender, exception); } finally { expectedResponses--; if (expectedResponses == 0 || done) { this.notify(); // make sure to awake waiting thread, but avoid unnecessary wakeups! } } } }