diff --git a/module/README.md b/module/README.md new file mode 100644 index 000000000..24bd3f543 --- /dev/null +++ b/module/README.md @@ -0,0 +1,25 @@ +--- +layout: pattern +title: Module +folder: module +permalink: /patterns/module/ +pumlid: JShB3OGm303HLg20nFVjnYGM1CN6ycTfVtFSsnjfzY5jPgUqkLqHwXy0mxUU8wuyqidQ8q4IjJqCO-QBWGOtVh5qyd5AKOmW4mT6Nu2-ZiAekapH_hkcSTNa-GC0 +categories: Creational Pattern +tags: + - Java + - Difficulty-Beginner +--- + +## Intent +Module pattern is used to implement the concept of software modules, defined by modular programming, in a programming language with incomplete direct support for the concept. + +![alt text](./etc/module.png "Module") + +## Applicability +The Module pattern can be considered a creational pattern and a structural pattern. It manages the creation and organization of other elements, and groups them as the structural pattern does. + +An object that applies this pattern can provide the equivalent of a namespace, providing the initialization and finalization process of a static class or a class with static members with cleaner, more concise syntax and semantics. + +## Credits + +* [Module](https://en.wikipedia.org/wiki/Module_pattern) diff --git a/module/etc/module.png b/module/etc/module.png new file mode 100644 index 000000000..a26807d29 Binary files /dev/null and b/module/etc/module.png differ diff --git a/module/etc/module.ucls b/module/etc/module.ucls new file mode 100644 index 000000000..d2519b856 --- /dev/null +++ b/module/etc/module.ucls @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/module/etc/module.urm.puml b/module/etc/module.urm.puml new file mode 100644 index 000000000..d78f12da8 --- /dev/null +++ b/module/etc/module.urm.puml @@ -0,0 +1,43 @@ +@startuml +package com.iluwatar.module { + class App { + + consoleLoggerModule : ConsoleLoggerModule {static} + + fileLoggerModule : FileLoggerModule {static} + - App() + + execute(args : String[]) {static} + + main(args : String[]) {static} + + prepare() {static} + + unprepare() {static} + } + class ConsoleLoggerModule { + - LOGGER : Logger {static} + + error : PrintStream + + output : PrintStream + - singleton : ConsoleLoggerModule {static} + - ConsoleLoggerModule() + + getSingleton() : ConsoleLoggerModule {static} + + prepare() + + printErrorString(value : String) + + printString(value : String) + + unprepare() + } + class FileLoggerModule { + - ERROR_FILE : String {static} + - LOGGER : Logger {static} + - OUTPUT_FILE : String {static} + + error : PrintStream + + output : PrintStream + - singleton : FileLoggerModule {static} + - FileLoggerModule() + + getSingleton() : FileLoggerModule {static} + + prepare() + + printErrorString(value : String) + + printString(value : String) + + unprepare() + } +} +FileLoggerModule --> "-singleton" FileLoggerModule +App --> "-consoleLoggerModule" ConsoleLoggerModule +ConsoleLoggerModule --> "-singleton" ConsoleLoggerModule +App --> "-fileLoggerModule" FileLoggerModule +@enduml \ No newline at end of file diff --git a/module/pom.xml b/module/pom.xml new file mode 100644 index 000000000..bc43e3e09 --- /dev/null +++ b/module/pom.xml @@ -0,0 +1,45 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.14.0-SNAPSHOT + + module + + + junit + junit + test + + + log4j + log4j + + + diff --git a/module/src/main/java/com/iluwatar/module/App.java b/module/src/main/java/com/iluwatar/module/App.java new file mode 100644 index 000000000..1c117722f --- /dev/null +++ b/module/src/main/java/com/iluwatar/module/App.java @@ -0,0 +1,92 @@ +/** + * 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.module; + +import java.io.FileNotFoundException; + +/** + * The Module pattern can be considered a Creational pattern and a Structural pattern. It manages + * the creation and organization of other elements, and groups them as the structural pattern does. + * An object that applies this pattern can provide the equivalent of a namespace, providing the + * initialization and finalization process of a static class or a class with static members with + * cleaner, more concise syntax and semantics. + *

+ * The below example demonstrates a use case for testing two different modules: File Logger and + * Console Logger + * + */ +public final class App { + + public static FileLoggerModule fileLoggerModule; + public static ConsoleLoggerModule consoleLoggerModule; + + /** + * Following method performs the initialization + * + * @throws FileNotFoundException if program is not able to find log files (output.txt and + * error.txt) + */ + public static void prepare() throws FileNotFoundException { + + /* Create new singleton objects and prepare their modules */ + fileLoggerModule = FileLoggerModule.getSingleton().prepare(); + consoleLoggerModule = ConsoleLoggerModule.getSingleton().prepare(); + } + + /** + * Following method performs the finalization + */ + public static void unprepare() { + + /* Close all resources */ + fileLoggerModule.unprepare(); + consoleLoggerModule.unprepare(); + } + + /** + * Following method is main executor + * + * @param args for providing default program arguments + */ + public static void execute(final String... args) { + + /* Send logs on file system */ + fileLoggerModule.printString("Message"); + fileLoggerModule.printErrorString("Error"); + + /* Send logs on console */ + consoleLoggerModule.printString("Message"); + consoleLoggerModule.printErrorString("Error"); + } + + /** + * Program entry point. + * + * @param args command line args. + * @throws FileNotFoundException if program is not able to find log files (output.txt and + * error.txt) + */ + public static void main(final String... args) throws FileNotFoundException { + prepare(); + execute(args); + unprepare(); + } + + private App() {} +} diff --git a/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java b/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java new file mode 100644 index 000000000..0efdd9033 --- /dev/null +++ b/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java @@ -0,0 +1,106 @@ +/** + * 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.module; + +import java.io.PrintStream; + +import org.apache.log4j.Logger; + +/** + * The ConsoleLoggerModule is responsible for showing logs on System Console + *

+ * The below example demonstrates a Console logger module, which can print simple and error messages + * in two designated formats + */ +public final class ConsoleLoggerModule { + + private static final Logger LOGGER = Logger.getLogger(ConsoleLoggerModule.class); + + private static ConsoleLoggerModule singleton = null; + + public PrintStream output = null; + public PrintStream error = null; + + private ConsoleLoggerModule() {} + + /** + * Static method to get single instance of class + * + * @return singleton instance of ConsoleLoggerModule + */ + public static ConsoleLoggerModule getSingleton() { + + if (ConsoleLoggerModule.singleton == null) { + ConsoleLoggerModule.singleton = new ConsoleLoggerModule(); + } + + return ConsoleLoggerModule.singleton; + } + + /** + * Following method performs the initialization + */ + public ConsoleLoggerModule prepare() { + + LOGGER.debug("ConsoleLoggerModule::prepare();"); + + this.output = new PrintStream(System.out); + this.error = new PrintStream(System.err); + + return this; + } + + /** + * Following method performs the finalization + */ + public void unprepare() { + + if (this.output != null) { + + this.output.flush(); + this.output.close(); + } + + if (this.error != null) { + + this.error.flush(); + this.error.close(); + } + + LOGGER.debug("ConsoleLoggerModule::unprepare();"); + } + + /** + * Used to print a message + * + * @param value will be printed on console + */ + public void printString(final String value) { + this.output.println(value); + } + + /** + * Used to print a error message + * + * @param value will be printed on error console + */ + public void printErrorString(final String value) { + this.error.println(value); + } +} diff --git a/module/src/main/java/com/iluwatar/module/FileLoggerModule.java b/module/src/main/java/com/iluwatar/module/FileLoggerModule.java new file mode 100644 index 000000000..e80444dab --- /dev/null +++ b/module/src/main/java/com/iluwatar/module/FileLoggerModule.java @@ -0,0 +1,114 @@ +/** + * 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.module; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintStream; + +import org.apache.log4j.Logger; + +/** + * The FileLoggerModule is responsible for showing logs on File System + *

+ * The below example demonstrates a File logger module, which can print simple and error messages in + * two designated files + */ +public final class FileLoggerModule { + + private static final Logger LOGGER = Logger.getLogger(FileLoggerModule.class); + + private static FileLoggerModule singleton = null; + + private static final String OUTPUT_FILE = "output.txt"; + private static final String ERROR_FILE = "error.txt"; + + public PrintStream output = null; + public PrintStream error = null; + + private FileLoggerModule() {} + + /** + * Static method to get single instance of class + * + * @return singleton instance of FileLoggerModule + */ + public static FileLoggerModule getSingleton() { + + if (FileLoggerModule.singleton == null) { + FileLoggerModule.singleton = new FileLoggerModule(); + } + + return FileLoggerModule.singleton; + } + + /** + * Following method performs the initialization + * + * @throws FileNotFoundException if program is not able to find log files (output.txt and + * error.txt) + */ + public FileLoggerModule prepare() throws FileNotFoundException { + + LOGGER.debug("FileLoggerModule::prepare();"); + + this.output = new PrintStream(new FileOutputStream(OUTPUT_FILE)); + this.error = new PrintStream(new FileOutputStream(ERROR_FILE)); + + return this; + } + + /** + * Following method performs the finalization + */ + public void unprepare() { + + if (this.output != null) { + + this.output.flush(); + this.output.close(); + } + + if (this.error != null) { + + this.error.flush(); + this.error.close(); + } + + LOGGER.debug("FileLoggerModule::unprepare();"); + } + + /** + * Used to print a message + * + * @param value will be printed in file + */ + public void printString(final String value) { + this.output.println(value); + } + + /** + * Used to print a error message + * + * @param value will be printed on error file + */ + public void printErrorString(final String value) { + this.error.println(value); + } +} diff --git a/module/src/main/resources/log4j.xml b/module/src/main/resources/log4j.xml new file mode 100644 index 000000000..b591c17e1 --- /dev/null +++ b/module/src/main/resources/log4j.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/module/src/test/java/com/iluwatar/module/AppTest.java b/module/src/test/java/com/iluwatar/module/AppTest.java new file mode 100644 index 000000000..5df6ab0f3 --- /dev/null +++ b/module/src/test/java/com/iluwatar/module/AppTest.java @@ -0,0 +1,37 @@ +/** + * 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.module; + +import java.io.FileNotFoundException; + +import com.iluwatar.module.App; + +import org.junit.Test; + +/** + * Tests that Module example runs without errors. + */ +public final class AppTest { + + @Test + public void test() throws FileNotFoundException { + final String[] args = {}; + App.main(args); + } +} diff --git a/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java b/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java new file mode 100644 index 000000000..7274aab14 --- /dev/null +++ b/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java @@ -0,0 +1,182 @@ +/** + * 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.module; + +import static org.junit.Assert.assertEquals; + +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; + +import org.apache.log4j.Logger; +import org.junit.Test; + +/** + * The Module pattern can be considered a Creational pattern and a Structural pattern. It manages + * the creation and organization of other elements, and groups them as the structural pattern does. + * An object that applies this pattern can provide the equivalent of a namespace, providing the + * initialization and finalization process of a static class or a class with static members with + * cleaner, more concise syntax and semantics. + *

+ * The below example demonstrates a JUnit test for testing two different modules: File Logger and + * Console Logger + */ +public final class FileLoggerModuleTest { + + private static final Logger LOGGER = Logger.getLogger(FileLoggerModuleTest.class); + + private static final String OUTPUT_FILE = "output.txt"; + private static final String ERROR_FILE = "error.txt"; + + private static final String MESSAGE = "MESSAGE"; + private static final String ERROR = "ERROR"; + + + /** + * This test verify that 'MESSAGE' is perfectly printed in output file + * + * @throws IOException if program is not able to find log files (output.txt and error.txt) + */ + @Test + public void testFileMessage() throws IOException { + + /* Get singletong instance of File Logger Module */ + final FileLoggerModule fileLoggerModule = FileLoggerModule.getSingleton(); + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + fileLoggerModule.prepare(); + + /* Print 'Message' in file */ + fileLoggerModule.printString(MESSAGE); + + /* Test if 'Message' is printed in file */ + assertEquals(readFirstLine(OUTPUT_FILE), MESSAGE); + + /* Unprepare to cleanup the modules */ + fileLoggerModule.unprepare(); + } + + /** + * This test verify that nothing is printed in output file + * + * @throws IOException if program is not able to find log files (output.txt and error.txt) + */ + @Test + public void testNoFileMessage() throws IOException { + + /* Get singletong instance of File Logger Module */ + final FileLoggerModule fileLoggerModule = FileLoggerModule.getSingleton(); + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + fileLoggerModule.prepare(); + + /* Test if nothing is printed in file */ + assertEquals(readFirstLine(OUTPUT_FILE), null); + + /* Unprepare to cleanup the modules */ + fileLoggerModule.unprepare(); + } + + /** + * This test verify that 'ERROR' is perfectly printed in error file + * + * @throws FileNotFoundException if program is not able to find log files (output.txt and + * error.txt) + */ + @Test + public void testFileErrorMessage() throws FileNotFoundException { + + /* Get singletong instance of File Logger Module */ + final FileLoggerModule fileLoggerModule = FileLoggerModule.getSingleton(); + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + fileLoggerModule.prepare(); + + /* Print 'Error' in file */ + fileLoggerModule.printErrorString(ERROR); + + /* Test if 'Message' is printed in file */ + assertEquals(readFirstLine(ERROR_FILE), ERROR); + + /* Unprepare to cleanup the modules */ + fileLoggerModule.unprepare(); + } + + /** + * This test verify that nothing is printed in error file + * + * @throws FileNotFoundException if program is not able to find log files (output.txt and + * error.txt) + */ + @Test + public void testNoFileErrorMessage() throws FileNotFoundException { + + /* Get singletong instance of File Logger Module */ + final FileLoggerModule fileLoggerModule = FileLoggerModule.getSingleton(); + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + fileLoggerModule.prepare(); + + /* Test if nothing is printed in file */ + assertEquals(readFirstLine(ERROR_FILE), null); + + /* Unprepare to cleanup the modules */ + fileLoggerModule.unprepare(); + } + + /** + * Utility method to read first line of a file + * + * @param file as file name to be read + * @return a string value as first line in file + */ + private static final String readFirstLine(final String file) { + + String firstLine = null; + BufferedReader bufferedReader = null; + try { + + /* Create a buffered reader */ + bufferedReader = new BufferedReader(new FileReader(file)); + + while (bufferedReader.ready()) { + + /* Read the line */ + firstLine = bufferedReader.readLine(); + } + + LOGGER.info("ModuleTest::readFirstLine() : firstLine : " + firstLine); + + } catch (final IOException e) { + LOGGER.error("ModuleTest::readFirstLine()", e); + } finally { + + if (bufferedReader != null) { + try { + bufferedReader.close(); + } catch (final IOException e) { + LOGGER.error("ModuleTest::readFirstLine()", e); + } + } + } + + return firstLine; + } +} diff --git a/pom.xml b/pom.xml index 06fcc9fe8..52f24a500 100644 --- a/pom.xml +++ b/pom.xml @@ -121,6 +121,7 @@ factory-kit feature-toggle value-object + module monad mute-idiom mutex