All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.kafka.clients.consumer.internals.RequestFuture Maven / Gradle / Ivy

There is a newer version: 3.9.0
Show newest version
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
 * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
 * to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */
package org.apache.kafka.clients.consumer.internals;

import org.apache.kafka.common.errors.RetriableException;
import org.apache.kafka.common.protocol.Errors;

import java.util.ArrayList;
import java.util.List;

/**
 * Result of an asynchronous request from {@link ConsumerNetworkClient}. Use {@link ConsumerNetworkClient#poll(long)}
 * (and variants) to finish a request future. Use {@link #isDone()} to check if the future is complete, and
 * {@link #succeeded()} to check if the request completed successfully. Typical usage might look like this:
 *
 * 
 *     RequestFuture future = client.send(api, request);
 *     client.poll(future);
 *
 *     if (future.succeeded()) {
 *         ClientResponse response = future.value();
 *         // Handle response
 *     } else {
 *         throw future.exception();
 *     }
 * 
* * @param Return type of the result (Can be Void if there is no response) */ public class RequestFuture { private boolean isDone = false; private T value; private RuntimeException exception; private List> listeners = new ArrayList<>(); /** * Check whether the response is ready to be handled * @return true if the response is ready, false otherwise */ public boolean isDone() { return isDone; } /** * Get the value corresponding to this request (only available if the request succeeded) * @return the value if it exists or null */ public T value() { return value; } /** * Check if the request succeeded; * @return true if the request completed and was successful */ public boolean succeeded() { return isDone && exception == null; } /** * Check if the request failed. * @return true if the request completed with a failure */ public boolean failed() { return isDone && exception != null; } /** * Check if the request is retriable (convenience method for checking if * the exception is an instance of {@link RetriableException}. * @return true if it is retriable, false otherwise */ public boolean isRetriable() { return exception instanceof RetriableException; } /** * Get the exception from a failed result (only available if the request failed) * @return The exception if it exists or null */ public RuntimeException exception() { return exception; } /** * Complete the request successfully. After this call, {@link #succeeded()} will return true * and the value can be obtained through {@link #value()}. * @param value corresponding value (or null if there is none) */ public void complete(T value) { if (isDone) throw new IllegalStateException("Invalid attempt to complete a request future which is already complete"); this.value = value; this.isDone = true; fireSuccess(); } /** * Raise an exception. The request will be marked as failed, and the caller can either * handle the exception or throw it. * @param e corresponding exception to be passed to caller */ public void raise(RuntimeException e) { if (isDone) throw new IllegalStateException("Invalid attempt to complete a request future which is already complete"); this.exception = e; this.isDone = true; fireFailure(); } /** * Raise an error. The request will be marked as failed. * @param error corresponding error to be passed to caller */ public void raise(Errors error) { raise(error.exception()); } private void fireSuccess() { for (RequestFutureListener listener : listeners) listener.onSuccess(value); } private void fireFailure() { for (RequestFutureListener listener : listeners) listener.onFailure(exception); } /** * Add a listener which will be notified when the future completes * @param listener */ public void addListener(RequestFutureListener listener) { if (isDone) { if (exception != null) listener.onFailure(exception); else listener.onSuccess(value); } else { this.listeners.add(listener); } } /** * Convert from a request future of one type to another type * @param adapter The adapter which does the conversion * @param The type of the future adapted to * @return The new future */ public RequestFuture compose(final RequestFutureAdapter adapter) { final RequestFuture adapted = new RequestFuture(); addListener(new RequestFutureListener() { @Override public void onSuccess(T value) { adapter.onSuccess(value, adapted); } @Override public void onFailure(RuntimeException e) { adapter.onFailure(e, adapted); } }); return adapted; } public void chain(final RequestFuture future) { addListener(new RequestFutureListener() { @Override public void onSuccess(T value) { future.complete(value); } @Override public void onFailure(RuntimeException e) { future.raise(e); } }); } public static RequestFuture failure(RuntimeException e) { RequestFuture future = new RequestFuture(); future.raise(e); return future; } public static RequestFuture voidSuccess() { RequestFuture future = new RequestFuture(); future.complete(null); return future; } public static RequestFuture coordinatorNotAvailable() { return failure(Errors.GROUP_COORDINATOR_NOT_AVAILABLE.exception()); } public static RequestFuture leaderNotAvailable() { return failure(Errors.LEADER_NOT_AVAILABLE.exception()); } public static RequestFuture noBrokersAvailable() { return failure(new NoAvailableBrokersException()); } public static RequestFuture staleMetadata() { return failure(new StaleMetadataException()); } }