package com.insightfullogic.java8.examples.chapter9; import com.insightfullogic.java8.examples.chapter1.Album; import com.insightfullogic.java8.examples.chapter1.Artist; import com.insightfullogic.java8.examples.chapter1.Track; import java.util.List; import java.util.concurrent.*; public class CompletableAlbumLookup implements AlbumLookup { private static final ExecutorService service = Executors.newFixedThreadPool(4); private final List<Track> tracks; private final List<Artist> artists; public CompletableAlbumLookup(List<Track> tracks, List<Artist> artists) { this.tracks = tracks; this.artists = artists; } // BEGIN lookupByName public Album lookupByName(String albumName) { CompletableFuture<List<Artist>> artistLookup = loginTo("artist") .thenCompose(artistLogin -> lookupArtists(albumName, artistLogin)); // <1> return loginTo("track") .thenCompose(trackLogin -> lookupTracks(albumName, trackLogin)) // <2> .thenCombine(artistLookup, (tracks, artists) -> new Album(albumName, tracks, artists)) // <3> .join(); // <4> } // END lookupByName // Variables Exists to satisfy code sample below private Track track; private Artist artist; // BEGIN lookupTrack CompletableFuture<Track> lookupTrack(String id) { return CompletableFuture.supplyAsync(() -> { // Some expensive work is done here <1> // ... return track; // <2> }, service); // <3> } // END lookupTrack // BEGIN createFuture CompletableFuture<Artist> createFuture(String id) { CompletableFuture<Artist> future = new CompletableFuture<>(); startJob(future); return future; } // END createFuture private void startJob(CompletableFuture<Artist> future) { // BEGIN complete future.complete(artist); // END complete } private void processExceptionally(CompletableFuture<Album> future, String name) { // BEGIN completeExceptionally future.completeExceptionally(new AlbumLookupException("Unable to find " + name)); // END completeExceptionally } // ----------------- FAKE LOOKUP METHODS ----------------- // Represent API lookup on external services private CompletableFuture<List<Artist>> lookupArtists(String albumName, Credentials credentials) { return CompletableFuture.completedFuture(artists); } private void sleep(long time) { try { Thread.sleep(time); } catch (InterruptedException e) { e.printStackTrace(); } } private CompletableFuture<List<Track>> lookupTracks(String albumName, Credentials credentials) { return CompletableFuture.supplyAsync(() -> { sleep(1000); return tracks; }, service); } private CompletableFuture<Credentials> loginTo(String serviceName) { return CompletableFuture.supplyAsync(() -> { if ("artist".equals(serviceName)) { sleep(1000); } return new Credentials(); }, service); } }