From adb94044ff7ba6c2a2bdc56b90d081b10788ff54 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Tue, 1 Mar 2016 17:28:28 +0530 Subject: [PATCH 1/7] Work on #385, created project and provided two mute methods --- mute-idiom/pom.xml | 47 +++++++++++ .../src/main/java/com/iluwatar/mute/App.java | 77 +++++++++++++++++++ .../com/iluwatar/mute/CheckedRunnable.java | 36 +++++++++ .../src/main/java/com/iluwatar/mute/Mute.java | 65 ++++++++++++++++ .../test/java/com/iluwatar/mute/AppTest.java | 15 ++++ .../test/java/com/iluwatar/mute/MuteTest.java | 62 +++++++++++++++ 6 files changed, 302 insertions(+) create mode 100644 mute-idiom/pom.xml create mode 100644 mute-idiom/src/main/java/com/iluwatar/mute/App.java create mode 100644 mute-idiom/src/main/java/com/iluwatar/mute/CheckedRunnable.java create mode 100644 mute-idiom/src/main/java/com/iluwatar/mute/Mute.java create mode 100644 mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java create mode 100644 mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java diff --git a/mute-idiom/pom.xml b/mute-idiom/pom.xml new file mode 100644 index 000000000..e4597446b --- /dev/null +++ b/mute-idiom/pom.xml @@ -0,0 +1,47 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.11.0-SNAPSHOT + + mute-idiom + + + junit + junit + test + + + org.mockito + mockito-core + test + + + diff --git a/mute-idiom/src/main/java/com/iluwatar/mute/App.java b/mute-idiom/src/main/java/com/iluwatar/mute/App.java new file mode 100644 index 000000000..edb5ebcc9 --- /dev/null +++ b/mute-idiom/src/main/java/com/iluwatar/mute/App.java @@ -0,0 +1,77 @@ +/** + * The MIT License + * Copyright (c) 2014 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.mute; + +import java.io.ByteArrayOutputStream; +import java.sql.Connection; +import java.sql.SQLException; + +public class App { + + public static void main(String[] args) { + + useOfLoggedMute(); + + useOfMute(); + } + + /* + * Typically used when the API declares some exception but cannot do so. Usually a signature mistake. + * In this example out is not supposed to throw exception as it is a ByteArrayOutputStream. So we + * utilize mute, which will throw AssertionError if unexpected exception occurs. + */ + private static void useOfMute() { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Mute.mute(() -> out.write("Hello".getBytes())); + } + + private static void useOfLoggedMute() { + Connection connection = openConnection(); + try { + readStuff(connection); + } catch (SQLException ex) { + ex.printStackTrace(); + } finally { + closeConnection(connection); + } + } + + /* + * All we can do while failed close of connection is to log it. + */ + private static void closeConnection(Connection connection) { + if (connection != null) { + Mute.loggedMute(() -> connection.close()); + } + } + + private static void readStuff(Connection connection) throws SQLException { + if (connection != null) { + connection.createStatement(); + } + } + + private static Connection openConnection() { + return null; + } +} diff --git a/mute-idiom/src/main/java/com/iluwatar/mute/CheckedRunnable.java b/mute-idiom/src/main/java/com/iluwatar/mute/CheckedRunnable.java new file mode 100644 index 000000000..7f99386f0 --- /dev/null +++ b/mute-idiom/src/main/java/com/iluwatar/mute/CheckedRunnable.java @@ -0,0 +1,36 @@ +/** + * The MIT License + * Copyright (c) 2014 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.mute; + +/** + * A runnable which may throw exception on execution. + * + */ +@FunctionalInterface +public interface CheckedRunnable { + /** + * Same as {@link Runnable#run()} with a possibility of exception in execution. + * @throws Exception if any exception occurs. + */ + public void run() throws Exception; +} diff --git a/mute-idiom/src/main/java/com/iluwatar/mute/Mute.java b/mute-idiom/src/main/java/com/iluwatar/mute/Mute.java new file mode 100644 index 000000000..ba055422b --- /dev/null +++ b/mute-idiom/src/main/java/com/iluwatar/mute/Mute.java @@ -0,0 +1,65 @@ +/** + * The MIT License + * Copyright (c) 2014 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.mute; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * A utility class that allows you to utilize mute idiom. + */ +public final class Mute { + + /** + * Executes the runnable and throws the exception occurred within a {@link AssertionError}. + * This method should be utilized to mute the operations that are guaranteed not to throw an exception. + * For instance {@link ByteArrayOutputStream#write(byte[])} declares in it's signature that it can throw + * an {@link IOException}, but in reality it cannot. This is because the bulk write method is not overridden + * in {@link ByteArrayOutputStream}. + * + * @param runnable a runnable that should never throw an exception on execution. + */ + public static void mute(CheckedRunnable runnable) { + try { + runnable.run(); + } catch (Exception e) { + throw new AssertionError(e); + } + } + + /** + * Executes the runnable and logs the exception occurred on {@link System#err}. + * This method should be utilized to mute the operations about which most you can do is log. + * For instance while closing a connection to database, all you can do is log the exception + * occurred. + * + * @param runnable a runnable that may throw an exception on execution. + */ + public static void loggedMute(CheckedRunnable runnable) { + try { + runnable.run(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java b/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java new file mode 100644 index 000000000..8079c6acb --- /dev/null +++ b/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java @@ -0,0 +1,15 @@ +package com.iluwatar.mute; + +import org.junit.Test; + +/** + * Tests that Mute idiom example runs without errors. + * + */ +public class AppTest { + + @Test + public void test() { + App.main(null); + } +} diff --git a/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java b/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java new file mode 100644 index 000000000..b0016a331 --- /dev/null +++ b/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java @@ -0,0 +1,62 @@ +/** + * The MIT License + * Copyright (c) 2014 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.mute; + +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +public class MuteTest { + + private static final String MESSAGE = "should not occur"; + + @Rule public ExpectedException exception = ExpectedException.none(); + + @Test + public void muteShouldRethrowUnexpectedExceptionAsAssertionError() throws Exception { + exception.expect(AssertionError.class); + exception.expectMessage(MESSAGE); + + Mute.mute(() -> methodThrowingException()); + } + + private void methodThrowingException() throws Exception { + throw new Exception(MESSAGE); + } + + @Test + public void loggedMuteShouldLogExceptionTraceBeforeSwallowingIt() throws IOException { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + System.setErr(new PrintStream(stream)); + + Mute.loggedMute(() -> methodThrowingException()); + + assertTrue(new String(stream.toByteArray()).contains(MESSAGE)); + } +} From 7aff77ab27d3f2339d82a533353b1614620c4893 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Tue, 15 Mar 2016 18:44:59 +0530 Subject: [PATCH 2/7] Used mockito to replicate SQLException while closing connection to show use of loggedMute --- mute-idiom/pom.xml | 82 +++++++++---------- .../src/main/java/com/iluwatar/mute/App.java | 12 ++- .../src/main/java/com/iluwatar/mute/Mute.java | 4 +- 3 files changed, 48 insertions(+), 50 deletions(-) diff --git a/mute-idiom/pom.xml b/mute-idiom/pom.xml index e4597446b..528b60967 100644 --- a/mute-idiom/pom.xml +++ b/mute-idiom/pom.xml @@ -1,47 +1,39 @@ - - - 4.0.0 - - com.iluwatar - java-design-patterns - 1.11.0-SNAPSHOT - - mute-idiom - - - junit - junit - test - - - org.mockito - mockito-core - test - - + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.11.0-SNAPSHOT + + mute-idiom + + + junit + junit + test + + + org.mockito + mockito-core + compile + + diff --git a/mute-idiom/src/main/java/com/iluwatar/mute/App.java b/mute-idiom/src/main/java/com/iluwatar/mute/App.java index edb5ebcc9..36da1c4f9 100644 --- a/mute-idiom/src/main/java/com/iluwatar/mute/App.java +++ b/mute-idiom/src/main/java/com/iluwatar/mute/App.java @@ -22,6 +22,9 @@ */ package com.iluwatar.mute; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; + import java.io.ByteArrayOutputStream; import java.sql.Connection; import java.sql.SQLException; @@ -46,8 +49,9 @@ public class App { } private static void useOfLoggedMute() { - Connection connection = openConnection(); + Connection connection = null; try { + connection = openConnection(); readStuff(connection); } catch (SQLException ex) { ex.printStackTrace(); @@ -71,7 +75,9 @@ public class App { } } - private static Connection openConnection() { - return null; + private static Connection openConnection() throws SQLException { + Connection mockedConnection = mock(Connection.class); + doThrow(SQLException.class).when(mockedConnection).close(); + return mockedConnection; } } diff --git a/mute-idiom/src/main/java/com/iluwatar/mute/Mute.java b/mute-idiom/src/main/java/com/iluwatar/mute/Mute.java index ba055422b..3e1ad2e2e 100644 --- a/mute-idiom/src/main/java/com/iluwatar/mute/Mute.java +++ b/mute-idiom/src/main/java/com/iluwatar/mute/Mute.java @@ -50,8 +50,8 @@ public final class Mute { /** * Executes the runnable and logs the exception occurred on {@link System#err}. * This method should be utilized to mute the operations about which most you can do is log. - * For instance while closing a connection to database, all you can do is log the exception - * occurred. + * For instance while closing a connection to database, or cleaning up a resource, + * all you can do is log the exception occurred. * * @param runnable a runnable that may throw an exception on execution. */ From c78dd2667a0106d5c62cb022db0efb6610676443 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Wed, 16 Mar 2016 12:40:46 +0530 Subject: [PATCH 3/7] Work on #385, added documentation and class diagram. Made refactoring changes to pass checkstyle and PMD checks --- mute-idiom/etc/mute-idiom.png | Bin 0 -> 13502 bytes mute-idiom/etc/mute-idiom.ucls | 45 ++++++++++++++++ .../src/main/java/com/iluwatar/mute/App.java | 50 +++++++++++++----- .../com/iluwatar/mute/CheckedRunnable.java | 3 +- .../src/main/java/com/iluwatar/mute/Mute.java | 3 ++ .../test/java/com/iluwatar/mute/AppTest.java | 2 +- .../test/java/com/iluwatar/mute/MuteTest.java | 20 ++++++- pom.xml | 1 + 8 files changed, 106 insertions(+), 18 deletions(-) create mode 100644 mute-idiom/etc/mute-idiom.png create mode 100644 mute-idiom/etc/mute-idiom.ucls diff --git a/mute-idiom/etc/mute-idiom.png b/mute-idiom/etc/mute-idiom.png new file mode 100644 index 0000000000000000000000000000000000000000..626cec827a8b6fb5083dfde75c94937d682ee64b GIT binary patch literal 13502 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mute-idiom/src/main/java/com/iluwatar/mute/App.java b/mute-idiom/src/main/java/com/iluwatar/mute/App.java index 36da1c4f9..a0eb815fd 100644 --- a/mute-idiom/src/main/java/com/iluwatar/mute/App.java +++ b/mute-idiom/src/main/java/com/iluwatar/mute/App.java @@ -20,6 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + package com.iluwatar.mute; import static org.mockito.Mockito.doThrow; @@ -28,33 +29,56 @@ import static org.mockito.Mockito.mock; import java.io.ByteArrayOutputStream; import java.sql.Connection; import java.sql.SQLException; +import java.sql.Statement; +/** + * Mute pattern is utilized when we need to suppress an exception due to an API flaw or in + * situation when all we can do to handle the exception is to log it. + * This pattern should not be used everywhere. It is very important to logically handle the + * exceptions in a system, but some situations like the ones described above require this pattern, + * so that we don't need to repeat + *
+ * 
+ *   try {
+ *     // code that may throwing exception we need to ignore or may never be thrown
+ *   } catch (Exception ex) {
+ *     // ignore by logging or throw error if unexpected exception occurs
+ *   }
+ * 
+ * 
every time we need to ignore an exception. + * + */ public class App { - public static void main(String[] args) { - + /** + * Program entry point. + * + * @param args command line args. + * @throws Exception if any exception occurs + */ + public static void main(String[] args) throws Exception { + useOfLoggedMute(); - + useOfMute(); } /* - * Typically used when the API declares some exception but cannot do so. Usually a signature mistake. - * In this example out is not supposed to throw exception as it is a ByteArrayOutputStream. So we - * utilize mute, which will throw AssertionError if unexpected exception occurs. + * Typically used when the API declares some exception but cannot do so. Usually a + * signature mistake.In this example out is not supposed to throw exception as it is a + * ByteArrayOutputStream. So we utilize mute, which will throw AssertionError if unexpected + * exception occurs. */ private static void useOfMute() { ByteArrayOutputStream out = new ByteArrayOutputStream(); Mute.mute(() -> out.write("Hello".getBytes())); } - private static void useOfLoggedMute() { + private static void useOfLoggedMute() throws SQLException { Connection connection = null; try { connection = openConnection(); readStuff(connection); - } catch (SQLException ex) { - ex.printStackTrace(); } finally { closeConnection(connection); } @@ -64,14 +88,12 @@ public class App { * All we can do while failed close of connection is to log it. */ private static void closeConnection(Connection connection) { - if (connection != null) { - Mute.loggedMute(() -> connection.close()); - } + Mute.loggedMute(() -> connection.close()); } private static void readStuff(Connection connection) throws SQLException { - if (connection != null) { - connection.createStatement(); + try (Statement statement = connection.createStatement()) { + System.out.println("Read data from statement"); } } diff --git a/mute-idiom/src/main/java/com/iluwatar/mute/CheckedRunnable.java b/mute-idiom/src/main/java/com/iluwatar/mute/CheckedRunnable.java index 7f99386f0..d1440636f 100644 --- a/mute-idiom/src/main/java/com/iluwatar/mute/CheckedRunnable.java +++ b/mute-idiom/src/main/java/com/iluwatar/mute/CheckedRunnable.java @@ -20,6 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + package com.iluwatar.mute; /** @@ -32,5 +33,5 @@ public interface CheckedRunnable { * Same as {@link Runnable#run()} with a possibility of exception in execution. * @throws Exception if any exception occurs. */ - public void run() throws Exception; + void run() throws Exception; } diff --git a/mute-idiom/src/main/java/com/iluwatar/mute/Mute.java b/mute-idiom/src/main/java/com/iluwatar/mute/Mute.java index 3e1ad2e2e..64169a8f5 100644 --- a/mute-idiom/src/main/java/com/iluwatar/mute/Mute.java +++ b/mute-idiom/src/main/java/com/iluwatar/mute/Mute.java @@ -29,6 +29,9 @@ import java.io.IOException; * A utility class that allows you to utilize mute idiom. */ public final class Mute { + + // The constructor is never meant to be called. + private Mute() {} /** * Executes the runnable and throws the exception occurred within a {@link AssertionError}. diff --git a/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java b/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java index 8079c6acb..2d4e344a9 100644 --- a/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java +++ b/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java @@ -9,7 +9,7 @@ import org.junit.Test; public class AppTest { @Test - public void test() { + public void test() throws Exception { App.main(null); } } diff --git a/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java b/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java index b0016a331..58cbfe893 100644 --- a/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java +++ b/mute-idiom/src/test/java/com/iluwatar/mute/MuteTest.java @@ -20,6 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ + package com.iluwatar.mute; import static org.junit.Assert.assertTrue; @@ -38,6 +39,11 @@ public class MuteTest { @Rule public ExpectedException exception = ExpectedException.none(); + @Test + public void muteShouldRunTheCheckedRunnableAndNotThrowAnyExceptionIfCheckedRunnableDoesNotThrowAnyException() { + Mute.mute(() -> methodNotThrowingAnyException()); + } + @Test public void muteShouldRethrowUnexpectedExceptionAsAssertionError() throws Exception { exception.expect(AssertionError.class); @@ -46,8 +52,9 @@ public class MuteTest { Mute.mute(() -> methodThrowingException()); } - private void methodThrowingException() throws Exception { - throw new Exception(MESSAGE); + @Test + public void loggedMuteShouldRunTheCheckedRunnableAndNotThrowAnyExceptionIfCheckedRunnableDoesNotThrowAnyException() { + Mute.loggedMute(() -> methodNotThrowingAnyException()); } @Test @@ -59,4 +66,13 @@ public class MuteTest { assertTrue(new String(stream.toByteArray()).contains(MESSAGE)); } + + + private void methodNotThrowingAnyException() { + System.out.println("Executed successfully"); + } + + private void methodThrowingException() throws Exception { + throw new Exception(MESSAGE); + } } diff --git a/pom.xml b/pom.xml index 555844660..57d030756 100644 --- a/pom.xml +++ b/pom.xml @@ -123,6 +123,7 @@ feature-toggle value-object monad + mute-idiom From e5217bbde8e8d8baf7d4b3b3e3453879b775d005 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Wed, 16 Mar 2016 12:48:53 +0530 Subject: [PATCH 4/7] Work on #385, added missing license template --- .../test/java/com/iluwatar/mute/AppTest.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java b/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java index 2d4e344a9..8075d9c85 100644 --- a/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java +++ b/mute-idiom/src/test/java/com/iluwatar/mute/AppTest.java @@ -1,3 +1,26 @@ +/** + * The MIT License + * Copyright (c) 2014 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + package com.iluwatar.mute; import org.junit.Test; From 4d820b12ffcfc118e21f90f3344c7df9a30884b5 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Sat, 26 Mar 2016 12:33:02 +0530 Subject: [PATCH 5/7] Changes after review. Added README --- mute-idiom/etc/mute-idiom.png | Bin 13502 -> 18505 bytes mute-idiom/etc/mute-idiom.ucls | 36 ++++++++++++++--- .../src/main/java/com/iluwatar/mute/App.java | 38 +++++++++--------- .../main/java/com/iluwatar/mute/Resource.java | 35 ++++++++++++++++ 4 files changed, 84 insertions(+), 25 deletions(-) create mode 100644 mute-idiom/src/main/java/com/iluwatar/mute/Resource.java diff --git a/mute-idiom/etc/mute-idiom.png b/mute-idiom/etc/mute-idiom.png index 626cec827a8b6fb5083dfde75c94937d682ee64b..203bdafc4e6873916f3d3c85f375eeba29622ca6 100644 GIT binary patch literal 18505 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 - + @@ -12,7 +12,7 @@ - + @@ -21,21 +21,47 @@ - + - + + + + + + + + + + + + + + + + + + + - + + + + + diff --git a/mute-idiom/src/main/java/com/iluwatar/mute/App.java b/mute-idiom/src/main/java/com/iluwatar/mute/App.java index a0eb815fd..8a2aca41e 100644 --- a/mute-idiom/src/main/java/com/iluwatar/mute/App.java +++ b/mute-idiom/src/main/java/com/iluwatar/mute/App.java @@ -23,13 +23,9 @@ package com.iluwatar.mute; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; - import java.io.ByteArrayOutputStream; -import java.sql.Connection; +import java.io.IOException; import java.sql.SQLException; -import java.sql.Statement; /** * Mute pattern is utilized when we need to suppress an exception due to an API flaw or in @@ -75,31 +71,33 @@ public class App { } private static void useOfLoggedMute() throws SQLException { - Connection connection = null; + Resource resource = null; try { - connection = openConnection(); - readStuff(connection); + resource = acquireResource(); + utilizeResource(resource); } finally { - closeConnection(connection); + closeResource(resource); } } /* - * All we can do while failed close of connection is to log it. + * All we can do while failed close of a resource is to log it. */ - private static void closeConnection(Connection connection) { - Mute.loggedMute(() -> connection.close()); + private static void closeResource(Resource resource) { + Mute.loggedMute(() -> resource.close()); } - private static void readStuff(Connection connection) throws SQLException { - try (Statement statement = connection.createStatement()) { - System.out.println("Read data from statement"); - } + private static void utilizeResource(Resource resource) throws SQLException { + System.out.println("Utilizing acquired resource: " + resource); } - private static Connection openConnection() throws SQLException { - Connection mockedConnection = mock(Connection.class); - doThrow(SQLException.class).when(mockedConnection).close(); - return mockedConnection; + private static Resource acquireResource() throws SQLException { + return new Resource() { + + @Override + public void close() throws IOException { + throw new IOException("Error in closing resource: " + this); + } + }; } } diff --git a/mute-idiom/src/main/java/com/iluwatar/mute/Resource.java b/mute-idiom/src/main/java/com/iluwatar/mute/Resource.java new file mode 100644 index 000000000..6970d06bc --- /dev/null +++ b/mute-idiom/src/main/java/com/iluwatar/mute/Resource.java @@ -0,0 +1,35 @@ +/** + * The MIT License + * Copyright (c) 2014 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.iluwatar.mute; + +import java.io.Closeable; + +/** + * Represents any resource that the application might acquire and that must be closed + * after it is utilized. Example of such resources can be a database connection, open + * files, sockets. + */ +public interface Resource extends Closeable { + +} From 80875a9ac86b3da6b7cecc495c1dd29b53c9686c Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Sat, 26 Mar 2016 12:36:50 +0530 Subject: [PATCH 6/7] Removed dependency on Mockito from pom --- mute-idiom/pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mute-idiom/pom.xml b/mute-idiom/pom.xml index 528b60967..bad6cb8c7 100644 --- a/mute-idiom/pom.xml +++ b/mute-idiom/pom.xml @@ -30,10 +30,5 @@ junit test - - org.mockito - mockito-core - compile -
From a395316a8003136666886690525dd1202df85596 Mon Sep 17 00:00:00 2001 From: Narendra Pathai Date: Sat, 26 Mar 2016 13:54:03 +0530 Subject: [PATCH 7/7] Added readme --- mute-idiom/README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 mute-idiom/README.md diff --git a/mute-idiom/README.md b/mute-idiom/README.md new file mode 100644 index 000000000..efc09f306 --- /dev/null +++ b/mute-idiom/README.md @@ -0,0 +1,28 @@ +--- +layout: pattern +title: Mute Idiom +folder: mute-idiom +permalink: /patterns/mute-idiom/ +categories: Other +tags: + - Java + - Difficulty-Beginner + - Idiom +--- + +## Intent +Provide a template to supress any exceptions that either are declared but cannot occur or should only be logged; +while executing some business logic. The template removes the need to write repeated `try-catch` blocks. + + +![alt text](./etc/mute-idiom.png "Mute Idiom") + +## Applicability +Use this idiom when + +* an API declares some exception but can never throw that exception. Eg. ByteArrayOutputStream bulk write method. +* you need to suppress some exception just by logging it, such as closing a resource. + +## Credits + +* [JOOQ: Mute Design Pattern](http://blog.jooq.org/2016/02/18/the-mute-design-pattern/)