@Override public void onNext(T value) { synchronized (lock) { // in theory we could implement ServerCallStreamObserver and expose isCancelled to our client, // but for current purposes we only need the StreamObserver API, so treat a cancelled observer // as something we just want to un-block from and return, and we'll trust the rest of our session // to shutdown accordingly. if (delegate instanceof ServerCallStreamObserver && ((ServerCallStreamObserver<T>) delegate).isCancelled()) { return; } while (!delegate.isReady()) { try { lock.wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } } delegate.onNext(value); }