6

I'm trying to create a small service to accept file upload, unzip it and then delete the uploaded file. Those three steps should be chained as futures. I'm using Google Guava library.

Workflow is:

A future to download the file, if the operation completed, then a future to unzip the file. If unzipping is done, a future to delete the original uploaded file.

But honestly, it isn't clear to me how I would chain the futures, and even how to create them in Guava's way. Documentation is simply terse and unclear. Ok, there is transform method but no concrete example at all. chain method is deprecated.

I miss RxJava library.

Chiron
  • 20,081
  • 17
  • 81
  • 133
  • Futures do not do work. Runnables do. – Brett Okken Jan 13 '15 at 12:12
  • @BrettOkken How to chain runnable in Guava's way? – Chiron Jan 13 '15 at 12:39
  • possible duplicate of [Is it possible to chain async calls using Guava?](http://stackoverflow.com/questions/8191891/is-it-possible-to-chain-async-calls-using-guava) – Joe Jan 13 '15 at 13:04
  • What's wrong with [`Futures.transform`](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/util/concurrent/Futures.html#transform%28com.google.common.util.concurrent.ListenableFuture,%20com.google.common.util.concurrent.AsyncFunction,%20java.util.concurrent.Executor%29) ? – Louis Wasserman Jan 14 '15 at 00:06
  • 1
    The `CompletableFuture` in java 8 also provides some similar functionality. http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html – Brett Okken Jan 19 '15 at 13:39
  • @LouisWasserman Unclear to me how to create a Guava future without `submit()` method of executor. – Chiron Jan 19 '15 at 14:05
  • Are you lpoking for ListenableFutureTask? – Louis Wasserman Jan 19 '15 at 17:00

2 Answers2

3

Futures.transform is not fluently chainable like RxJava, but you can still use it to set up Futures that depend on one another. Here is a concrete example:

final ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());

final ListenableFuture<FileClass> fileFuture = service.submit(() -> fileDownloader.download())
final ListenableFuture<UnzippedFileClass> unzippedFileFuture = Futures.transform(fileFuture, 
      //need to cast this lambda
      (Function<FileClass, UnzippedFileClass>) file -> fileUnzipper.unzip(file));
final ListenableFuture<Void> deletedFileFuture = Futures.transform(unzippedFileFuture, 
      (Function<UnzippedFileClass, Void>) unzippedFile -> fileDeleter.delete(unzippedFile));
deletedFileFuture.get(); //or however you want to wait for the result

This example assumes fileDownloader.download() returns an instance of FileClass, fileUpzipper.unzip() returns an UnzippedFileClass etc. If FileDownloader.download() instead returns a ListenableFuture<FileClass>, use AsyncFunction instead of Function.

This example also uses Java 8 lambdas for brevity. If you are not using Java 8, pass in anonymous implementations of Function or AsyncFunction instead:

Futures.transform(fileFuture, new AsyncFunction<FileClass, UpzippedFileClass>() {
        @Override
        public ListenableFuture<UnzippedFileClass> apply(final FileClass input) throws Exception {
            return fileUnzipper.unzip();
        }
    });

More info on transform here: http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/util/concurrent/Futures.html#transform (scroll or search for "transform" -- deep linking appears to be broken currently)

martiansnoop
  • 2,316
  • 2
  • 16
  • 16
2

Guava extends the Future interface with ListenableFuture for this purpose.

Something like this should work:

Runnable downloader, unzipper;
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());

service.submit(downloader).addListener(unzipper, service);

I would include deleting the file in the unzipper, since it is a near instantaneous action, and it would complicate the code to separate it.

Brett Okken
  • 6,210
  • 1
  • 19
  • 25
Bohemian
  • 412,405
  • 93
  • 575
  • 722