Skip to content

Commit 100a72a

Browse files
committed
Merge pull request iluwatar#402 from iluwatar/mute-idiom
Implements Mute idiom
2 parents 2f5a2be + a395316 commit 100a72a

File tree

11 files changed

+493
-0
lines changed

11 files changed

+493
-0
lines changed

mute-idiom/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
layout: pattern
3+
title: Mute Idiom
4+
folder: mute-idiom
5+
permalink: /patterns/mute-idiom/
6+
categories: Other
7+
tags:
8+
- Java
9+
- Difficulty-Beginner
10+
- Idiom
11+
---
12+
13+
## Intent
14+
Provide a template to supress any exceptions that either are declared but cannot occur or should only be logged;
15+
while executing some business logic. The template removes the need to write repeated `try-catch` blocks.
16+
17+
18+
![alt text](./etc/mute-idiom.png "Mute Idiom")
19+
20+
## Applicability
21+
Use this idiom when
22+
23+
* an API declares some exception but can never throw that exception. Eg. ByteArrayOutputStream bulk write method.
24+
* you need to suppress some exception just by logging it, such as closing a resource.
25+
26+
## Credits
27+
28+
* [JOOQ: Mute Design Pattern](http://blog.jooq.org/2016/02/18/the-mute-design-pattern/)

mute-idiom/etc/mute-idiom.png

18.1 KB
Loading

mute-idiom/etc/mute-idiom.ucls

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
3+
realizations="true" associations="true" dependencies="true" nesting-relationships="true">
4+
<class id="1" language="java" name="com.iluwatar.mute.App" project="mute-idiom"
5+
file="/mute-idiom/src/main/java/com/iluwatar/mute/App.java" binary="false" corner="BOTTOM_RIGHT">
6+
<position height="-1" width="-1" x="168" y="234"/>
7+
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
8+
sort-features="false" accessors="true" visibility="true">
9+
<attributes public="true" package="true" protected="true" private="false" static="true"/>
10+
<operations public="true" package="true" protected="true" private="false" static="true"/>
11+
</display>
12+
</class>
13+
<class id="2" language="java" name="com.iluwatar.mute.Mute" project="mute-idiom"
14+
file="/mute-idiom/src/main/java/com/iluwatar/mute/Mute.java" binary="false" corner="BOTTOM_RIGHT">
15+
<position height="115" width="203" x="70" y="375"/>
16+
<display autosize="false" stereotype="true" package="true" initial-value="false" signature="true"
17+
sort-features="false" accessors="true" visibility="true">
18+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
19+
<operations public="true" package="true" protected="true" private="false" static="true"/>
20+
</display>
21+
</class>
22+
<interface id="3" language="java" name="com.iluwatar.mute.CheckedRunnable" project="mute-idiom"
23+
file="/mute-idiom/src/main/java/com/iluwatar/mute/CheckedRunnable.java" binary="false" corner="BOTTOM_RIGHT">
24+
<position height="-1" width="-1" x="407" y="432"/>
25+
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
26+
sort-features="false" accessors="true" visibility="true">
27+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
28+
<operations public="true" package="true" protected="true" private="true" static="true"/>
29+
</display>
30+
</interface>
31+
<interface id="4" language="java" name="com.iluwatar.mute.Resource" project="mute-idiom"
32+
file="/mute-idiom/src/main/java/com/iluwatar/mute/Resource.java" binary="false" corner="BOTTOM_RIGHT">
33+
<position height="-1" width="-1" x="383" y="235"/>
34+
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
35+
sort-features="false" accessors="true" visibility="true">
36+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
37+
<operations public="true" package="true" protected="true" private="true" static="true"/>
38+
</display>
39+
</interface>
40+
<interface id="5" language="java" name="java.io.Closeable" project="dao"
41+
file="/opt/Softwares/Eclipses/MARS/eclipse/jre/lib/rt.jar" binary="true" corner="BOTTOM_RIGHT">
42+
<position height="-1" width="-1" x="384" y="109"/>
43+
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
44+
sort-features="false" accessors="true" visibility="true">
45+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
46+
<operations public="true" package="true" protected="true" private="true" static="true"/>
47+
</display>
48+
</interface>
49+
<dependency id="6">
50+
<end type="SOURCE" refId="1"/>
51+
<end type="TARGET" refId="4"/>
52+
</dependency>
53+
<dependency id="7">
54+
<end type="SOURCE" refId="1"/>
55+
<end type="TARGET" refId="2"/>
56+
</dependency>
57+
<dependency id="8">
58+
<end type="SOURCE" refId="2"/>
59+
<end type="TARGET" refId="3"/>
60+
</dependency>
61+
<generalization id="9">
62+
<end type="SOURCE" refId="4"/>
63+
<end type="TARGET" refId="5"/>
64+
</generalization>
65+
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
66+
sort-features="false" accessors="true" visibility="true">
67+
<attributes public="true" package="true" protected="true" private="true" static="true"/>
68+
<operations public="true" package="true" protected="true" private="true" static="true"/>
69+
</classifier-display>
70+
<association-display labels="true" multiplicity="true"/>
71+
</class-diagram>

mute-idiom/pom.xml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?xml version="1.0"?>
2+
<!-- The MIT License Copyright (c) 2014 Ilkka Seppälä Permission is hereby
3+
granted, free of charge, to any person obtaining a copy of this software
4+
and associated documentation files (the "Software"), to deal in the Software
5+
without restriction, including without limitation the rights to use, copy,
6+
modify, merge, publish, distribute, sublicense, and/or sell copies of the
7+
Software, and to permit persons to whom the Software is furnished to do so,
8+
subject to the following conditions: The above copyright notice and this
9+
permission notice shall be included in all copies or substantial portions
10+
of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
11+
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
13+
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
14+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
15+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
16+
DEALINGS IN THE SOFTWARE. -->
17+
<project
18+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
19+
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
20+
<modelVersion>4.0.0</modelVersion>
21+
<parent>
22+
<groupId>com.iluwatar</groupId>
23+
<artifactId>java-design-patterns</artifactId>
24+
<version>1.11.0-SNAPSHOT</version>
25+
</parent>
26+
<artifactId>mute-idiom</artifactId>
27+
<dependencies>
28+
<dependency>
29+
<groupId>junit</groupId>
30+
<artifactId>junit</artifactId>
31+
<scope>test</scope>
32+
</dependency>
33+
</dependencies>
34+
</project>
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/**
2+
* The MIT License
3+
* Copyright (c) 2014 Ilkka Seppälä
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
24+
package com.iluwatar.mute;
25+
26+
import java.io.ByteArrayOutputStream;
27+
import java.io.IOException;
28+
import java.sql.SQLException;
29+
30+
/**
31+
* Mute pattern is utilized when we need to suppress an exception due to an API flaw or in
32+
* situation when all we can do to handle the exception is to log it.
33+
* This pattern should not be used everywhere. It is very important to logically handle the
34+
* exceptions in a system, but some situations like the ones described above require this pattern,
35+
* so that we don't need to repeat
36+
* <pre>
37+
* <code>
38+
* try {
39+
* // code that may throwing exception we need to ignore or may never be thrown
40+
* } catch (Exception ex) {
41+
* // ignore by logging or throw error if unexpected exception occurs
42+
* }
43+
* </code>
44+
* </pre> every time we need to ignore an exception.
45+
*
46+
*/
47+
public class App {
48+
49+
/**
50+
* Program entry point.
51+
*
52+
* @param args command line args.
53+
* @throws Exception if any exception occurs
54+
*/
55+
public static void main(String[] args) throws Exception {
56+
57+
useOfLoggedMute();
58+
59+
useOfMute();
60+
}
61+
62+
/*
63+
* Typically used when the API declares some exception but cannot do so. Usually a
64+
* signature mistake.In this example out is not supposed to throw exception as it is a
65+
* ByteArrayOutputStream. So we utilize mute, which will throw AssertionError if unexpected
66+
* exception occurs.
67+
*/
68+
private static void useOfMute() {
69+
ByteArrayOutputStream out = new ByteArrayOutputStream();
70+
Mute.mute(() -> out.write("Hello".getBytes()));
71+
}
72+
73+
private static void useOfLoggedMute() throws SQLException {
74+
Resource resource = null;
75+
try {
76+
resource = acquireResource();
77+
utilizeResource(resource);
78+
} finally {
79+
closeResource(resource);
80+
}
81+
}
82+
83+
/*
84+
* All we can do while failed close of a resource is to log it.
85+
*/
86+
private static void closeResource(Resource resource) {
87+
Mute.loggedMute(() -> resource.close());
88+
}
89+
90+
private static void utilizeResource(Resource resource) throws SQLException {
91+
System.out.println("Utilizing acquired resource: " + resource);
92+
}
93+
94+
private static Resource acquireResource() throws SQLException {
95+
return new Resource() {
96+
97+
@Override
98+
public void close() throws IOException {
99+
throw new IOException("Error in closing resource: " + this);
100+
}
101+
};
102+
}
103+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* The MIT License
3+
* Copyright (c) 2014 Ilkka Seppälä
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
24+
package com.iluwatar.mute;
25+
26+
/**
27+
* A runnable which may throw exception on execution.
28+
*
29+
*/
30+
@FunctionalInterface
31+
public interface CheckedRunnable {
32+
/**
33+
* Same as {@link Runnable#run()} with a possibility of exception in execution.
34+
* @throws Exception if any exception occurs.
35+
*/
36+
void run() throws Exception;
37+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* The MIT License
3+
* Copyright (c) 2014 Ilkka Seppälä
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
package com.iluwatar.mute;
24+
25+
import java.io.ByteArrayOutputStream;
26+
import java.io.IOException;
27+
28+
/**
29+
* A utility class that allows you to utilize mute idiom.
30+
*/
31+
public final class Mute {
32+
33+
// The constructor is never meant to be called.
34+
private Mute() {}
35+
36+
/**
37+
* Executes the <code>runnable</code> and throws the exception occurred within a {@link AssertionError}.
38+
* This method should be utilized to mute the operations that are guaranteed not to throw an exception.
39+
* For instance {@link ByteArrayOutputStream#write(byte[])} declares in it's signature that it can throw
40+
* an {@link IOException}, but in reality it cannot. This is because the bulk write method is not overridden
41+
* in {@link ByteArrayOutputStream}.
42+
*
43+
* @param runnable a runnable that should never throw an exception on execution.
44+
*/
45+
public static void mute(CheckedRunnable runnable) {
46+
try {
47+
runnable.run();
48+
} catch (Exception e) {
49+
throw new AssertionError(e);
50+
}
51+
}
52+
53+
/**
54+
* Executes the <code>runnable</code> and logs the exception occurred on {@link System#err}.
55+
* This method should be utilized to mute the operations about which most you can do is log.
56+
* For instance while closing a connection to database, or cleaning up a resource,
57+
* all you can do is log the exception occurred.
58+
*
59+
* @param runnable a runnable that may throw an exception on execution.
60+
*/
61+
public static void loggedMute(CheckedRunnable runnable) {
62+
try {
63+
runnable.run();
64+
} catch (Exception e) {
65+
e.printStackTrace();
66+
}
67+
}
68+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* The MIT License
3+
* Copyright (c) 2014 Ilkka Seppälä
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
24+
package com.iluwatar.mute;
25+
26+
import java.io.Closeable;
27+
28+
/**
29+
* Represents any resource that the application might acquire and that must be closed
30+
* after it is utilized. Example of such resources can be a database connection, open
31+
* files, sockets.
32+
*/
33+
public interface Resource extends Closeable {
34+
35+
}

0 commit comments

Comments
 (0)