Common utilities for Google APIs in Java
—
The core API provides fundamental asynchronous programming utilities, service lifecycle management, and functional interfaces that form the foundation for Google API client libraries.
A future that supports adding listeners, similar to Guava's ListenableFuture. This is the primary async result type used throughout Google API libraries.
/**
* A future that can have listeners added to be called when the computation completes
* @param <V> The result type returned by this Future's get method
*/
interface ApiFuture<V> extends Future<V> {
/**
* Registers a listener to be run on the given executor
* @param listener The listener to run when the computation is complete
* @param executor The executor to run the listener in
*/
void addListener(Runnable listener, Executor executor);
}Static utility methods for working with ApiFuture instances, providing transformation, combination, and creation operations.
/**
* Static utility methods for ApiFuture instances
*/
class ApiFutures {
/**
* Registers a callback to be run when the given ApiFuture completes
* @param future The future to attach the callback to
* @param callback The callback to execute on completion
* @param executor The executor to run the callback in
*/
static <V> void addCallback(
ApiFuture<V> future,
ApiFutureCallback<? super V> callback,
Executor executor
);
/**
* Creates an ApiFuture which has its value set immediately upon construction
* @param value The value to set
* @return A future with the given value
*/
static <V> ApiFuture<V> immediateFuture(V value);
/**
* Creates an ApiFuture which has an exception set immediately upon construction
* @param throwable The exception to set
* @return A future with the given exception
*/
static <V> ApiFuture<V> immediateFailedFuture(Throwable throwable);
/**
* Creates an ApiFuture which is cancelled immediately upon construction
* @return A cancelled future
*/
static <V> ApiFuture<V> immediateCancelledFuture();
/**
* Returns a new ApiFuture whose result is the product of applying the given Function to the result of the given ApiFuture
* @param input The future to transform
* @param function The function to apply to the input future's result
* @param executor The executor to run the transformation in
* @return A future with the transformed result
*/
static <I, O> ApiFuture<O> transform(
ApiFuture<? extends I> input,
ApiFunction<? super I, ? extends O> function,
Executor executor
);
/**
* Returns a new ApiFuture whose result is asynchronously derived from the result of the given ApiFuture
* @param input The future to transform
* @param function The function to apply to the input future's result
* @param executor The executor to run the transformation in
* @return A future with the transformed result
*/
static <I, O> ApiFuture<O> transformAsync(
ApiFuture<I> input,
ApiAsyncFunction<I, O> function,
Executor executor
);
/**
* Creates an ApiFuture whose result is a list containing the results of the given ApiFutures
* @param futures The futures to combine
* @return A future containing a list of all results
*/
static <V> ApiFuture<List<V>> allAsList(
Iterable<? extends ApiFuture<? extends V>> futures
);
/**
* Returns a new ApiFuture whose result is taken from the given primary input or, if the primary input fails with the given exception type, from the result provided by the fallback
* @param input The primary input future
* @param exceptionType The exception type to catch
* @param callback The fallback function to apply on exception
* @param executor The executor to run the fallback in
* @return A future with error handling applied
*/
static <V, X extends Throwable> ApiFuture<V> catching(
ApiFuture<? extends V> input,
Class<X> exceptionType,
ApiFunction<? super X, ? extends V> callback,
Executor executor
);
/**
* Returns a new ApiFuture whose result is asynchronously taken from the given primary input or, if the primary input fails with the given exception type, from the result provided by the fallback
* @param input The primary input future
* @param exceptionType The exception type to catch
* @param callback The async fallback function to apply on exception
* @param executor The executor to run the fallback in
* @return A future with async error handling applied
*/
static <V, X extends Throwable> ApiFuture<V> catchingAsync(
ApiFuture<V> input,
Class<X> exceptionType,
ApiAsyncFunction<X, V> callback,
Executor executor
);
/**
* Creates an ApiFuture whose result is a list containing the results of the given ApiFutures, in the same order, but where null is returned for failed futures
* @param futures The futures to combine
* @return A future containing a list with successful results and nulls for failures
*/
@BetaApi
static <V> ApiFuture<List<V>> successfulAsList(
Iterable<? extends ApiFuture<? extends V>> futures
);
}Usage Examples:
import com.google.api.core.ApiFuture;
import com.google.api.core.ApiFutures;
import com.google.common.util.concurrent.MoreExecutors;
// Create immediate futures
ApiFuture<String> completedFuture = ApiFutures.immediateFuture("Hello");
ApiFuture<String> failedFuture = ApiFutures.immediateFailedFuture(new RuntimeException("Error"));
// Transform results
ApiFuture<Integer> lengthFuture = ApiFutures.transform(
completedFuture,
String::length,
MoreExecutors.directExecutor()
);
// Handle errors
ApiFuture<String> withFallback = ApiFutures.catching(
failedFuture,
RuntimeException.class,
throwable -> "Default value",
MoreExecutors.directExecutor()
);
// Combine multiple futures
List<ApiFuture<String>> futures = Arrays.asList(
ApiFutures.immediateFuture("one"),
ApiFutures.immediateFuture("two")
);
ApiFuture<List<String>> combined = ApiFutures.allAsList(futures);An ApiFuture whose result can be set programmatically. Useful for bridging callback-based APIs to the future-based programming model.
/**
* An ApiFuture whose result can be set manually
* @param <V> The result type
*/
class SettableApiFuture<V> implements ApiFuture<V> {
/**
* Creates a new SettableApiFuture that can be completed or cancelled by a later method call
* @return A new SettableApiFuture
*/
static <V> SettableApiFuture<V> create();
/**
* Sets the result of this Future unless this Future has already been cancelled or set
* @param value The value to set
* @return True if this attempt completed this Future, false if it was already complete
*/
boolean set(V value);
/**
* Sets the result of this Future to the given exception unless this Future has already been cancelled or set
* @param throwable The exception to set
* @return True if this attempt completed this Future, false if it was already complete
*/
boolean setException(Throwable throwable);
}Usage Example:
import com.google.api.core.SettableApiFuture;
// Create a settable future
SettableApiFuture<String> future = SettableApiFuture.create();
// Set the result from another thread or callback
someAsyncOperation(result -> {
if (result.isSuccess()) {
future.set(result.getValue());
} else {
future.setException(result.getException());
}
});
// Use the future
String result = future.get(); // Blocks until setCore functional interfaces for transformations and callbacks in the async programming model.
/**
* A transformation function from one type to another
* @param <F> The input type
* @param <T> The output type
*/
@FunctionalInterface
interface ApiFunction<F, T> {
/**
* Applies this function to the given argument
* @param input The function argument
* @return The function result
*/
T apply(F input);
}
/**
* A transformation function that returns an ApiFuture
* @param <I> The input type
* @param <O> The output type
*/
@FunctionalInterface
interface ApiAsyncFunction<I, O> {
/**
* Applies this function to the given argument, returning an ApiFuture
* @param input The function argument
* @return An ApiFuture containing the function result
* @throws Exception If the transformation fails
*/
ApiFuture<O> apply(I input) throws Exception;
}
/**
* A callback to be notified when an ApiFuture completes
* @param <V> The result type
*/
interface ApiFutureCallback<V> {
/**
* Invoked when a computation fails or is cancelled
* @param t The failure cause
*/
void onFailure(Throwable t);
/**
* Invoked when a computation completes successfully
* @param result The computation result
*/
void onSuccess(V result);
}Interfaces and base classes for managing the lifecycle of long-running services with startup, shutdown, and state monitoring.
/**
* An object with an operational state, asynchronous startup and shutdown lifecycles
*/
interface ApiService {
/**
* If the service state is NEW, this initiates service startup and returns immediately
* @return This service instance
*/
ApiService startAsync();
/**
* If the service is STARTING or RUNNING, this initiates service shutdown and returns immediately
* @return This service instance
*/
ApiService stopAsync();
/**
* Waits for the Service to reach the RUNNING state
* @throws IllegalStateException If the service reaches a state other than RUNNING
*/
void awaitRunning();
/**
* Waits for the Service to reach the RUNNING state for no more than the given time
* @param timeout The maximum time to wait
* @param unit The time unit of the timeout argument
* @throws TimeoutException If the service does not reach RUNNING within the timeout
* @throws IllegalStateException If the service reaches a state other than RUNNING
*/
void awaitRunning(long timeout, TimeUnit unit) throws TimeoutException;
/**
* Waits for the Service to reach the TERMINATED state
* @throws IllegalStateException If the service fails
*/
void awaitTerminated();
/**
* Waits for the Service to reach the TERMINATED state for no more than the given time
* @param timeout The maximum time to wait
* @param unit The time unit of the timeout argument
* @throws TimeoutException If the service does not reach TERMINATED within the timeout
* @throws IllegalStateException If the service fails
*/
void awaitTerminated(long timeout, TimeUnit unit) throws TimeoutException;
/**
* Returns true if this service is RUNNING
* @return True if the service is running
*/
boolean isRunning();
/**
* Returns the current state of this service
* @return The current service state
*/
State state();
/**
* Returns the Throwable that caused this service to fail
* @return The failure cause, or null if the service has not failed
*/
Throwable failureCause();
/**
* Registers a Listener to be executed on the given executor
* @param listener The listener to register
* @param executor The executor to run the listener on
*/
void addListener(Listener listener, Executor executor);
/**
* The lifecycle states of a service
*/
enum State {
NEW, STARTING, RUNNING, STOPPING, TERMINATED, FAILED
}
/**
* A listener for the various state changes that a Service goes through in its lifecycle
*/
abstract class Listener {
/**
* Called when the service transitions from NEW to STARTING
*/
public void starting() {}
/**
* Called when the service transitions from STARTING to RUNNING
*/
public void running() {}
/**
* Called when the service transitions to the STOPPING state
* @param from The previous state
*/
public void stopping(State from) {}
/**
* Called when the service transitions to the TERMINATED state
* @param from The previous state
*/
public void terminated(State from) {}
/**
* Called when the service transitions to the FAILED state
* @param from The previous state
* @param failure The failure that caused the transition
*/
public void failed(State from, Throwable failure) {}
}
}Base implementation of ApiService that handles state management and listener notification. Subclasses only need to implement the actual start and stop logic.
/**
* Base implementation of ApiService
*/
abstract class AbstractApiService implements ApiService {
/**
* Invoked to start the service. This method should be idempotent
*/
protected abstract void doStart();
/**
* Invoked to stop the service. This method should be idempotent
*/
protected abstract void doStop();
/**
* Implementing classes should invoke this method once their service has started
*/
protected final void notifyStarted();
/**
* Implementing classes should invoke this method once their service has stopped
*/
protected final void notifyStopped();
/**
* Invoke this method to transition the service to the FAILED state
* @param cause The exception that caused the service to fail
*/
protected final void notifyFailed(Throwable cause);
}Usage Example:
import com.google.api.core.AbstractApiService;
public class MyService extends AbstractApiService {
private volatile boolean running = false;
@Override
protected void doStart() {
// Start your service logic here
new Thread(() -> {
try {
// Initialize resources
running = true;
notifyStarted(); // Signal that startup completed
// Run service loop
while (running) {
// Service work
Thread.sleep(1000);
}
} catch (Exception e) {
notifyFailed(e); // Signal failure
}
}).start();
}
@Override
protected void doStop() {
running = false;
// Cleanup resources
notifyStopped(); // Signal that shutdown completed
}
}
// Usage
MyService service = new MyService();
service.startAsync().awaitRunning();
// Service is now running
service.stopAsync().awaitTerminated();
// Service is now stoppedAbstraction for time sources that can be mocked in tests, providing both high-resolution nanosecond timing and standard millisecond timing.
/**
* A supplier of time values
*/
interface ApiClock {
/**
* Returns the current value of the running JVM's high-resolution time source, in nanoseconds
* @return The current value of the running JVM's high-resolution time source, in nanoseconds
*/
long nanoTime();
/**
* Returns the current time in milliseconds
* @return The difference, measured in milliseconds, between the current time and midnight, January 1, 1970 UTC
*/
long millisTime();
}
/**
* A Clock that returns the current system nano time
*/
class NanoClock implements ApiClock {
/**
* Returns the default NanoClock instance
* @return The default clock instance
*/
static ApiClock getDefaultClock();
@Override
public long nanoTime() {
return System.nanoTime();
}
@Override
public long millisTime() {
return java.util.concurrent.TimeUnit.MILLISECONDS.convert(nanoTime(), java.util.concurrent.TimeUnit.NANOSECONDS);
}
}
/**
* A Clock that returns the current system time in milliseconds
*/
class CurrentMillisClock implements ApiClock {
/**
* Returns the default CurrentMillisClock instance
* @return The default clock instance
*/
static ApiClock getDefaultClock();
@Override
public long nanoTime() {
return java.util.concurrent.TimeUnit.NANOSECONDS.convert(millisTime(), java.util.concurrent.TimeUnit.MILLISECONDS);
}
@Override
public long millisTime() {
return System.currentTimeMillis();
}
}Abstract base classes for implementing custom ApiFuture types and forwarding decorators.
/**
* An abstract implementation of ApiFuture, for easier extension
* @param <V> The result type returned by this Future's get method
*/
abstract class AbstractApiFuture<V> implements ApiFuture<V> {
/**
* Sets the result of this AbstractApiFuture unless it has already been cancelled or set
* @param value The value to set
* @return True if the value was set, false if the future was already complete
*/
protected boolean set(V value);
/**
* Sets the result of this AbstractApiFuture to the given exception unless it has already been cancelled or set
* @param throwable The exception to set
* @return True if the exception was set, false if the future was already complete
*/
protected boolean setException(Throwable throwable);
/**
* Subclasses can override this method to be notified when this future is cancelled
*/
protected void interruptTask();
}
/**
* A Future that forwards all calls to another future
* @param <T> The result type returned by this Future's get method
*/
class ForwardingApiFuture<T> implements ApiFuture<T> {
/**
* Constructor that takes the delegate future
* @param delegate The future to forward calls to
*/
protected ForwardingApiFuture(ApiFuture<T> delegate);
}Install with Tessl CLI
npx tessl i tessl/maven-com-google-api--api-common