diff --git a/promise/etc/promise.png b/promise/etc/promise.png index 1a0f67108..0aef198ac 100644 Binary files a/promise/etc/promise.png and b/promise/etc/promise.png differ diff --git a/promise/etc/promise.ucls b/promise/etc/promise.ucls index cdfb6ed7f..e7fefec1c 100644 --- a/promise/etc/promise.ucls +++ b/promise/etc/promise.ucls @@ -25,7 +25,7 @@ - + @@ -67,42 +67,38 @@ - + - + - - - - - + - + + + + + - - - - - + - - - + + + diff --git a/promise/src/main/java/com/iluwatar/promise/App.java b/promise/src/main/java/com/iluwatar/promise/App.java index 3a1ecfa01..1315f0927 100644 --- a/promise/src/main/java/com/iluwatar/promise/App.java +++ b/promise/src/main/java/com/iluwatar/promise/App.java @@ -21,19 +21,10 @@ * THE SOFTWARE. */ package com.iluwatar.promise; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; -import java.net.URL; import java.util.Map; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -59,7 +50,12 @@ import java.util.concurrent.Executors; */ public class App { + private static final String URL = "https://raw.githubusercontent.com/iluwatar/java-design-patterns/Promise/promise/README.md"; + private ExecutorService executor; + private CountDownLatch canStop = new CountDownLatch(2); + private App() { + executor = Executors.newFixedThreadPool(2); } /** @@ -69,67 +65,80 @@ public class App { * @throws ExecutionException if an execution error occurs. */ public static void main(String[] args) throws InterruptedException, ExecutionException { - ExecutorService executor = Executors.newSingleThreadExecutor(); + App app = new App(); try { - promiseUsage(executor); + app.run(); } finally { - executor.shutdownNow(); + app.stop(); } } - private static void promiseUsage(Executor executor) - throws InterruptedException, ExecutionException { - String urlString = "https://raw.githubusercontent.com/iluwatar/java-design-patterns/Promise/promise/README.md"; - Promise lineCountPromise = new Promise().fulfillInAsync(() -> { - return downloadFile(urlString); - }, executor).then(fileLocation -> { - return countLines(fileLocation); - }); + private void run() throws InterruptedException, ExecutionException { + promiseUsage(); + } + + private void promiseUsage() { - Promise> charFrequencyPromise = new Promise().fulfillInAsync(() -> { - return String.valueOf(downloadFile(urlString)); - }, executor).then(fileLocation -> { - return characterFrequency(fileLocation); - }); + countLines() + .then( + count -> { + System.out.println("Line count is: " + count); + taskCompleted(); + } + ); - lineCountPromise.get(); - System.out.println("Line count is: " + lineCountPromise.get()); - charFrequencyPromise.get(); - System.out.println("Char frequency is: " + charFrequencyPromise.get()); + lowestCharFrequency() + .then( + charFrequency -> { + System.out.println("Char with lowest frequency is: " + charFrequency); + taskCompleted(); + } + ); } - private static Map characterFrequency(String fileLocation) { - // TODO Auto-generated method stub - return null; + private Promise lowestCharFrequency() { + return characterFrequency() + .then( + charFrequency -> { + return Utility.lowestFrequencyChar(charFrequency).orElse(null); + } + ); } - private static Integer countLines(String fileLocation) { - int lineCount = 0; - try (Reader reader = new FileReader(fileLocation); - BufferedReader bufferedReader = new BufferedReader(reader);) { - for (String line; (line = bufferedReader.readLine()) != null; ) { - lineCount++; - } - } catch (IOException ex) { - ex.printStackTrace(); - } - return lineCount; + private Promise> characterFrequency() { + return download(URL) + .then( + fileLocation -> { + return Utility.characterFrequency(fileLocation); + } + ); } - private static String downloadFile(String urlString) throws InterruptedException, IOException { - URL url = new URL(urlString); - File file = File.createTempFile("promise_pattern", null); - try (Reader reader = new InputStreamReader(url.openStream()); - BufferedReader bufferedReader = new BufferedReader(reader); - FileWriter writer = new FileWriter(file)) { - for (String line; (line = bufferedReader.readLine()) != null; ) { - writer.write(line); - writer.write("\n"); - } - } catch (IOException ex) { - ex.printStackTrace(); - } - System.out.println("File downloaded at: " + file.getAbsolutePath()); - return file.getAbsolutePath(); + private Promise countLines() { + return download(URL) + .then( + fileLocation -> { + return Utility.countLines(fileLocation); + } + ); + } + + private Promise download(String urlString) { + Promise downloadPromise = new Promise() + .fulfillInAsync( + () -> { + return Utility.downloadFile(urlString); + }, executor); + + return downloadPromise; + } + + private void stop() throws InterruptedException { + canStop.await(); + executor.shutdownNow(); + } + + private void taskCompleted() { + canStop.countDown(); } } diff --git a/promise/src/main/java/com/iluwatar/promise/Utility.java b/promise/src/main/java/com/iluwatar/promise/Utility.java new file mode 100644 index 000000000..2cfad46d0 --- /dev/null +++ b/promise/src/main/java/com/iluwatar/promise/Utility.java @@ -0,0 +1,91 @@ +package com.iluwatar.promise; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Optional; +import java.util.Map.Entry; + +public class Utility { + + public static Map characterFrequency(String fileLocation) { + Map characterToFrequency = new HashMap<>(); + try (Reader reader = new FileReader(fileLocation); + BufferedReader bufferedReader = new BufferedReader(reader);) { + for (String line; (line = bufferedReader.readLine()) != null;) { + for (char c : line.toCharArray()) { + if (!characterToFrequency.containsKey(c)) { + characterToFrequency.put(c, 1); + } else { + characterToFrequency.put(c, characterToFrequency.get(c) + 1); + } + } + } + } catch (IOException ex) { + ex.printStackTrace(); + } + return characterToFrequency; + } + + public static Optional lowestFrequencyChar(Map charFrequency) { + Optional lowestFrequencyChar = Optional.empty(); + if (charFrequency.isEmpty()) { + return lowestFrequencyChar; + } + + Iterator> iterator = charFrequency.entrySet().iterator(); + Entry entry = iterator.next(); + int minFrequency = entry.getValue(); + lowestFrequencyChar = Optional.of(entry.getKey()); + + while (iterator.hasNext()) { + entry = iterator.next(); + if (entry.getValue() < minFrequency) { + minFrequency = entry.getValue(); + lowestFrequencyChar = Optional.of(entry.getKey()); + } + } + + return lowestFrequencyChar; + } + + public static Integer countLines(String fileLocation) { + int lineCount = 0; + try (Reader reader = new FileReader(fileLocation); + BufferedReader bufferedReader = new BufferedReader(reader);) { + while (bufferedReader.readLine() != null) { + lineCount++; + } + } catch (IOException ex) { + ex.printStackTrace(); + } + return lineCount; + } + + public static String downloadFile(String urlString) throws MalformedURLException, IOException { + System.out.println("Downloading contents from url: " + urlString); + URL url = new URL(urlString); + File file = File.createTempFile("promise_pattern", null); + try (Reader reader = new InputStreamReader(url.openStream()); + BufferedReader bufferedReader = new BufferedReader(reader); + FileWriter writer = new FileWriter(file)) { + for (String line; (line = bufferedReader.readLine()) != null; ) { + writer.write(line); + writer.write("\n"); + } + System.out.println("File downloaded at: " + file.getAbsolutePath()); + return file.getAbsolutePath(); + } catch (IOException ex) { + throw ex; + } + } +}