class RaftClosure<T> implements Closure {

    private static final Logger LOG = Log.logger(RaftStoreClosure.class);

    private final CompletableFuture<RaftResult<T>> future;

    public RaftClosure() {
        this.future = new CompletableFuture<>();
    }

    public T waitFinished() throws Throwable {
        RaftResult<T> result = this.get();
        if (result.status().isOk()) {
            return result.callback().get();
        } else {
            throw result.exception();
        }
    }

    public Status status() {
        return this.get().status();
    }

    private RaftResult<T> get() {<FILL_FUNCTION_BODY>}

    public void complete(Status status) {
        this.future.complete(new RaftResult<>(status));
    }

    public void complete(Status status, Supplier<T> callback) {
        // This callback is called by consumer thread(like grizzly)
        this.future.complete(new RaftResult<>(status, callback));
    }

    public void failure(Status status, Throwable exception) {
        this.future.complete(new RaftResult<>(status, exception));
    }

    @Override
    public void run(Status status) {
        if (status.isOk()) {
            this.complete(status);
        } else {
            LOG.error("Failed to apply command: {}", status);
            String msg = "Failed to apply command in raft node with error: " +
                         status.getErrorMsg();
            this.failure(status, new BackendException(msg));
        }
    }
}

        try {
            return this.future.get(RaftContext.WAIT_RAFTLOG_TIMEOUT,
                                   TimeUnit.MILLISECONDS);
        } catch (ExecutionException e) {
            throw new BackendException("ExecutionException", e);
        } catch (InterruptedException e) {
            throw new BackendException("InterruptedException", e);
        } catch (TimeoutException e) {
            throw new BackendException("Wait closure timeout");
        }
    
<no_super_class>