Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Moves promise to Java 11
  • Loading branch information
anuragagarwal561994 committed Dec 29, 2019
commit 0ef06c6bebc60bc5ef9ebbc05261a7501eb4ae91
55 changes: 27 additions & 28 deletions promise/src/main/java/com/iluwatar/promise/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,19 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The Promise object is used for asynchronous computations. A Promise represents an operation
* that hasn't completed yet, but is expected in the future.
* The Promise object is used for asynchronous computations. A Promise represents an operation that
* hasn't completed yet, but is expected in the future.
*
* <p>A Promise represents a proxy for a value not necessarily known when the promise is created. It
* <p>A Promise represents a proxy for a value not necessarily known when the promise is created.
* It
* allows you to associate dependent promises to an asynchronous action's eventual success value or
* failure reason. This lets asynchronous methods return values like synchronous methods: instead
* of the final value, the asynchronous method returns a promise of having a value at some point
* in the future.
* failure reason. This lets asynchronous methods return values like synchronous methods: instead of
* the final value, the asynchronous method returns a promise of having a value at some point in the
* future.
*
* <p>Promises provide a few advantages over callback objects:
* <ul>
Expand All @@ -58,14 +58,15 @@
* a file download promise, then a promise of character frequency, then a promise of lowest
* frequency character which is finally consumed and result is printed on console.
* </ul>
*
*
* @see CompletableFuture
*/
public class App {

private static final Logger LOGGER = LoggerFactory.getLogger(App.class);

private static final String DEFAULT_URL = "https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/promise/README.md";
private static final String DEFAULT_URL =
"https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/promise/README.md";
private final ExecutorService executor;
private final CountDownLatch stopLatch;

Expand All @@ -76,12 +77,13 @@ private App() {

/**
* Program entry point.
*
* @param args arguments
* @throws InterruptedException if main thread is interrupted.
* @throws ExecutionException if an execution error occurs.
* @throws ExecutionException if an execution error occurs.
*/
public static void main(String[] args) throws InterruptedException, ExecutionException {
App app = new App();
var app = new App();
try {
app.promiseUsage();
} finally {
Expand All @@ -102,11 +104,11 @@ private void promiseUsage() {
private void calculateLowestFrequencyChar() {
lowestFrequencyChar()
.thenAccept(
charFrequency -> {
LOGGER.info("Char with lowest frequency is: {}", charFrequency);
taskCompleted();
}
);
charFrequency -> {
LOGGER.info("Char with lowest frequency is: {}", charFrequency);
taskCompleted();
}
);
}

/*
Expand All @@ -116,38 +118,35 @@ private void calculateLowestFrequencyChar() {
private void calculateLineCount() {
countLines()
.thenAccept(
count -> {
LOGGER.info("Line count is: {}", count);
taskCompleted();
}
);
count -> {
LOGGER.info("Line count is: {}", count);
taskCompleted();
}
);
}

/*
* Calculate the character frequency of a file and when that promise is fulfilled,
* then promise to apply function to calculate lowest character frequency.
*/
private Promise<Character> lowestFrequencyChar() {
return characterFrequency()
.thenApply(Utility::lowestFrequencyChar);
return characterFrequency().thenApply(Utility::lowestFrequencyChar);
}

/*
* Download the file at DEFAULT_URL and when that promise is fulfilled,
* then promise to apply function to calculate character frequency.
*/
private Promise<Map<Character, Integer>> characterFrequency() {
return download(DEFAULT_URL)
.thenApply(Utility::characterFrequency);
private Promise<Map<Character, Long>> characterFrequency() {
return download(DEFAULT_URL).thenApply(Utility::characterFrequency);
}

/*
* Download the file at DEFAULT_URL and when that promise is fulfilled,
* then promise to apply function to count lines in that file.
*/
private Promise<Integer> countLines() {
return download(DEFAULT_URL)
.thenApply(Utility::countLines);
return download(DEFAULT_URL).thenApply(Utility::countLines);
}

/*
Expand Down
45 changes: 25 additions & 20 deletions promise/src/main/java/com/iluwatar/promise/Promise.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@
/**
* A Promise represents a proxy for a value not necessarily known when the promise is created. It
* allows you to associate dependent promises to an asynchronous action's eventual success value or
* failure reason. This lets asynchronous methods return values like synchronous methods: instead
* of the final value, the asynchronous method returns a promise of having a value at some point
* in the future.
*
* failure reason. This lets asynchronous methods return values like synchronous methods: instead of
* the final value, the asynchronous method returns a promise of having a value at some point in the
* future.
*
* @param <T> type of result.
*/
public class Promise<T> extends PromiseSupport<T> {
Expand All @@ -51,6 +51,7 @@ public Promise() {

/**
* Fulfills the promise with the provided value.
*
* @param value the fulfilled value that can be accessed using {@link #get()}.
*/
@Override
Expand All @@ -61,8 +62,9 @@ public void fulfill(T value) {

/**
* Fulfills the promise with exception due to error in execution.
* @param exception the exception will be wrapped in {@link ExecutionException}
* when accessing the value using {@link #get()}.
*
* @param exception the exception will be wrapped in {@link ExecutionException} when accessing the
* value using {@link #get()}.
*/
@Override
public void fulfillExceptionally(Exception exception) {
Expand All @@ -86,10 +88,10 @@ private void postFulfillment() {
}

/**
* Executes the task using the executor in other thread and fulfills the promise returned
* once the task completes either successfully or with an exception.
*
* @param task the task that will provide the value to fulfill the promise.
* Executes the task using the executor in other thread and fulfills the promise returned once the
* task completes either successfully or with an exception.
*
* @param task the task that will provide the value to fulfill the promise.
* @param executor the executor in which the task should be run.
* @return a promise that represents the result of running the task provided.
*/
Expand All @@ -105,21 +107,23 @@ public Promise<T> fulfillInAsync(final Callable<T> task, Executor executor) {
}

/**
* Returns a new promise that, when this promise is fulfilled normally, is fulfilled with
* result of this promise as argument to the action provided.
* Returns a new promise that, when this promise is fulfilled normally, is fulfilled with result
* of this promise as argument to the action provided.
*
* @param action action to be executed.
* @return a new promise.
*/
public Promise<Void> thenAccept(Consumer<? super T> action) {
Promise<Void> dest = new Promise<>();
var dest = new Promise<Void>();
fulfillmentAction = new ConsumeAction(this, dest, action);
return dest;
}

/**
* Set the exception handler on this promise.
* @param exceptionHandler a consumer that will handle the exception occurred while fulfilling
* the promise.
*
* @param exceptionHandler a consumer that will handle the exception occurred while fulfilling the
* promise.
* @return this
*/
public Promise<T> onError(Consumer<? super Throwable> exceptionHandler) {
Expand All @@ -128,8 +132,9 @@ public Promise<T> onError(Consumer<? super Throwable> exceptionHandler) {
}

/**
* Returns a new promise that, when this promise is fulfilled normally, is fulfilled with
* result of this promise as argument to the function provided.
* Returns a new promise that, when this promise is fulfilled normally, is fulfilled with result
* of this promise as argument to the function provided.
*
* @param func function to be executed.
* @return a new promise.
*/
Expand All @@ -140,8 +145,8 @@ public <V> Promise<V> thenApply(Function<? super T, V> func) {
}

/**
* Accesses the value from source promise and calls the consumer, then fulfills the
* destination promise.
* Accesses the value from source promise and calls the consumer, then fulfills the destination
* promise.
*/
private class ConsumeAction implements Runnable {

Expand Down
14 changes: 6 additions & 8 deletions promise/src/main/java/com/iluwatar/promise/PromiseSupport.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,15 @@
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* A really simplified implementation of future that allows completing it successfully with a value
* A really simplified implementation of future that allows completing it successfully with a value
* or exceptionally with an exception.
*/
class PromiseSupport<T> implements Future<T> {

private static final Logger LOGGER = LoggerFactory.getLogger(PromiseSupport.class);

private static final int RUNNING = 1;
Expand Down Expand Up @@ -93,13 +92,12 @@ public T get() throws InterruptedException, ExecutionException {
}
if (state == COMPLETED) {
return value;
}
}
throw new ExecutionException(exception);
}

@Override
public T get(long timeout, TimeUnit unit)
throws ExecutionException, TimeoutException {
public T get(long timeout, TimeUnit unit) throws ExecutionException {
synchronized (lock) {
while (state == RUNNING) {
try {
Expand All @@ -110,10 +108,10 @@ public T get(long timeout, TimeUnit unit)
}
}
}

if (state == COMPLETED) {
return value;
}
}
throw new ExecutionException(exception);
}
}
Loading