diff --git a/module/README.md b/module/README.md index d3d6b8746..24bd3f543 100644 --- a/module/README.md +++ b/module/README.md @@ -4,26 +4,22 @@ title: Module folder: module permalink: /patterns/module/ pumlid: JShB3OGm303HLg20nFVjnYGM1CN6ycTfVtFSsnjfzY5jPgUqkLqHwXy0mxUU8wuyqidQ8q4IjJqCO-QBWGOtVh5qyd5AKOmW4mT6Nu2-ZiAekapH_hkcSTNa-GC0 -categories: Persistence Tier +categories: Creational Pattern tags: - Java - Difficulty-Beginner --- ## Intent -A layer of mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself +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 is a design pattern used to implement the concept of software modules, defined by modular programming, in a programming language with incomplete direct support for the concept. - 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. -It supports specific cases where a class or object can be considered structured, procedural data. And, vice versa, migrate structured, procedural data, and considered as object-oriented. - ## 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/src/main/java/com/iluwatar/module/App.java b/module/src/main/java/com/iluwatar/module/App.java index 9dab6a00c..0ca43d5c2 100644 --- a/module/src/main/java/com/iluwatar/module/App.java +++ b/module/src/main/java/com/iluwatar/module/App.java @@ -35,23 +35,35 @@ import java.io.FileNotFoundException; */ public final class App { - private static final String OUTPUT_FILE = "output.txt"; - private static final String ERROR_FILE = "error.txt"; - - public static FilePrinterModule filePrinterModule = null; + public static FileLoggerModule fileLoggerModule = null; + public static ConsoleLoggerModule consoleLoggerModule = null; public static void prepare() throws FileNotFoundException { - filePrinterModule = FilePrinterModule.getSingleton(); + + fileLoggerModule = FileLoggerModule.getSingleton(); + consoleLoggerModule = ConsoleLoggerModule.getSingleton(); - filePrinterModule.prepare(OUTPUT_FILE, ERROR_FILE); + /* Prepare modules */ + fileLoggerModule.prepare(); + consoleLoggerModule.prepare(); } public static void unprepare() { - filePrinterModule.unprepare(); + + /* Close all resources */ + fileLoggerModule.unprepare(); + consoleLoggerModule.unprepare(); } public static final void execute(final String... args) { - filePrinterModule.printString("Hello World"); + + /* Send logs on file system */ + fileLoggerModule.printString("Message"); + fileLoggerModule.printErrorString("Error"); + + /* Send logs on console */ + consoleLoggerModule.printString("Message"); + consoleLoggerModule.printErrorString("Error"); } /** 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..097f85b0e --- /dev/null +++ b/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java @@ -0,0 +1,106 @@ +/** + * The MIT License Copyright (c) 2016 Amit Dixit + * + * 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.PrintStream; + +import org.apache.log4j.Logger; + +/** + * 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 Console logger module, which can print + * simple and error messages in two designated formats + */ +public 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() { + } + + public static final ConsoleLoggerModule getSingleton() { + + if (ConsoleLoggerModule.singleton == null) { + ConsoleLoggerModule.singleton = new ConsoleLoggerModule(); + } + + return ConsoleLoggerModule.singleton; + } + + /** + * + * @throws FileNotFoundException + */ + public final void prepare() { + + logger.debug("ConsoleLoggerModule::prepare();"); + + this.output = new PrintStream(System.out); + this.error = new PrintStream(System.err); + } + + /** + * + */ + public final 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();"); + } + + /** + * + * @param value + */ + public final void printString(final String value) { + this.output.println(value); + } + + /** + * + * @param value + */ + public final void printErrorString(final String value) { + this.error.println(value); + } +} diff --git a/module/src/main/java/com/iluwatar/module/FilePrinterModule.java b/module/src/main/java/com/iluwatar/module/FileLoggerModule.java similarity index 57% rename from module/src/main/java/com/iluwatar/module/FilePrinterModule.java rename to module/src/main/java/com/iluwatar/module/FileLoggerModule.java index 879492248..d1df062de 100644 --- a/module/src/main/java/com/iluwatar/module/FilePrinterModule.java +++ b/module/src/main/java/com/iluwatar/module/FileLoggerModule.java @@ -1,11 +1,3 @@ -package com.iluwatar.module; - -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.PrintStream; - -import org.apache.log4j.Logger; - /** * The MIT License Copyright (c) 2016 Amit Dixit * @@ -27,39 +19,60 @@ import org.apache.log4j.Logger; * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -public final class FilePrinterModule { +package com.iluwatar.module; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintStream; + +import org.apache.log4j.Logger; + +/** + * 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 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(FilePrinterModule.class); + .getLogger(FileLoggerModule.class); - private static FilePrinterModule singleton = null; + 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 FilePrinterModule() { + private FileLoggerModule() { } - public static final FilePrinterModule getSingleton() { + public static final FileLoggerModule getSingleton() { - if (FilePrinterModule.singleton == null) { - FilePrinterModule.singleton = new FilePrinterModule(); + if (FileLoggerModule.singleton == null) { + FileLoggerModule.singleton = new FileLoggerModule(); } - return FilePrinterModule.singleton; + return FileLoggerModule.singleton; } /** * * @throws FileNotFoundException */ - public final void prepare(final String outputFile, final String errorFile) - throws FileNotFoundException { + public final void prepare() throws FileNotFoundException { - logger.debug("MainModule::prepare();"); + logger.debug("FileLoggerModule::prepare();"); - this.output = new PrintStream(new FileOutputStream(outputFile)); - this.error = new PrintStream(new FileOutputStream(errorFile)); + this.output = new PrintStream(new FileOutputStream(OUTPUT_FILE)); + this.error = new PrintStream(new FileOutputStream(ERROR_FILE)); } /** @@ -79,7 +92,7 @@ public final class FilePrinterModule { this.error.close(); } - logger.debug("MainModule::unprepare();"); + logger.debug("FileLoggerModule::unprepare();"); } /** @@ -87,7 +100,7 @@ public final class FilePrinterModule { * @param value */ public final void printString(final String value) { - this.output.print(value); + this.output.println(value); } /** @@ -95,6 +108,6 @@ public final class FilePrinterModule { * @param value */ public final void printErrorString(final String value) { - this.error.print(value); + this.error.println(value); } } diff --git a/module/src/test/java/com/iluwatar/module/ModuleTest.java b/module/src/test/java/com/iluwatar/module/ModuleTest.java index 797e7f26a..cf3435850 100644 --- a/module/src/test/java/com/iluwatar/module/ModuleTest.java +++ b/module/src/test/java/com/iluwatar/module/ModuleTest.java @@ -24,19 +24,21 @@ import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; +import java.io.InputStreamReader; import org.apache.log4j.Logger; import org.junit.Test; /** - * The Data Mapper (DM) is a layer of software that separates the in-memory - * objects from the database. Its responsibility is to transfer data between the - * two and also to isolate them from each other. With Data Mapper the in-memory - * objects needn't know even that there's a database present; they need no SQL - * interface code, and certainly no knowledge of the database schema. (The - * database schema is always ignorant of the objects that use it.) Since it's a - * form of Mapper , Data Mapper itself is even unknown to the domain layer. + * 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 class ModuleTest { @@ -54,23 +56,23 @@ public class ModuleTest { * @throws IOException */ @Test - public void testPositiveMessage() throws IOException { + public void positiveTestConsoleMessage() throws IOException { /* Prepare the essential sub modules, to perform the sequence of jobs */ - final FilePrinterModule filePrinterModule = FilePrinterModule + final FileLoggerModule fileLoggerModule = FileLoggerModule .getSingleton(); /* Prepare the essential sub modules, to perform the sequence of jobs */ - filePrinterModule.prepare(OUTPUT_FILE, ERROR_FILE); + fileLoggerModule.prepare(); /* Print 'Message' in file */ - filePrinterModule.printString(MESSAGE); + fileLoggerModule.printString(MESSAGE); - /* Test if 'Message' is printed in file */ - assertEquals(readFirstLine(OUTPUT_FILE), MESSAGE); + /* Test if 'Message' is printed on console */ + assertEquals(readFirstLine(), MESSAGE); /* Unprepare to cleanup the modules */ - filePrinterModule.unprepare(); + fileLoggerModule.unprepare(); } /** @@ -79,20 +81,20 @@ public class ModuleTest { * @throws IOException */ @Test - public void testNegativeMessage() throws IOException { + public void negativeTestConsoleMessage() throws IOException { /* Prepare the essential sub modules, to perform the sequence of jobs */ - final FilePrinterModule filePrinterModule = FilePrinterModule + final ConsoleLoggerModule consoleLoggerModule = ConsoleLoggerModule .getSingleton(); /* Prepare the essential sub modules, to perform the sequence of jobs */ - filePrinterModule.prepare(OUTPUT_FILE, ERROR_FILE); + consoleLoggerModule.prepare(); - /* Test if nothing is printed in file */ - assertEquals(readFirstLine(OUTPUT_FILE), null); + /* Test if nothing is printed on console */ + assertEquals(readFirstLine(), null); /* Unprepare to cleanup the modules */ - filePrinterModule.unprepare(); + consoleLoggerModule.unprepare(); } /** @@ -101,23 +103,23 @@ public class ModuleTest { * @throws FileNotFoundException */ @Test - public void testPositiveErrorMessage() throws FileNotFoundException { + public void positiveTestConsoleErrorMessage() { /* Prepare the essential sub modules, to perform the sequence of jobs */ - final FilePrinterModule filePrinterModule = FilePrinterModule + final ConsoleLoggerModule consoleLoggerModule = ConsoleLoggerModule .getSingleton(); /* Prepare the essential sub modules, to perform the sequence of jobs */ - filePrinterModule.prepare(OUTPUT_FILE, ERROR_FILE); + consoleLoggerModule.prepare(); /* Print 'Error' in file */ - filePrinterModule.printErrorString(ERROR); + consoleLoggerModule.printErrorString(ERROR); - /* Test if 'Message' is printed in file */ - assertEquals(readFirstLine(ERROR_FILE), ERROR); + /* Test if 'Message' is printed on console */ + assertEquals(readFirstLine(), ERROR); /* Unprepare to cleanup the modules */ - filePrinterModule.unprepare(); + consoleLoggerModule.unprepare(); } /** @@ -126,20 +128,152 @@ public class ModuleTest { * @throws FileNotFoundException */ @Test - public void testNegativeErrorMessage() throws FileNotFoundException { + public void negativeTestConsoleErrorMessage() { /* Prepare the essential sub modules, to perform the sequence of jobs */ - final FilePrinterModule filePrinterModule = FilePrinterModule + final ConsoleLoggerModule consoleLoggerModule = ConsoleLoggerModule .getSingleton(); /* Prepare the essential sub modules, to perform the sequence of jobs */ - filePrinterModule.prepare(OUTPUT_FILE, ERROR_FILE); + consoleLoggerModule.prepare(); + + /* Test if nothing is printed on console */ + assertEquals(readFirstLine(), null); + + /* Unprepare to cleanup the modules */ + consoleLoggerModule.unprepare(); + } + + /** + * This test verify that 'MESSAGE' is perfectly printed in output file + * + * @throws IOException + */ + @Test + public void positiveTestFileMessage() throws IOException { + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + 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 + */ + @Test + public void negativeTestFileMessage() throws IOException { + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + 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 + */ + @Test + public void positiveTestFileErrorMessage() throws FileNotFoundException { + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + 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 + */ + @Test + public void negativeTestFileErrorMessage() throws FileNotFoundException { + + /* Prepare the essential sub modules, to perform the sequence of jobs */ + 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 */ - filePrinterModule.unprepare(); + fileLoggerModule.unprepare(); + } + + /** + * Utility method to read first line of a file + * + * @param file + * @return + */ + private static final String readFirstLine() { + + String firstLine = null; + BufferedReader bufferedReader = null; + try { + + /* Create a buffered reader */ + bufferedReader = new BufferedReader( + new InputStreamReader(System.in)); + + /* Read the line */ + firstLine = bufferedReader.readLine(); + + logger.info("ModuleTest::readFirstLineFromConsole() : firstLine : " + + firstLine); + + } catch (final IOException e) { + logger.error("ModuleTest::readFirstLineFromConsole()", e); + } finally { + + if (bufferedReader != null) { + try { + bufferedReader.close(); + } catch (final IOException e) { + logger.error("ModuleTest::readFirstLineFromConsole()", e); + } + } + } + + return firstLine; } /** @@ -160,17 +294,18 @@ public class ModuleTest { /* Read the line */ firstLine = bufferedReader.readLine(); - logger.info("ModuleTest::readFile() : firstLine : " + firstLine); + logger.info("ModuleTest::readFirstLine() : firstLine : " + + firstLine); } catch (final IOException e) { - logger.error("ModuleTest::readFile()", e); + logger.error("ModuleTest::readFirstLine()", e); } finally { if (bufferedReader != null) { try { bufferedReader.close(); } catch (final IOException e) { - logger.error("ModuleTest::readFile()", e); + logger.error("ModuleTest::readFirstLine()", e); } } }