diff --git a/.gitignore b/.gitignore
index bd55eacaf..589d3fb13 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,4 +11,9 @@ target
.idea
*.iml
*.swp
+datanucleus.log
+/bin/
+/bin/
+/bin/
+data-mapper/src/main/resources/log4j.xml
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 0bd0f0595..deb436cd2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,12 +1,18 @@
language: java
-
jdk:
- - oraclejdk8
+- oraclejdk8
-# whitelist
-branches:
- only:
- - master
+env:
+ global:
+ - GH_REF: github.com/iluwatar/java-design-patterns.git
+ - secure: LxTDuNS/rBWIvKkaEqr79ImZAe48mCdoYCF41coxNXgNoippo4GIBArknqtv+XvdkiuRZ1yGyj6pn8GU33c/yn+krddTUkVCwTbVatbalW5jhQjDbHYym/JcxaK9ZS/3JTeGcWrBgiPqHEEDhCf26vPZsXoMSeVCEORVKTp1BSg=
+
+before_install:
+- export DISPLAY=:99.0
+- sh -e /etc/init.d/xvfb start
after_success:
- - mvn clean test jacoco:report coveralls:report
\ No newline at end of file
+- mvn clean test jacoco:report coveralls:report
+- bash update-ghpages.sh
+
+sudo: false # route the build to the container-based infrastructure for a faster build
diff --git a/CODE_COVERAGE.md b/CODE_COVERAGE.md
new file mode 100644
index 000000000..589c7ad79
--- /dev/null
+++ b/CODE_COVERAGE.md
@@ -0,0 +1,13 @@
+# Code Coverage Report generation
+
+To generate the code coverage report, execute the following command:
+> mvn clean verify
+
+This will generate code coverage report in each of the modules. In order to view the same, open the following file in your browser.
+> target/site/jacoco/index.html
+
+Please note that the above folder is created under each of the modules. For example:
+* adapter/target/site/jacoco/index.html
+* busniess-delegate/target/site/jacoco/index.html
+
+
diff --git a/CONTRIBUTING.MD b/CONTRIBUTING.MD
new file mode 100644
index 000000000..39087fbf1
--- /dev/null
+++ b/CONTRIBUTING.MD
@@ -0,0 +1,4 @@
+This is great you have something to contribute!
+
+Before going any further please read the [wiki](https://github.com/iluwatar/java-design-patterns/wiki)
+with conventions and rules we used for this project.
diff --git a/LICENSE.md b/LICENSE.md
index d1f75f80a..e73cf6618 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2014 Ilkka Seppälä
+Copyright (c) 2014-2016 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
diff --git a/README.md b/README.md
index 59312ea84..811d6a17a 100644
--- a/README.md
+++ b/README.md
@@ -1,738 +1,46 @@
-# Design pattern samples in Java.
+
-## Build status, coverage and static analysis:
+# Design patterns implemented in Java
- [](https://coveralls.io/r/iluwatar/java-design-patterns?branch=master)
-
-
+[](https://travis-ci.org/iluwatar/java-design-patterns)
+[](https://coveralls.io/r/iluwatar/java-design-patterns?branch=master)
+[](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)
+[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-## Introduction
+# Introduction
-Design patterns are formalized best practices that the programmer can use to solve common problems when designing an application or system.
+Design patterns are formalized best practices that the programmer can use to
+solve common problems when designing an application or system.
-Design patterns can speed up the development process by providing tested, proven development paradigms.
+Design patterns can speed up the development process by providing tested, proven
+development paradigms.
-Reusing design patterns helps to prevent subtle issues that can cause major problems, and it also improves code readability for coders and architects who are familiar with the patterns.
+Reusing design patterns helps to prevent subtle issues that can cause major
+problems, and it also improves code readability for coders and architects who
+are familiar with the patterns.
-## List of Design Patterns
+# Getting started
-### Creational Patterns
+Before you dive into the material, you should be familiar with various
+[Programming/Software Design Principles](http://webpro.github.io/programming-principles/).
-Creational design patterns abstract the instantiation process. They help make a system independent of how its objects are created, composed, and represented.
-
-* [Abstract Factory](#abstract-factory)
-* [Builder](#builder)
-* [Factory Method](#factory-method)
-* [Prototype](#prototype)
-* [Property](#property)
-* [Singleton](#singleton)
-* [Multiton](#multiton)
-* [Object Pool](#object-pool)
-
-### Structural Patterns
-
-Structural patterns are concerned with how classes and objects are composed to form larger structures.
-
-* [Adapter](#adapter)
-* [Bridge](#bridge)
-* [Composite](#composite)
-* [Decorator](#decorator)
-* [Facade](#facade)
-* [Flyweight](#flyweight)
-* [Proxy](#proxy)
-* [Service Locator](#service-locator)
-* [Servant](#servant)
-* [Event Aggregator](#event-aggregator)
-
-### Behavioral Patterns
-
-Behavioral patterns are concerned with algorithms and the assignment of responsibilites between objects.
-
-* [Chain of responsibility](#chain-of-responsibility)
-* [Command](#command)
-* [Interpreter](#interpreter)
-* [Iterator](#iterator)
-* [Mediator](#mediator)
-* [Memento](#memento)
-* [Observer](#observer)
-* [State](#state)
-* [Strategy](#strategy)
-* [Template method](#template-method)
-* [Visitor](#visitor)
-* [Null Object](#null-object)
-* [Intercepting Filter](#intercepting-filter)
-* [Specification](#specification)
-* [Dependency Injection](#dependency-injection)
-
-### Concurrency Patterns
-
-Concurrency patterns are those types of design patterns that deal with the multi-threaded programming paradigm.
-
-* [Double Checked Locking](#double-checked-locking)
-* [Thread Pool](#thread-pool)
-
-### Presentation Tier Patterns
-
-Presentation Tier patterns are the top-most level of the application, this is concerned with translating tasks and results to something the user can understand.
-
-* [Model-View-Controller](#model-view-controller)
-* [Model-View-Presenter](#model-view-presenter)
-* [Flux](#flux)
-
-### Architectural Patterns
-
-An architectural pattern is a general, reusable solution to a commonly occurring problem in software architecture within a given context.
-
-* [Data Access Object](#dao)
-* [Service Layer](#service-layer)
-
-### Integration Patterns
-
-Integration patterns are concerned with how software applications communicate and exchange data.
-
-* [Tolerant Reader](#tolerant-reader)
-
-### Idioms
-
-A programming idiom is a means of expressing a recurring construct in one or more programming languages. Generally speaking, a programming idiom is an expression of a simple task, algorithm, or data structure that is not a built-in feature in the programming language being used, or, conversely, the use of an unusual or notable feature that is built into a programming language. What distinguishes idioms from patterns is generally the size, the idioms tend to be something small while the patterns are larger.
-
-* [Execute Around](#execute-around)
-* [Poison Pill](#poison-pill)
-* [Callback](#callback)
-* [Lazy Loading](#lazy-loading)
-* [Double Dispatch](#double-dispatch)
-* [Resource Acquisition Is Initialization](#resource-acquisition-is-initialization)
-* [Private Class Data](#private-class-data)
-
-## Abstract Factory [↑](#list-of-design-patterns)
-**Intent:** Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
-
-
-
-**Applicability:** Use the Abstract Factory pattern when
-* a system should be independent of how its products are created, composed and represented
-* a system should be configured with one of multiple families of products
-* a family of related product objects is designed to be used together, and you need to enforce this constraint
-* you want to provide a class library of products, and you want to reveal just their interfaces, not their implementations
-
-**Real world examples:**
-* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
-
-## Builder [↑](#list-of-design-patterns)
-**Intent:** Separate the construction of a complex object from its representation so that the same construction process can create different representations.
-
-
-
-**Applicability:** Use the Builder pattern when
-* the algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled
-* the construction process must allow different representations for the object that's constructed
-
-**Real world examples:**
-* [java.lang.StringBuilder](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html)
-* [Apache Camel builders](https://github.com/apache/camel/tree/0e195428ee04531be27a0b659005e3aa8d159d23/camel-core/src/main/java/org/apache/camel/builder)
-
-## Factory Method [↑](#list-of-design-patterns)
-**Intent:** Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
-
-
-
-**Applicability:** Use the Factory Method pattern when
-* a class can't anticipate the class of objects it must create
-* a class wants its subclasses to specify the objects it creates
-* classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate
-
-## Prototype [↑](#list-of-design-patterns)
-**Intent:** Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
-
-
-
-**Applicability:** Use the Prototype pattern when a system should be independent of how its products are created, composed and represented; and
-* when the classes to instantiate are specified at run-time, for example, by dynamic loading; or
-* to avoid building a class hierarchy of factories that parallels the class hierarchy of products; or
-* when instances of a class can have one of only a few different combinations of state. It may be more convenient to install a corresponding number of prototypes and clone them rather than instantiating the class manually, each time with the appropriate state
-
-**Real world examples:**
-* [java.lang.Object#clone()](http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#clone%28%29)
-
-## Singleton [↑](#list-of-design-patterns)
-**Intent:** Ensure a class only has one instance, and provide a global point of access to it.
-
-
-
-**Applicability:** Use the Singleton pattern when
-* there must be exactly one instance of a class, and it must be accessible to clients from a well-known access point
-* when the sole instance should be extensible by subclassing, and clients should be able to use an extended instance without modifying their code
-
-**Typical Use Case:**
-* the logging class
-* managing a connection to a database
-* file manager
-
-**Real world examples:**
-* [java.lang.Runtime#getRuntime()](http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#getRuntime%28%29)
-
-## Adapter [↑](#list-of-design-patterns)
-**Intent:** Convert the interface of a class into another interface the clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
-
-
-
-**Applicability:** Use the Adapter pattern when
-* you want to use an existing class, and its interface does not match the one you need
-* you want to create a reusable class that cooperates with unrelated or unforeseen classes, that is, classes that don't necessarily have compatible interfaces
-* you need to use several existing subclasses, but it's impractical to adapt their interface by subclassing every one. An object adapter can adapt the interface of its parent class.
-
-**Real world examples:**
-* [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29)
-
-## Bridge [↑](#list-of-design-patterns)
-**Intent:** Decouple an abstraction from its implementation so that the two can vary independently.
-
-
-
-
-**Applicability:** Use the Bridge pattern when
-* you want to avoid a permanent binding between an abstraction and its implementation. This might be the case, for example, when the implementation must be selected or switched at run-time.
-* both the abstractions and their implementations should be extensible by subclassing. In this case, the Bridge pattern lets you combine the different abstractions and implementations and extend them independently
-* changes in the implementation of an abstraction should have no impact on clients; that is, their code should not have to be recompiled.
-* you have a proliferation of classes. Such a class hierarchy indicates the need for splitting an object into two parts. Rumbaugh uses the term "nested generalizations" to refer to such class hierarchies
-* you want to share an implementation among multiple objects (perhaps using reference counting), and this fact should be hidden from the client. A simple example is Coplien's String class, in which multiple objects can share the same string representation.
-
-## Composite [↑](#list-of-design-patterns)
-**Intent:** Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
-
-
-
-**Applicability:** Use the Composite pattern when
-* you want to represent part-whole hierarchies of objects
-* you want clients to be able to ignore the difference between compositions of objects and individual objects. Clients will treat all objects in the composite structure uniformly
-
-**Real world examples:**
-* [java.awt.Container](http://docs.oracle.com/javase/8/docs/api/java/awt/Container.html) and [java.awt.Component](http://docs.oracle.com/javase/8/docs/api/java/awt/Component.html)
-* [Apache Wicket](https://github.com/apache/wicket) component tree, see [Component](https://github.com/apache/wicket/blob/91e154702ab1ff3481ef6cbb04c6044814b7e130/wicket-core/src/main/java/org/apache/wicket/Component.java) and [MarkupContainer](https://github.com/apache/wicket/blob/b60ec64d0b50a611a9549809c9ab216f0ffa3ae3/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java)
-
-## Decorator [↑](#list-of-design-patterns)
-**Intent:** Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
-
-
-
-**Applicability:** Use Decorator
-* to add responsibilities to individual objects dynamically and transparently, that is, without affecting other objects
-* for responsibilities that can be withdrawn
-* when extension by subclassing is impractical. Sometimes a large number of independent extensions are possible and would produce an explosion of sublasses to support every combination. Or a class definition may be hidden or otherwise unavailable for subclassing
-
-## Facade [↑](#list-of-design-patterns)
-**Intent:** Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use.
-
-
-
-**Applicability:** Use the Facade pattern when
-* you want to provide a simple interface to a complex subsystem. Subsystems often get more complex as they evolve. Most patterns, when applied, result in more and smaller classes. This makes the subsystem more reusable and easier to customize, but it also becomes harder to use for clients that don't need to customize it. A facade can provide a simple default view of the subsystem that is good enough for most clients. Only clients needing more customizability will need to look beyond the facade.
-* there are many dependencies between clients and the implementation classes of an abstraction. Introduce a facade to decouple the subsystem from clients and other subsystems, thereby promoting subsystem independence and portability.
-* you want to layer your subsystems. Use a facade to define an entry point to each subsystem level. If subsystems are dependent, the you can simplify the dependencies between them by making them communicate with each other solely through their facades
-
-## Flyweight [↑](#list-of-design-patterns)
-**Intent:** Use sharing to support large numbers of fine-grained objects efficiently.
-
-
-
-**Applicability:** The Flyweight pattern's effectiveness depends heavily on how and where it's used. Apply the Flyweight pattern when all of the following are true
-* an application uses a large number of objects
-* storage costs are high because of the sheer quantity of objects
-* most object state can be made extrinsic
-* many groups of objects may be replaced by relatively few shared objects once extrinsic state is removed
-* the application doesn't depend on object identity. Since flyweight objects may be shared, identity tests will return true for conceptually distinct objects.
-
-**Real world examples:**
-* [java.lang.Integer#valueOf(int)](http://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#valueOf%28int%29)
-
-## Proxy [↑](#list-of-design-patterns)
-**Intent:** Provide a surrogate or placeholder for another object to control access to it.
-
-
-
-**Applicability:** Proxy is applicable whenever there is a need for a more versatile or sophisticated reference to an object than a simple pointer. Here are several common situations in which the Proxy pattern is applicable
-
-* a remote proxy provides a local representative for an object in a different address space.
-* a virtual proxy creates expensive objects on demand.
-* a protection proxy controls access to the original object. Protection proxies are useful when objects should have different access rights.
-
-**Typical Use Case:**
-
-* Control access to another object
-* Lazy initialization
-* implement logging
-* facilitate network connection
-* to count references to an object
-
-**Real world examples:**
-* [java.lang.reflect.Proxy](http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Proxy.html)
-* [Apache Commons Proxy](https://commons.apache.org/proper/commons-proxy/)
-
-## Service Locator [↑](#list-of-design-patterns)
-**Intent:** Encapsulate the processes involved in obtaining a service with a strong abstraction layer.
-
-
-
-**Applicability:** The service locator pattern is applicable whenever we want to locate/fetch various services using JNDI which, typically, is a redundant and expensive lookup. The service Locator pattern addresses this expensive lookup by making use of caching techniques ie. for the very first time a particular service is requested, the service Locator looks up in JNDI, fetched the relavant service and then finally caches this service object. Now, further lookups of the same service via Service Locator is done in its cache which improves the performance of application to great extent.
-
-**Typical Use Case:**
-
-* When network hits are expensive and time consuming
-* lookups of services are done quite frequently
-* large number of services are being used
-
-## Chain of responsibility [↑](#list-of-design-patterns)
-**Intent:** Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
-
-
-
-**Applicability:** Use Chain of Responsibility when
-* more than one object may handle a request, and the handler isn't known a priori. The handler should be ascertained automatically
-* you want to issue a request to one of several objects without specifying the receiver explicitly
-* the set of objects that can handle a request should be specified dynamically
-
-**Real world examples:**
-* [java.util.logging.Logger#log()](http://docs.oracle.com/javase/8/docs/api/java/util/logging/Logger.html#log%28java.util.logging.Level,%20java.lang.String%29)
-* [Apache Commons Chain](https://commons.apache.org/proper/commons-chain/index.html)
-
-## Command [↑](#list-of-design-patterns)
-**Intent:** Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
-
-
-
-**Applicability:** Use the Command pattern when you want to
-
-* parameterize objects by an action to perform. You can express such parameterization in a procedural language with a callback function, that is, a function that's registered somewhere to be called at a later point. Commands are an object-oriented replacement for callbacks.
-* specify, queue, and execute requests at different times. A Command object can have a lifetime independent of the original request. If the receiver of a request can be represented in an address space-independent way, then you can transfer a command object for the request to a different process and fulfill the request there
-* support undo. The Command's execute operation can store state for reversing its effects in the command itself. The Command interface must have an added Unexecute operation that reverses the effects of a previous call to execute. Executed commands are stored in a history list. Unlimited-level undo and redo is achieved by traversing this list backwards and forwards calling unexecute and execute, respectively
-* support logging changes so that they can be reapplied in case of a system crash. By augmenting the Command interface with load and store operations, you can keep a persistent log of changes. Recovering from a crash involves reloading logged commands from disk and re-executing them with the execute operation
-* structure a system around high-level operations build on primitive operations. Such a structure is common in information systems that support transactions. A transaction encapsulates a set of changes to data. The Command pattern offers a way to model transactions. Commands have a common interface, letting you invoke all transactions the same way. The pattern also makes it easy to extend the system with new transactions
-
-**Typical Use Case:**
-
-* to keep a history of requests
-* implement callback functionality
-* implement the undo functionality
-
-**Real world examples:**
-* [java.lang.Runnable](http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html)
-
-## Interpreter [↑](#list-of-design-patterns)
-**Intent:** Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
-
-
-
-**Applicability:** Use the Interpreter pattern when there is a language to interpret, and you can represent statements in the language as abstract syntax trees. The Interpreter pattern works best when
-* the grammar is simple. For complex grammars, the class hierarchy for the grammar becomes large and unmanageable. Tools such as parser generators are a better alternative in such cases. They can interpret expressions without building abstract syntax trees, which can save space and possibly time
-* efficiency is not a critical concern. The most efficient interpreters are usually not implemented by interpreting parse trees directly but by first translating them into another form. For example, regular expressions are often transformed into state machines. But even then, the translator can be implemented by the Interpreter pattern, so the pattern is still applicable
-
-## Iterator [↑](#list-of-design-patterns)
-**Intent:** Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
-
-
-
-**Applicability:** Use the Iterator pattern
-* to access an aggregate object's contents without exposing its internal representation
-* to support multiple traversals of aggregate objects
-* to provide a uniform interface for traversing different aggregate structures
-
-**Real world examples:**
-* [java.util.Iterator](http://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html)
-
-## Mediator [↑](#list-of-design-patterns)
-**Intent:** Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
-
-
-
-**Applicability:** Use the Mediator pattern when
-* a set of objects communicate in well-defined but complex ways. The resulting interdependencies are unstructured and difficult to understand
-* reusing an object is difficult because it refers to and communicates with many other objects
-* a behavior that's distributed between several classes should be customizable without a lot of subclassing
-
-## Memento [↑](#list-of-design-patterns)
-**Intent:** Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.
-
-
-
-**Applicability:** Use the Memento pattern when
-* a snapshot of an object's state must be saved so that it can be restored to that state later, and
-* a direct interface to obtaining the state would expose implementation details and break the object's encapsulation
-
-**Real world examples:**
-* [java.util.Date](http://docs.oracle.com/javase/8/docs/api/java/util/Date.html)
-
-## Observer [↑](#list-of-design-patterns)
-**Intent:** Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
-
-
-
-**Applicability:** Use the Observer pattern in any of the following situations
-
-* when an abstraction has two aspects, one dependent on the other. Encapsulating these aspects in separate objects lets you vary and reuse them independently
-* when a change to one object requires changing others, and you don't know how many objects need to be changed
-* when an object should be able to notify other objects without making assumptions about who these objects are. In other words, you don't want these objects tightly coupled
-
-**Typical Use Case:**
-
-* changing in one object leads to a change in other objects
-
-**Real world examples:**
-* [java.util.Observer](http://docs.oracle.com/javase/8/docs/api/java/util/Observer.html)
-
-## State [↑](#list-of-design-patterns)
-**Intent:** Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
-
-
-
-**Applicability:** Use the State pattern in either of the following cases
-* an object's behavior depends on its state, and it must change its behavior at run-time depending on that state
-* operations have large, multipart conditional statements that depend on the object's state. This state is usually represented by one or more enumerated constants. Often, several operations will contain this same conditional structure. The State pattern puts each branch of the conditional in a separate class. This lets you treat the object's state as an object in its own right that can vary independently from other objects.
-
-## Strategy [↑](#list-of-design-patterns)
-**Intent:** Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
-
-
-
-**Applicability:** Use the Strategy pattern when
-* many related classes differ only in their behavior. Strategies provide a way to configure a class either one of many behaviors
-* you need different variants of an algorithm. for example, you might define algorithms reflecting different space/time trade-offs. Strategies can be used when these variants are implemented as a class hierarchy of algorithms
-* an algorithm uses data that clients shouldn't know about. Use the Strategy pattern to avoid exposing complex, algorithm-specific data structures
-* a class defines many behaviors, and these appear as multiple conditional statements in its operations. Instead of many conditionals, move related conditional branches into their own Strategy class
-
-## Template method [↑](#list-of-design-patterns)
-**Intent:** Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
-
-
-
-**Applicability:** The Template Method pattern should be used
-* to implement the invariant parts of an algorithm once and leave it up to subclasses to implement the behavior that can vary
-* when common behavior among subclasses should be factored and localized in a common class to avoid code duplication. This is good example of "refactoring to generalize" as described by Opdyke and Johnson. You first identify the differences in the existing code and then separate the differences into new operations. Finally, you replace the differing code with a template method that calls one of these new operations
-* to control subclasses extensions. You can define a template method that calls "hook" operations at specific points, thereby permitting extensions only at those points
-
-## Visitor [↑](#list-of-design-patterns)
-**Intent:** Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.
-
-
-
-**Applicability:** Use the Visitor pattern when
-* an object structure contains many classes of objects with differing interfaces, and you want to perform operations on these objects that depend on their concrete classes
-* many distinct and unrelated operations need to be performed on objects in an object structure, and you want to avoid "polluting" their classes with these operations. Visitor lets you keep related operations together by defining them in one class. When the object structure is shared by many applications, use Visitor to put operations in just those applications that need them
-* the classes defining the object structure rarely change, but you often want to define new operations over the structure. Changing the object structure classes requires redefining the interface to all visitors, which is potentially costly. If the object structure classes change often, then it's probably better to define the operations in those classes
-
-**Real world examples:**
-* [Apache Wicket](https://github.com/apache/wicket) component tree, see [MarkupContainer](https://github.com/apache/wicket/blob/b60ec64d0b50a611a9549809c9ab216f0ffa3ae3/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java)
-
-## Model-View-Presenter [↑](#list-of-design-patterns)
-**Intent:** Apply a "Separation of Concerns" principle in a way that allows developers to build and test user interfaces.
-
-
-
-**Applicability:** Use the Model-View-Presenter in any of the following situations
-* when you want to improve the "Separation of Concerns" principle in presentation logic
-* when a user interface development and testing is necessary.
-
-## Data Access Object [↑](#list-of-design-patterns)
-**Intent:** Object provides an abstract interface to some type of database or other persistence mechanism.
-
-
-
-**Applicability:** Use the Data Access Object in any of the following situations
-* when you want to consolidate how the data layer is accessed
-* when you want to avoid writing multiple data retrieval/persistence layers
-
-## Double Checked Locking [↑](#list-of-design-patterns)
-**Intent:** Reduce the overhead of acquiring a lock by first testing the locking criterion (the "lock hint") without actually acquiring the lock. Only if the locking criterion check indicates that locking is required does the actual locking logic proceed.
-
-
-
-**Applicability:** Use the Double Checked Locking pattern when
-* there is a concurrent access in object creation, e.g. singleton, where you want to create single instance of the same class and checking if it's null or not maybe not be enough when there are two or more threads that checks if instance is null or not.
-* there is a concurrent access on a method where method's behaviour changes according to the some constraints and these constraint change within this method.
-
-## Servant [↑](#list-of-design-patterns)
-**Intent:** Servant is used for providing some behavior to a group of classes. Instead of defining that behavior in each class - or when we cannot factor out this behavior in the common parent class - it is defined once in the Servant.
-
-
-
-**Applicability:** Use the Servant pattern when
-* When we want some objects to perform a common action and don't want to define this action as a method in every class.
-
-## Null Object [↑](#list-of-design-patterns)
-**Intent:** In most object-oriented languages, such as Java or C#, references may be null. These references need to be checked to ensure they are not null before invoking any methods, because methods typically cannot be invoked on null references. Instead of using a null reference to convey absence of an object (for instance, a non-existent customer), one uses an object which implements the expected interface, but whose method body is empty. The advantage of this approach over a working default implementation is that a Null Object is very predictable and has no side effects: it does nothing.
-
-
-
-**Applicability:** Use the Null Object pattern when
-* You want to avoid explicit null checks and keep the algorithm elegant and easy to read.
-
-## Event Aggregator [↑](#list-of-design-patterns)
-**Intent:** A system with lots of objects can lead to complexities when a client wants to subscribe to events. The client has to find and register for each object individually, if each object has multiple events then each event requires a separate subscription. An Event Aggregator acts as a single source of events for many objects. It registers for all the events of the many objects allowing clients to register with just the aggregator.
-
-
-
-**Applicability:** Use the Event Aggregator pattern when
-* Event Aggregator is a good choice when you have lots of objects that are potential event sources. Rather than have the observer deal with registering with them all, you can centralize the registration logic to the Event Aggregator. As well as simplifying registration, a Event Aggregator also simplifies the memory management issues in using observers.
-
-## Callback [↑](#list-of-design-patterns)
-**Intent:** Callback is a piece of executable code that is passed as an argument to other code, which is expected to call back (execute) the argument at some convenient time.
-
-
-
-**Applicability:** Use the Callback pattern when
-* When some arbitrary synchronous or asynchronous action must be performed after execution of some defined activity.
-
-**Real world examples:**
-* [CyclicBarrier] (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html#CyclicBarrier%28int,%20java.lang.Runnable%29) constructor can accept callback that will be triggered every time when barrier is tripped.
-
-## Intercepting Filter [↑](#list-of-design-patterns)
-**Intent:** Provide pluggable filters to conduct necessary pre-processing and post-processing to requests from a client to a target
-
-
-
-**Applicability:** Use the Intercepting Filter pattern when
-* a system uses pre-processing or post-processing requests
-* a system should do the authentication/ authorization/ logging or tracking of request and then pass the requests to corresponding handlers
-* you want a modular approach to configuring pre-processing and post-processing schemes
-
-## Execute Around [↑](#list-of-design-patterns)
-**Intent:** Execute Around idiom frees the user from certain actions that should always be executed before and after the business method. A good example of this is resource allocation and deallocation leaving the user to specify only what to do with the resource.
-
-
-
-**Applicability:** Use the Execute Around idiom when
-* You use an API that requires methods to be called in pairs such as open/close or allocate/deallocate.
-
-## Property [↑](#list-of-design-patterns)
-**Intent:** Create hierarchy of objects and new objects using already existing objects as parents.
-
-
-
-**Applicability:** Use the Property pattern when
-* when you like to have objects with dynamic set of fields and prototype inheritance
-
-**Real world examples:**
-* [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) prototype inheritance
-
-## Poison Pill [↑](#list-of-design-patterns)
-**Intent:** Poison Pill is known predefined data item that allows to provide graceful shutdown for separate distributed consumption process.
-
-
-
-**Applicability:** Use the Poison Pill idiom when
-* need to send signal from one thread/process to another to terminate
-
-**Real world examples:**
-* [akka.actor.PoisonPill](http://doc.akka.io/docs/akka/2.1.4/java/untyped-actors.html)
-
-## Lazy Loading [↑](#list-of-design-patterns)
-**Intent:** Lazy loading is a design pattern commonly used to defer initialization of an object until the point at which it is needed. It can contribute to efficiency in the program's operation if properly and appropriately used.
-
-
-
-**Applicability:** Use the Lazy Loading idiom when
-* eager loading is expensive or the object to be loaded might not be needed at all
-
-**Real world examples:**
-* JPA annotations @OneToOne, @OneToMany, @ManyToOne, @ManyToMany and fetch = FetchType.LAZY
-
-## Service Layer [↑](#list-of-design-patterns)
-**Intent:** Service Layer is an abstraction over domain logic. Typically applications require multiple kinds of interfaces to the data
-they store and logic they implement: data loaders, user interfaces, integration gateways, and others. Despite their different purposes, these interfaces often need common interactions with the application to access and manipulate its data and invoke its business logic. The Service Layer fulfills this role.
-
-
-
-**Applicability:** Use the Service Layer pattern when
-* you want to encapsulate domain logic under API
-* you need to implement multiple interfaces with common logic and data
-
-## Specification [↑](#list-of-design-patterns)
-**Intent:** Specification pattern separates the statement of how to match a candidate, from the
-candidate object that it is matched against. As well as its usefulness in selection, it is also valuable for
-validation and for building to order
-
-
-
-**Applicability:** Use the Specification pattern when
-* You need to select a subset of objects based on some criteria, and to refresh the selection at various times
-* You need to check that only suitable objects are used for a certain role (validation)
-
-## Tolerant Reader [↑](#list-of-design-patterns)
-**Intent:** Tolerant Reader is an integration pattern that helps creating robust communication systems. The idea is to be as tolerant as possible when reading data from another service. This way, when the communication schema changes, the readers must not break.
-
-
-
-**Applicability:** Use the Tolerant Reader pattern when
-* The communication schema can evolve and change and yet the receiving side should not break
-
-## Model-View-Controller [↑](#list-of-design-patterns)
-**Intent:** Separate the user interface into three interconnected components: the model, the view and the controller. Let the model manage the data, the view display the data and the controller mediate updating the data and redrawing the display.
-
-
-
-**Applicability:** Use the Model-View-Controller pattern when
-* you want to clearly separate the domain data from its user interface representation
-
-## Flux [↑](#list-of-design-patterns)
-**Intent:** Flux eschews MVC in favor of a unidirectional data flow. When a user interacts with a view, the view propagates an action through a central dispatcher, to the various stores that hold the application's data and business logic, which updates all of the views that are affected.
-
-
-
-**Applicability:** Use the Flux pattern when
-* You want to focus on creating explicit and understandable update paths for your application's data, which makes tracing changes during development simpler and makes bugs easier to track down and fix.
-
-## Double Dispatch [↑](#list-of-design-patterns)
-**Intent:** Double Dispatch pattern is a way to create maintainable dynamic behavior based on receiver and parameter types.
-
-
-
-**Applicability:** Use the Double Dispatch pattern when
-* The dynamic behavior is not defined only based on receiving object's type but also on the receiving method's parameter type.
-
-**Real world examples:**
-* [ObjectOutputStream](https://docs.oracle.com/javase/8/docs/api/java/io/ObjectOutputStream.html)
-
-## Multiton [↑](#list-of-design-patterns)
-**Intent:** Ensure a class only has limited number of instances, and provide a global point of access to them.
-
-
-
-**Applicability:** Use the Multiton pattern when
-* there must be specific number of instances of a class, and they must be accessible to clients from a well-known access point
-
-## Resource Acquisition Is Initialization [↑](#list-of-design-patterns)
-**Intent:** Resource Acquisition Is Initialization pattern can be used to implement exception safe resource management.
-
-
-
-**Applicability:** Use the Resource Acquisition Is Initialization pattern when
-* You have resources that must be closed in every condition
-
-## Thread Pool [↑](#list-of-design-patterns)
-**Intent:** It is often the case that tasks to be executed are short-lived and the number of tasks is large. Creating a new thread for each task would make the system spend more time creating and destroying the threads than executing the actual tasks. Thread Pool solves this problem by reusing existing threads and eliminating the latency of creating new threads.
-
-
-
-**Applicability:** Use the Thread Pool pattern when
-* You have a large number of short-lived tasks to be executed in parallel
-
-## Private Class Data [↑](#list-of-design-patterns)
-**Intent:** Private Class Data design pattern seeks to reduce exposure of attributes by limiting their visibility. It reduces the number of class attributes by encapsulating them in single Data object.
-
-
-
-**Applicability:** Use the Private Class Data pattern when
-* You want to prevent write access to class data members
-
-## Object Pool [↑](#list-of-design-patterns)
-**Intent:** When objects are expensive to create and they are needed only for short periods of time it is advantageous to utilize the Object Pool pattern. The Object Pool provides a cache for instantiated objects tracking which ones are in use and which are available.
-
-
-
-**Applicability:** Use the Object Pool pattern when
-* The objects are expensive to create (allocation cost)
-* You need a large number of short-lived objects (memory fragmentation)
-
-## Dependency Injection [↑](#list-of-design-patterns)
-**Intent:** Dependency Injection is a software design pattern in which one or more dependencies (or services) are injected, or passed by reference, into a dependent object (or client) and are made part of the client's state. The pattern separates the creation of a client's dependencies from its own behavior, which allows program designs to be loosely coupled and to follow the inversion of control and single responsibility principles.
-
-
-
-**Applicability:** Use the Dependency Injection pattern when
-* When you need to remove knowledge of concrete implementation from object
-* To enable unit testing of classes in isolation using mock objects or stubs
-
-
-
-# Frequently asked questions
-
-**Q: What is the difference between State and Strategy patterns? **
-
-While the implementation is similar they solve different problems. The State pattern deals with what state an object is in - it encapsulates state-dependent behavior. The Strategy pattern deals with how an object performs a certain task - it encapsulates an algorithm.
-
-**Q: What is the difference between Strategy and Template Method patterns? **
-
-In Template Method the algorithm is chosen at compile time via inheritance. With Strategy pattern the algorithm is chosen at runtime via composition.
-
-**Q: What is the difference between Proxy and Decorator patterns? **
-
-The difference is the intent of the patterns. While Proxy controls access to the object Decorator is used to add responsibilities to the object.
-
-**Q: What is the difference between Chain of Responsibility and Intercepting Filter patterns? **
-
-While the implementations look similar there are differences. The Chain of Responsibility forms a chain of request processors and the processors are then executed one by one until the correct processor is found. In Intercepting Filter the chain is constructed from filters and the whole chain is always executed.
-
-**Q: What is the difference between Visitor and Double Dispatch patterns? **
-
-The Visitor pattern is a means of adding a new operation to existing classes. Double dispatch is a means of dispatching function calls with respect to two polymorphic types, rather than a single polymorphic type, which is what languages like C++ and Java support directly.
-
-**Q: What are the differences between Flyweight and Object Pool patterns? **
-
-They differ in the way they are used.
-
-Pooled objects can simultaneously be used by a single "client" only. For that, a pooled object must be checked out from the pool, then it can be used by a client, and then the client must return the object back to the pool. Multiple instances of identical objects may exist, up to the maximal capacity of the pool.
-
-In contrast, a Flyweight object is singleton, and it can be used simultaneously by multiple clients.
-
-As for concurrent access, pooled objects can be mutable and they usually don't need to be thread safe, as typically, only one thread is going to use a specific instance at the same time. Flyweight must either be immutable (the best option), or implement thread safety.
-
-As for performance and scalability, pools can become bottlenecks, if all the pooled objects are in use and more clients need them, threads will become blocked waiting for available object from the pool. This is not the case with Flyweight.
+All designs should be as simple as possible. You should start with KISS, YAGNI,
+and Do The Simplest Thing That Could Possibly Work principles. Complexity and
+patterns should only be introduced when they are needed for practical
+extensibility.
+Once you are familiar with these concepts you can start drilling down into
+patterns by any of the following approaches
+ - Using difficulty tags, `Difficulty-Beginner`, `Difficulty-Intermediate` & `Difficulty-Expert`.
+ - Using pattern categories, `Creational`, `Behavioral` and others.
+ - Search for a specific pattern. Can't find one? Please report a new pattern [here](https://github.com/iluwatar/java-design-patterns/issues).
# How to contribute
-**To add a new pattern** you need to do the following steps:
-
-1. Fork the repository.
-2. Implement the code changes in your fork. Remember to add sufficient comments documenting the implementation.
-3. Create a simple class diagram from your example code.
-4. Add description of the pattern in README.md and link to the class diagram.
-5. Create a pull request.
-
-**To work on one of the raised issues** you need to do the following steps:
-
-1. Fork the repository.
-2. Implement the code changes in your fork. Remember to add sufficient comments documenting the implementation. Reference the issue id e.g. #52 in your commit messages.
-3. Create a pull request.
-
-**For creating/editing UML diagrams** you need [ObjectAid UML Explorer for Eclipse](http://www.objectaid.com/home).
-
-**For inspiration** check out the following sources:
-
-* there is a good list of design patterns at [Wikipedia](http://en.wikipedia.org/wiki/Software_design_pattern)
-* Martin Fowler's [Catalog of Patterns of Enterprise Application Architecture](http://martinfowler.com/eaaCatalog/)
-* [pattern language for microservices](http://microservices.io/patterns/index.html)
-* Microsoft's [Cloud Design Patterns](http://download.microsoft.com/download/B/B/6/BB69622C-AB5D-4D5F-9A12-B81B952C1169/CloudDesignPatternsBook-PDF.pdf)
-
-**Links to patterns applied in real world applications** are welcome. The links should be added to the corresponding section of the `README.md`.
-
-
-
-# Versioning
-
-Java-design-patterns project uses [semantic versioning](http://semver.org/) scheme.
-
-
-
-# Credits
-
-* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
-* [Effective Java (2nd Edition)](http://www.amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683)
-* [Java Generics and Collections](http://www.amazon.com/Java-Generics-Collections-Maurice-Naftalin/dp/0596527756/)
-* [Let’s Modify the Objects-First Approach into Design-Patterns-First](http://edu.pecinovsky.cz/papers/2006_ITiCSE_Design_Patterns_First.pdf)
-* [Pattern Languages of Program Design](http://www.amazon.com/Pattern-Languages-Program-Design-Coplien/dp/0201607344/ref=sr_1_1)
-* [Martin Fowler - Event Aggregator](http://martinfowler.com/eaaDev/EventAggregator.html)
-* [TutorialsPoint - Intercepting Filter](http://www.tutorialspoint.com/design_pattern/intercepting_filter_pattern.htm)
-* [Presentation Tier Patterns](http://www.javagyan.com/tutorials/corej2eepatterns/presentation-tier-patterns)
-* [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](http://www.amazon.com/Functional-Programming-Java-Harnessing-Expressions/dp/1937785467/ref=sr_1_1)
-* [Martin Fowler - Service Layer](http://martinfowler.com/eaaCatalog/serviceLayer.html)
-* [Martin Fowler - Specifications](http://martinfowler.com/apsupp/spec.pdf)
-* [Martin Fowler - Tolerant Reader](http://martinfowler.com/bliki/TolerantReader.html)
-* [Trygve Reenskaug - Model-view-controller](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)
-* [Flux - Application architecture for building user interfaces](http://facebook.github.io/flux/)
-
-
+If you are willing to contribute to the project you will find the relevant information in our [developer wiki](https://github.com/iluwatar/java-design-patterns/wiki). We will help you and answer your questions in the [Gitter chatroom](https://gitter.im/iluwatar/java-design-patterns).
# License
diff --git a/abstract-document/README.md b/abstract-document/README.md
new file mode 100644
index 000000000..bf28ff999
--- /dev/null
+++ b/abstract-document/README.md
@@ -0,0 +1,31 @@
+---
+layout: pattern
+title: Abstract Document
+folder: abstract-document
+permalink: /patterns/abstract-document/
+categories: Structural
+tags:
+ - Java
+ - Difficulty-Intermediate
+---
+
+## Intent
+Achieve flexibility of untyped languages and keep the type-safety
+
+
+
+
+
+
+## Applicability
+Use the Abstract Document Pattern when
+
+* there is a need to add new properties on the fly
+* you want a flexible way to organize domain in tree like structure
+* you want more loosely coupled system
+
+
+## Credits
+
+* [Wikipedia: Abstract Document Pattern](https://en.wikipedia.org/wiki/Abstract_Document_Pattern)
+* [Martin Fowler: Dealing with properties](http://martinfowler.com/apsupp/properties.pdf)
\ No newline at end of file
diff --git a/abstract-document/etc/abstract-document-base.png b/abstract-document/etc/abstract-document-base.png
new file mode 100644
index 000000000..13345dbb8
Binary files /dev/null and b/abstract-document/etc/abstract-document-base.png differ
diff --git a/abstract-document/etc/abstract-document-base.ucls b/abstract-document/etc/abstract-document-base.ucls
new file mode 100644
index 000000000..bfe927ed9
--- /dev/null
+++ b/abstract-document/etc/abstract-document-base.ucls
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/abstract-document/etc/abstract-document.png b/abstract-document/etc/abstract-document.png
new file mode 100644
index 000000000..98d186f7e
Binary files /dev/null and b/abstract-document/etc/abstract-document.png differ
diff --git a/abstract-document/etc/abstract-document.ucls b/abstract-document/etc/abstract-document.ucls
new file mode 100644
index 000000000..ad97457fd
--- /dev/null
+++ b/abstract-document/etc/abstract-document.ucls
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/abstract-document/pom.xml b/abstract-document/pom.xml
new file mode 100644
index 000000000..b7a348d26
--- /dev/null
+++ b/abstract-document/pom.xml
@@ -0,0 +1,42 @@
+
+
+
+ 4.0.0
+
+ java-design-patterns
+ com.iluwatar
+ 1.13.0-SNAPSHOT
+
+ abstract-document
+
+
+ junit
+ junit
+ test
+
+
+
\ No newline at end of file
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/AbstractDocument.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/AbstractDocument.java
new file mode 100644
index 000000000..4bf8f0d14
--- /dev/null
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/AbstractDocument.java
@@ -0,0 +1,72 @@
+/**
+ * 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.abstractdocument;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+/**
+ * Abstract implementation of Document interface
+ */
+public abstract class AbstractDocument implements Document {
+
+ private final Map properties;
+
+ protected AbstractDocument(Map properties) {
+ Objects.requireNonNull(properties, "properties map is required");
+ this.properties = properties;
+ }
+
+ @Override
+ public Void put(String key, Object value) {
+ properties.put(key, value);
+ return null;
+ }
+
+ @Override
+ public Object get(String key) {
+ return properties.get(key);
+ }
+
+ @Override
+ public Stream children(String key, Function, T> constructor) {
+ Optional>> any = Stream.of(get(key)).filter(el -> el != null)
+ .map(el -> (List>) el).findAny();
+ return any.isPresent() ? any.get().stream().map(constructor) : Stream.empty();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(getClass().getName()).append("[");
+ properties.entrySet()
+ .forEach(e -> builder.append("[").append(e.getKey()).append(" : ").append(e.getValue()).append("]"));
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/App.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/App.java
new file mode 100644
index 000000000..d7758b6f7
--- /dev/null
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/App.java
@@ -0,0 +1,88 @@
+/**
+ * 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.abstractdocument;
+
+import com.iluwatar.abstractdocument.domain.Car;
+import com.iluwatar.abstractdocument.domain.HasModel;
+import com.iluwatar.abstractdocument.domain.HasParts;
+import com.iluwatar.abstractdocument.domain.HasPrice;
+import com.iluwatar.abstractdocument.domain.HasType;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The Abstract Document pattern enables handling additional, non-static
+ * properties. This pattern uses concept of traits to enable type safety and
+ * separate properties of different classes into set of interfaces.
+ *
+ *
+ * In Abstract Document pattern,({@link AbstractDocument}) fully implements
+ * {@link Document}) interface. Traits are then defined to enable access to
+ * properties in usual, static way.
+ */
+public class App {
+
+ /**
+ * Executes the App
+ */
+ public App() {
+ System.out.println("Constructing parts and car");
+
+ Map carProperties = new HashMap<>();
+ carProperties.put(HasModel.PROPERTY, "300SL");
+ carProperties.put(HasPrice.PROPERTY, 10000L);
+
+ Map wheelProperties = new HashMap<>();
+ wheelProperties.put(HasType.PROPERTY, "wheel");
+ wheelProperties.put(HasModel.PROPERTY, "15C");
+ wheelProperties.put(HasPrice.PROPERTY, 100L);
+
+ Map doorProperties = new HashMap<>();
+ doorProperties.put(HasType.PROPERTY, "door");
+ doorProperties.put(HasModel.PROPERTY, "Lambo");
+ doorProperties.put(HasPrice.PROPERTY, 300L);
+
+ carProperties.put(HasParts.PROPERTY, Arrays.asList(wheelProperties, doorProperties));
+
+ Car car = new Car(carProperties);
+
+ System.out.println("Here is our car:");
+ System.out.println("-> model: " + car.getModel().get());
+ System.out.println("-> price: " + car.getPrice().get());
+ System.out.println("-> parts: ");
+ car.getParts().forEach(p -> System.out
+ .println("\t" + p.getType().get() + "/" + p.getModel().get() + "/" + p.getPrice().get()));
+ }
+
+ /**
+ * Program entry point
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ new App();
+ }
+
+}
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/Document.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/Document.java
new file mode 100644
index 000000000..7705f37eb
--- /dev/null
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/Document.java
@@ -0,0 +1,59 @@
+/**
+ * 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.abstractdocument;
+
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+/**
+ * Document interface
+ */
+public interface Document {
+
+ /**
+ * Puts the value related to the key
+ *
+ * @param key element key
+ * @param value element value
+ * @return Void
+ */
+ Void put(String key, Object value);
+
+ /**
+ * Gets the value for the key
+ *
+ * @param key element key
+ * @return value or null
+ */
+ Object get(String key);
+
+ /**
+ * Gets the stream of child documents
+ *
+ * @param key element key
+ * @param constructor constructor of child class
+ * @return child documents
+ */
+ Stream children(String key, Function, T> constructor);
+}
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/Car.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/Car.java
new file mode 100644
index 000000000..e29ee63da
--- /dev/null
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/Car.java
@@ -0,0 +1,38 @@
+/**
+ * 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.abstractdocument.domain;
+
+import java.util.Map;
+
+import com.iluwatar.abstractdocument.AbstractDocument;
+
+/**
+ * Car entity
+ */
+public class Car extends AbstractDocument implements HasModel, HasPrice, HasParts {
+
+ public Car(Map properties) {
+ super(properties);
+ }
+
+}
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasModel.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasModel.java
new file mode 100644
index 000000000..fbd8c0d7f
--- /dev/null
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasModel.java
@@ -0,0 +1,40 @@
+/**
+ * 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.abstractdocument.domain;
+
+import java.util.Optional;
+
+import com.iluwatar.abstractdocument.Document;
+
+/**
+ * HasModel trait for static access to 'model' property
+ */
+public interface HasModel extends Document {
+
+ String PROPERTY = "model";
+
+ default Optional getModel() {
+ return Optional.ofNullable((String) get(PROPERTY));
+ }
+
+}
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasParts.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasParts.java
new file mode 100644
index 000000000..581702cc9
--- /dev/null
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasParts.java
@@ -0,0 +1,40 @@
+/**
+ * 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.abstractdocument.domain;
+
+import java.util.stream.Stream;
+
+import com.iluwatar.abstractdocument.Document;
+
+/**
+ * HasParts trait for static access to 'parts' property
+ */
+public interface HasParts extends Document {
+
+ String PROPERTY = "parts";
+
+ default Stream getParts() {
+ return children(PROPERTY, Part::new);
+ }
+
+}
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasPrice.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasPrice.java
new file mode 100644
index 000000000..3d1d0e3e7
--- /dev/null
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasPrice.java
@@ -0,0 +1,40 @@
+/**
+ * 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.abstractdocument.domain;
+
+import java.util.Optional;
+
+import com.iluwatar.abstractdocument.Document;
+
+/**
+ * HasPrice trait for static access to 'price' property
+ */
+public interface HasPrice extends Document {
+
+ String PROPERTY = "price";
+
+ default Optional getPrice() {
+ return Optional.ofNullable((Number) get(PROPERTY));
+ }
+
+}
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasType.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasType.java
new file mode 100644
index 000000000..b0f292bb6
--- /dev/null
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasType.java
@@ -0,0 +1,40 @@
+/**
+ * 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.abstractdocument.domain;
+
+import com.iluwatar.abstractdocument.Document;
+
+import java.util.Optional;
+
+/**
+ * HasType trait for static access to 'type' property
+ */
+public interface HasType extends Document {
+
+ String PROPERTY = "type";
+
+ default Optional getType() {
+ return Optional.ofNullable((String) get(PROPERTY));
+ }
+
+}
diff --git a/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/Part.java b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/Part.java
new file mode 100644
index 000000000..e42f099d9
--- /dev/null
+++ b/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/Part.java
@@ -0,0 +1,38 @@
+/**
+ * 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.abstractdocument.domain;
+
+import java.util.Map;
+
+import com.iluwatar.abstractdocument.AbstractDocument;
+
+/**
+ * Part entity
+ */
+public class Part extends AbstractDocument implements HasType, HasModel, HasPrice {
+
+ public Part(Map properties) {
+ super(properties);
+ }
+
+}
diff --git a/abstract-document/src/test/java/com/iluwatar/abstractdocument/AbstractDocumentTest.java b/abstract-document/src/test/java/com/iluwatar/abstractdocument/AbstractDocumentTest.java
new file mode 100644
index 000000000..b6467e232
--- /dev/null
+++ b/abstract-document/src/test/java/com/iluwatar/abstractdocument/AbstractDocumentTest.java
@@ -0,0 +1,88 @@
+/**
+ * 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.abstractdocument;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+
+/**
+ * AbstractDocument test class
+ */
+public class AbstractDocumentTest {
+
+ private static final String KEY = "key";
+ private static final String VALUE = "value";
+
+ private class DocumentImplementation extends AbstractDocument {
+
+ DocumentImplementation(Map properties) {
+ super(properties);
+ }
+ }
+
+ private DocumentImplementation document = new DocumentImplementation(new HashMap<>());
+
+ @Test
+ public void shouldPutAndGetValue() {
+ document.put(KEY, VALUE);
+ assertEquals(VALUE, document.get(KEY));
+ }
+
+ @Test
+ public void shouldRetrieveChildren() {
+ Map child1 = new HashMap<>();
+ Map child2 = new HashMap<>();
+ List> children = Arrays.asList(child1, child2);
+
+ document.put(KEY, children);
+
+ Stream childrenStream = document.children(KEY, DocumentImplementation::new);
+ assertNotNull(children);
+ assertEquals(2, childrenStream.count());
+ }
+
+ @Test
+ public void shouldRetrieveEmptyStreamForNonExistingChildren() {
+ Stream children = document.children(KEY, DocumentImplementation::new);
+ assertNotNull(children);
+ assertEquals(0, children.count());
+ }
+
+ @Test
+ public void shouldIncludePropsInToString() {
+ Map props = new HashMap<>();
+ props.put(KEY, VALUE);
+ DocumentImplementation document = new DocumentImplementation(props);
+ assertNotNull(document.toString().contains(KEY));
+ assertNotNull(document.toString().contains(VALUE));
+ }
+
+}
diff --git a/abstract-document/src/test/java/com/iluwatar/abstractdocument/AppTest.java b/abstract-document/src/test/java/com/iluwatar/abstractdocument/AppTest.java
new file mode 100644
index 000000000..787ae3aa6
--- /dev/null
+++ b/abstract-document/src/test/java/com/iluwatar/abstractdocument/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.abstractdocument;
+
+import org.junit.Test;
+
+/**
+ * Simple App test
+ */
+public class AppTest {
+
+ @Test
+ public void shouldExecuteAppWithoutException() {
+ App.main(null);
+ }
+
+}
diff --git a/abstract-document/src/test/java/com/iluwatar/abstractdocument/DomainTest.java b/abstract-document/src/test/java/com/iluwatar/abstractdocument/DomainTest.java
new file mode 100644
index 000000000..437244a3d
--- /dev/null
+++ b/abstract-document/src/test/java/com/iluwatar/abstractdocument/DomainTest.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.abstractdocument;
+
+import com.iluwatar.abstractdocument.domain.Car;
+import com.iluwatar.abstractdocument.domain.HasModel;
+import com.iluwatar.abstractdocument.domain.HasParts;
+import com.iluwatar.abstractdocument.domain.HasPrice;
+import com.iluwatar.abstractdocument.domain.HasType;
+import com.iluwatar.abstractdocument.domain.Part;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import static junit.framework.TestCase.assertEquals;
+
+/**
+ * Test for Part and Car
+ */
+public class DomainTest {
+
+ private static final String TEST_PART_TYPE = "test-part-type";
+ private static final String TEST_PART_MODEL = "test-part-model";
+ private static final long TEST_PART_PRICE = 0L;
+
+ private static final String TEST_CAR_MODEL = "test-car-model";
+ private static final long TEST_CAR_PRICE = 1L;
+
+ @Test
+ public void shouldConstructPart() {
+ Map partProperties = new HashMap<>();
+ partProperties.put(HasType.PROPERTY, TEST_PART_TYPE);
+ partProperties.put(HasModel.PROPERTY, TEST_PART_MODEL);
+ partProperties.put(HasPrice.PROPERTY, TEST_PART_PRICE);
+ Part part = new Part(partProperties);
+
+ assertEquals(TEST_PART_TYPE, part.getType().get());
+ assertEquals(TEST_PART_MODEL, part.getModel().get());
+ assertEquals(TEST_PART_PRICE, part.getPrice().get());
+ }
+
+ @Test
+ public void shouldConstructCar() {
+ Map carProperties = new HashMap<>();
+ carProperties.put(HasModel.PROPERTY, TEST_CAR_MODEL);
+ carProperties.put(HasPrice.PROPERTY, TEST_CAR_PRICE);
+ carProperties.put(HasParts.PROPERTY, Arrays.asList(new HashMap<>(), new HashMap<>()));
+ Car car = new Car(carProperties);
+
+ assertEquals(TEST_CAR_MODEL, car.getModel().get());
+ assertEquals(TEST_CAR_PRICE, car.getPrice().get());
+ assertEquals(2, car.getParts().count());
+ }
+
+}
diff --git a/abstract-factory/README.md b/abstract-factory/README.md
new file mode 100644
index 000000000..485599b98
--- /dev/null
+++ b/abstract-factory/README.md
@@ -0,0 +1,36 @@
+---
+layout: pattern
+title: Abstract Factory
+folder: abstract-factory
+permalink: /patterns/abstract-factory/
+categories: Creational
+tags:
+ - Java
+ - Gang Of Four
+ - Difficulty-Intermediate
+---
+
+## Also known as
+Kit
+
+## Intent
+Provide an interface for creating families of related or dependent
+objects without specifying their concrete classes.
+
+
+
+## Applicability
+Use the Abstract Factory pattern when
+
+* a system should be independent of how its products are created, composed and represented
+* a system should be configured with one of multiple families of products
+* a family of related product objects is designed to be used together, and you need to enforce this constraint
+* you want to provide a class library of products, and you want to reveal just their interfaces, not their implementations
+
+## Real world examples
+
+* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
+
+## Credits
+
+* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/abstract-factory/pom.xml b/abstract-factory/pom.xml
index a071aee26..ec0f700a5 100644
--- a/abstract-factory/pom.xml
+++ b/abstract-factory/pom.xml
@@ -1,11 +1,35 @@
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
abstract-factory
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java
index 3f77a521c..aae396f1d 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java
@@ -1,29 +1,115 @@
-package com.iluwatar.abstractfactory;
-
-/**
- *
- * The essence of the Abstract Factory pattern is a factory interface
- * (KingdomFactory) and its implementations (ElfKingdomFactory,
- * OrcKingdomFactory).
- *
- * The example uses both concrete implementations to create a king, a castle and
- * an army.
- *
- */
-public class App {
-
- public static void main(String[] args) {
- createKingdom(new ElfKingdomFactory());
- createKingdom(new OrcKingdomFactory());
- }
-
- public static void createKingdom(KingdomFactory factory) {
- King king = factory.createKing();
- Castle castle = factory.createCastle();
- Army army = factory.createArmy();
- System.out.println("The kingdom was created.");
- System.out.println(king);
- System.out.println(castle);
- System.out.println(army);
- }
-}
+/**
+ * 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.abstractfactory;
+
+/**
+ *
+ * The Abstract Factory pattern provides a way to encapsulate a group of individual factories that have a common theme
+ * without specifying their concrete classes. In normal usage, the client software creates a concrete implementation of
+ * the abstract factory and then uses the generic interface of the factory to create the concrete objects that are part
+ * of the theme. The client does not know (or care) which concrete objects it gets from each of these internal
+ * factories, since it uses only the generic interfaces of their products. This pattern separates the details of
+ * implementation of a set of objects from their general usage and relies on object composition, as object creation is
+ * implemented in methods exposed in the factory interface.
+ *
+ * The essence of the Abstract Factory pattern is a factory interface ({@link KingdomFactory}) and its implementations (
+ * {@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses both concrete implementations to create a
+ * king, a castle and an army.
+ *
+ */
+public class App {
+
+ private King king;
+ private Castle castle;
+ private Army army;
+
+ /**
+ * Creates kingdom
+ */
+ public void createKingdom(final KingdomFactory factory) {
+ setKing(factory.createKing());
+ setCastle(factory.createCastle());
+ setArmy(factory.createArmy());
+ }
+
+ King getKing(final KingdomFactory factory) {
+ return factory.createKing();
+ }
+
+ public King getKing() {
+ return king;
+ }
+
+ private void setKing(final King king) {
+ this.king = king;
+ }
+
+ Castle getCastle(final KingdomFactory factory) {
+ return factory.createCastle();
+ }
+
+ public Castle getCastle() {
+ return castle;
+ }
+
+ private void setCastle(final Castle castle) {
+ this.castle = castle;
+ }
+
+ Army getArmy(final KingdomFactory factory) {
+ return factory.createArmy();
+ }
+
+ public Army getArmy() {
+ return army;
+ }
+
+ private void setArmy(final Army army) {
+ this.army = army;
+ }
+
+ /**
+ * Program entry point
+ *
+ * @param args
+ * command line args
+ */
+ public static void main(String[] args) {
+
+ App app = new App();
+
+ System.out.println("Elf Kingdom");
+ app.createKingdom(new ElfKingdomFactory());
+ System.out.println(app.getArmy().getDescription());
+ System.out.println(app.getCastle().getDescription());
+ System.out.println(app.getKing().getDescription());
+
+ System.out.println("\nOrc Kingdom");
+ app.createKingdom(new OrcKingdomFactory());
+ System.out.println(app.getArmy().getDescription());
+ System.out.println(app.getCastle().getDescription());
+ System.out.println(app.getKing().getDescription());
+
+ }
+
+}
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Army.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Army.java
index 39e023e3b..d9e7f9989 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Army.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Army.java
@@ -1,5 +1,33 @@
-package com.iluwatar.abstractfactory;
-
-public interface Army {
-
-}
+/**
+ * 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.abstractfactory;
+
+/**
+ *
+ * Army interface
+ *
+ */
+public interface Army {
+
+ String getDescription();
+}
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Castle.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Castle.java
index 277daea56..adea2327e 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Castle.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/Castle.java
@@ -1,5 +1,33 @@
-package com.iluwatar.abstractfactory;
-
-public interface Castle {
-
-}
+/**
+ * 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.abstractfactory;
+
+/**
+ *
+ * Castle interface
+ *
+ */
+public interface Castle {
+
+ String getDescription();
+}
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfArmy.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfArmy.java
index 473106222..2969a8615 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfArmy.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfArmy.java
@@ -1,10 +1,38 @@
-package com.iluwatar.abstractfactory;
-
-public class ElfArmy implements Army {
-
- @Override
- public String toString() {
- return "This is the Elven Army!";
- }
-
-}
+/**
+ * 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.abstractfactory;
+
+/**
+ *
+ * ElfArmy
+ *
+ */
+public class ElfArmy implements Army {
+
+ static final String DESCRIPTION = "This is the Elven Army!";
+
+ @Override
+ public String getDescription() {
+ return DESCRIPTION;
+ }
+}
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfCastle.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfCastle.java
index 851baf84f..5321bfeba 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfCastle.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfCastle.java
@@ -1,10 +1,38 @@
-package com.iluwatar.abstractfactory;
-
-public class ElfCastle implements Castle {
-
- @Override
- public String toString() {
- return "This is the Elven castle!";
- }
-
-}
+/**
+ * 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.abstractfactory;
+
+/**
+ *
+ * ElfCastle
+ *
+ */
+public class ElfCastle implements Castle {
+
+ static final String DESCRIPTION = "This is the Elven castle!";
+
+ @Override
+ public String getDescription() {
+ return DESCRIPTION;
+ }
+}
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfKing.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfKing.java
index eafaccf49..1eb892e6f 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfKing.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfKing.java
@@ -1,10 +1,38 @@
-package com.iluwatar.abstractfactory;
-
-public class ElfKing implements King {
-
- @Override
- public String toString() {
- return "This is the Elven king!";
- }
-
-}
+/**
+ * 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.abstractfactory;
+
+/**
+ *
+ * ElfKing
+ *
+ */
+public class ElfKing implements King {
+
+ static final String DESCRIPTION = "This is the Elven king!";
+
+ @Override
+ public String getDescription() {
+ return DESCRIPTION;
+ }
+}
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfKingdomFactory.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfKingdomFactory.java
index eb4b99685..9d48ab25f 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfKingdomFactory.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/ElfKingdomFactory.java
@@ -1,22 +1,44 @@
-package com.iluwatar.abstractfactory;
-
-/**
- *
- * Concrete factory.
- *
- */
-public class ElfKingdomFactory implements KingdomFactory {
-
- public Castle createCastle() {
- return new ElfCastle();
- }
-
- public King createKing() {
- return new ElfKing();
- }
-
- public Army createArmy() {
- return new ElfArmy();
- }
-
-}
+/**
+ * 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.abstractfactory;
+
+/**
+ *
+ * ElfKingdomFactory concrete factory.
+ *
+ */
+public class ElfKingdomFactory implements KingdomFactory {
+
+ public Castle createCastle() {
+ return new ElfCastle();
+ }
+
+ public King createKing() {
+ return new ElfKing();
+ }
+
+ public Army createArmy() {
+ return new ElfArmy();
+ }
+
+}
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/King.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/King.java
index 12a9c1f13..ec1cff4d1 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/King.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/King.java
@@ -1,5 +1,33 @@
-package com.iluwatar.abstractfactory;
-
-public interface King {
-
-}
+/**
+ * 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.abstractfactory;
+
+/**
+ *
+ * King interface
+ *
+ */
+public interface King {
+
+ String getDescription();
+}
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/KingdomFactory.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/KingdomFactory.java
index e5b4b4050..d8258fd8b 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/KingdomFactory.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/KingdomFactory.java
@@ -1,16 +1,38 @@
-package com.iluwatar.abstractfactory;
-
-/**
- *
- * The factory interface.
- *
- */
-public interface KingdomFactory {
-
- Castle createCastle();
-
- King createKing();
-
- Army createArmy();
-
-}
+/**
+ * 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.abstractfactory;
+
+/**
+ *
+ * KingdomFactory factory interface.
+ *
+ */
+public interface KingdomFactory {
+
+ Castle createCastle();
+
+ King createKing();
+
+ Army createArmy();
+
+}
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcArmy.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcArmy.java
index b0e202d51..261ad37c9 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcArmy.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcArmy.java
@@ -1,10 +1,38 @@
-package com.iluwatar.abstractfactory;
-
-public class OrcArmy implements Army {
-
- @Override
- public String toString() {
- return "This is the Orcish Army!";
- }
-
-}
+/**
+ * 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.abstractfactory;
+
+/**
+ *
+ * OrcArmy
+ *
+ */
+public class OrcArmy implements Army {
+
+ static final String DESCRIPTION = "This is the Orc Army!";
+
+ @Override
+ public String getDescription() {
+ return DESCRIPTION;
+ }
+}
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcCastle.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcCastle.java
index 785884a59..cb2a92652 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcCastle.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcCastle.java
@@ -1,10 +1,38 @@
-package com.iluwatar.abstractfactory;
-
-public class OrcCastle implements Castle {
-
- @Override
- public String toString() {
- return "This is the Orcish castle!";
- }
-
-}
+/**
+ * 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.abstractfactory;
+
+/**
+ *
+ * OrcCastle
+ *
+ */
+public class OrcCastle implements Castle {
+
+ static final String DESCRIPTION = "This is the Orc castle!";
+
+ @Override
+ public String getDescription() {
+ return DESCRIPTION;
+ }
+}
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcKing.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcKing.java
index 27ea8afd4..ba7576492 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcKing.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcKing.java
@@ -1,10 +1,38 @@
-package com.iluwatar.abstractfactory;
-
-public class OrcKing implements King {
-
- @Override
- public String toString() {
- return "This is the Orc king!";
- }
-
-}
+/**
+ * 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.abstractfactory;
+
+/**
+ *
+ * OrcKing
+ *
+ */
+public class OrcKing implements King {
+
+ static final String DESCRIPTION = "This is the Orc king!";
+
+ @Override
+ public String getDescription() {
+ return DESCRIPTION;
+ }
+}
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcKingdomFactory.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcKingdomFactory.java
index 2f2a2a54d..2d740cf0d 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcKingdomFactory.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/OrcKingdomFactory.java
@@ -1,22 +1,43 @@
-package com.iluwatar.abstractfactory;
-
-/**
- *
- * Concrete factory.
- *
- */
-public class OrcKingdomFactory implements KingdomFactory {
-
- public Castle createCastle() {
- return new OrcCastle();
- }
-
- public King createKing() {
- return new OrcKing();
- }
-
- public Army createArmy() {
- return new OrcArmy();
- }
-
-}
+/**
+ * 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.abstractfactory;
+
+/**
+ *
+ * OrcKingdomFactory concrete factory.
+ *
+ */
+public class OrcKingdomFactory implements KingdomFactory {
+
+ public Castle createCastle() {
+ return new OrcCastle();
+ }
+
+ public King createKing() {
+ return new OrcKing();
+ }
+
+ public Army createArmy() {
+ return new OrcArmy();
+ }
+}
diff --git a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java
new file mode 100644
index 000000000..216f0443a
--- /dev/null
+++ b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AbstractFactoryTest.java
@@ -0,0 +1,100 @@
+/**
+ * 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.abstractfactory;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class AbstractFactoryTest {
+
+ private App app = new App();
+ private KingdomFactory elfFactory;
+ private KingdomFactory orcFactory;
+
+ @Before
+ public void setUp() {
+ elfFactory = new ElfKingdomFactory();
+ orcFactory = new OrcKingdomFactory();
+ }
+
+ @Test
+ public void king() {
+ final King elfKing = app.getKing(elfFactory);
+ assertTrue(elfKing instanceof ElfKing);
+ assertEquals(ElfKing.DESCRIPTION, elfKing.getDescription());
+ final King orcKing = app.getKing(orcFactory);
+ assertTrue(orcKing instanceof OrcKing);
+ assertEquals(OrcKing.DESCRIPTION, orcKing.getDescription());
+ }
+
+ @Test
+ public void castle() {
+ final Castle elfCastle = app.getCastle(elfFactory);
+ assertTrue(elfCastle instanceof ElfCastle);
+ assertEquals(ElfCastle.DESCRIPTION, elfCastle.getDescription());
+ final Castle orcCastle = app.getCastle(orcFactory);
+ assertTrue(orcCastle instanceof OrcCastle);
+ assertEquals(OrcCastle.DESCRIPTION, orcCastle.getDescription());
+ }
+
+ @Test
+ public void army() {
+ final Army elfArmy = app.getArmy(elfFactory);
+ assertTrue(elfArmy instanceof ElfArmy);
+ assertEquals(ElfArmy.DESCRIPTION, elfArmy.getDescription());
+ final Army orcArmy = app.getArmy(orcFactory);
+ assertTrue(orcArmy instanceof OrcArmy);
+ assertEquals(OrcArmy.DESCRIPTION, orcArmy.getDescription());
+ }
+
+ @Test
+ public void createElfKingdom() {
+ app.createKingdom(elfFactory);
+ final King king = app.getKing();
+ final Castle castle = app.getCastle();
+ final Army army = app.getArmy();
+ assertTrue(king instanceof ElfKing);
+ assertEquals(ElfKing.DESCRIPTION, king.getDescription());
+ assertTrue(castle instanceof ElfCastle);
+ assertEquals(ElfCastle.DESCRIPTION, castle.getDescription());
+ assertTrue(army instanceof ElfArmy);
+ assertEquals(ElfArmy.DESCRIPTION, army.getDescription());
+ }
+
+ @Test
+ public void createOrcKingdom() {
+ app.createKingdom(orcFactory);
+ final King king = app.getKing();
+ final Castle castle = app.getCastle();
+ final Army army = app.getArmy();
+ assertTrue(king instanceof OrcKing);
+ assertEquals(OrcKing.DESCRIPTION, king.getDescription());
+ assertTrue(castle instanceof OrcCastle);
+ assertEquals(OrcCastle.DESCRIPTION, castle.getDescription());
+ assertTrue(army instanceof OrcArmy);
+ assertEquals(OrcArmy.DESCRIPTION, army.getDescription());
+ }
+}
diff --git a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AppTest.java b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AppTest.java
index 0241ed8ce..a965284f7 100644
--- a/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AppTest.java
+++ b/abstract-factory/src/test/java/com/iluwatar/abstractfactory/AppTest.java
@@ -1,13 +1,38 @@
-package com.iluwatar.abstractfactory;
-import org.junit.Test;
-
-import com.iluwatar.abstractfactory.App;
-
-public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
-}
+/**
+ * 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.abstractfactory;
+
+import org.junit.Test;
+
+import java.io.IOException;
+
+/**
+ * Tests that Abstract Factory example runs without errors.
+ */
+public class AppTest {
+ @Test
+ public void test() throws IOException {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/adapter/README.md b/adapter/README.md
new file mode 100644
index 000000000..ea3baa7fa
--- /dev/null
+++ b/adapter/README.md
@@ -0,0 +1,37 @@
+---
+layout: pattern
+title: Adapter
+folder: adapter
+permalink: /patterns/adapter/
+categories: Structural
+tags:
+ - Java
+ - Gang Of Four
+ - Difficulty-Beginner
+---
+
+## Also known as
+Wrapper
+
+## Intent
+Convert the interface of a class into another interface the clients
+expect. Adapter lets classes work together that couldn't otherwise because of
+incompatible interfaces.
+
+
+
+## Applicability
+Use the Adapter pattern when
+
+* you want to use an existing class, and its interface does not match the one you need
+* you want to create a reusable class that cooperates with unrelated or unforeseen classes, that is, classes that don't necessarily have compatible interfaces
+* you need to use several existing subclasses, but it's impractical to adapt their interface by subclassing every one. An object adapter can adapt the interface of its parent class.
+
+## Real world examples
+
+* [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29)
+
+## Credits
+
+* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
diff --git a/adapter/etc/adapter.png b/adapter/etc/adapter.png
index 511bb5880..f43358b04 100644
Binary files a/adapter/etc/adapter.png and b/adapter/etc/adapter.png differ
diff --git a/adapter/etc/adapter.ucls b/adapter/etc/adapter.ucls
index 8c09f0399..290ff544e 100644
--- a/adapter/etc/adapter.ucls
+++ b/adapter/etc/adapter.ucls
@@ -1,61 +1,61 @@
-
-
-
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
+
+
+
+
-
+
+
+
+
+
-
-
+
+
diff --git a/adapter/etc/adapter_1.png b/adapter/etc/adapter_1.png
deleted file mode 100644
index 64eb34b84..000000000
Binary files a/adapter/etc/adapter_1.png and /dev/null differ
diff --git a/adapter/pom.xml b/adapter/pom.xml
index 7a6861fca..2c99796f4 100644
--- a/adapter/pom.xml
+++ b/adapter/pom.xml
@@ -1,11 +1,35 @@
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
adapter
@@ -14,5 +38,10 @@
junit
test
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/adapter/src/main/java/com/iluwatar/adapter/App.java b/adapter/src/main/java/com/iluwatar/adapter/App.java
index 43a93fa44..29c313b59 100644
--- a/adapter/src/main/java/com/iluwatar/adapter/App.java
+++ b/adapter/src/main/java/com/iluwatar/adapter/App.java
@@ -1,21 +1,60 @@
-package com.iluwatar.adapter;
-
-/**
- *
- * There are two variations of the Adapter pattern: The class adapter implements
- * the adaptee's interface whereas the object adapter uses composition to
- * contain the adaptee in the adapter object. This example uses the object
- * adapter approach.
- *
- * The Adapter (GnomeEngineer) converts the interface of the target class
- * (GoblinGlider) into a suitable one expected by the client
- * (GnomeEngineeringManager).
- *
- */
-public class App {
-
- public static void main(String[] args) {
- Engineer manager = new GnomeEngineeringManager();
- manager.operateDevice();
- }
-}
+/**
+ * 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.adapter;
+
+/**
+ * An adapter helps two incompatible interfaces to work together. This is the real world definition
+ * for an adapter. Interfaces may be incompatible but the inner functionality should suit the need.
+ * The Adapter design pattern allows otherwise incompatible classes to work together by converting
+ * the interface of one class into an interface expected by the clients.
+ *
+ *
+ * There are two variations of the Adapter pattern: The class adapter implements the adaptee's
+ * interface whereas the object adapter uses composition to contain the adaptee in the adapter
+ * object. This example uses the object adapter approach.
+ *
+ *
+ * The Adapter ({@link BattleFishingBoat}) converts the interface of the adaptee class (
+ * {@link FishingBoat}) into a suitable one expected by the client ( {@link BattleShip} ).
+ *
+ *
+ * The story of this implementation is this.
+ * Pirates are coming! we need a {@link BattleShip} to fight! We have a {@link FishingBoat} and our
+ * captain. We have no time to make up a new ship! we need to reuse this {@link FishingBoat}. The
+ * captain needs a battleship which can fire and move. The spec is in {@link BattleShip}. We will
+ * use the Adapter pattern to reuse {@link FishingBoat}.
+ *
+ */
+public class App {
+
+ /**
+ * Program entry point.
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ Captain captain = new Captain(new BattleFishingBoat());
+ captain.move();
+ captain.fire();
+ }
+}
diff --git a/adapter/src/main/java/com/iluwatar/adapter/BattleFishingBoat.java b/adapter/src/main/java/com/iluwatar/adapter/BattleFishingBoat.java
new file mode 100644
index 000000000..a591818fe
--- /dev/null
+++ b/adapter/src/main/java/com/iluwatar/adapter/BattleFishingBoat.java
@@ -0,0 +1,51 @@
+/**
+ * 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.adapter;
+
+/**
+ *
+ * Adapter class. Adapts the interface of the device ({@link FishingBoat}) into {@link BattleShip}
+ * interface expected by the client ({@link Captain}).
+ * In this case we added a new function fire to suit the interface. We are reusing the
+ * {@link FishingBoat} without changing itself. The Adapter class can just map the functions of the
+ * Adaptee or add, delete features of the Adaptee.
+ *
+ */
+public class BattleFishingBoat implements BattleShip {
+
+ private FishingBoat boat;
+
+ public BattleFishingBoat() {
+ boat = new FishingBoat();
+ }
+
+ @Override
+ public void fire() {
+ System.out.println("fire!");
+ }
+
+ @Override
+ public void move() {
+ boat.sail();
+ }
+}
diff --git a/adapter/src/main/java/com/iluwatar/adapter/BattleShip.java b/adapter/src/main/java/com/iluwatar/adapter/BattleShip.java
new file mode 100644
index 000000000..6a29a5034
--- /dev/null
+++ b/adapter/src/main/java/com/iluwatar/adapter/BattleShip.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.adapter;
+
+/**
+ * The interface expected by the client.
+ * A Battleship can fire and move.
+ *
+ */
+public interface BattleShip {
+
+ void fire();
+
+ void move();
+
+}
diff --git a/adapter/src/main/java/com/iluwatar/adapter/Captain.java b/adapter/src/main/java/com/iluwatar/adapter/Captain.java
new file mode 100644
index 000000000..34f783cd4
--- /dev/null
+++ b/adapter/src/main/java/com/iluwatar/adapter/Captain.java
@@ -0,0 +1,55 @@
+/**
+ * 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.adapter;
+
+/**
+ * The Captain uses {@link BattleShip} to fight.
+ * This is the client in the pattern.
+ */
+public class Captain implements BattleShip {
+
+ private BattleShip battleship;
+
+ public Captain() {
+
+ }
+
+ public Captain(BattleShip battleship) {
+ this.battleship = battleship;
+ }
+
+ public void setBattleship(BattleShip battleship) {
+ this.battleship = battleship;
+ }
+
+ @Override
+ public void fire() {
+ battleship.fire();
+ }
+
+ @Override
+ public void move() {
+ battleship.move();
+ }
+
+}
diff --git a/adapter/src/main/java/com/iluwatar/adapter/Engineer.java b/adapter/src/main/java/com/iluwatar/adapter/Engineer.java
deleted file mode 100644
index 7478b5b69..000000000
--- a/adapter/src/main/java/com/iluwatar/adapter/Engineer.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.iluwatar.adapter;
-
-/**
- *
- * Engineers can operate devices.
- *
- */
-public interface Engineer {
-
- void operateDevice();
-
-}
diff --git a/adapter/src/main/java/com/iluwatar/adapter/FishingBoat.java b/adapter/src/main/java/com/iluwatar/adapter/FishingBoat.java
new file mode 100644
index 000000000..307437038
--- /dev/null
+++ b/adapter/src/main/java/com/iluwatar/adapter/FishingBoat.java
@@ -0,0 +1,40 @@
+/**
+ * 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.adapter;
+
+/**
+ *
+ * Device class (adaptee in the pattern). We want to reuse this class
+ *
+ */
+public class FishingBoat {
+
+ public void sail() {
+ System.out.println("The Boat is moving to that place");
+ }
+
+ public void fish() {
+ System.out.println("fishing ...");
+ }
+
+}
diff --git a/adapter/src/main/java/com/iluwatar/adapter/GnomeEngineer.java b/adapter/src/main/java/com/iluwatar/adapter/GnomeEngineer.java
deleted file mode 100644
index 62fab599f..000000000
--- a/adapter/src/main/java/com/iluwatar/adapter/GnomeEngineer.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.iluwatar.adapter;
-
-/**
- *
- * Adapter class. Adapts the interface of the device (GoblinGlider) into
- * Engineer interface expected by the client (GnomeEngineeringManager).
- *
- */
-public class GnomeEngineer implements Engineer {
-
- private GoblinGlider glider;
-
- public GnomeEngineer() {
- glider = new GoblinGlider();
- }
-
- @Override
- public void operateDevice() {
- glider.attachGlider();
- glider.gainSpeed();
- glider.takeOff();
- }
-
-}
diff --git a/adapter/src/main/java/com/iluwatar/adapter/GnomeEngineeringManager.java b/adapter/src/main/java/com/iluwatar/adapter/GnomeEngineeringManager.java
deleted file mode 100644
index 6d0010d74..000000000
--- a/adapter/src/main/java/com/iluwatar/adapter/GnomeEngineeringManager.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.iluwatar.adapter;
-
-/**
- *
- * GnomeEngineering manager uses Engineer to operate devices.
- *
- */
-public class GnomeEngineeringManager implements Engineer {
-
- private Engineer engineer;
-
- public GnomeEngineeringManager() {
- engineer = new GnomeEngineer();
- }
-
- @Override
- public void operateDevice() {
- engineer.operateDevice();
- }
-}
diff --git a/adapter/src/main/java/com/iluwatar/adapter/GoblinGlider.java b/adapter/src/main/java/com/iluwatar/adapter/GoblinGlider.java
deleted file mode 100644
index ff1dbeb8d..000000000
--- a/adapter/src/main/java/com/iluwatar/adapter/GoblinGlider.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.iluwatar.adapter;
-
-/**
- *
- * Device class (adaptee in the pattern).
- *
- */
-public class GoblinGlider {
-
- public void attachGlider() {
- System.out.println("Glider attached.");
- }
-
- public void gainSpeed() {
- System.out.println("Gaining speed.");
- }
-
- public void takeOff() {
- System.out.println("Lift-off!");
- }
-}
diff --git a/adapter/src/test/java/com/iluwatar/adapter/AdapterPatternTest.java b/adapter/src/test/java/com/iluwatar/adapter/AdapterPatternTest.java
new file mode 100644
index 000000000..263c9ab02
--- /dev/null
+++ b/adapter/src/test/java/com/iluwatar/adapter/AdapterPatternTest.java
@@ -0,0 +1,83 @@
+/**
+ * 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.adapter;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Test class
+ *
+ */
+public class AdapterPatternTest {
+
+ private Map beans;
+
+ private static final String BATTLESHIP_BEAN = "engineer";
+
+ private static final String CAPTAIN_BEAN = "captain";
+
+ /**
+ * This method runs before the test execution and sets the bean objects in the beans Map.
+ */
+ @Before
+ public void setup() {
+ beans = new HashMap<>();
+
+ BattleFishingBoat battleFishingBoat = spy(new BattleFishingBoat());
+ beans.put(BATTLESHIP_BEAN, battleFishingBoat);
+
+ Captain captain = new Captain();
+ captain.setBattleship((BattleFishingBoat) beans.get(BATTLESHIP_BEAN));
+ beans.put(CAPTAIN_BEAN, captain);
+ }
+
+ /**
+ * This test asserts that when we use the move() method on a captain bean(client), it is
+ * internally calling move method on the battleship object. The Adapter ({@link BattleFishingBoat}
+ * ) converts the interface of the target class ( {@link FishingBoat}) into a suitable one
+ * expected by the client ({@link Captain} ).
+ */
+ @Test
+ public void testAdapter() {
+ BattleShip captain = (BattleShip) beans.get(CAPTAIN_BEAN);
+
+ // when captain moves
+ captain.move();
+
+ // the captain internally calls the battleship object to move
+ BattleShip battleship = (BattleShip) beans.get(BATTLESHIP_BEAN);
+ verify(battleship).move();
+
+ // same with above with firing
+ captain.fire();
+ verify(battleship).fire();
+
+ }
+}
diff --git a/adapter/src/test/java/com/iluwatar/adapter/AppTest.java b/adapter/src/test/java/com/iluwatar/adapter/AppTest.java
index cd9d713b0..4f5fcd91d 100644
--- a/adapter/src/test/java/com/iluwatar/adapter/AppTest.java
+++ b/adapter/src/test/java/com/iluwatar/adapter/AppTest.java
@@ -1,14 +1,38 @@
-package com.iluwatar.adapter;
-
-import org.junit.Test;
-
-import com.iluwatar.adapter.App;
-
-public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
-}
+/**
+ * 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.adapter;
+
+import org.junit.Test;
+
+import java.io.IOException;
+
+/**
+ * Tests that Adapter example runs without errors.
+ */
+public class AppTest {
+ @Test
+ public void test() throws IOException {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/aggregator-microservices/README.md b/aggregator-microservices/README.md
new file mode 100644
index 000000000..e65f26d9a
--- /dev/null
+++ b/aggregator-microservices/README.md
@@ -0,0 +1,29 @@
+---
+layout: pattern
+title: Aggregator Microservices
+folder: aggregator-microservices
+permalink: /patterns/aggregator-microservices/
+categories: Architectural
+tags:
+- Java
+- Spring
+---
+
+## Intent
+
+The user makes a single call to the Aggregator, and the aggregator then calls each relevant microservice and collects
+the data, apply business logic to it, and further publish is as a REST Endpoint.
+More variations of the aggregator are:
+- Proxy Microservice Design Pattern: A different microservice is called upon the business need.
+- Chained Microservice Design Pattern: In this case each microservice is dependent/ chained to a series
+of other microservices.
+
+
+
+## Applicability
+
+Use the Aggregator Microservices pattern when you need a unified API for various microservices, regardless the client device.
+
+## Credits
+
+* [Microservice Design Patterns](http://blog.arungupta.me/microservice-design-patterns/)
diff --git a/aggregator-microservices/aggregator-service/pom.xml b/aggregator-microservices/aggregator-service/pom.xml
new file mode 100644
index 000000000..169d0da94
--- /dev/null
+++ b/aggregator-microservices/aggregator-service/pom.xml
@@ -0,0 +1,88 @@
+
+
+
+
+ aggregator-microservices
+ com.iluwatar
+ 1.13.0-SNAPSHOT
+
+ 4.0.0
+
+ aggregator-service
+ jar
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+
+
+
+
+
+ org.springframework
+ spring-webmvc
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ junit
+ junit
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+
+
+ repackage
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/Aggregator.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/Aggregator.java
new file mode 100644
index 000000000..639349db9
--- /dev/null
+++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/Aggregator.java
@@ -0,0 +1,58 @@
+/**
+ * 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.aggregator.microservices;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * The aggregator aggregates calls on various micro-services, collects
+ * data and further publishes them under a REST endpoint.
+ */
+@RestController
+public class Aggregator {
+
+
+ @Resource
+ private ProductInformationClient informationClient;
+
+ @Resource
+ private ProductInventoryClient inventoryClient;
+
+
+ /**
+ * Retrieves product data.
+ *
+ * @return a Product.
+ */
+ @RequestMapping("/product")
+ public Product getProduct() {
+ Product product = new Product();
+ product.setTitle(informationClient.getProductTitle());
+ product.setProductInventories(inventoryClient.getProductInventories());
+ return product;
+ }
+
+}
diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/App.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/App.java
new file mode 100644
index 000000000..25bb9ee6f
--- /dev/null
+++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/App.java
@@ -0,0 +1,39 @@
+/**
+ * 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.aggregator.microservices;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class App {
+
+ /**
+ * Program entry point
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ SpringApplication.run(App.class, args);
+ }
+}
diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/Product.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/Product.java
new file mode 100644
index 000000000..edf0c121d
--- /dev/null
+++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/Product.java
@@ -0,0 +1,57 @@
+/**
+ * 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.aggregator.microservices;
+
+/**
+ * Encapsulates all the data for a Product that clients will request.
+ */
+public class Product {
+
+ /**
+ * The title of the product.
+ */
+ private String title;
+
+
+ /**
+ * The inventories of the product.
+ */
+ private int productInventories;
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public int getProductInventories() {
+ return productInventories;
+ }
+
+ public void setProductInventories(int productInventories) {
+ this.productInventories = productInventories;
+ }
+
+}
diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClient.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClient.java
new file mode 100644
index 000000000..863db4759
--- /dev/null
+++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClient.java
@@ -0,0 +1,32 @@
+/**
+ * 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.aggregator.microservices;
+
+/**
+ * Interface for the Information micro-service.
+ */
+public interface ProductInformationClient {
+
+ String getProductTitle();
+
+}
diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClientImpl.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClientImpl.java
new file mode 100644
index 000000000..1c5c1527c
--- /dev/null
+++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInformationClientImpl.java
@@ -0,0 +1,53 @@
+/**
+ * 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.aggregator.microservices;
+
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+/**
+ * An adapter to communicate with information micro-service.
+ */
+@Component
+public class ProductInformationClientImpl implements ProductInformationClient {
+
+ @Override
+ public String getProductTitle() {
+ String response = null;
+ try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+ HttpGet httpGet = new HttpGet("http://localhost:51515/information");
+ try (CloseableHttpResponse httpResponse = httpClient.execute(httpGet)) {
+ response = EntityUtils.toString(httpResponse.getEntity());
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return response;
+ }
+}
diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClient.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClient.java
new file mode 100644
index 000000000..22be900b3
--- /dev/null
+++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClient.java
@@ -0,0 +1,31 @@
+/**
+ * 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.aggregator.microservices;
+
+/**
+ * Interface to Inventory micro-service.
+ */
+public interface ProductInventoryClient {
+
+ int getProductInventories();
+}
diff --git a/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClientImpl.java b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClientImpl.java
new file mode 100644
index 000000000..14d0a32c4
--- /dev/null
+++ b/aggregator-microservices/aggregator-service/src/main/java/com/iluwatar/aggregator/microservices/ProductInventoryClientImpl.java
@@ -0,0 +1,53 @@
+/**
+ * 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.aggregator.microservices;
+
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+/**
+ * An adapter to communicate with inventory micro-service.
+ */
+@Component
+public class ProductInventoryClientImpl implements ProductInventoryClient {
+
+ @Override
+ public int getProductInventories() {
+ String response = "0";
+ try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+ HttpGet httpGet = new HttpGet("http://localhost:51516/inventories");
+ try (CloseableHttpResponse httpResponse = httpClient.execute(httpGet)) {
+ response = EntityUtils.toString(httpResponse.getEntity());
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return Integer.parseInt(response);
+ }
+}
diff --git a/aggregator-microservices/aggregator-service/src/main/resources/application.properties b/aggregator-microservices/aggregator-service/src/main/resources/application.properties
new file mode 100644
index 000000000..69f581712
--- /dev/null
+++ b/aggregator-microservices/aggregator-service/src/main/resources/application.properties
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+server.port=50004
\ No newline at end of file
diff --git a/aggregator-microservices/aggregator-service/src/test/java/com/iluwatar/aggregator/microservices/AggregatorTest.java b/aggregator-microservices/aggregator-service/src/test/java/com/iluwatar/aggregator/microservices/AggregatorTest.java
new file mode 100644
index 000000000..95d36fe25
--- /dev/null
+++ b/aggregator-microservices/aggregator-service/src/test/java/com/iluwatar/aggregator/microservices/AggregatorTest.java
@@ -0,0 +1,67 @@
+/**
+ * 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.aggregator.microservices;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+public class AggregatorTest {
+
+ @InjectMocks
+ private Aggregator aggregator;
+
+ @Mock
+ private ProductInformationClient informationClient;
+
+ @Mock
+ private ProductInventoryClient inventoryClient;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ /**
+ * Tests getting the data for a desktop client
+ */
+ @Test
+ public void testGetProduct() {
+ String title = "The Product Title.";
+ int inventories = 5;
+
+ when(informationClient.getProductTitle()).thenReturn(title);
+ when(inventoryClient.getProductInventories()).thenReturn(inventories);
+
+ Product testProduct = aggregator.getProduct();
+
+ assertEquals(title, testProduct.getTitle());
+ assertEquals(inventories, testProduct.getProductInventories());
+ }
+
+}
\ No newline at end of file
diff --git a/aggregator-microservices/etc/aggregator-microservice.png b/aggregator-microservices/etc/aggregator-microservice.png
new file mode 100644
index 000000000..ad344a7e1
Binary files /dev/null and b/aggregator-microservices/etc/aggregator-microservice.png differ
diff --git a/aggregator-microservices/information-microservice/pom.xml b/aggregator-microservices/information-microservice/pom.xml
new file mode 100644
index 000000000..986540344
--- /dev/null
+++ b/aggregator-microservices/information-microservice/pom.xml
@@ -0,0 +1,79 @@
+
+
+
+
+ aggregator-microservices
+ com.iluwatar
+ 1.13.0-SNAPSHOT
+
+ 4.0.0
+
+ information-microservice
+ jar
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+
+
+
+
+
+ org.springframework
+ spring-webmvc
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ junit
+ junit
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+
+
+ repackage
+
+
+
+
+
+
+
diff --git a/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationApplication.java b/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationApplication.java
new file mode 100644
index 000000000..c93219c17
--- /dev/null
+++ b/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationApplication.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.information.microservice;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * Inventory Application starts container (Spring Boot) and exposes the Inventory micro-service.
+ */
+@SpringBootApplication
+public class InformationApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(InformationApplication.class, args);
+ }
+}
diff --git a/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationController.java b/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationController.java
new file mode 100644
index 000000000..37ec45c1b
--- /dev/null
+++ b/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationController.java
@@ -0,0 +1,41 @@
+/**
+ * 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.information.microservice;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class InformationController {
+
+ /**
+ * Endpoint to retrieve a product's informations.
+ *
+ * @return product inventory.
+ */
+ @RequestMapping(value = "/information", method = RequestMethod.GET)
+ public String getProductTitle() {
+ return "The Product Title.";
+ }
+}
diff --git a/aggregator-microservices/information-microservice/src/main/resources/application.properties b/aggregator-microservices/information-microservice/src/main/resources/application.properties
new file mode 100644
index 000000000..3c8452f1f
--- /dev/null
+++ b/aggregator-microservices/information-microservice/src/main/resources/application.properties
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+server.port=51515
\ No newline at end of file
diff --git a/aggregator-microservices/information-microservice/src/test/java/com/iluwatar/information/microservice/InformationControllerTest.java b/aggregator-microservices/information-microservice/src/test/java/com/iluwatar/information/microservice/InformationControllerTest.java
new file mode 100644
index 000000000..9c3a6b98d
--- /dev/null
+++ b/aggregator-microservices/information-microservice/src/test/java/com/iluwatar/information/microservice/InformationControllerTest.java
@@ -0,0 +1,39 @@
+/**
+ * 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.information.microservice;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class InformationControllerTest {
+
+ @Test
+ public void shouldGetProductTitle() {
+ InformationController infoController = new InformationController();
+
+ String title = infoController.getProductTitle();
+
+ Assert.assertEquals("The Product Title.", title);
+ }
+
+}
\ No newline at end of file
diff --git a/aggregator-microservices/inventory-microservice/pom.xml b/aggregator-microservices/inventory-microservice/pom.xml
new file mode 100644
index 000000000..f8844dd39
--- /dev/null
+++ b/aggregator-microservices/inventory-microservice/pom.xml
@@ -0,0 +1,79 @@
+
+
+
+
+ aggregator-microservices
+ com.iluwatar
+ 1.13.0-SNAPSHOT
+
+ 4.0.0
+
+ inventory-microservice
+ jar
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+
+
+
+
+
+ org.springframework
+ spring-webmvc
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ junit
+ junit
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+
+
+ repackage
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryApplication.java b/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryApplication.java
new file mode 100644
index 000000000..3e2cf9e60
--- /dev/null
+++ b/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryApplication.java
@@ -0,0 +1,38 @@
+/**
+ * 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.inventory.microservice;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * Inventory Application starts container (Spring Boot) and exposes the Inventory micro-service.
+ */
+@SpringBootApplication
+public class InventoryApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(InventoryApplication.class, args);
+ }
+
+}
diff --git a/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryController.java b/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryController.java
new file mode 100644
index 000000000..483e28bf3
--- /dev/null
+++ b/aggregator-microservices/inventory-microservice/src/main/java/com/iluwatar/inventory/microservice/InventoryController.java
@@ -0,0 +1,42 @@
+/**
+ * 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.inventory.microservice;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class InventoryController {
+
+ /**
+ * Endpoint to retrieve a product's inventories.
+ *
+ * @return product inventory.
+ */
+ @RequestMapping(value = "/inventories", method = RequestMethod.GET)
+ public int getProductInventories() {
+ return 5;
+ }
+
+}
diff --git a/aggregator-microservices/inventory-microservice/src/main/resources/application.properties b/aggregator-microservices/inventory-microservice/src/main/resources/application.properties
new file mode 100644
index 000000000..36f7589fc
--- /dev/null
+++ b/aggregator-microservices/inventory-microservice/src/main/resources/application.properties
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+server.port=51516
\ No newline at end of file
diff --git a/aggregator-microservices/inventory-microservice/src/test/java/com/iluwatar/inventory/microservice/InventoryControllerTest.java b/aggregator-microservices/inventory-microservice/src/test/java/com/iluwatar/inventory/microservice/InventoryControllerTest.java
new file mode 100644
index 000000000..787ec0e61
--- /dev/null
+++ b/aggregator-microservices/inventory-microservice/src/test/java/com/iluwatar/inventory/microservice/InventoryControllerTest.java
@@ -0,0 +1,38 @@
+/**
+ * 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.inventory.microservice;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class InventoryControllerTest {
+
+ @Test
+ public void testGetProductInventories() throws Exception {
+ InventoryController inventoryController = new InventoryController();
+
+ int numberOfInventories = inventoryController.getProductInventories();
+
+ Assert.assertEquals(5, numberOfInventories);
+ }
+}
\ No newline at end of file
diff --git a/aggregator-microservices/pom.xml b/aggregator-microservices/pom.xml
new file mode 100644
index 000000000..0133e9ea4
--- /dev/null
+++ b/aggregator-microservices/pom.xml
@@ -0,0 +1,43 @@
+
+
+
+
+ java-design-patterns
+ com.iluwatar
+ 1.13.0-SNAPSHOT
+
+ 4.0.0
+ aggregator-microservices
+ pom
+
+
+ information-microservice
+ aggregator-service
+ inventory-microservice
+
+
\ No newline at end of file
diff --git a/api-gateway/README.md b/api-gateway/README.md
new file mode 100644
index 000000000..23014ae0b
--- /dev/null
+++ b/api-gateway/README.md
@@ -0,0 +1,30 @@
+---
+layout: pattern
+title: API Gateway
+folder: api-gateway
+permalink: /patterns/api-gateway/
+categories: Architectural
+tags:
+- Java
+- Difficulty-Intermediate
+- Spring
+---
+
+## Intent
+
+Aggregate calls to microservices in a single location: the API Gateway. The user makes a single
+call to the API Gateway, and the API Gateway then calls each relevant microservice.
+
+
+
+## Applicability
+
+Use the API Gateway pattern when
+
+* you're also using the Microservices pattern and need a single point of aggregation for your
+microservice calls
+
+## Credits
+
+* [microservices.io - API Gateway](http://microservices.io/patterns/apigateway.html)
+* [NGINX - Building Microservices: Using an API Gateway](https://www.nginx.com/blog/building-microservices-using-an-api-gateway/)
diff --git a/api-gateway/api-gateway-service/pom.xml b/api-gateway/api-gateway-service/pom.xml
new file mode 100644
index 000000000..87a1ebb5e
--- /dev/null
+++ b/api-gateway/api-gateway-service/pom.xml
@@ -0,0 +1,87 @@
+
+
+
+
+ api-gateway
+ com.iluwatar
+ 1.13.0-SNAPSHOT
+
+ 4.0.0
+ api-gateway-service
+ jar
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+
+
+
+
+
+ org.springframework
+ spring-webmvc
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ junit
+ junit
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+ org.apache.httpcomponents
+ httpclient
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+
+
+ repackage
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ApiGateway.java b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ApiGateway.java
new file mode 100644
index 000000000..60f0b6d54
--- /dev/null
+++ b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ApiGateway.java
@@ -0,0 +1,64 @@
+/**
+ * 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.api.gateway;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * The ApiGateway aggregates calls to microservices based on the needs of the individual clients.
+ */
+@RestController
+public class ApiGateway {
+
+ @Resource
+ private ImageClient imageClient;
+
+ @Resource
+ private PriceClient priceClient;
+
+ /**
+ * Retrieves product information that desktop clients need
+ * @return Product information for clients on a desktop
+ */
+ @RequestMapping("/desktop")
+ public DesktopProduct getProductDesktop() {
+ DesktopProduct desktopProduct = new DesktopProduct();
+ desktopProduct.setImagePath(imageClient.getImagePath());
+ desktopProduct.setPrice(priceClient.getPrice());
+ return desktopProduct;
+ }
+
+ /**
+ * Retrieves product information that mobile clients need
+ * @return Product information for clients on a mobile device
+ */
+ @RequestMapping("/mobile")
+ public MobileProduct getProductMobile() {
+ MobileProduct mobileProduct = new MobileProduct();
+ mobileProduct.setPrice(priceClient.getPrice());
+ return mobileProduct;
+ }
+}
diff --git a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/App.java b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/App.java
new file mode 100644
index 000000000..9a644a0f7
--- /dev/null
+++ b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/App.java
@@ -0,0 +1,66 @@
+/**
+ * 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.api.gateway;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * With the Microservices pattern, a client may need data from multiple different microservices.
+ * If the client called each microservice directly, that could contribute to longer load times,
+ * since the client would have to make a network request for each microservice called. Moreover,
+ * having the client call each microservice directly ties the client to that microservice - if the
+ * internal implementations of the microservices change (for example, if two microservices are
+ * combined sometime in the future) or if the location (host and port) of a microservice changes,
+ * then every client that makes use of those microservices must be updated.
+ *
+ *
+ * The intent of the API Gateway pattern is to alleviate some of these issues. In the API Gateway
+ * pattern, an additional entity (the API Gateway) is placed between the client and the
+ * microservices. The job of the API Gateway is to aggregate the calls to the microservices.
+ * Rather than the client calling each microservice individually, the client calls the API Gateway
+ * a single time. The API Gateway then calls each of the microservices that the client needs.
+ *
+ *
+ * This implementation shows what the API Gateway pattern could look like for an e-commerce site.
+ * The {@link ApiGateway} makes calls to the Image and Price microservices using the
+ * {@link ImageClientImpl} and {@link PriceClientImpl} respectively. Customers viewing the site on a
+ * desktop device can see both price information and an image of a product, so the {@link ApiGateway}
+ * calls both of the microservices and aggregates the data in the {@link DesktopProduct} model.
+ * However, mobile users only see price information; they do not see a product image. For mobile
+ * users, the {@link ApiGateway} only retrieves price information, which it uses to populate the
+ * {@link MobileProduct}.
+ */
+@SpringBootApplication
+public class App {
+
+ /**
+ * Program entry point
+ *
+ * @param args
+ * command line args
+ */
+ public static void main(String[] args) {
+ SpringApplication.run(App.class, args);
+ }
+}
diff --git a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/DesktopProduct.java b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/DesktopProduct.java
new file mode 100644
index 000000000..0a04db402
--- /dev/null
+++ b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/DesktopProduct.java
@@ -0,0 +1,54 @@
+/**
+ * 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.api.gateway;
+
+/**
+ * Encapsulates all of the information that a desktop client needs to display a product.
+ */
+public class DesktopProduct {
+ /**
+ * The price of the product
+ */
+ private String price;
+
+ /**
+ * The path to the image of the product
+ */
+ private String imagePath;
+
+ public String getPrice() {
+ return price;
+ }
+
+ public void setPrice(String price) {
+ this.price = price;
+ }
+
+ public String getImagePath() {
+ return imagePath;
+ }
+
+ public void setImagePath(String imagePath) {
+ this.imagePath = imagePath;
+ }
+}
diff --git a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClient.java b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClient.java
new file mode 100644
index 000000000..935dab778
--- /dev/null
+++ b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClient.java
@@ -0,0 +1,30 @@
+/**
+ * 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.api.gateway;
+
+/**
+ * An interface used to communicate with the Image microservice
+ */
+public interface ImageClient {
+ String getImagePath();
+}
diff --git a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClientImpl.java b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClientImpl.java
new file mode 100644
index 000000000..64fde1e66
--- /dev/null
+++ b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/ImageClientImpl.java
@@ -0,0 +1,56 @@
+/**
+ * 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.api.gateway;
+
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+/**
+ * An adapter to communicate with the Image microservice
+ */
+@Component
+public class ImageClientImpl implements ImageClient{
+ /**
+ * Makes a simple HTTP Get request to the Image microservice
+ * @return The path to the image
+ */
+ @Override
+ public String getImagePath() {
+ String response = null;
+ try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+ HttpGet httpGet = new HttpGet("http://localhost:50005/image-path");
+ try (CloseableHttpResponse httpResponse = httpClient.execute(httpGet)) {
+ response = EntityUtils.toString(httpResponse.getEntity());
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return response;
+ }
+}
diff --git a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/MobileProduct.java b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/MobileProduct.java
new file mode 100644
index 000000000..db358b781
--- /dev/null
+++ b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/MobileProduct.java
@@ -0,0 +1,41 @@
+/**
+ * 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.api.gateway;
+
+/**
+ * Encapsulates all of the information that mobile client needs to display a product.
+ */
+public class MobileProduct {
+ /**
+ * The price of the product
+ */
+ private String price;
+
+ public String getPrice() {
+ return price;
+ }
+
+ public void setPrice(String price) {
+ this.price = price;
+ }
+}
diff --git a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClient.java b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClient.java
new file mode 100644
index 000000000..44497b997
--- /dev/null
+++ b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClient.java
@@ -0,0 +1,30 @@
+/**
+ * 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.api.gateway;
+
+/**
+ * An interface used to communicate with the Price microservice
+ */
+public interface PriceClient {
+ String getPrice();
+}
diff --git a/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClientImpl.java b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClientImpl.java
new file mode 100644
index 000000000..bdc7cb00b
--- /dev/null
+++ b/api-gateway/api-gateway-service/src/main/java/com/iluwatar/api/gateway/PriceClientImpl.java
@@ -0,0 +1,56 @@
+/**
+ * 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.api.gateway;
+
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+/**
+ * An adapter to communicate with the Price microservice
+ */
+@Component
+public class PriceClientImpl implements PriceClient{
+ /**
+ * Makes a simple HTTP Get request to the Price microservice
+ * @return The price of the product
+ */
+ @Override
+ public String getPrice() {
+ String response = null;
+ try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+ HttpGet httpGet = new HttpGet("http://localhost:50006/price");
+ try (CloseableHttpResponse httpResponse = httpClient.execute(httpGet)) {
+ response = EntityUtils.toString(httpResponse.getEntity());
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return response;
+ }
+}
diff --git a/api-gateway/api-gateway-service/src/main/resources/application.properties b/api-gateway/api-gateway-service/src/main/resources/application.properties
new file mode 100644
index 000000000..69f581712
--- /dev/null
+++ b/api-gateway/api-gateway-service/src/main/resources/application.properties
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+server.port=50004
\ No newline at end of file
diff --git a/api-gateway/api-gateway-service/src/test/java/com/iluwatar/api/gateway/ApiGatewayTest.java b/api-gateway/api-gateway-service/src/test/java/com/iluwatar/api/gateway/ApiGatewayTest.java
new file mode 100644
index 000000000..d1a210f05
--- /dev/null
+++ b/api-gateway/api-gateway-service/src/test/java/com/iluwatar/api/gateway/ApiGatewayTest.java
@@ -0,0 +1,78 @@
+/**
+ * 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.api.gateway;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+public class ApiGatewayTest {
+
+ @InjectMocks
+ private ApiGateway apiGateway;
+
+ @Mock
+ private ImageClient imageClient;
+
+ @Mock
+ private PriceClient priceClient;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ /**
+ * Tests getting the data for a desktop client
+ */
+ @Test
+ public void testGetProductDesktop() {
+ String imagePath = "/product-image.png";
+ String price = "20";
+ when(imageClient.getImagePath()).thenReturn(imagePath);
+ when(priceClient.getPrice()).thenReturn(price);
+
+ DesktopProduct desktopProduct = apiGateway.getProductDesktop();
+
+ assertEquals(price, desktopProduct.getPrice());
+ assertEquals(imagePath, desktopProduct.getImagePath());
+ }
+
+ /**
+ * Tests getting the data for a mobile client
+ */
+ @Test
+ public void testGetProductMobile() {
+ String price = "20";
+ when(priceClient.getPrice()).thenReturn(price);
+
+ MobileProduct mobileProduct = apiGateway.getProductMobile();
+
+ assertEquals(price, mobileProduct.getPrice());
+ }
+}
diff --git a/api-gateway/etc/api-gateway.png b/api-gateway/etc/api-gateway.png
new file mode 100644
index 000000000..bb3ec2e2e
Binary files /dev/null and b/api-gateway/etc/api-gateway.png differ
diff --git a/api-gateway/etc/api-gateway.ucls b/api-gateway/etc/api-gateway.ucls
new file mode 100644
index 000000000..4a74c2108
--- /dev/null
+++ b/api-gateway/etc/api-gateway.ucls
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api-gateway/image-microservice/etc/image-microservice.png b/api-gateway/image-microservice/etc/image-microservice.png
new file mode 100644
index 000000000..340285a14
Binary files /dev/null and b/api-gateway/image-microservice/etc/image-microservice.png differ
diff --git a/api-gateway/image-microservice/etc/image-microservice.ucls b/api-gateway/image-microservice/etc/image-microservice.ucls
new file mode 100644
index 000000000..d3520768f
--- /dev/null
+++ b/api-gateway/image-microservice/etc/image-microservice.ucls
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api-gateway/image-microservice/pom.xml b/api-gateway/image-microservice/pom.xml
new file mode 100644
index 000000000..c29932fae
--- /dev/null
+++ b/api-gateway/image-microservice/pom.xml
@@ -0,0 +1,79 @@
+
+
+
+
+ api-gateway
+ com.iluwatar
+ 1.13.0-SNAPSHOT
+
+
+ 4.0.0
+ image-microservice
+ jar
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+
+
+
+
+
+ org.springframework
+ spring-webmvc
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ junit
+ junit
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+
+
+ repackage
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api-gateway/image-microservice/src/main/java/com/iluwatar/image/microservice/ImageApplication.java b/api-gateway/image-microservice/src/main/java/com/iluwatar/image/microservice/ImageApplication.java
new file mode 100644
index 000000000..b4cb3d250
--- /dev/null
+++ b/api-gateway/image-microservice/src/main/java/com/iluwatar/image/microservice/ImageApplication.java
@@ -0,0 +1,43 @@
+/**
+ * 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.image.microservice;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * ImageApplication starts up Spring Boot, exposing endpoints for the Image microservice through
+ * the {@link ImageController}.
+ */
+@SpringBootApplication
+public class ImageApplication {
+
+ /**
+ * Microservice entry point
+ * @param args
+ * command line args
+ */
+ public static void main(String[] args) {
+ SpringApplication.run(ImageApplication.class, args);
+ }
+}
diff --git a/api-gateway/image-microservice/src/main/java/com/iluwatar/image/microservice/ImageController.java b/api-gateway/image-microservice/src/main/java/com/iluwatar/image/microservice/ImageController.java
new file mode 100644
index 000000000..16faf5b70
--- /dev/null
+++ b/api-gateway/image-microservice/src/main/java/com/iluwatar/image/microservice/ImageController.java
@@ -0,0 +1,43 @@
+/**
+ * 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.image.microservice;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Exposes the Image microservice's endpoints
+ */
+@RestController
+public class ImageController {
+
+ /**
+ * An endpoint for a user to retrieve an image path
+ * @return An image path
+ */
+ @RequestMapping(value = "/image-path", method = RequestMethod.GET)
+ public String getImagePath() {
+ return "/product-image.png";
+ }
+}
diff --git a/api-gateway/image-microservice/src/main/resources/application.properties b/api-gateway/image-microservice/src/main/resources/application.properties
new file mode 100644
index 000000000..aeda0c24c
--- /dev/null
+++ b/api-gateway/image-microservice/src/main/resources/application.properties
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+server.port=50005
\ No newline at end of file
diff --git a/api-gateway/image-microservice/src/test/java/com/iluwatar/image/microservice/ImageControllerTest.java b/api-gateway/image-microservice/src/test/java/com/iluwatar/image/microservice/ImageControllerTest.java
new file mode 100644
index 000000000..cf0c099c1
--- /dev/null
+++ b/api-gateway/image-microservice/src/test/java/com/iluwatar/image/microservice/ImageControllerTest.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.image.microservice;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ImageControllerTest {
+ @Test
+ public void testGetImagePath() {
+ ImageController imageController = new ImageController();
+
+ String imagePath = imageController.getImagePath();
+
+ Assert.assertEquals("/product-image.png", imagePath);
+ }
+}
diff --git a/api-gateway/pom.xml b/api-gateway/pom.xml
new file mode 100644
index 000000000..471ffda7d
--- /dev/null
+++ b/api-gateway/pom.xml
@@ -0,0 +1,43 @@
+
+
+
+
+ java-design-patterns
+ com.iluwatar
+ 1.13.0-SNAPSHOT
+
+ 4.0.0
+ api-gateway
+ pom
+
+
+ image-microservice
+ price-microservice
+ api-gateway-service
+
+
\ No newline at end of file
diff --git a/api-gateway/price-microservice/etc/price-microservice.png b/api-gateway/price-microservice/etc/price-microservice.png
new file mode 100644
index 000000000..7c5716025
Binary files /dev/null and b/api-gateway/price-microservice/etc/price-microservice.png differ
diff --git a/api-gateway/price-microservice/etc/price-microservice.ucls b/api-gateway/price-microservice/etc/price-microservice.ucls
new file mode 100644
index 000000000..5878395b6
--- /dev/null
+++ b/api-gateway/price-microservice/etc/price-microservice.ucls
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api-gateway/price-microservice/pom.xml b/api-gateway/price-microservice/pom.xml
new file mode 100644
index 000000000..24e9663aa
--- /dev/null
+++ b/api-gateway/price-microservice/pom.xml
@@ -0,0 +1,79 @@
+
+
+
+
+ api-gateway
+ com.iluwatar
+ 1.13.0-SNAPSHOT
+
+
+ 4.0.0
+ price-microservice
+ jar
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+
+
+
+
+
+ org.springframework
+ spring-webmvc
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ junit
+ junit
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring-boot.version}
+
+
+
+ repackage
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/api-gateway/price-microservice/src/main/java/com/iluwatar/price/microservice/PriceApplication.java b/api-gateway/price-microservice/src/main/java/com/iluwatar/price/microservice/PriceApplication.java
new file mode 100644
index 000000000..e777c7c2b
--- /dev/null
+++ b/api-gateway/price-microservice/src/main/java/com/iluwatar/price/microservice/PriceApplication.java
@@ -0,0 +1,43 @@
+/**
+ * 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.price.microservice;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * PriceApplication starts up Spring Boot, exposing endpoints for the Price microservice through
+ * the {@link PriceController}.
+ */
+@SpringBootApplication
+public class PriceApplication {
+
+ /**
+ * Microservice entry point
+ * @param args
+ * command line args
+ */
+ public static void main(String[] args) {
+ SpringApplication.run(PriceApplication.class, args);
+ }
+}
diff --git a/api-gateway/price-microservice/src/main/java/com/iluwatar/price/microservice/PriceController.java b/api-gateway/price-microservice/src/main/java/com/iluwatar/price/microservice/PriceController.java
new file mode 100644
index 000000000..ec43618fa
--- /dev/null
+++ b/api-gateway/price-microservice/src/main/java/com/iluwatar/price/microservice/PriceController.java
@@ -0,0 +1,43 @@
+/**
+ * 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.price.microservice;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Exposes the Price microservice's endpoints
+ */
+@RestController
+public class PriceController {
+
+ /**
+ * An endpoint for a user to retrieve a product's price
+ * @return A product's price
+ */
+ @RequestMapping(value = "/price", method = RequestMethod.GET)
+ public String getPrice() {
+ return "20";
+ }
+}
diff --git a/api-gateway/price-microservice/src/main/resources/application.properties b/api-gateway/price-microservice/src/main/resources/application.properties
new file mode 100644
index 000000000..f0b479dfd
--- /dev/null
+++ b/api-gateway/price-microservice/src/main/resources/application.properties
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+
+server.port=50006
\ No newline at end of file
diff --git a/api-gateway/price-microservice/src/test/java/com/iluwatar/price/microservice/PriceControllerTest.java b/api-gateway/price-microservice/src/test/java/com/iluwatar/price/microservice/PriceControllerTest.java
new file mode 100644
index 000000000..c289549f2
--- /dev/null
+++ b/api-gateway/price-microservice/src/test/java/com/iluwatar/price/microservice/PriceControllerTest.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.price.microservice;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class PriceControllerTest {
+ @Test
+ public void testgetPrice() {
+ PriceController priceController = new PriceController();
+
+ String price = priceController.getPrice();
+
+ Assert.assertEquals("20", price);
+ }
+}
diff --git a/async-method-invocation/README.md b/async-method-invocation/README.md
new file mode 100644
index 000000000..2d99820c5
--- /dev/null
+++ b/async-method-invocation/README.md
@@ -0,0 +1,33 @@
+---
+layout: pattern
+title: Async Method Invocation
+folder: async-method-invocation
+permalink: /patterns/async-method-invocation/
+categories: Concurrency
+tags:
+ - Java
+ - Difficulty-Intermediate
+ - Functional
+ - Reactive
+---
+
+## Intent
+Asynchronous method invocation is pattern where the calling thread
+is not blocked while waiting results of tasks. The pattern provides parallel
+processing of multiple independent tasks and retrieving the results via
+callbacks or waiting until everything is done.
+
+
+
+## Applicability
+Use async method invocation pattern when
+
+* you have multiple independent tasks that can run in parallel
+* you need to improve the performance of a group of sequential tasks
+* you have limited amount of processing capacity or long running tasks and the
+ caller should not wait the tasks to be ready
+
+## Real world examples
+
+* [FutureTask](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/FutureTask.html), [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) and [ExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html) (Java)
+* [Task-based Asynchronous Pattern](https://msdn.microsoft.com/en-us/library/hh873175.aspx) (.NET)
diff --git a/async-method-invocation/etc/async-method-invocation.png b/async-method-invocation/etc/async-method-invocation.png
new file mode 100644
index 000000000..764895d7a
Binary files /dev/null and b/async-method-invocation/etc/async-method-invocation.png differ
diff --git a/async-method-invocation/etc/async-method-invocation.ucls b/async-method-invocation/etc/async-method-invocation.ucls
new file mode 100644
index 000000000..f2e189eae
--- /dev/null
+++ b/async-method-invocation/etc/async-method-invocation.ucls
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/async-method-invocation/pom.xml b/async-method-invocation/pom.xml
new file mode 100644
index 000000000..d912df965
--- /dev/null
+++ b/async-method-invocation/pom.xml
@@ -0,0 +1,47 @@
+
+
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.13.0-SNAPSHOT
+
+ async-method-invocation
+
+
+ junit
+ junit
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java
new file mode 100644
index 000000000..0a56dc166
--- /dev/null
+++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java
@@ -0,0 +1,125 @@
+/**
+ * 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.async.method.invocation;
+
+import java.util.concurrent.Callable;
+
+/**
+ * This application demonstrates the async method invocation pattern. Key parts of the pattern are
+ * AsyncResult
which is an intermediate container for an asynchronously evaluated value,
+ * AsyncCallback
which can be provided to be executed on task completion and AsyncExecutor
+ * that manages the execution of the async tasks.
+ *
+ * The main method shows example flow of async invocations. The main thread starts multiple tasks with variable
+ * durations and then continues its own work. When the main thread has done it's job it collects the results of the
+ * async tasks. Two of the tasks are handled with callbacks, meaning the callbacks are executed immediately when the
+ * tasks complete.
+ *
+ * Noteworthy difference of thread usage between the async results and callbacks is that the async results are collected
+ * in the main thread but the callbacks are executed within the worker threads. This should be noted when working with
+ * thread pools.
+ *
+ * Java provides its own implementations of async method invocation pattern. FutureTask, CompletableFuture and
+ * ExecutorService are the real world implementations of this pattern. But due to the nature of parallel programming,
+ * the implementations are not trivial. This example does not take all possible scenarios into account but rather
+ * provides a simple version that helps to understand the pattern.
+ *
+ * @see AsyncResult
+ * @see AsyncCallback
+ * @see AsyncExecutor
+ *
+ * @see java.util.concurrent.FutureTask
+ * @see java.util.concurrent.CompletableFuture
+ * @see java.util.concurrent.ExecutorService
+ */
+public class App {
+
+ /**
+ * Program entry point
+ */
+ public static void main(String[] args) throws Exception {
+ // construct a new executor that will run async tasks
+ AsyncExecutor executor = new ThreadAsyncExecutor();
+
+ // start few async tasks with varying processing times, two last with callback handlers
+ AsyncResult asyncResult1 = executor.startProcess(lazyval(10, 500));
+ AsyncResult asyncResult2 = executor.startProcess(lazyval("test", 300));
+ AsyncResult asyncResult3 = executor.startProcess(lazyval(50L, 700));
+ AsyncResult asyncResult4 = executor.startProcess(lazyval(20, 400), callback("Callback result 4"));
+ AsyncResult asyncResult5 = executor.startProcess(lazyval("callback", 600), callback("Callback result 5"));
+
+ // emulate processing in the current thread while async tasks are running in their own threads
+ Thread.sleep(350); // Oh boy I'm working hard here
+ log("Some hard work done");
+
+ // wait for completion of the tasks
+ Integer result1 = executor.endProcess(asyncResult1);
+ String result2 = executor.endProcess(asyncResult2);
+ Long result3 = executor.endProcess(asyncResult3);
+ asyncResult4.await();
+ asyncResult5.await();
+
+ // log the results of the tasks, callbacks log immediately when complete
+ log("Result 1: " + result1);
+ log("Result 2: " + result2);
+ log("Result 3: " + result3);
+ }
+
+ /**
+ * Creates a callable that lazily evaluates to given value with artificial delay.
+ *
+ * @param value
+ * value to evaluate
+ * @param delayMillis
+ * artificial delay in milliseconds
+ * @return new callable for lazy evaluation
+ */
+ private static Callable lazyval(T value, long delayMillis) {
+ return () -> {
+ Thread.sleep(delayMillis);
+ log("Task completed with: " + value);
+ return value;
+ };
+ }
+
+ /**
+ * Creates a simple callback that logs the complete status of the async result.
+ *
+ * @param name
+ * callback name
+ * @return new async callback
+ */
+ private static AsyncCallback callback(String name) {
+ return (value, ex) -> {
+ if (ex.isPresent()) {
+ log(name + " failed: " + ex.map(Exception::getMessage).orElse(""));
+ } else {
+ log(name + ": " + value);
+ }
+ };
+ }
+
+ private static void log(String msg) {
+ System.out.println(String.format("[%1$-10s] - %2$s", Thread.currentThread().getName(), msg));
+ }
+}
diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncCallback.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncCallback.java
new file mode 100644
index 000000000..2fddba683
--- /dev/null
+++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncCallback.java
@@ -0,0 +1,43 @@
+/**
+ * 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.async.method.invocation;
+
+import java.util.Optional;
+
+/**
+ *
+ * AsyncCallback interface
+ *
+ * @param
+ *
+ */
+public interface AsyncCallback {
+
+ /**
+ * Complete handler which is executed when async task is completed or fails execution.
+ *
+ * @param value the evaluated value from async task, undefined when execution fails
+ * @param ex empty value if execution succeeds, some exception if executions fails
+ */
+ void onComplete(T value, Optional ex);
+}
diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncExecutor.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncExecutor.java
new file mode 100644
index 000000000..eb1afa4f3
--- /dev/null
+++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncExecutor.java
@@ -0,0 +1,63 @@
+/**
+ * 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.async.method.invocation;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+
+/**
+ *
+ * AsyncExecutor interface
+ *
+ */
+public interface AsyncExecutor {
+
+ /**
+ * Starts processing of an async task. Returns immediately with async result.
+ *
+ * @param task task to be executed asynchronously
+ * @return async result for the task
+ */
+ AsyncResult startProcess(Callable task);
+
+ /**
+ * Starts processing of an async task. Returns immediately with async result. Executes callback
+ * when the task is completed.
+ *
+ * @param task task to be executed asynchronously
+ * @param callback callback to be executed on task completion
+ * @return async result for the task
+ */
+ AsyncResult startProcess(Callable task, AsyncCallback callback);
+
+ /**
+ * Ends processing of an async task. Blocks the current thread if necessary and returns the
+ * evaluated value of the completed task.
+ *
+ * @param asyncResult async result of a task
+ * @return evaluated value of the completed task
+ * @throws ExecutionException if execution has failed, containing the root cause
+ * @throws InterruptedException if the execution is interrupted
+ */
+ T endProcess(AsyncResult asyncResult) throws ExecutionException, InterruptedException;
+}
diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncResult.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncResult.java
new file mode 100644
index 000000000..bcd97adbc
--- /dev/null
+++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncResult.java
@@ -0,0 +1,55 @@
+/**
+ * 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.async.method.invocation;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ *
+ * AsyncResult interface
+ */
+public interface AsyncResult {
+
+ /**
+ * Status of the async task execution.
+ *
+ * @return true
if execution is completed or failed
+ */
+ boolean isCompleted();
+
+ /**
+ * Gets the value of completed async task.
+ *
+ * @return evaluated value or throws ExecutionException if execution has failed
+ * @throws ExecutionException if execution has failed, containing the root cause
+ * @throws IllegalStateException if execution is not completed
+ */
+ T getValue() throws ExecutionException;
+
+ /**
+ * Blocks the current thread until the async task is completed.
+ *
+ * @throws InterruptedException if the execution is interrupted
+ */
+ void await() throws InterruptedException;
+}
diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java
new file mode 100644
index 000000000..7f96d9ab7
--- /dev/null
+++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java
@@ -0,0 +1,150 @@
+/**
+ * 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.async.method.invocation;
+
+import java.util.Optional;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ *
+ * Implementation of async executor that creates a new thread for every task.
+ *
+ */
+public class ThreadAsyncExecutor implements AsyncExecutor {
+
+ /** Index for thread naming */
+ private final AtomicInteger idx = new AtomicInteger(0);
+
+ @Override
+ public AsyncResult startProcess(Callable task) {
+ return startProcess(task, null);
+ }
+
+ @Override
+ public AsyncResult startProcess(Callable task, AsyncCallback callback) {
+ CompletableResult result = new CompletableResult<>(callback);
+ new Thread(() -> {
+ try {
+ result.setValue(task.call());
+ } catch (Exception ex) {
+ result.setException(ex);
+ }
+ } , "executor-" + idx.incrementAndGet()).start();
+ return result;
+ }
+
+ @Override
+ public T endProcess(AsyncResult asyncResult) throws ExecutionException, InterruptedException {
+ if (asyncResult.isCompleted()) {
+ return asyncResult.getValue();
+ } else {
+ asyncResult.await();
+ return asyncResult.getValue();
+ }
+ }
+
+ /**
+ * Simple implementation of async result that allows completing it successfully with a value or exceptionally with an
+ * exception. A really simplified version from its real life cousins FutureTask and CompletableFuture.
+ *
+ * @see java.util.concurrent.FutureTask
+ * @see java.util.concurrent.CompletableFuture
+ */
+ private static class CompletableResult implements AsyncResult {
+
+ static final int RUNNING = 1;
+ static final int FAILED = 2;
+ static final int COMPLETED = 3;
+
+ final Object lock;
+ final Optional> callback;
+
+ volatile int state = RUNNING;
+ T value;
+ Exception exception;
+
+ CompletableResult(AsyncCallback callback) {
+ this.lock = new Object();
+ this.callback = Optional.ofNullable(callback);
+ }
+
+ /**
+ * Sets the value from successful execution and executes callback if available. Notifies any thread waiting for
+ * completion.
+ *
+ * @param value
+ * value of the evaluated task
+ */
+ void setValue(T value) {
+ this.value = value;
+ this.state = COMPLETED;
+ this.callback.ifPresent(ac -> ac.onComplete(value, Optional.empty()));
+ synchronized (lock) {
+ lock.notifyAll();
+ }
+ }
+
+ /**
+ * Sets the exception from failed execution and executes callback if available. Notifies any thread waiting for
+ * completion.
+ *
+ * @param exception
+ * exception of the failed task
+ */
+ void setException(Exception exception) {
+ this.exception = exception;
+ this.state = FAILED;
+ this.callback.ifPresent(ac -> ac.onComplete(null, Optional.of(exception)));
+ synchronized (lock) {
+ lock.notifyAll();
+ }
+ }
+
+ @Override
+ public boolean isCompleted() {
+ return state > RUNNING;
+ }
+
+ @Override
+ public T getValue() throws ExecutionException {
+ if (state == COMPLETED) {
+ return value;
+ } else if (state == FAILED) {
+ throw new ExecutionException(exception);
+ } else {
+ throw new IllegalStateException("Execution not completed yet");
+ }
+ }
+
+ @Override
+ public void await() throws InterruptedException {
+ synchronized (lock) {
+ if (!isCompleted()) {
+ lock.wait();
+ }
+ }
+ }
+ }
+}
diff --git a/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/AppTest.java b/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/AppTest.java
new file mode 100644
index 000000000..117a75f2a
--- /dev/null
+++ b/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/AppTest.java
@@ -0,0 +1,39 @@
+/**
+ * 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.async.method.invocation;
+
+import org.junit.Test;
+
+/**
+ *
+ * Application test
+ *
+ */
+public class AppTest {
+
+ @Test
+ public void test() throws Exception {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java b/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java
new file mode 100644
index 000000000..b4a23222a
--- /dev/null
+++ b/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java
@@ -0,0 +1,312 @@
+/**
+ * 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.async.method.invocation;
+
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Matchers;
+
+import java.util.Optional;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+
+import static org.junit.Assert.*;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.*;
+import static org.mockito.internal.verification.VerificationModeFactory.times;
+
+/**
+ * Date: 12/6/15 - 10:49 AM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class ThreadAsyncExecutorTest {
+
+ /**
+ * Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)}
+ */
+ @Test(timeout = 3000)
+ public void testSuccessfulTaskWithoutCallback() throws Exception {
+ // Instantiate a new executor and start a new 'null' task ...
+ final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
+
+ final Object result = new Object();
+ final Callable task = mock(Callable.class);
+ when(task.call()).thenReturn(result);
+
+ final AsyncResult asyncResult = executor.startProcess(task);
+ assertNotNull(asyncResult);
+ asyncResult.await(); // Prevent timing issues, and wait until the result is available
+ assertTrue(asyncResult.isCompleted());
+
+ // Our task should only execute once ...
+ verify(task, times(1)).call();
+
+ // ... and the result should be exactly the same object
+ assertSame(result, asyncResult.getValue());
+ }
+
+ /**
+ * Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)}
+ */
+ @Test(timeout = 3000)
+ public void testSuccessfulTaskWithCallback() throws Exception {
+ // Instantiate a new executor and start a new 'null' task ...
+ final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
+
+ final Object result = new Object();
+ final Callable task = mock(Callable.class);
+ when(task.call()).thenReturn(result);
+
+ final AsyncCallback callback = mock(AsyncCallback.class);
+ final AsyncResult asyncResult = executor.startProcess(task, callback);
+ assertNotNull(asyncResult);
+ asyncResult.await(); // Prevent timing issues, and wait until the result is available
+ assertTrue(asyncResult.isCompleted());
+
+ // Our task should only execute once ...
+ verify(task, times(1)).call();
+
+ // ... same for the callback, we expect our object
+ final ArgumentCaptor> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
+ verify(callback, times(1)).onComplete(eq(result), optionalCaptor.capture());
+
+ final Optional optionalException = optionalCaptor.getValue();
+ assertNotNull(optionalException);
+ assertFalse(optionalException.isPresent());
+
+ // ... and the result should be exactly the same object
+ assertSame(result, asyncResult.getValue());
+ }
+
+ /**
+ * Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a task takes a while
+ * to execute
+ */
+ @Test(timeout = 5000)
+ public void testLongRunningTaskWithoutCallback() throws Exception {
+ // Instantiate a new executor and start a new 'null' task ...
+ final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
+
+ final Object result = new Object();
+ final Callable task = mock(Callable.class);
+ when(task.call()).thenAnswer(i -> {
+ Thread.sleep(1500);
+ return result;
+ });
+
+ final AsyncResult asyncResult = executor.startProcess(task);
+ assertNotNull(asyncResult);
+ assertFalse(asyncResult.isCompleted());
+
+ try {
+ asyncResult.getValue();
+ fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
+ } catch (IllegalStateException e) {
+ assertNotNull(e.getMessage());
+ }
+
+ // Our task should only execute once, but it can take a while ...
+ verify(task, timeout(3000).times(1)).call();
+
+ // Prevent timing issues, and wait until the result is available
+ asyncResult.await();
+ assertTrue(asyncResult.isCompleted());
+ verifyNoMoreInteractions(task);
+
+ // ... and the result should be exactly the same object
+ assertSame(result, asyncResult.getValue());
+ }
+
+ /**
+ * Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when a task
+ * takes a while to execute
+ */
+ @Test(timeout = 5000)
+ public void testLongRunningTaskWithCallback() throws Exception {
+ // Instantiate a new executor and start a new 'null' task ...
+ final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
+
+ final Object result = new Object();
+ final Callable task = mock(Callable.class);
+ when(task.call()).thenAnswer(i -> {
+ Thread.sleep(1500);
+ return result;
+ });
+
+ final AsyncCallback callback = mock(AsyncCallback.class);
+ final AsyncResult asyncResult = executor.startProcess(task, callback);
+ assertNotNull(asyncResult);
+ assertFalse(asyncResult.isCompleted());
+
+ verifyZeroInteractions(callback);
+
+ try {
+ asyncResult.getValue();
+ fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
+ } catch (IllegalStateException e) {
+ assertNotNull(e.getMessage());
+ }
+
+ // Our task should only execute once, but it can take a while ...
+ verify(task, timeout(3000).times(1)).call();
+
+ final ArgumentCaptor> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
+ verify(callback, timeout(3000).times(1)).onComplete(eq(result), optionalCaptor.capture());
+
+ final Optional optionalException = optionalCaptor.getValue();
+ assertNotNull(optionalException);
+ assertFalse(optionalException.isPresent());
+
+ // Prevent timing issues, and wait until the result is available
+ asyncResult.await();
+ assertTrue(asyncResult.isCompleted());
+ verifyNoMoreInteractions(task, callback);
+
+ // ... and the result should be exactly the same object
+ assertSame(result, asyncResult.getValue());
+ }
+
+ /**
+ * Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a task takes a while
+ * to execute, while waiting on the result using {@link ThreadAsyncExecutor#endProcess(AsyncResult)}
+ */
+ @Test(timeout = 5000)
+ public void testEndProcess() throws Exception {
+ // Instantiate a new executor and start a new 'null' task ...
+ final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
+
+ final Object result = new Object();
+ final Callable task = mock(Callable.class);
+ when(task.call()).thenAnswer(i -> {
+ Thread.sleep(1500);
+ return result;
+ });
+
+ final AsyncResult asyncResult = executor.startProcess(task);
+ assertNotNull(asyncResult);
+ assertFalse(asyncResult.isCompleted());
+
+ try {
+ asyncResult.getValue();
+ fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
+ } catch (IllegalStateException e) {
+ assertNotNull(e.getMessage());
+ }
+
+ assertSame(result, executor.endProcess(asyncResult));
+ verify(task, times(1)).call();
+ assertTrue(asyncResult.isCompleted());
+
+ // Calling end process a second time while already finished should give the same result
+ assertSame(result, executor.endProcess(asyncResult));
+ verifyNoMoreInteractions(task);
+ }
+
+ /**
+ * Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable)} when the callable is 'null'
+ */
+ @Test(timeout = 3000)
+ public void testNullTask() throws Exception {
+ // Instantiate a new executor and start a new 'null' task ...
+ final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
+ final AsyncResult asyncResult = executor.startProcess(null);
+
+ assertNotNull("The AsyncResult should not be 'null', even though the task was 'null'.", asyncResult);
+ asyncResult.await(); // Prevent timing issues, and wait until the result is available
+ assertTrue(asyncResult.isCompleted());
+
+ try {
+ asyncResult.getValue();
+ fail("Expected ExecutionException with NPE as cause");
+ } catch (final ExecutionException e) {
+ assertNotNull(e.getMessage());
+ assertNotNull(e.getCause());
+ assertEquals(NullPointerException.class, e.getCause().getClass());
+ }
+
+ }
+
+ /**
+ * Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when the
+ * callable is 'null', but the asynchronous callback is provided
+ */
+ @Test(timeout = 3000)
+ public void testNullTaskWithCallback() throws Exception {
+ // Instantiate a new executor and start a new 'null' task ...
+ final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
+ final AsyncCallback callback = mock(AsyncCallback.class);
+ final AsyncResult asyncResult = executor.startProcess(null, callback);
+
+ assertNotNull("The AsyncResult should not be 'null', even though the task was 'null'.", asyncResult);
+ asyncResult.await(); // Prevent timing issues, and wait until the result is available
+ assertTrue(asyncResult.isCompleted());
+
+ final ArgumentCaptor> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
+ verify(callback, times(1)).onComplete(Matchers.isNull(), optionalCaptor.capture());
+
+ final Optional optionalException = optionalCaptor.getValue();
+ assertNotNull(optionalException);
+ assertTrue(optionalException.isPresent());
+
+ final Exception exception = optionalException.get();
+ assertNotNull(exception);
+ assertEquals(NullPointerException.class, exception.getClass());
+
+ try {
+ asyncResult.getValue();
+ fail("Expected ExecutionException with NPE as cause");
+ } catch (final ExecutionException e) {
+ assertNotNull(e.getMessage());
+ assertNotNull(e.getCause());
+ assertEquals(NullPointerException.class, e.getCause().getClass());
+ }
+
+ }
+
+ /**
+ * Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when both
+ * the callable and the asynchronous callback are 'null'
+ */
+ @Test(timeout = 3000)
+ public void testNullTaskWithNullCallback() throws Exception {
+ // Instantiate a new executor and start a new 'null' task ...
+ final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
+ final AsyncResult asyncResult = executor.startProcess(null, null);
+
+ assertNotNull("The AsyncResult should not be 'null', even though the task and callback were 'null'.", asyncResult);
+ asyncResult.await(); // Prevent timing issues, and wait until the result is available
+ assertTrue(asyncResult.isCompleted());
+
+ try {
+ asyncResult.getValue();
+ fail("Expected ExecutionException with NPE as cause");
+ } catch (final ExecutionException e) {
+ assertNotNull(e.getMessage());
+ assertNotNull(e.getCause());
+ assertEquals(NullPointerException.class, e.getCause().getClass());
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/bridge/README.md b/bridge/README.md
new file mode 100644
index 000000000..49dad14e4
--- /dev/null
+++ b/bridge/README.md
@@ -0,0 +1,33 @@
+---
+layout: pattern
+title: Bridge
+folder: bridge
+permalink: /patterns/bridge/
+categories: Structural
+tags:
+ - Java
+ - Gang Of Four
+ - Difficulty-Intermediate
+---
+
+## Also known as
+Handle/Body
+
+## Intent
+Decouple an abstraction from its implementation so that the two can
+vary independently.
+
+
+
+## Applicability
+Use the Bridge pattern when
+
+* you want to avoid a permanent binding between an abstraction and its implementation. This might be the case, for example, when the implementation must be selected or switched at run-time.
+* both the abstractions and their implementations should be extensible by subclassing. In this case, the Bridge pattern lets you combine the different abstractions and implementations and extend them independently
+* changes in the implementation of an abstraction should have no impact on clients; that is, their code should not have to be recompiled.
+* you have a proliferation of classes. Such a class hierarchy indicates the need for splitting an object into two parts. Rumbaugh uses the term "nested generalizations" to refer to such class hierarchies
+* you want to share an implementation among multiple objects (perhaps using reference counting), and this fact should be hidden from the client. A simple example is Coplien's String class, in which multiple objects can share the same string representation.
+
+## Credits
+
+* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/bridge/etc/bridge.png b/bridge/etc/bridge.png
index 472fe51e7..00d3e611c 100644
Binary files a/bridge/etc/bridge.png and b/bridge/etc/bridge.png differ
diff --git a/bridge/etc/bridge.ucls b/bridge/etc/bridge.ucls
index 86455e7fb..2eda6e1d1 100644
--- a/bridge/etc/bridge.ucls
+++ b/bridge/etc/bridge.ucls
@@ -1,18 +1,18 @@
-
-
+
+
-
-
+
+
@@ -21,25 +21,25 @@
-
+
-
-
+
+
-
-
+
+
@@ -48,7 +48,7 @@
-
+
@@ -57,7 +57,7 @@
-
+
@@ -66,7 +66,7 @@
-
+
@@ -75,7 +75,7 @@
-
+
@@ -84,7 +84,7 @@
-
+
@@ -93,7 +93,7 @@
-
+
@@ -101,48 +101,52 @@
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
+
-
-
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
diff --git a/bridge/etc/bridge_1.png b/bridge/etc/bridge_1.png
deleted file mode 100644
index 3152efdf6..000000000
Binary files a/bridge/etc/bridge_1.png and /dev/null differ
diff --git a/bridge/pom.xml b/bridge/pom.xml
index 4718a01bf..a7a3883c8 100644
--- a/bridge/pom.xml
+++ b/bridge/pom.xml
@@ -1,11 +1,35 @@
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
bridge
@@ -14,5 +38,10 @@
junit
test
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/bridge/src/main/java/com/iluwatar/bridge/App.java b/bridge/src/main/java/com/iluwatar/bridge/App.java
index 3797653d4..27b37b6b3 100644
--- a/bridge/src/main/java/com/iluwatar/bridge/App.java
+++ b/bridge/src/main/java/com/iluwatar/bridge/App.java
@@ -1,35 +1,61 @@
-package com.iluwatar.bridge;
-
-/**
- *
- * In Bridge pattern both abstraction (MagicWeapon) and implementation
- * (MagicWeaponImp) have their own class hierarchies. The interface of the
- * implementations can be changed without affecting the clients.
- *
- */
-public class App {
-
- public static void main(String[] args) {
- BlindingMagicWeapon blindingMagicWeapon = new BlindingMagicWeapon(
- new Excalibur());
- blindingMagicWeapon.wield();
- blindingMagicWeapon.blind();
- blindingMagicWeapon.swing();
- blindingMagicWeapon.unwield();
-
- FlyingMagicWeapon flyingMagicWeapon = new FlyingMagicWeapon(
- new Mjollnir());
- flyingMagicWeapon.wield();
- flyingMagicWeapon.fly();
- flyingMagicWeapon.swing();
- flyingMagicWeapon.unwield();
-
- SoulEatingMagicWeapon soulEatingMagicWeapon = new SoulEatingMagicWeapon(
- new Stormbringer());
- soulEatingMagicWeapon.wield();
- soulEatingMagicWeapon.swing();
- soulEatingMagicWeapon.eatSoul();
- soulEatingMagicWeapon.unwield();
-
- }
-}
+/**
+ * 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.bridge;
+
+/**
+ *
+ * The Bridge pattern can also be thought of as two layers of abstraction. With Bridge, you can
+ * decouple an abstraction from its implementation so that the two can vary independently.
+ *
+ * In Bridge pattern both abstraction ({@link MagicWeapon}) and implementation (
+ * {@link MagicWeaponImpl}) have their own class hierarchies. The interface of the implementations
+ * can be changed without affecting the clients.
+ *
+ */
+public class App {
+
+ /**
+ * Program entry point
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ BlindingMagicWeapon blindingMagicWeapon = new BlindingMagicWeapon(new Excalibur());
+ blindingMagicWeapon.wield();
+ blindingMagicWeapon.blind();
+ blindingMagicWeapon.swing();
+ blindingMagicWeapon.unwield();
+
+ FlyingMagicWeapon flyingMagicWeapon = new FlyingMagicWeapon(new Mjollnir());
+ flyingMagicWeapon.wield();
+ flyingMagicWeapon.fly();
+ flyingMagicWeapon.swing();
+ flyingMagicWeapon.unwield();
+
+ SoulEatingMagicWeapon soulEatingMagicWeapon = new SoulEatingMagicWeapon(new Stormbringer());
+ soulEatingMagicWeapon.wield();
+ soulEatingMagicWeapon.swing();
+ soulEatingMagicWeapon.eatSoul();
+ soulEatingMagicWeapon.unwield();
+ }
+}
diff --git a/bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeapon.java b/bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeapon.java
index 5421c6d5e..045039ef0 100644
--- a/bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeapon.java
+++ b/bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeapon.java
@@ -1,33 +1,59 @@
-package com.iluwatar.bridge;
-
-public class BlindingMagicWeapon extends MagicWeapon {
-
- public BlindingMagicWeapon(BlindingMagicWeaponImp imp) {
- super(imp);
- }
-
- @Override
- public BlindingMagicWeaponImp getImp() {
- return (BlindingMagicWeaponImp) imp;
- }
-
- @Override
- public void wield() {
- getImp().wieldImp();
- }
-
- @Override
- public void swing() {
- getImp().swingImp();
- }
-
- @Override
- public void unwield() {
- getImp().unwieldImp();
- }
-
- public void blind() {
- getImp().blindImp();
- }
-
-}
+/**
+ * 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.bridge;
+
+/**
+ *
+ * BlindingMagicWeapon
+ *
+ */
+public class BlindingMagicWeapon extends MagicWeapon {
+
+ public BlindingMagicWeapon(BlindingMagicWeaponImpl imp) {
+ super(imp);
+ }
+
+ @Override
+ public BlindingMagicWeaponImpl getImp() {
+ return (BlindingMagicWeaponImpl) imp;
+ }
+
+ @Override
+ public void wield() {
+ getImp().wieldImp();
+ }
+
+ @Override
+ public void swing() {
+ getImp().swingImp();
+ }
+
+ @Override
+ public void unwield() {
+ getImp().unwieldImp();
+ }
+
+ public void blind() {
+ getImp().blindImp();
+ }
+}
diff --git a/bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeaponImp.java b/bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeaponImp.java
deleted file mode 100644
index 0686ce917..000000000
--- a/bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeaponImp.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.iluwatar.bridge;
-
-public abstract class BlindingMagicWeaponImp extends MagicWeaponImp {
-
- public abstract void blindImp();
-
-}
diff --git a/bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeaponImpl.java b/bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeaponImpl.java
new file mode 100644
index 000000000..83f31e709
--- /dev/null
+++ b/bridge/src/main/java/com/iluwatar/bridge/BlindingMagicWeaponImpl.java
@@ -0,0 +1,34 @@
+/**
+ * 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.bridge;
+
+/**
+ *
+ * BlindingMagicWeaponImpl
+ *
+ */
+public abstract class BlindingMagicWeaponImpl extends MagicWeaponImpl {
+
+ public abstract void blindImp();
+
+}
diff --git a/bridge/src/main/java/com/iluwatar/bridge/Excalibur.java b/bridge/src/main/java/com/iluwatar/bridge/Excalibur.java
index 52298c900..2523b3557 100644
--- a/bridge/src/main/java/com/iluwatar/bridge/Excalibur.java
+++ b/bridge/src/main/java/com/iluwatar/bridge/Excalibur.java
@@ -1,26 +1,51 @@
-package com.iluwatar.bridge;
-
-public class Excalibur extends BlindingMagicWeaponImp {
-
- @Override
- public void wieldImp() {
- System.out.println("wielding Excalibur");
- }
-
- @Override
- public void swingImp() {
- System.out.println("swinging Excalibur");
- }
-
- @Override
- public void unwieldImp() {
- System.out.println("unwielding Excalibur");
- }
-
- @Override
- public void blindImp() {
- System.out
- .println("bright light streams from Excalibur blinding the enemy");
- }
-
-}
+/**
+ * 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.bridge;
+
+/**
+ *
+ * Excalibur
+ *
+ */
+public class Excalibur extends BlindingMagicWeaponImpl {
+
+ @Override
+ public void wieldImp() {
+ System.out.println("wielding Excalibur");
+ }
+
+ @Override
+ public void swingImp() {
+ System.out.println("swinging Excalibur");
+ }
+
+ @Override
+ public void unwieldImp() {
+ System.out.println("unwielding Excalibur");
+ }
+
+ @Override
+ public void blindImp() {
+ System.out.println("bright light streams from Excalibur blinding the enemy");
+ }
+}
diff --git a/bridge/src/main/java/com/iluwatar/bridge/FlyingMagicWeapon.java b/bridge/src/main/java/com/iluwatar/bridge/FlyingMagicWeapon.java
index 9cb1902f9..0988c179c 100644
--- a/bridge/src/main/java/com/iluwatar/bridge/FlyingMagicWeapon.java
+++ b/bridge/src/main/java/com/iluwatar/bridge/FlyingMagicWeapon.java
@@ -1,32 +1,59 @@
-package com.iluwatar.bridge;
-
-public class FlyingMagicWeapon extends MagicWeapon {
-
- public FlyingMagicWeapon(FlyingMagicWeaponImp imp) {
- super(imp);
- }
-
- public FlyingMagicWeaponImp getImp() {
- return (FlyingMagicWeaponImp) imp;
- }
-
- @Override
- public void wield() {
- getImp().wieldImp();
- }
-
- @Override
- public void swing() {
- getImp().swingImp();
- }
-
- @Override
- public void unwield() {
- getImp().unwieldImp();
- }
-
- public void fly() {
- getImp().flyImp();
- }
-
-}
+/**
+ * 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.bridge;
+
+/**
+ *
+ * FlyingMagicWeapon
+ *
+ */
+public class FlyingMagicWeapon extends MagicWeapon {
+
+ public FlyingMagicWeapon(FlyingMagicWeaponImpl imp) {
+ super(imp);
+ }
+
+ public FlyingMagicWeaponImpl getImp() {
+ return (FlyingMagicWeaponImpl) imp;
+ }
+
+ @Override
+ public void wield() {
+ getImp().wieldImp();
+ }
+
+ @Override
+ public void swing() {
+ getImp().swingImp();
+ }
+
+ @Override
+ public void unwield() {
+ getImp().unwieldImp();
+ }
+
+ public void fly() {
+ getImp().flyImp();
+ }
+
+}
diff --git a/bridge/src/main/java/com/iluwatar/bridge/FlyingMagicWeaponImp.java b/bridge/src/main/java/com/iluwatar/bridge/FlyingMagicWeaponImp.java
deleted file mode 100644
index 37fa8a0f9..000000000
--- a/bridge/src/main/java/com/iluwatar/bridge/FlyingMagicWeaponImp.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.iluwatar.bridge;
-
-public abstract class FlyingMagicWeaponImp extends MagicWeaponImp {
-
- public abstract void flyImp();
-
-}
diff --git a/bridge/src/main/java/com/iluwatar/bridge/FlyingMagicWeaponImpl.java b/bridge/src/main/java/com/iluwatar/bridge/FlyingMagicWeaponImpl.java
new file mode 100644
index 000000000..4bdb8801b
--- /dev/null
+++ b/bridge/src/main/java/com/iluwatar/bridge/FlyingMagicWeaponImpl.java
@@ -0,0 +1,34 @@
+/**
+ * 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.bridge;
+
+/**
+ *
+ * FlyingMagicWeaponImpl
+ *
+ */
+public abstract class FlyingMagicWeaponImpl extends MagicWeaponImpl {
+
+ public abstract void flyImp();
+
+}
diff --git a/bridge/src/main/java/com/iluwatar/bridge/MagicWeapon.java b/bridge/src/main/java/com/iluwatar/bridge/MagicWeapon.java
index b03435c51..038da7c4f 100644
--- a/bridge/src/main/java/com/iluwatar/bridge/MagicWeapon.java
+++ b/bridge/src/main/java/com/iluwatar/bridge/MagicWeapon.java
@@ -1,26 +1,47 @@
-package com.iluwatar.bridge;
-
-/**
- *
- * Abstraction interface.
- *
- */
-public abstract class MagicWeapon {
-
- protected MagicWeaponImp imp;
-
- public MagicWeapon(MagicWeaponImp imp) {
- this.imp = imp;
- }
-
- public abstract void wield();
-
- public abstract void swing();
-
- public abstract void unwield();
-
- public MagicWeaponImp getImp() {
- return imp;
- }
-
-}
+/**
+ * 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.bridge;
+
+/**
+ *
+ * MagicWeapon
+ *
+ */
+public abstract class MagicWeapon {
+
+ protected MagicWeaponImpl imp;
+
+ public MagicWeapon(MagicWeaponImpl imp) {
+ this.imp = imp;
+ }
+
+ public abstract void wield();
+
+ public abstract void swing();
+
+ public abstract void unwield();
+
+ public MagicWeaponImpl getImp() {
+ return imp;
+ }
+}
diff --git a/bridge/src/main/java/com/iluwatar/bridge/MagicWeaponImp.java b/bridge/src/main/java/com/iluwatar/bridge/MagicWeaponImp.java
deleted file mode 100644
index cf972c115..000000000
--- a/bridge/src/main/java/com/iluwatar/bridge/MagicWeaponImp.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.iluwatar.bridge;
-
-/**
- *
- * Implementation interface.
- *
- */
-public abstract class MagicWeaponImp {
-
- public abstract void wieldImp();
-
- public abstract void swingImp();
-
- public abstract void unwieldImp();
-
-}
diff --git a/bridge/src/main/java/com/iluwatar/bridge/MagicWeaponImpl.java b/bridge/src/main/java/com/iluwatar/bridge/MagicWeaponImpl.java
new file mode 100644
index 000000000..01f91825b
--- /dev/null
+++ b/bridge/src/main/java/com/iluwatar/bridge/MagicWeaponImpl.java
@@ -0,0 +1,38 @@
+/**
+ * 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.bridge;
+
+/**
+ *
+ * MagicWeaponImpl
+ *
+ */
+public abstract class MagicWeaponImpl {
+
+ public abstract void wieldImp();
+
+ public abstract void swingImp();
+
+ public abstract void unwieldImp();
+
+}
diff --git a/bridge/src/main/java/com/iluwatar/bridge/Mjollnir.java b/bridge/src/main/java/com/iluwatar/bridge/Mjollnir.java
index 0c21f8d07..0cc31b471 100644
--- a/bridge/src/main/java/com/iluwatar/bridge/Mjollnir.java
+++ b/bridge/src/main/java/com/iluwatar/bridge/Mjollnir.java
@@ -1,26 +1,51 @@
-package com.iluwatar.bridge;
-
-public class Mjollnir extends FlyingMagicWeaponImp {
-
- @Override
- public void wieldImp() {
- System.out.println("wielding Mjollnir");
- }
-
- @Override
- public void swingImp() {
- System.out.println("swinging Mjollnir");
- }
-
- @Override
- public void unwieldImp() {
- System.out.println("unwielding Mjollnir");
- }
-
- @Override
- public void flyImp() {
- System.out
- .println("Mjollnir hits the enemy in the air and returns back to the owner's hand");
- }
-
-}
+/**
+ * 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.bridge;
+
+/**
+ *
+ * Mjollnir
+ *
+ */
+public class Mjollnir extends FlyingMagicWeaponImpl {
+
+ @Override
+ public void wieldImp() {
+ System.out.println("wielding Mjollnir");
+ }
+
+ @Override
+ public void swingImp() {
+ System.out.println("swinging Mjollnir");
+ }
+
+ @Override
+ public void unwieldImp() {
+ System.out.println("unwielding Mjollnir");
+ }
+
+ @Override
+ public void flyImp() {
+ System.out.println("Mjollnir hits the enemy in the air and returns back to the owner's hand");
+ }
+}
diff --git a/bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeapon.java b/bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeapon.java
index dbbec102d..d62f7644b 100644
--- a/bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeapon.java
+++ b/bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeapon.java
@@ -1,33 +1,60 @@
-package com.iluwatar.bridge;
-
-public class SoulEatingMagicWeapon extends MagicWeapon {
-
- public SoulEatingMagicWeapon(SoulEatingMagicWeaponImp imp) {
- super(imp);
- }
-
- @Override
- public SoulEatingMagicWeaponImp getImp() {
- return (SoulEatingMagicWeaponImp) imp;
- }
-
- @Override
- public void wield() {
- getImp().wieldImp();
- }
-
- @Override
- public void swing() {
- getImp().swingImp();
- }
-
- @Override
- public void unwield() {
- getImp().unwieldImp();
- }
-
- public void eatSoul() {
- getImp().eatSoulImp();
- }
-
-}
+/**
+ * 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.bridge;
+
+/**
+ *
+ * SoulEatingMagicWeapon
+ *
+ */
+public class SoulEatingMagicWeapon extends MagicWeapon {
+
+ public SoulEatingMagicWeapon(SoulEatingMagicWeaponImpl imp) {
+ super(imp);
+ }
+
+ @Override
+ public SoulEatingMagicWeaponImpl getImp() {
+ return (SoulEatingMagicWeaponImpl) imp;
+ }
+
+ @Override
+ public void wield() {
+ getImp().wieldImp();
+ }
+
+ @Override
+ public void swing() {
+ getImp().swingImp();
+ }
+
+ @Override
+ public void unwield() {
+ getImp().unwieldImp();
+ }
+
+ public void eatSoul() {
+ getImp().eatSoulImp();
+ }
+
+}
diff --git a/bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeaponImp.java b/bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeaponImp.java
deleted file mode 100644
index 3c1a557dd..000000000
--- a/bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeaponImp.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.iluwatar.bridge;
-
-public abstract class SoulEatingMagicWeaponImp extends MagicWeaponImp {
-
- public abstract void eatSoulImp();
-
-}
diff --git a/bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeaponImpl.java b/bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeaponImpl.java
new file mode 100644
index 000000000..ad8bec48f
--- /dev/null
+++ b/bridge/src/main/java/com/iluwatar/bridge/SoulEatingMagicWeaponImpl.java
@@ -0,0 +1,34 @@
+/**
+ * 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.bridge;
+
+/**
+ *
+ * SoulEatingMagicWeaponImpl
+ *
+ */
+public abstract class SoulEatingMagicWeaponImpl extends MagicWeaponImpl {
+
+ public abstract void eatSoulImp();
+
+}
diff --git a/bridge/src/main/java/com/iluwatar/bridge/Stormbringer.java b/bridge/src/main/java/com/iluwatar/bridge/Stormbringer.java
index 55b5960c9..91cad9cc2 100644
--- a/bridge/src/main/java/com/iluwatar/bridge/Stormbringer.java
+++ b/bridge/src/main/java/com/iluwatar/bridge/Stormbringer.java
@@ -1,25 +1,51 @@
-package com.iluwatar.bridge;
-
-public class Stormbringer extends SoulEatingMagicWeaponImp {
-
- @Override
- public void wieldImp() {
- System.out.println("wielding Stormbringer");
- }
-
- @Override
- public void swingImp() {
- System.out.println("swinging Stormbringer");
- }
-
- @Override
- public void unwieldImp() {
- System.out.println("unwielding Stormbringer");
- }
-
- @Override
- public void eatSoulImp() {
- System.out.println("Stormbringer devours the enemy's soul");
- }
-
-}
+/**
+ * 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.bridge;
+
+/**
+ *
+ * Stormbringer
+ *
+ */
+public class Stormbringer extends SoulEatingMagicWeaponImpl {
+
+ @Override
+ public void wieldImp() {
+ System.out.println("wielding Stormbringer");
+ }
+
+ @Override
+ public void swingImp() {
+ System.out.println("swinging Stormbringer");
+ }
+
+ @Override
+ public void unwieldImp() {
+ System.out.println("unwielding Stormbringer");
+ }
+
+ @Override
+ public void eatSoulImp() {
+ System.out.println("Stormbringer devours the enemy's soul");
+ }
+}
diff --git a/bridge/src/test/java/com/iluwatar/bridge/AppTest.java b/bridge/src/test/java/com/iluwatar/bridge/AppTest.java
index 196008950..1b9b63d7f 100644
--- a/bridge/src/test/java/com/iluwatar/bridge/AppTest.java
+++ b/bridge/src/test/java/com/iluwatar/bridge/AppTest.java
@@ -1,14 +1,39 @@
-package com.iluwatar.bridge;
-
-import org.junit.Test;
-
-import com.iluwatar.bridge.App;
-
-public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
-}
+/**
+ * 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.bridge;
+
+import org.junit.Test;
+
+/**
+ *
+ * Application test
+ *
+ */
+public class AppTest {
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/bridge/src/test/java/com/iluwatar/bridge/BlindingMagicWeaponTest.java b/bridge/src/test/java/com/iluwatar/bridge/BlindingMagicWeaponTest.java
new file mode 100644
index 000000000..54435555e
--- /dev/null
+++ b/bridge/src/test/java/com/iluwatar/bridge/BlindingMagicWeaponTest.java
@@ -0,0 +1,55 @@
+/**
+ * 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.bridge;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.internal.verification.VerificationModeFactory.times;
+
+/**
+ * Date: 12/6/15 - 11:15 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class BlindingMagicWeaponTest extends MagicWeaponTest {
+
+ /**
+ * Invoke all possible actions on the weapon and check if the actions are executed on the actual
+ * underlying weapon implementation.
+ */
+ @Test
+ public void testExcalibur() throws Exception {
+ final Excalibur excalibur = spy(new Excalibur());
+ final BlindingMagicWeapon blindingMagicWeapon = new BlindingMagicWeapon(excalibur);
+
+ testBasicWeaponActions(blindingMagicWeapon, excalibur);
+
+ blindingMagicWeapon.blind();
+ verify(excalibur, times(1)).blindImp();
+ verifyNoMoreInteractions(excalibur);
+ }
+
+}
diff --git a/bridge/src/test/java/com/iluwatar/bridge/FlyingMagicWeaponTest.java b/bridge/src/test/java/com/iluwatar/bridge/FlyingMagicWeaponTest.java
new file mode 100644
index 000000000..9053a7bb0
--- /dev/null
+++ b/bridge/src/test/java/com/iluwatar/bridge/FlyingMagicWeaponTest.java
@@ -0,0 +1,55 @@
+/**
+ * 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.bridge;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.internal.verification.VerificationModeFactory.times;
+
+/**
+ * Date: 12/6/15 - 11:26 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class FlyingMagicWeaponTest extends MagicWeaponTest {
+
+ /**
+ * Invoke all possible actions on the weapon and check if the actions are executed on the actual
+ * underlying weapon implementation.
+ */
+ @Test
+ public void testMjollnir() throws Exception {
+ final Mjollnir mjollnir = spy(new Mjollnir());
+ final FlyingMagicWeapon flyingMagicWeapon = new FlyingMagicWeapon(mjollnir);
+
+ testBasicWeaponActions(flyingMagicWeapon, mjollnir);
+
+ flyingMagicWeapon.fly();
+ verify(mjollnir, times(1)).flyImp();
+ verifyNoMoreInteractions(mjollnir);
+ }
+
+}
\ No newline at end of file
diff --git a/bridge/src/test/java/com/iluwatar/bridge/MagicWeaponTest.java b/bridge/src/test/java/com/iluwatar/bridge/MagicWeaponTest.java
new file mode 100644
index 000000000..6408fd256
--- /dev/null
+++ b/bridge/src/test/java/com/iluwatar/bridge/MagicWeaponTest.java
@@ -0,0 +1,64 @@
+/**
+ * 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.bridge;
+
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.internal.verification.VerificationModeFactory.times;
+
+/**
+ * Date: 12/6/15 - 11:28 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class MagicWeaponTest {
+
+ /**
+ * Invoke the basic actions of the given weapon, and test if the underlying weapon implementation
+ * is invoked
+ *
+ * @param weaponImpl The spied weapon implementation where actions are bridged to
+ * @param weapon The weapon, handled by the app
+ */
+ protected final void testBasicWeaponActions(final MagicWeapon weapon,
+ final MagicWeaponImpl weaponImpl) {
+ assertNotNull(weapon);
+ assertNotNull(weaponImpl);
+ assertNotNull(weapon.getImp());
+
+ weapon.swing();
+ verify(weaponImpl, times(1)).swingImp();
+ verifyNoMoreInteractions(weaponImpl);
+
+ weapon.wield();
+ verify(weaponImpl, times(1)).wieldImp();
+ verifyNoMoreInteractions(weaponImpl);
+
+ weapon.unwield();
+ verify(weaponImpl, times(1)).unwieldImp();
+ verifyNoMoreInteractions(weaponImpl);
+
+ }
+
+}
diff --git a/bridge/src/test/java/com/iluwatar/bridge/SoulEatingMagicWeaponTest.java b/bridge/src/test/java/com/iluwatar/bridge/SoulEatingMagicWeaponTest.java
new file mode 100644
index 000000000..0bd0a6b8d
--- /dev/null
+++ b/bridge/src/test/java/com/iluwatar/bridge/SoulEatingMagicWeaponTest.java
@@ -0,0 +1,55 @@
+/**
+ * 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.bridge;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.internal.verification.VerificationModeFactory.times;
+
+/**
+ * Date: 12/6/15 - 11:43 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SoulEatingMagicWeaponTest extends MagicWeaponTest {
+
+ /**
+ * Invoke all possible actions on the weapon and check if the actions are executed on the actual
+ * underlying weapon implementation.
+ */
+ @Test
+ public void testStormBringer() throws Exception {
+ final Stormbringer stormbringer = spy(new Stormbringer());
+ final SoulEatingMagicWeapon soulEatingMagicWeapon = new SoulEatingMagicWeapon(stormbringer);
+
+ testBasicWeaponActions(soulEatingMagicWeapon, stormbringer);
+
+ soulEatingMagicWeapon.eatSoul();
+ verify(stormbringer, times(1)).eatSoulImp();
+ verifyNoMoreInteractions(stormbringer);
+ }
+
+}
\ No newline at end of file
diff --git a/builder/README.md b/builder/README.md
new file mode 100644
index 000000000..5d1f3d24d
--- /dev/null
+++ b/builder/README.md
@@ -0,0 +1,34 @@
+---
+layout: pattern
+title: Builder
+folder: builder
+permalink: /patterns/builder/
+categories: Creational
+tags:
+ - Java
+ - Gang Of Four
+ - Difficulty-Intermediate
+---
+
+## Intent
+Separate the construction of a complex object from its
+representation so that the same construction process can create different
+representations.
+
+
+
+## Applicability
+Use the Builder pattern when
+
+* the algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled
+* the construction process must allow different representations for the object that's constructed
+
+## Real world examples
+
+* [java.lang.StringBuilder](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html)
+* [Apache Camel builders](https://github.com/apache/camel/tree/0e195428ee04531be27a0b659005e3aa8d159d23/camel-core/src/main/java/org/apache/camel/builder)
+
+## Credits
+
+* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [Effective Java (2nd Edition)](http://www.amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683)
diff --git a/builder/etc/builder.ucls b/builder/etc/builder.ucls
index 06a83ced7..073c5cea7 100644
--- a/builder/etc/builder.ucls
+++ b/builder/etc/builder.ucls
@@ -28,7 +28,7 @@
-
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
builder
diff --git a/builder/src/main/java/com/iluwatar/builder/App.java b/builder/src/main/java/com/iluwatar/builder/App.java
index e38e5a0c3..d421de7b6 100644
--- a/builder/src/main/java/com/iluwatar/builder/App.java
+++ b/builder/src/main/java/com/iluwatar/builder/App.java
@@ -1,38 +1,77 @@
-package com.iluwatar.builder;
-
-import com.iluwatar. builder.Hero.HeroBuilder;
-
-/**
- *
- * This is the Builder pattern variation as described by Joshua Bloch in
- * Effective Java 2nd Edition.
- *
- * We want to build Hero objects, but its construction is complex because of the
- * many parameters needed. To aid the user we introduce HeroBuilder class.
- * HeroBuilder takes the minimum parameters to build Hero object in its
- * constructor. After that additional configuration for the Hero object can be
- * done using the fluent HeroBuilder interface. When configuration is ready the
- * build method is called to receive the final Hero object.
- *
- */
-public class App {
-
- public static void main(String[] args) {
-
- Hero mage = new HeroBuilder(Profession.MAGE, "Riobard")
- .withHairColor(HairColor.BLACK).withWeapon(Weapon.DAGGER)
- .build();
- System.out.println(mage);
-
- Hero warrior = new HeroBuilder(Profession.WARRIOR, "Amberjill")
- .withHairColor(HairColor.BLOND)
- .withHairType(HairType.LONG_CURLY).withArmor(Armor.CHAIN_MAIL)
- .withWeapon(Weapon.SWORD).build();
- System.out.println(warrior);
-
- Hero thief = new HeroBuilder(Profession.THIEF, "Desmond")
- .withHairType(HairType.BALD).withWeapon(Weapon.BOW).build();
- System.out.println(thief);
-
- }
-}
+/**
+ * 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.builder;
+
+import com.iluwatar.builder.Hero.Builder;
+
+/**
+ *
+ * The intention of the Builder pattern is to find a solution to the telescoping constructor
+ * anti-pattern. The telescoping constructor anti-pattern occurs when the increase of object
+ * constructor parameter combination leads to an exponential list of constructors. Instead of using
+ * numerous constructors, the builder pattern uses another object, a builder, that receives each
+ * initialization parameter step by step and then returns the resulting constructed object at once.
+ *
+ * The Builder pattern has another benefit. It can be used for objects that contain flat data (html
+ * code, SQL query, X.509 certificate...), that is to say, data that can't be easily edited. This
+ * type of data cannot be edited step by step and must be edited at once. The best way to construct
+ * such an object is to use a builder class.
+ *
+ * In this example we have the Builder pattern variation as described by Joshua Bloch in Effective
+ * Java 2nd Edition.
+ *
+ * We want to build {@link Hero} objects, but its construction is complex because of the many
+ * parameters needed. To aid the user we introduce {@link Builder} class. {@link Hero.Builder}
+ * takes the minimum parameters to build {@link Hero} object in its constructor. After that
+ * additional configuration for the {@link Hero} object can be done using the fluent
+ * {@link Builder} interface. When configuration is ready the build method is called to receive
+ * the final {@link Hero} object.
+ *
+ */
+public class App {
+
+ /**
+ * Program entry point
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+
+ Hero mage =
+ new Hero.Builder(Profession.MAGE, "Riobard").withHairColor(HairColor.BLACK)
+ .withWeapon(Weapon.DAGGER).build();
+ System.out.println(mage);
+
+ Hero warrior =
+ new Hero.Builder(Profession.WARRIOR, "Amberjill").withHairColor(HairColor.BLOND)
+ .withHairType(HairType.LONG_CURLY).withArmor(Armor.CHAIN_MAIL).withWeapon(Weapon.SWORD)
+ .build();
+ System.out.println(warrior);
+
+ Hero thief =
+ new Hero.Builder(Profession.THIEF, "Desmond").withHairType(HairType.BALD)
+ .withWeapon(Weapon.BOW).build();
+ System.out.println(thief);
+
+ }
+}
diff --git a/builder/src/main/java/com/iluwatar/builder/Armor.java b/builder/src/main/java/com/iluwatar/builder/Armor.java
index ebec6a47d..a0a4fe582 100644
--- a/builder/src/main/java/com/iluwatar/builder/Armor.java
+++ b/builder/src/main/java/com/iluwatar/builder/Armor.java
@@ -1,17 +1,44 @@
-package com.iluwatar.builder;
-
-public enum Armor {
-
- CLOTHES("clothes"), LEATHER("leather"), CHAIN_MAIL("chain mail"), PLATE_MAIL("plate mail");
-
- private String title;
-
- Armor(String title) {
- this.title = title;
- }
-
- @Override
- public String toString() {
- return title;
- }
-}
+/**
+ * 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.builder;
+
+/**
+ *
+ * Armor enumeration
+ *
+ */
+public enum Armor {
+
+ CLOTHES("clothes"), LEATHER("leather"), CHAIN_MAIL("chain mail"), PLATE_MAIL("plate mail");
+
+ private String title;
+
+ Armor(String title) {
+ this.title = title;
+ }
+
+ @Override
+ public String toString() {
+ return title;
+ }
+}
diff --git a/builder/src/main/java/com/iluwatar/builder/HairColor.java b/builder/src/main/java/com/iluwatar/builder/HairColor.java
index a73044754..3c3195cc6 100644
--- a/builder/src/main/java/com/iluwatar/builder/HairColor.java
+++ b/builder/src/main/java/com/iluwatar/builder/HairColor.java
@@ -1,12 +1,39 @@
-package com.iluwatar.builder;
-
-public enum HairColor {
-
- WHITE, BLOND, RED, BROWN, BLACK;
-
- @Override
- public String toString() {
- return name().toLowerCase();
- }
-
-}
+/**
+ * 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.builder;
+
+/**
+ *
+ * HairColor enumeration
+ *
+ */
+public enum HairColor {
+
+ WHITE, BLOND, RED, BROWN, BLACK;
+
+ @Override
+ public String toString() {
+ return name().toLowerCase();
+ }
+
+}
diff --git a/builder/src/main/java/com/iluwatar/builder/HairType.java b/builder/src/main/java/com/iluwatar/builder/HairType.java
index 075699a58..8d15b0f30 100644
--- a/builder/src/main/java/com/iluwatar/builder/HairType.java
+++ b/builder/src/main/java/com/iluwatar/builder/HairType.java
@@ -1,17 +1,45 @@
-package com.iluwatar.builder;
-
-public enum HairType {
-
- BALD("bald"), SHORT("short"), CURLY("curly"), LONG_STRAIGHT("long straight"), LONG_CURLY("long curly");
-
- private String title;
-
- HairType(String title) {
- this.title = title;
- }
-
- @Override
- public String toString() {
- return title;
- }
-}
+/**
+ * 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.builder;
+
+/**
+ *
+ * HairType enumeration
+ *
+ */
+public enum HairType {
+
+ BALD("bald"), SHORT("short"), CURLY("curly"), LONG_STRAIGHT("long straight"), LONG_CURLY(
+ "long curly");
+
+ private String title;
+
+ HairType(String title) {
+ this.title = title;
+ }
+
+ @Override
+ public String toString() {
+ return title;
+ }
+}
diff --git a/builder/src/main/java/com/iluwatar/builder/Hero.java b/builder/src/main/java/com/iluwatar/builder/Hero.java
index 75513eeda..25445851a 100644
--- a/builder/src/main/java/com/iluwatar/builder/Hero.java
+++ b/builder/src/main/java/com/iluwatar/builder/Hero.java
@@ -1,129 +1,149 @@
+/**
+ * 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.builder;
/**
*
- * The class with many parameters.
+ * Hero, the class with many parameters.
*
*/
-public class Hero {
+public final class Hero {
- private final Profession profession;
- private final String name;
- private final HairType hairType;
- private final HairColor hairColor;
- private final Armor armor;
- private final Weapon weapon;
+ private final Profession profession;
+ private final String name;
+ private final HairType hairType;
+ private final HairColor hairColor;
+ private final Armor armor;
+ private final Weapon weapon;
- public Profession getProfession() {
- return profession;
- }
+ private Hero(Builder builder) {
+ this.profession = builder.profession;
+ this.name = builder.name;
+ this.hairColor = builder.hairColor;
+ this.hairType = builder.hairType;
+ this.weapon = builder.weapon;
+ this.armor = builder.armor;
+ }
- public String getName() {
- return name;
- }
+ public Profession getProfession() {
+ return profession;
+ }
- public HairType getHairType() {
- return hairType;
- }
+ public String getName() {
+ return name;
+ }
- public HairColor getHairColor() {
- return hairColor;
- }
+ public HairType getHairType() {
+ return hairType;
+ }
- public Armor getArmor() {
- return armor;
- }
+ public HairColor getHairColor() {
+ return hairColor;
+ }
- public Weapon getWeapon() {
- return weapon;
- }
+ public Armor getArmor() {
+ return armor;
+ }
- @Override
- public String toString() {
+ public Weapon getWeapon() {
+ return weapon;
+ }
- StringBuilder sb = new StringBuilder();
- sb.append("This is a ");
- sb.append(profession);
- sb.append(" named ");
- sb.append(name);
- if (hairColor != null || hairType != null) {
- sb.append(" with ");
- if (hairColor != null) {
- sb.append(hairColor);
- sb.append(" ");
- }
- if (hairType != null) {
- sb.append(hairType);
- sb.append(" ");
- }
- sb.append(hairType != HairType.BALD ? "hair" : "head");
- }
- if (armor != null) {
- sb.append(" wearing ");
- sb.append(armor);
- }
- if (weapon != null) {
- sb.append(" and wielding a ");
- sb.append(weapon);
- }
- sb.append(".");
- return sb.toString();
- }
+ @Override
+ public String toString() {
- private Hero(HeroBuilder builder) {
- this.profession = builder.profession;
- this.name = builder.name;
- this.hairColor = builder.hairColor;
- this.hairType = builder.hairType;
- this.weapon = builder.weapon;
- this.armor = builder.armor;
- }
+ StringBuilder sb = new StringBuilder();
+ sb.append("This is a ")
+ .append(profession)
+ .append(" named ")
+ .append(name);
+ if (hairColor != null || hairType != null) {
+ sb.append(" with ");
+ if (hairColor != null) {
+ sb.append(hairColor).append(' ');
+ }
+ if (hairType != null) {
+ sb.append(hairType).append(' ');
+ }
+ sb.append(hairType != HairType.BALD ? "hair" : "head");
+ }
+ if (armor != null) {
+ sb.append(" wearing ").append(armor);
+ }
+ if (weapon != null) {
+ sb.append(" and wielding a ").append(weapon);
+ }
+ sb.append('.');
+ return sb.toString();
+ }
- /**
- *
- * The builder class.
- *
- */
- public static class HeroBuilder {
+ /**
+ *
+ * The builder class.
+ *
+ */
+ public static class Builder {
- private final Profession profession;
- private final String name;
- private HairType hairType;
- private HairColor hairColor;
- private Armor armor;
- private Weapon weapon;
+ private final Profession profession;
+ private final String name;
+ private HairType hairType;
+ private HairColor hairColor;
+ private Armor armor;
+ private Weapon weapon;
- public HeroBuilder(Profession profession, String name) {
- if (profession == null || name == null) {
- throw new IllegalArgumentException(
- "profession and name can not be null");
- }
- this.profession = profession;
- this.name = name;
- }
+ /**
+ * Constructor
+ */
+ public Builder(Profession profession, String name) {
+ if (profession == null || name == null) {
+ throw new IllegalArgumentException("profession and name can not be null");
+ }
+ this.profession = profession;
+ this.name = name;
+ }
- public HeroBuilder withHairType(HairType hairType) {
- this.hairType = hairType;
- return this;
- }
+ public Builder withHairType(HairType hairType) {
+ this.hairType = hairType;
+ return this;
+ }
- public HeroBuilder withHairColor(HairColor hairColor) {
- this.hairColor = hairColor;
- return this;
- }
+ public Builder withHairColor(HairColor hairColor) {
+ this.hairColor = hairColor;
+ return this;
+ }
- public HeroBuilder withArmor(Armor armor) {
- this.armor = armor;
- return this;
- }
+ public Builder withArmor(Armor armor) {
+ this.armor = armor;
+ return this;
+ }
- public HeroBuilder withWeapon(Weapon weapon) {
- this.weapon = weapon;
- return this;
- }
+ public Builder withWeapon(Weapon weapon) {
+ this.weapon = weapon;
+ return this;
+ }
- public Hero build() {
- return new Hero(this);
- }
- }
+ public Hero build() {
+ return new Hero(this);
+ }
+ }
}
diff --git a/builder/src/main/java/com/iluwatar/builder/Profession.java b/builder/src/main/java/com/iluwatar/builder/Profession.java
index 487fc5133..7be5b999e 100644
--- a/builder/src/main/java/com/iluwatar/builder/Profession.java
+++ b/builder/src/main/java/com/iluwatar/builder/Profession.java
@@ -1,12 +1,38 @@
-package com.iluwatar.builder;
-
-public enum Profession {
-
- WARRIOR, THIEF, MAGE, PRIEST;
-
- @Override
- public String toString() {
- return name().toLowerCase();
- }
-
-}
+/**
+ * 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.builder;
+
+/**
+ *
+ * Profession enumeration
+ *
+ */
+public enum Profession {
+
+ WARRIOR, THIEF, MAGE, PRIEST;
+
+ @Override
+ public String toString() {
+ return name().toLowerCase();
+ }
+}
diff --git a/builder/src/main/java/com/iluwatar/builder/Weapon.java b/builder/src/main/java/com/iluwatar/builder/Weapon.java
index 99622ddac..97d347d24 100644
--- a/builder/src/main/java/com/iluwatar/builder/Weapon.java
+++ b/builder/src/main/java/com/iluwatar/builder/Weapon.java
@@ -1,12 +1,38 @@
-package com.iluwatar.builder;
-
-public enum Weapon {
-
- DAGGER, SWORD, AXE, WARHAMMER, BOW;
-
- @Override
- public String toString() {
- return name().toLowerCase();
- }
-
-}
+/**
+ * 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.builder;
+
+/**
+ *
+ * Weapon enumeration
+ *
+ */
+public enum Weapon {
+
+ DAGGER, SWORD, AXE, WARHAMMER, BOW;
+
+ @Override
+ public String toString() {
+ return name().toLowerCase();
+ }
+}
diff --git a/builder/src/test/java/com/iluwatar/builder/AppTest.java b/builder/src/test/java/com/iluwatar/builder/AppTest.java
index 462ad3a9a..e83db9f9f 100644
--- a/builder/src/test/java/com/iluwatar/builder/AppTest.java
+++ b/builder/src/test/java/com/iluwatar/builder/AppTest.java
@@ -1,14 +1,39 @@
-package com.iluwatar.builder;
-
-import org.junit.Test;
-
-import com.iluwatar. builder.App;
-
-public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
-}
+/**
+ * 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.builder;
+
+import org.junit.Test;
+
+/**
+ *
+ * Application test
+ *
+ */
+public class AppTest {
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/builder/src/test/java/com/iluwatar/builder/HeroTest.java b/builder/src/test/java/com/iluwatar/builder/HeroTest.java
new file mode 100644
index 000000000..b0a73a9d0
--- /dev/null
+++ b/builder/src/test/java/com/iluwatar/builder/HeroTest.java
@@ -0,0 +1,78 @@
+/**
+ * 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.builder;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Date: 12/6/15 - 11:01 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class HeroTest {
+
+ /**
+ * Test if we get the expected exception when trying to create a hero without a profession
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testMissingProfession() throws Exception {
+ new Hero.Builder(null, "Sir without a job");
+ }
+
+ /**
+ * Test if we get the expected exception when trying to create a hero without a name
+ */
+ @Test(expected = IllegalArgumentException.class)
+ public void testMissingName() throws Exception {
+ new Hero.Builder(Profession.THIEF, null);
+ }
+
+ /**
+ * Test if the hero build by the builder has the correct attributes, as requested
+ */
+ @Test
+ public void testBuildHero() throws Exception {
+ final String heroName = "Sir Lancelot";
+
+ final Hero hero = new Hero.Builder(Profession.WARRIOR, heroName)
+ .withArmor(Armor.CHAIN_MAIL)
+ .withWeapon(Weapon.SWORD)
+ .withHairType(HairType.LONG_CURLY)
+ .withHairColor(HairColor.BLOND)
+ .build();
+
+ assertNotNull(hero);
+ assertNotNull(hero.toString());
+ assertEquals(Profession.WARRIOR, hero.getProfession());
+ assertEquals(heroName, hero.getName());
+ assertEquals(Armor.CHAIN_MAIL, hero.getArmor());
+ assertEquals(Weapon.SWORD, hero.getWeapon());
+ assertEquals(HairType.LONG_CURLY, hero.getHairType());
+ assertEquals(HairColor.BLOND, hero.getHairColor());
+
+ }
+
+}
\ No newline at end of file
diff --git a/business-delegate/README.md b/business-delegate/README.md
new file mode 100644
index 000000000..e6e249122
--- /dev/null
+++ b/business-delegate/README.md
@@ -0,0 +1,29 @@
+---
+layout: pattern
+title: Business Delegate
+folder: business-delegate
+permalink: /patterns/business-delegate/
+categories: Business Tier
+tags:
+ - Java
+ - Difficulty-Intermediate
+---
+
+## Intent
+The Business Delegate pattern adds an abstraction layer between
+presentation and business tiers. By using the pattern we gain loose coupling
+between the tiers and encapsulate knowledge about how to locate, connect to,
+and interact with the business objects that make up the application.
+
+
+
+## Applicability
+Use the Business Delegate pattern when
+
+* you want loose coupling between presentation and business tiers
+* you want to orchestrate calls to multiple business services
+* you want to encapsulate service lookups and service calls
+
+## Credits
+
+* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
diff --git a/business-delegate/etc/business-delegate.png b/business-delegate/etc/business-delegate.png
new file mode 100644
index 000000000..928cf9346
Binary files /dev/null and b/business-delegate/etc/business-delegate.png differ
diff --git a/business-delegate/etc/business-delegate.ucls b/business-delegate/etc/business-delegate.ucls
new file mode 100644
index 000000000..668a6579e
--- /dev/null
+++ b/business-delegate/etc/business-delegate.ucls
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/business-delegate/pom.xml b/business-delegate/pom.xml
new file mode 100644
index 000000000..c6f7e0c37
--- /dev/null
+++ b/business-delegate/pom.xml
@@ -0,0 +1,48 @@
+
+
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.13.0-SNAPSHOT
+
+ business-delegate
+
+
+ junit
+ junit
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/App.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/App.java
new file mode 100644
index 000000000..e9a264322
--- /dev/null
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/App.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.business.delegate;
+
+/**
+ * The Business Delegate pattern adds an abstraction layer between the presentation and business
+ * tiers. By using the pattern we gain loose coupling between the tiers. The Business Delegate
+ * encapsulates knowledge about how to locate, connect to, and interact with the business objects
+ * that make up the application.
+ *
+ *
Some of the services the Business Delegate uses are instantiated directly, and some can be
+ * retrieved through service lookups. The Business Delegate itself may contain business logic too
+ * potentially tying together multiple service calls, exception handling, retrying etc.
+ *
+ *
In this example the client ({@link Client}) utilizes a business delegate (
+ * {@link BusinessDelegate}) to execute a task. The Business Delegate then selects the appropriate
+ * service and makes the service call.
+ */
+public class App {
+
+ /**
+ * Program entry point.
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+
+ BusinessDelegate businessDelegate = new BusinessDelegate();
+ BusinessLookup businessLookup = new BusinessLookup();
+ businessLookup.setEjbService(new EjbService());
+ businessLookup.setJmsService(new JmsService());
+
+ businessDelegate.setLookupService(businessLookup);
+ businessDelegate.setServiceType(ServiceType.EJB);
+
+ Client client = new Client(businessDelegate);
+ client.doTask();
+
+ businessDelegate.setServiceType(ServiceType.JMS);
+ client.doTask();
+ }
+}
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessDelegate.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessDelegate.java
new file mode 100644
index 000000000..81aa9a0f1
--- /dev/null
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessDelegate.java
@@ -0,0 +1,46 @@
+/**
+ * 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.business.delegate;
+
+/**
+ * BusinessDelegate separates the presentation and business tiers
+ */
+public class BusinessDelegate {
+
+ private BusinessLookup lookupService;
+ private BusinessService businessService;
+ private ServiceType serviceType;
+
+ public void setLookupService(BusinessLookup businessLookup) {
+ this.lookupService = businessLookup;
+ }
+
+ public void setServiceType(ServiceType serviceType) {
+ this.serviceType = serviceType;
+ }
+
+ public void doTask() {
+ businessService = lookupService.getBusinessService(serviceType);
+ businessService.doProcessing();
+ }
+}
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessLookup.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessLookup.java
new file mode 100644
index 000000000..7e1045e7f
--- /dev/null
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessLookup.java
@@ -0,0 +1,53 @@
+/**
+ * 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.business.delegate;
+
+/**
+ * Class for performing service lookups.
+ */
+public class BusinessLookup {
+
+ private EjbService ejbService;
+
+ private JmsService jmsService;
+
+ /**
+ * @param serviceType Type of service instance to be returned.
+ * @return Service instance.
+ */
+ public BusinessService getBusinessService(ServiceType serviceType) {
+ if (serviceType.equals(ServiceType.EJB)) {
+ return ejbService;
+ } else {
+ return jmsService;
+ }
+ }
+
+ public void setJmsService(JmsService jmsService) {
+ this.jmsService = jmsService;
+ }
+
+ public void setEjbService(EjbService ejbService) {
+ this.ejbService = ejbService;
+ }
+}
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessService.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessService.java
new file mode 100644
index 000000000..f5784964a
--- /dev/null
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/BusinessService.java
@@ -0,0 +1,33 @@
+/**
+ * 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.business.delegate;
+
+/**
+ *
+ * Interface for service implementations
+ *
+ */
+public interface BusinessService {
+
+ void doProcessing();
+}
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/Client.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/Client.java
new file mode 100644
index 000000000..8c6bf59a1
--- /dev/null
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/Client.java
@@ -0,0 +1,41 @@
+/**
+ * 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.business.delegate;
+
+/**
+ *
+ * Client utilizes BusinessDelegate to call the business tier
+ *
+ */
+public class Client {
+
+ private BusinessDelegate businessDelegate;
+
+ public Client(BusinessDelegate businessDelegate) {
+ this.businessDelegate = businessDelegate;
+ }
+
+ public void doTask() {
+ businessDelegate.doTask();
+ }
+}
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/EjbService.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/EjbService.java
new file mode 100644
index 000000000..7296f63b4
--- /dev/null
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/EjbService.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.business.delegate;
+
+/**
+ *
+ * Service EJB implementation
+ *
+ */
+public class EjbService implements BusinessService {
+
+ @Override
+ public void doProcessing() {
+ System.out.println("EjbService is now processing");
+ }
+}
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/JmsService.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/JmsService.java
new file mode 100644
index 000000000..5b71ce57d
--- /dev/null
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/JmsService.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.business.delegate;
+
+/**
+ *
+ * Service JMS implementation
+ *
+ */
+public class JmsService implements BusinessService {
+
+ @Override
+ public void doProcessing() {
+ System.out.println("JmsService is now processing");
+ }
+}
diff --git a/business-delegate/src/main/java/com/iluwatar/business/delegate/ServiceType.java b/business-delegate/src/main/java/com/iluwatar/business/delegate/ServiceType.java
new file mode 100644
index 000000000..06d0a42b9
--- /dev/null
+++ b/business-delegate/src/main/java/com/iluwatar/business/delegate/ServiceType.java
@@ -0,0 +1,33 @@
+/**
+ * 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.business.delegate;
+
+/**
+ *
+ * Enumeration for service types
+ *
+ */
+public enum ServiceType {
+
+ EJB, JMS;
+}
diff --git a/business-delegate/src/test/java/com/iluwatar/business/delegate/AppTest.java b/business-delegate/src/test/java/com/iluwatar/business/delegate/AppTest.java
new file mode 100644
index 000000000..1767b7ac5
--- /dev/null
+++ b/business-delegate/src/test/java/com/iluwatar/business/delegate/AppTest.java
@@ -0,0 +1,38 @@
+/**
+ * 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.business.delegate;
+
+import org.junit.Test;
+
+import java.io.IOException;
+
+/**
+ * Tests that Business Delegate example runs without errors.
+ */
+public class AppTest {
+ @Test
+ public void test() throws IOException {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/business-delegate/src/test/java/com/iluwatar/business/delegate/BusinessDelegateTest.java b/business-delegate/src/test/java/com/iluwatar/business/delegate/BusinessDelegateTest.java
new file mode 100644
index 000000000..aec4ea14b
--- /dev/null
+++ b/business-delegate/src/test/java/com/iluwatar/business/delegate/BusinessDelegateTest.java
@@ -0,0 +1,100 @@
+/**
+ * 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.business.delegate;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * The Business Delegate pattern adds an abstraction layer between the presentation and business
+ * tiers. By using the pattern we gain loose coupling between the tiers. The Business Delegate
+ * encapsulates knowledge about how to locate, connect to, and interact with the business objects
+ * that make up the application.
+ *
+ *
Some of the services the Business Delegate uses are instantiated directly, and some can be
+ * retrieved through service lookups. The Business Delegate itself may contain business logic too
+ * potentially tying together multiple service calls, exception handling, retrying etc.
+ */
+public class BusinessDelegateTest {
+
+ private EjbService ejbService;
+
+ private JmsService jmsService;
+
+ private BusinessLookup businessLookup;
+
+ private BusinessDelegate businessDelegate;
+
+ /**
+ * This method sets up the instance variables of this test class. It is executed before the
+ * execution of every test.
+ */
+ @Before
+ public void setup() {
+ ejbService = spy(new EjbService());
+ jmsService = spy(new JmsService());
+
+ businessLookup = spy(new BusinessLookup());
+ businessLookup.setEjbService(ejbService);
+ businessLookup.setJmsService(jmsService);
+
+ businessDelegate = spy(new BusinessDelegate());
+ businessDelegate.setLookupService(businessLookup);
+ }
+
+ /**
+ * In this example the client ({@link Client}) utilizes a business delegate (
+ * {@link BusinessDelegate}) to execute a task. The Business Delegate then selects the appropriate
+ * service and makes the service call.
+ */
+ @Test
+ public void testBusinessDelegate() {
+
+ // setup a client object
+ Client client = new Client(businessDelegate);
+
+ // set the service type
+ businessDelegate.setServiceType(ServiceType.EJB);
+
+ // action
+ client.doTask();
+
+ // verifying that the businessDelegate was used by client during doTask() method.
+ verify(businessDelegate).doTask();
+ verify(ejbService).doProcessing();
+
+ // set the service type
+ businessDelegate.setServiceType(ServiceType.JMS);
+
+ // action
+ client.doTask();
+
+ // verifying that the businessDelegate was used by client during doTask() method.
+ verify(businessDelegate, times(2)).doTask();
+ verify(jmsService).doProcessing();
+ }
+}
diff --git a/caching/.gitignore b/caching/.gitignore
new file mode 100644
index 000000000..b83d22266
--- /dev/null
+++ b/caching/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/caching/README.md b/caching/README.md
new file mode 100644
index 000000000..2b89d0559
--- /dev/null
+++ b/caching/README.md
@@ -0,0 +1,28 @@
+---
+layout: pattern
+title: Caching
+folder: caching
+permalink: /patterns/caching/
+categories: Other
+tags:
+ - Java
+ - Difficulty-Intermediate
+ - Performance
+---
+
+## Intent
+To avoid expensive re-acquisition of resources by not releasing
+the resources immediately after their use. The resources retain their identity, are kept in some
+fast-access storage, and are re-used to avoid having to acquire them again.
+
+
+
+## Applicability
+Use the Caching pattern(s) when
+
+* Repetitious acquisition, initialization, and release of the same resource causes unnecessary performance overhead.
+
+## Credits
+
+* [Write-through, write-around, write-back: Cache explained](http://www.computerweekly.com/feature/Write-through-write-around-write-back-Cache-explained)
+* [Read-Through, Write-Through, Write-Behind, and Refresh-Ahead Caching](https://docs.oracle.com/cd/E15357_01/coh.360/e15723/cache_rtwtwbra.htm#COHDG5177)
diff --git a/caching/etc/caching.png b/caching/etc/caching.png
new file mode 100644
index 000000000..6b3b2d055
Binary files /dev/null and b/caching/etc/caching.png differ
diff --git a/caching/etc/caching.ucls b/caching/etc/caching.ucls
new file mode 100644
index 000000000..815a62ec9
--- /dev/null
+++ b/caching/etc/caching.ucls
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/caching/pom.xml b/caching/pom.xml
new file mode 100644
index 000000000..c20842a89
--- /dev/null
+++ b/caching/pom.xml
@@ -0,0 +1,75 @@
+
+
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.13.0-SNAPSHOT
+
+ caching
+
+
+ junit
+ junit
+ test
+
+
+ org.mongodb
+ mongodb-driver
+ 3.0.4
+
+
+ org.mongodb
+ mongodb-driver-core
+ 3.0.4
+
+
+ org.mongodb
+ bson
+ 3.0.4
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.19
+
+ false
+
+
+
+
+
diff --git a/caching/src/main/java/com/iluwatar/caching/App.java b/caching/src/main/java/com/iluwatar/caching/App.java
new file mode 100644
index 000000000..8e5a84085
--- /dev/null
+++ b/caching/src/main/java/com/iluwatar/caching/App.java
@@ -0,0 +1,139 @@
+/**
+ * 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.caching;
+
+/**
+ *
+ * The Caching pattern describes how to avoid expensive re-acquisition of resources by not releasing
+ * the resources immediately after their use. The resources retain their identity, are kept in some
+ * fast-access storage, and are re-used to avoid having to acquire them again. There are three main
+ * caching strategies/techniques in this pattern; each with their own pros and cons. They are:
+ * write-through
which writes data to the cache and DB in a single transaction,
+ * write-around
which writes data immediately into the DB instead of the cache, and
+ * write-behind
which writes data into the cache initially whilst the data is only
+ * written into the DB when the cache is full. The read-through
strategy is also
+ * included in the mentioned three strategies -- returns data from the cache to the caller if
+ * it exists else queries from DB and stores it into the cache for future use. These
+ * strategies determine when the data in the cache should be written back to the backing store (i.e.
+ * Database) and help keep both data sources synchronized/up-to-date. This pattern can improve
+ * performance and also helps to maintain consistency between data held in the cache and the data in
+ * the underlying data store.
+ *
+ * In this example, the user account ({@link UserAccount}) entity is used as the underlying
+ * application data. The cache itself is implemented as an internal (Java) data structure. It adopts
+ * a Least-Recently-Used (LRU) strategy for evicting data from itself when its full. The three
+ * strategies are individually tested. The testing of the cache is restricted towards saving and
+ * querying of user accounts from the underlying data store ( {@link DbManager}). The main class (
+ * {@link App} is not aware of the underlying mechanics of the application (i.e. save and query) and
+ * whether the data is coming from the cache or the DB (i.e. separation of concern). The AppManager
+ * ({@link AppManager}) handles the transaction of data to-and-from the underlying data store
+ * (depending on the preferred caching policy/strategy).
+ *
+ * App --> AppManager --> CacheStore/LRUCache/CachingPolicy --> DBManager
+ *
+ *
+ * @see CacheStore
+ * @See LRUCache
+ * @see CachingPolicy
+ *
+ */
+public class App {
+
+ /**
+ * Program entry point
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ AppManager.initDb(false); // VirtualDB (instead of MongoDB) was used in running the JUnit tests
+ // and the App class to avoid Maven compilation errors. Set flag to
+ // true to run the tests with MongoDB (provided that MongoDB is
+ // installed and socket connection is open).
+ AppManager.initCacheCapacity(3);
+ App app = new App();
+ app.useReadAndWriteThroughStrategy();
+ app.useReadThroughAndWriteAroundStrategy();
+ app.useReadThroughAndWriteBehindStrategy();
+ }
+
+ /**
+ * Read-through and write-through
+ */
+ public void useReadAndWriteThroughStrategy() {
+ System.out.println("# CachingPolicy.THROUGH");
+ AppManager.initCachingPolicy(CachingPolicy.THROUGH);
+
+ UserAccount userAccount1 = new UserAccount("001", "John", "He is a boy.");
+
+ AppManager.save(userAccount1);
+ System.out.println(AppManager.printCacheContent());
+ AppManager.find("001");
+ AppManager.find("001");
+ }
+
+ /**
+ * Read-through and write-around
+ */
+ public void useReadThroughAndWriteAroundStrategy() {
+ System.out.println("# CachingPolicy.AROUND");
+ AppManager.initCachingPolicy(CachingPolicy.AROUND);
+
+ UserAccount userAccount2 = new UserAccount("002", "Jane", "She is a girl.");
+
+ AppManager.save(userAccount2);
+ System.out.println(AppManager.printCacheContent());
+ AppManager.find("002");
+ System.out.println(AppManager.printCacheContent());
+ userAccount2 = AppManager.find("002");
+ userAccount2.setUserName("Jane G.");
+ AppManager.save(userAccount2);
+ System.out.println(AppManager.printCacheContent());
+ AppManager.find("002");
+ System.out.println(AppManager.printCacheContent());
+ AppManager.find("002");
+ }
+
+ /**
+ * Read-through and write-behind
+ */
+ public void useReadThroughAndWriteBehindStrategy() {
+ System.out.println("# CachingPolicy.BEHIND");
+ AppManager.initCachingPolicy(CachingPolicy.BEHIND);
+
+ UserAccount userAccount3 = new UserAccount("003", "Adam", "He likes food.");
+ UserAccount userAccount4 = new UserAccount("004", "Rita", "She hates cats.");
+ UserAccount userAccount5 = new UserAccount("005", "Isaac", "He is allergic to mustard.");
+
+ AppManager.save(userAccount3);
+ AppManager.save(userAccount4);
+ AppManager.save(userAccount5);
+ System.out.println(AppManager.printCacheContent());
+ AppManager.find("003");
+ System.out.println(AppManager.printCacheContent());
+ UserAccount userAccount6 = new UserAccount("006", "Yasha", "She is an only child.");
+ AppManager.save(userAccount6);
+ System.out.println(AppManager.printCacheContent());
+ AppManager.find("004");
+ System.out.println(AppManager.printCacheContent());
+ }
+}
diff --git a/caching/src/main/java/com/iluwatar/caching/AppManager.java b/caching/src/main/java/com/iluwatar/caching/AppManager.java
new file mode 100644
index 000000000..2967c759f
--- /dev/null
+++ b/caching/src/main/java/com/iluwatar/caching/AppManager.java
@@ -0,0 +1,109 @@
+/**
+ * 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.caching;
+
+import java.text.ParseException;
+
+/**
+ *
+ * AppManager helps to bridge the gap in communication between the main class and the application's
+ * back-end. DB connection is initialized through this class. The chosen caching strategy/policy is
+ * also initialized here. Before the cache can be used, the size of the cache has to be set.
+ * Depending on the chosen caching policy, AppManager will call the appropriate function in the
+ * CacheStore class.
+ *
+ */
+public final class AppManager {
+
+ private static CachingPolicy cachingPolicy;
+
+ private AppManager() {
+ }
+
+ /**
+ *
+ * Developer/Tester is able to choose whether the application should use MongoDB as its underlying
+ * data storage or a simple Java data structure to (temporarily) store the data/objects during
+ * runtime.
+ */
+ public static void initDb(boolean useMongoDb) {
+ if (useMongoDb) {
+ try {
+ DbManager.connect();
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ } else {
+ DbManager.createVirtualDb();
+ }
+ }
+
+ /**
+ * Initialize caching policy
+ */
+ public static void initCachingPolicy(CachingPolicy policy) {
+ cachingPolicy = policy;
+ if (cachingPolicy == CachingPolicy.BEHIND) {
+ Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
+ @Override
+ public void run() {
+ CacheStore.flushCache();
+ }
+ }));
+ }
+ CacheStore.clearCache();
+ }
+
+ public static void initCacheCapacity(int capacity) {
+ CacheStore.initCapacity(capacity);
+ }
+
+ /**
+ * Find user account
+ */
+ public static UserAccount find(String userId) {
+ if (cachingPolicy == CachingPolicy.THROUGH || cachingPolicy == CachingPolicy.AROUND) {
+ return CacheStore.readThrough(userId);
+ } else if (cachingPolicy == CachingPolicy.BEHIND) {
+ return CacheStore.readThroughWithWriteBackPolicy(userId);
+ }
+ return null;
+ }
+
+ /**
+ * Save user account
+ */
+ public static void save(UserAccount userAccount) {
+ if (cachingPolicy == CachingPolicy.THROUGH) {
+ CacheStore.writeThrough(userAccount);
+ } else if (cachingPolicy == CachingPolicy.AROUND) {
+ CacheStore.writeAround(userAccount);
+ } else if (cachingPolicy == CachingPolicy.BEHIND) {
+ CacheStore.writeBehind(userAccount);
+ }
+ }
+
+ public static String printCacheContent() {
+ return CacheStore.print();
+ }
+}
diff --git a/caching/src/main/java/com/iluwatar/caching/CacheStore.java b/caching/src/main/java/com/iluwatar/caching/CacheStore.java
new file mode 100644
index 000000000..5903f8219
--- /dev/null
+++ b/caching/src/main/java/com/iluwatar/caching/CacheStore.java
@@ -0,0 +1,156 @@
+/**
+ * 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.caching;
+
+import java.util.List;
+
+/**
+ *
+ * The caching strategies are implemented in this class.
+ *
+ */
+public class CacheStore {
+
+ static LruCache cache;
+
+ private CacheStore() {
+ }
+
+ /**
+ * Init cache capacity
+ */
+ public static void initCapacity(int capacity) {
+ if (null == cache) {
+ cache = new LruCache(capacity);
+ } else {
+ cache.setCapacity(capacity);
+ }
+ }
+
+ /**
+ * Get user account using read-through cache
+ */
+ public static UserAccount readThrough(String userId) {
+ if (cache.contains(userId)) {
+ System.out.println("# Cache Hit!");
+ return cache.get(userId);
+ }
+ System.out.println("# Cache Miss!");
+ UserAccount userAccount = DbManager.readFromDb(userId);
+ cache.set(userId, userAccount);
+ return userAccount;
+ }
+
+ /**
+ * Get user account using write-through cache
+ */
+ public static void writeThrough(UserAccount userAccount) {
+ if (cache.contains(userAccount.getUserId())) {
+ DbManager.updateDb(userAccount);
+ } else {
+ DbManager.writeToDb(userAccount);
+ }
+ cache.set(userAccount.getUserId(), userAccount);
+ }
+
+ /**
+ * Get user account using write-around cache
+ */
+ public static void writeAround(UserAccount userAccount) {
+ if (cache.contains(userAccount.getUserId())) {
+ DbManager.updateDb(userAccount);
+ cache.invalidate(userAccount.getUserId()); // Cache data has been updated -- remove older
+ // version from cache.
+ } else {
+ DbManager.writeToDb(userAccount);
+ }
+ }
+
+ /**
+ * Get user account using read-through cache with write-back policy
+ */
+ public static UserAccount readThroughWithWriteBackPolicy(String userId) {
+ if (cache.contains(userId)) {
+ System.out.println("# Cache Hit!");
+ return cache.get(userId);
+ }
+ System.out.println("# Cache Miss!");
+ UserAccount userAccount = DbManager.readFromDb(userId);
+ if (cache.isFull()) {
+ System.out.println("# Cache is FULL! Writing LRU data to DB...");
+ UserAccount toBeWrittenToDb = cache.getLruData();
+ DbManager.upsertDb(toBeWrittenToDb);
+ }
+ cache.set(userId, userAccount);
+ return userAccount;
+ }
+
+ /**
+ * Set user account
+ */
+ public static void writeBehind(UserAccount userAccount) {
+ if (cache.isFull() && !cache.contains(userAccount.getUserId())) {
+ System.out.println("# Cache is FULL! Writing LRU data to DB...");
+ UserAccount toBeWrittenToDb = cache.getLruData();
+ DbManager.upsertDb(toBeWrittenToDb);
+ }
+ cache.set(userAccount.getUserId(), userAccount);
+ }
+
+ /**
+ * Clears cache
+ */
+ public static void clearCache() {
+ if (null != cache) {
+ cache.clear();
+ }
+ }
+
+ /**
+ * Writes remaining content in the cache into the DB.
+ */
+ public static void flushCache() {
+ System.out.println("# flushCache...");
+ if (null == cache) {
+ return;
+ }
+ List listOfUserAccounts = cache.getCacheDataInListForm();
+ for (UserAccount userAccount : listOfUserAccounts) {
+ DbManager.upsertDb(userAccount);
+ }
+ }
+
+ /**
+ * Print user accounts
+ */
+ public static String print() {
+ List listOfUserAccounts = cache.getCacheDataInListForm();
+ StringBuilder sb = new StringBuilder();
+ sb.append("\n--CACHE CONTENT--\n");
+ for (UserAccount userAccount : listOfUserAccounts) {
+ sb.append(userAccount.toString() + "\n");
+ }
+ sb.append("----\n");
+ return sb.toString();
+ }
+}
diff --git a/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java b/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java
new file mode 100644
index 000000000..490113baa
--- /dev/null
+++ b/caching/src/main/java/com/iluwatar/caching/CachingPolicy.java
@@ -0,0 +1,42 @@
+/**
+ * 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.caching;
+
+/**
+ *
+ * Enum class containing the three caching strategies implemented in the pattern.
+ *
+ */
+public enum CachingPolicy {
+ THROUGH("through"), AROUND("around"), BEHIND("behind");
+
+ private String policy;
+
+ private CachingPolicy(String policy) {
+ this.policy = policy;
+ }
+
+ public String getPolicy() {
+ return policy;
+ }
+}
diff --git a/caching/src/main/java/com/iluwatar/caching/DbManager.java b/caching/src/main/java/com/iluwatar/caching/DbManager.java
new file mode 100644
index 000000000..c12461d0c
--- /dev/null
+++ b/caching/src/main/java/com/iluwatar/caching/DbManager.java
@@ -0,0 +1,164 @@
+/**
+ * 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.caching;
+
+import java.text.ParseException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.bson.Document;
+
+import com.mongodb.MongoClient;
+import com.mongodb.client.FindIterable;
+import com.mongodb.client.MongoDatabase;
+import com.mongodb.client.model.UpdateOptions;
+
+/**
+ *
+ * DBManager handles the communication with the underlying data store i.e. Database. It contains the
+ * implemented methods for querying, inserting, and updating data. MongoDB was used as the database
+ * for the application.
+ *
+ * Developer/Tester is able to choose whether the application should use MongoDB as its underlying
+ * data storage (connect()) or a simple Java data structure to (temporarily) store the data/objects
+ * during runtime (createVirtualDB()).
+ *
+ */
+public final class DbManager {
+
+ private static MongoClient mongoClient;
+ private static MongoDatabase db;
+ private static boolean useMongoDB;
+
+ private static Map virtualDB;
+
+ private DbManager() {
+ }
+
+ /**
+ * Create DB
+ */
+ public static void createVirtualDb() {
+ useMongoDB = false;
+ virtualDB = new HashMap<>();
+ }
+
+ /**
+ * Connect to DB
+ */
+ public static void connect() throws ParseException {
+ useMongoDB = true;
+ mongoClient = new MongoClient();
+ db = mongoClient.getDatabase("test");
+ }
+
+ /**
+ * Read user account from DB
+ */
+ public static UserAccount readFromDb(String userId) {
+ if (!useMongoDB) {
+ if (virtualDB.containsKey(userId)) {
+ return virtualDB.get(userId);
+ }
+ return null;
+ }
+ if (null == db) {
+ try {
+ connect();
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+ FindIterable iterable =
+ db.getCollection("user_accounts").find(new Document("userID", userId));
+ if (iterable == null) {
+ return null;
+ }
+ Document doc = iterable.first();
+ return new UserAccount(userId, doc.getString("userName"), doc.getString("additionalInfo"));
+ }
+
+ /**
+ * Write user account to DB
+ */
+ public static void writeToDb(UserAccount userAccount) {
+ if (!useMongoDB) {
+ virtualDB.put(userAccount.getUserId(), userAccount);
+ return;
+ }
+ if (null == db) {
+ try {
+ connect();
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+ db.getCollection("user_accounts").insertOne(
+ new Document("userID", userAccount.getUserId()).append("userName",
+ userAccount.getUserName()).append("additionalInfo", userAccount.getAdditionalInfo()));
+ }
+
+ /**
+ * Update DB
+ */
+ public static void updateDb(UserAccount userAccount) {
+ if (!useMongoDB) {
+ virtualDB.put(userAccount.getUserId(), userAccount);
+ return;
+ }
+ if (null == db) {
+ try {
+ connect();
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+ db.getCollection("user_accounts").updateOne(
+ new Document("userID", userAccount.getUserId()),
+ new Document("$set", new Document("userName", userAccount.getUserName()).append(
+ "additionalInfo", userAccount.getAdditionalInfo())));
+ }
+
+ /**
+ *
+ * Insert data into DB if it does not exist. Else, update it.
+ */
+ public static void upsertDb(UserAccount userAccount) {
+ if (!useMongoDB) {
+ virtualDB.put(userAccount.getUserId(), userAccount);
+ return;
+ }
+ if (null == db) {
+ try {
+ connect();
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ }
+ db.getCollection("user_accounts").updateOne(
+ new Document("userID", userAccount.getUserId()),
+ new Document("$set", new Document("userID", userAccount.getUserId()).append("userName",
+ userAccount.getUserName()).append("additionalInfo", userAccount.getAdditionalInfo())),
+ new UpdateOptions().upsert(true));
+ }
+}
diff --git a/caching/src/main/java/com/iluwatar/caching/LruCache.java b/caching/src/main/java/com/iluwatar/caching/LruCache.java
new file mode 100644
index 000000000..5c5549afd
--- /dev/null
+++ b/caching/src/main/java/com/iluwatar/caching/LruCache.java
@@ -0,0 +1,187 @@
+/**
+ * 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.caching;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * Data structure/implementation of the application's cache. The data structure consists of a hash
+ * table attached with a doubly linked-list. The linked-list helps in capturing and maintaining the
+ * LRU data in the cache. When a data is queried (from the cache), added (to the cache), or updated,
+ * the data is moved to the front of the list to depict itself as the most-recently-used data. The
+ * LRU data is always at the end of the list.
+ *
+ */
+public class LruCache {
+
+ class Node {
+ String userId;
+ UserAccount userAccount;
+ Node previous;
+ Node next;
+
+ public Node(String userId, UserAccount userAccount) {
+ this.userId = userId;
+ this.userAccount = userAccount;
+ }
+ }
+
+ int capacity;
+ Map cache = new HashMap<>();
+ Node head;
+ Node end;
+
+ public LruCache(int capacity) {
+ this.capacity = capacity;
+ }
+
+ /**
+ * Get user account
+ */
+ public UserAccount get(String userId) {
+ if (cache.containsKey(userId)) {
+ Node node = cache.get(userId);
+ remove(node);
+ setHead(node);
+ return node.userAccount;
+ }
+ return null;
+ }
+
+ /**
+ *
+ * Remove node from linked list.
+ */
+ public void remove(Node node) {
+ if (node.previous != null) {
+ node.previous.next = node.next;
+ } else {
+ head = node.next;
+ }
+ if (node.next != null) {
+ node.next.previous = node.previous;
+ } else {
+ end = node.previous;
+ }
+ }
+
+ /**
+ *
+ * Move node to the front of the list.
+ */
+ public void setHead(Node node) {
+ node.next = head;
+ node.previous = null;
+ if (head != null) {
+ head.previous = node;
+ }
+ head = node;
+ if (end == null) {
+ end = head;
+ }
+ }
+
+ /**
+ * Set user account
+ */
+ public void set(String userId, UserAccount userAccount) {
+ if (cache.containsKey(userId)) {
+ Node old = cache.get(userId);
+ old.userAccount = userAccount;
+ remove(old);
+ setHead(old);
+ } else {
+ Node newNode = new Node(userId, userAccount);
+ if (cache.size() >= capacity) {
+ System.out.println("# Cache is FULL! Removing " + end.userId + " from cache...");
+ cache.remove(end.userId); // remove LRU data from cache.
+ remove(end);
+ setHead(newNode);
+ } else {
+ setHead(newNode);
+ }
+ cache.put(userId, newNode);
+ }
+ }
+
+ public boolean contains(String userId) {
+ return cache.containsKey(userId);
+ }
+
+ /**
+ * Invalidate cache for user
+ */
+ public void invalidate(String userId) {
+ System.out.println("# " + userId + " has been updated! Removing older version from cache...");
+ Node toBeRemoved = cache.get(userId);
+ remove(toBeRemoved);
+ cache.remove(userId);
+ }
+
+ public boolean isFull() {
+ return cache.size() >= capacity;
+ }
+
+ public UserAccount getLruData() {
+ return end.userAccount;
+ }
+
+ /**
+ * Clear cache
+ */
+ public void clear() {
+ head = null;
+ end = null;
+ cache.clear();
+ }
+
+ /**
+ *
+ * Returns cache data in list form.
+ */
+ public List getCacheDataInListForm() {
+ ArrayList listOfCacheData = new ArrayList<>();
+ Node temp = head;
+ while (temp != null) {
+ listOfCacheData.add(temp.userAccount);
+ temp = temp.next;
+ }
+ return listOfCacheData;
+ }
+
+ /**
+ * Set cache capacity
+ */
+ public void setCapacity(int newCapacity) {
+ if (capacity > newCapacity) {
+ clear(); // Behavior can be modified to accommodate for decrease in cache size. For now, we'll
+ // just clear the cache.
+ } else {
+ this.capacity = newCapacity;
+ }
+ }
+}
diff --git a/caching/src/main/java/com/iluwatar/caching/UserAccount.java b/caching/src/main/java/com/iluwatar/caching/UserAccount.java
new file mode 100644
index 000000000..e2444ad72
--- /dev/null
+++ b/caching/src/main/java/com/iluwatar/caching/UserAccount.java
@@ -0,0 +1,72 @@
+/**
+ * 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.caching;
+
+/**
+ *
+ * Entity class (stored in cache and DB) used in the application.
+ *
+ */
+public class UserAccount {
+ private String userId;
+ private String userName;
+ private String additionalInfo;
+
+ /**
+ * Constructor
+ */
+ public UserAccount(String userId, String userName, String additionalInfo) {
+ this.userId = userId;
+ this.userName = userName;
+ this.additionalInfo = additionalInfo;
+ }
+
+ public String getUserId() {
+ return userId;
+ }
+
+ public void setUserId(String userId) {
+ this.userId = userId;
+ }
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public String getAdditionalInfo() {
+ return additionalInfo;
+ }
+
+ public void setAdditionalInfo(String additionalInfo) {
+ this.additionalInfo = additionalInfo;
+ }
+
+ @Override
+ public String toString() {
+ return userId + ", " + userName + ", " + additionalInfo;
+ }
+}
diff --git a/caching/src/test/java/com/iluwatar/caching/AppTest.java b/caching/src/test/java/com/iluwatar/caching/AppTest.java
new file mode 100644
index 000000000..90ed1c275
--- /dev/null
+++ b/caching/src/test/java/com/iluwatar/caching/AppTest.java
@@ -0,0 +1,38 @@
+/**
+ * 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.caching;
+
+import org.junit.Test;
+
+import java.io.IOException;
+
+/**
+ * Tests that Caching example runs without errors.
+ */
+public class AppTest {
+ @Test
+ public void test() throws IOException {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/caching/src/test/java/com/iluwatar/caching/CachingTest.java b/caching/src/test/java/com/iluwatar/caching/CachingTest.java
new file mode 100644
index 000000000..19262a3b6
--- /dev/null
+++ b/caching/src/test/java/com/iluwatar/caching/CachingTest.java
@@ -0,0 +1,63 @@
+/**
+ * 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.caching;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ * Application test
+ *
+ */
+public class CachingTest {
+ App app;
+
+ /**
+ * Setup of application test includes: initializing DB connection and cache size/capacity.
+ */
+ @Before
+ public void setUp() {
+ AppManager.initDb(false); // VirtualDB (instead of MongoDB) was used in running the JUnit tests
+ // to avoid Maven compilation errors. Set flag to true to run the
+ // tests with MongoDB (provided that MongoDB is installed and socket
+ // connection is open).
+ AppManager.initCacheCapacity(3);
+ app = new App();
+ }
+
+ @Test
+ public void testReadAndWriteThroughStrategy() {
+ app.useReadAndWriteThroughStrategy();
+ }
+
+ @Test
+ public void testReadThroughAndWriteAroundStrategy() {
+ app.useReadThroughAndWriteAroundStrategy();
+ }
+
+ @Test
+ public void testReadThroughAndWriteBehindStrategy() {
+ app.useReadThroughAndWriteBehindStrategy();
+ }
+}
diff --git a/callback/README.md b/callback/README.md
new file mode 100644
index 000000000..a408fd5e0
--- /dev/null
+++ b/callback/README.md
@@ -0,0 +1,28 @@
+---
+layout: pattern
+title: Callback
+folder: callback
+permalink: /patterns/callback/
+categories: Other
+tags:
+ - Java
+ - Difficulty-Beginner
+ - Functional
+ - Idiom
+---
+
+## Intent
+Callback is a piece of executable code that is passed as an
+argument to other code, which is expected to call back (execute) the argument
+at some convenient time.
+
+
+
+## Applicability
+Use the Callback pattern when
+
+* when some arbitrary synchronous or asynchronous action must be performed after execution of some defined activity.
+
+## Real world examples
+
+* [CyclicBarrier](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html#CyclicBarrier%28int,%20java.lang.Runnable%29) constructor can accept callback that will be triggered every time when barrier is tripped.
diff --git a/callback/pom.xml b/callback/pom.xml
index 862fb53a1..4fe17d143 100644
--- a/callback/pom.xml
+++ b/callback/pom.xml
@@ -1,11 +1,35 @@
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
callback
diff --git a/callback/src/main/java/com/iluwatar/callback/App.java b/callback/src/main/java/com/iluwatar/callback/App.java
index 546a6b507..bc1b2890e 100644
--- a/callback/src/main/java/com/iluwatar/callback/App.java
+++ b/callback/src/main/java/com/iluwatar/callback/App.java
@@ -1,19 +1,47 @@
+/**
+ * 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.callback;
/**
- * Callback pattern is more native for functional languages where function is treated as first-class citizen.
- * Prior to Java8 can be simulated using simple (alike command) interfaces.
+ *
+ * Callback pattern is more native for functional languages where functions are treated as
+ * first-class citizens. Prior to Java 8 callbacks can be simulated using simple (alike command)
+ * interfaces.
+ *
*/
public class App {
- public static void main(String[] args) {
- Task task = new SimpleTask();
- Callback callback = new Callback() {
- @Override
- public void call() {
- System.out.println("I'm done now.");
- }
- };
- task.executeWith(callback);
- }
+ /**
+ * Program entry point
+ */
+ public static void main(String[] args) {
+ Task task = new SimpleTask();
+ Callback callback = new Callback() {
+ @Override
+ public void call() {
+ System.out.println("I'm done now.");
+ }
+ };
+ task.executeWith(callback);
+ }
}
diff --git a/callback/src/main/java/com/iluwatar/callback/Callback.java b/callback/src/main/java/com/iluwatar/callback/Callback.java
index 9e757e218..78932a24e 100644
--- a/callback/src/main/java/com/iluwatar/callback/Callback.java
+++ b/callback/src/main/java/com/iluwatar/callback/Callback.java
@@ -1,9 +1,33 @@
+/**
+ * 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.callback;
/**
+ *
* Callback interface
+ *
*/
public interface Callback {
- public void call();
+ void call();
}
diff --git a/callback/src/main/java/com/iluwatar/callback/LambdasApp.java b/callback/src/main/java/com/iluwatar/callback/LambdasApp.java
new file mode 100644
index 000000000..78ca63e0b
--- /dev/null
+++ b/callback/src/main/java/com/iluwatar/callback/LambdasApp.java
@@ -0,0 +1,41 @@
+/**
+ * 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.callback;
+
+/**
+ *
+ * This example generates the exact same output as {@link App} however the callback has been
+ * defined as a Lambdas expression.
+ *
+ */
+public class LambdasApp {
+
+ /**
+ * Program entry point
+ */
+ public static void main(String[] args) {
+ Task task = new SimpleTask();
+ Callback c = () -> System.out.println("I'm done now.");
+ task.executeWith(c);
+ }
+}
diff --git a/callback/src/main/java/com/iluwatar/callback/SimpleTask.java b/callback/src/main/java/com/iluwatar/callback/SimpleTask.java
index f8a27ba10..2a7385607 100644
--- a/callback/src/main/java/com/iluwatar/callback/SimpleTask.java
+++ b/callback/src/main/java/com/iluwatar/callback/SimpleTask.java
@@ -1,13 +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.callback;
/**
+ *
* Implementation of task that need to be executed
+ *
*/
public class SimpleTask extends Task {
- @Override
- public void execute() {
- System.out.println("Perform some important activity.");
- }
-
+ @Override
+ public void execute() {
+ System.out.println("Perform some important activity and after call the callback method.");
+ }
}
diff --git a/callback/src/main/java/com/iluwatar/callback/Task.java b/callback/src/main/java/com/iluwatar/callback/Task.java
index df7bf8ae8..9580c91cb 100644
--- a/callback/src/main/java/com/iluwatar/callback/Task.java
+++ b/callback/src/main/java/com/iluwatar/callback/Task.java
@@ -1,16 +1,43 @@
+/**
+ * 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.callback;
/**
+ *
* Template-method class for callback hook execution
+ *
*/
public abstract class Task {
- public final void executeWith(Callback callback) {
- execute();
- if (callback != null) {
- callback.call();
- }
- }
+ /**
+ * Execute with callback
+ */
+ public final void executeWith(Callback callback) {
+ execute();
+ if (callback != null) {
+ callback.call();
+ }
+ }
- public abstract void execute();
+ public abstract void execute();
}
diff --git a/callback/src/test/java/com/iluwatar/callback/AppTest.java b/callback/src/test/java/com/iluwatar/callback/AppTest.java
index 5d7febcee..b7ab3fe75 100644
--- a/callback/src/test/java/com/iluwatar/callback/AppTest.java
+++ b/callback/src/test/java/com/iluwatar/callback/AppTest.java
@@ -1,14 +1,38 @@
+/**
+ * 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.callback;
import org.junit.Test;
-import com.iluwatar.callback.App;
+import java.io.IOException;
+/**
+ * Tests that Callback example runs without errors.
+ */
public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
+ @Test
+ public void test() throws IOException {
+ String[] args = {};
+ App.main(args);
+ }
}
diff --git a/callback/src/test/java/com/iluwatar/callback/CallbackTest.java b/callback/src/test/java/com/iluwatar/callback/CallbackTest.java
new file mode 100644
index 000000000..b48ac36ff
--- /dev/null
+++ b/callback/src/test/java/com/iluwatar/callback/CallbackTest.java
@@ -0,0 +1,79 @@
+/**
+ * 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.callback;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Add a field as a counter. Every time the callback method is called increment this field. Unit
+ * test checks that the field is being incremented.
+ *
+ * Could be done with mock objects as well where the call method call is verified.
+ */
+public class CallbackTest {
+
+ private Integer callingCount = 0;
+
+ @Test
+ public void test() {
+ Callback callback = new Callback() {
+ @Override
+ public void call() {
+ callingCount++;
+ }
+ };
+
+ Task task = new SimpleTask();
+
+ assertEquals("Initial calling count of 0", new Integer(0), callingCount);
+
+ task.executeWith(callback);
+
+ assertEquals("Callback called once", new Integer(1), callingCount);
+
+ task.executeWith(callback);
+
+ assertEquals("Callback called twice", new Integer(2), callingCount);
+
+ }
+
+ @Test
+ public void testWithLambdasExample() {
+ Callback callback = () -> callingCount++;
+
+ Task task = new SimpleTask();
+
+ assertEquals("Initial calling count of 0", new Integer(0), callingCount);
+
+ task.executeWith(callback);
+
+ assertEquals("Callback called once", new Integer(1), callingCount);
+
+ task.executeWith(callback);
+
+ assertEquals("Callback called twice", new Integer(2), callingCount);
+
+ }
+}
diff --git a/chain/README.md b/chain/README.md
new file mode 100644
index 000000000..ef18f6f64
--- /dev/null
+++ b/chain/README.md
@@ -0,0 +1,34 @@
+---
+layout: pattern
+title: Chain of responsibility
+folder: chain
+permalink: /patterns/chain/
+categories: Behavioral
+tags:
+ - Java
+ - Gang Of Four
+ - Difficulty-Intermediate
+---
+
+## Intent
+Avoid coupling the sender of a request to its receiver by giving
+more than one object a chance to handle the request. Chain the receiving
+objects and pass the request along the chain until an object handles it.
+
+
+
+## Applicability
+Use Chain of Responsibility when
+
+* more than one object may handle a request, and the handler isn't known a priori. The handler should be ascertained automatically
+* you want to issue a request to one of several objects without specifying the receiver explicitly
+* the set of objects that can handle a request should be specified dynamically
+
+## Real world examples
+
+* [java.util.logging.Logger#log()](http://docs.oracle.com/javase/8/docs/api/java/util/logging/Logger.html#log%28java.util.logging.Level,%20java.lang.String%29)
+* [Apache Commons Chain](https://commons.apache.org/proper/commons-chain/index.html)
+
+## Credits
+
+* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/chain/pom.xml b/chain/pom.xml
index 3e960293a..ee3b92401 100644
--- a/chain/pom.xml
+++ b/chain/pom.xml
@@ -1,11 +1,35 @@
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
chain
diff --git a/chain/src/main/java/com/iluwatar/chain/App.java b/chain/src/main/java/com/iluwatar/chain/App.java
index 21d206696..cd6a200de 100644
--- a/chain/src/main/java/com/iluwatar/chain/App.java
+++ b/chain/src/main/java/com/iluwatar/chain/App.java
@@ -1,22 +1,53 @@
-package com.iluwatar.chain;
-
-/**
- *
- * Chain of Responsibility organizes request handlers (RequestHandler) into a
- * chain where each handler has a chance to act on the request on its turn. In
- * this example the king (OrcKing) makes requests and the military orcs
- * (OrcCommander, OrcOfficer, OrcSoldier) form the handler chain.
- *
- */
-public class App {
-
- public static void main(String[] args) {
-
- OrcKing king = new OrcKing();
- king.makeRequest(new Request(RequestType.DEFEND_CASTLE, "defend castle"));
- king.makeRequest(new Request(RequestType.TORTURE_PRISONER,
- "torture prisoner"));
- king.makeRequest(new Request(RequestType.COLLECT_TAX, "collect tax"));
-
- }
-}
+/**
+ * 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.chain;
+
+/**
+ *
+ * The Chain of Responsibility pattern is a design pattern consisting of command objects and a
+ * series of processing objects. Each processing object contains logic that defines the types of
+ * command objects that it can handle; the rest are passed to the next processing object in the
+ * chain. A mechanism also exists for adding new processing objects to the end of this chain.
+ *
+ * In this example we organize the request handlers ({@link RequestHandler}) into a chain where each
+ * handler has a chance to act on the request on its turn. Here the king ({@link OrcKing}) makes
+ * requests and the military orcs ({@link OrcCommander}, {@link OrcOfficer}, {@link OrcSoldier})
+ * form the handler chain.
+ *
+ */
+public class App {
+
+ /**
+ * Program entry point
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+
+ OrcKing king = new OrcKing();
+ king.makeRequest(new Request(RequestType.DEFEND_CASTLE, "defend castle"));
+ king.makeRequest(new Request(RequestType.TORTURE_PRISONER, "torture prisoner"));
+ king.makeRequest(new Request(RequestType.COLLECT_TAX, "collect tax"));
+
+ }
+}
diff --git a/chain/src/main/java/com/iluwatar/chain/OrcCommander.java b/chain/src/main/java/com/iluwatar/chain/OrcCommander.java
index 1f5f4de86..a1f2bf284 100644
--- a/chain/src/main/java/com/iluwatar/chain/OrcCommander.java
+++ b/chain/src/main/java/com/iluwatar/chain/OrcCommander.java
@@ -1,22 +1,50 @@
-package com.iluwatar.chain;
-
-public class OrcCommander extends RequestHandler {
-
- public OrcCommander(RequestHandler handler) {
- super(handler);
- }
-
- @Override
- public void handleRequest(Request req) {
- if (req.getRequestType().equals(RequestType.DEFEND_CASTLE)) {
- printHandling(req);
- } else {
- super.handleRequest(req);
- }
- }
-
- @Override
- public String toString() {
- return "Orc commander";
- }
-}
+/**
+ * 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.chain;
+
+/**
+ *
+ * OrcCommander
+ *
+ */
+public class OrcCommander extends RequestHandler {
+
+ public OrcCommander(RequestHandler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void handleRequest(Request req) {
+ if (req.getRequestType().equals(RequestType.DEFEND_CASTLE)) {
+ printHandling(req);
+ req.markHandled();
+ } else {
+ super.handleRequest(req);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Orc commander";
+ }
+}
diff --git a/chain/src/main/java/com/iluwatar/chain/OrcKing.java b/chain/src/main/java/com/iluwatar/chain/OrcKing.java
index afd2616fe..3b13c4a53 100644
--- a/chain/src/main/java/com/iluwatar/chain/OrcKing.java
+++ b/chain/src/main/java/com/iluwatar/chain/OrcKing.java
@@ -1,24 +1,46 @@
-package com.iluwatar.chain;
-
-/**
- *
- * Makes requests that are handled by the chain.
- *
- */
-public class OrcKing {
-
- RequestHandler chain;
-
- public OrcKing() {
- buildChain();
- }
-
- private void buildChain() {
- chain = new OrcCommander(new OrcOfficer(new OrcSoldier(null)));
- }
-
- public void makeRequest(Request req) {
- chain.handleRequest(req);
- }
-
-}
+/**
+ * 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.chain;
+
+/**
+ *
+ * OrcKing makes requests that are handled by the chain.
+ *
+ */
+public class OrcKing {
+
+ RequestHandler chain;
+
+ public OrcKing() {
+ buildChain();
+ }
+
+ private void buildChain() {
+ chain = new OrcCommander(new OrcOfficer(new OrcSoldier(null)));
+ }
+
+ public void makeRequest(Request req) {
+ chain.handleRequest(req);
+ }
+
+}
diff --git a/chain/src/main/java/com/iluwatar/chain/OrcOfficer.java b/chain/src/main/java/com/iluwatar/chain/OrcOfficer.java
index c09729cc8..ea35722c1 100644
--- a/chain/src/main/java/com/iluwatar/chain/OrcOfficer.java
+++ b/chain/src/main/java/com/iluwatar/chain/OrcOfficer.java
@@ -1,23 +1,51 @@
-package com.iluwatar.chain;
-
-public class OrcOfficer extends RequestHandler {
-
- public OrcOfficer(RequestHandler handler) {
- super(handler);
- }
-
- @Override
- public void handleRequest(Request req) {
- if (req.getRequestType().equals(RequestType.TORTURE_PRISONER)) {
- printHandling(req);
- } else {
- super.handleRequest(req);
- }
- }
-
- @Override
- public String toString() {
- return "Orc officer";
- }
-
-}
+/**
+ * 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.chain;
+
+/**
+ *
+ * OrcOfficer
+ *
+ */
+public class OrcOfficer extends RequestHandler {
+
+ public OrcOfficer(RequestHandler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void handleRequest(Request req) {
+ if (req.getRequestType().equals(RequestType.TORTURE_PRISONER)) {
+ printHandling(req);
+ req.markHandled();
+ } else {
+ super.handleRequest(req);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Orc officer";
+ }
+
+}
diff --git a/chain/src/main/java/com/iluwatar/chain/OrcSoldier.java b/chain/src/main/java/com/iluwatar/chain/OrcSoldier.java
index f52c7d543..d7601bf4f 100644
--- a/chain/src/main/java/com/iluwatar/chain/OrcSoldier.java
+++ b/chain/src/main/java/com/iluwatar/chain/OrcSoldier.java
@@ -1,22 +1,50 @@
-package com.iluwatar.chain;
-
-public class OrcSoldier extends RequestHandler {
-
- public OrcSoldier(RequestHandler handler) {
- super(handler);
- }
-
- @Override
- public void handleRequest(Request req) {
- if (req.getRequestType().equals(RequestType.COLLECT_TAX)) {
- printHandling(req);
- } else {
- super.handleRequest(req);
- }
- }
-
- @Override
- public String toString() {
- return "Orc soldier";
- }
-}
+/**
+ * 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.chain;
+
+/**
+ *
+ * OrcSoldier
+ *
+ */
+public class OrcSoldier extends RequestHandler {
+
+ public OrcSoldier(RequestHandler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void handleRequest(Request req) {
+ if (req.getRequestType().equals(RequestType.COLLECT_TAX)) {
+ printHandling(req);
+ req.markHandled();
+ } else {
+ super.handleRequest(req);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Orc soldier";
+ }
+}
diff --git a/chain/src/main/java/com/iluwatar/chain/Request.java b/chain/src/main/java/com/iluwatar/chain/Request.java
index ad55522f0..399eddb36 100644
--- a/chain/src/main/java/com/iluwatar/chain/Request.java
+++ b/chain/src/main/java/com/iluwatar/chain/Request.java
@@ -1,33 +1,100 @@
-package com.iluwatar.chain;
-
-public class Request {
-
- private String requestDescription;
- private RequestType requestType;
-
- public Request(RequestType requestType, String requestDescription) {
- this.setRequestType(requestType);
- this.setRequestDescription(requestDescription);
- }
-
- public String getRequestDescription() {
- return requestDescription;
- }
-
- public void setRequestDescription(String requestDescription) {
- this.requestDescription = requestDescription;
- }
-
- public RequestType getRequestType() {
- return requestType;
- }
-
- public void setRequestType(RequestType requestType) {
- this.requestType = requestType;
- }
-
- @Override
- public String toString() {
- return getRequestDescription();
- }
-}
+/**
+ * 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.chain;
+
+import java.util.Objects;
+
+/**
+ * Request
+ */
+public class Request {
+
+ /**
+ * The type of this request, used by each item in the chain to see if they should or can handle
+ * this particular request
+ */
+ private final RequestType requestType;
+
+ /**
+ * A description of the request
+ */
+ private final String requestDescription;
+
+ /**
+ * Indicates if the request is handled or not. A request can only switch state from unhandled to
+ * handled, there's no way to 'unhandle' a request
+ */
+ private boolean handled;
+
+ /**
+ * Create a new request of the given type and accompanied description.
+ *
+ * @param requestType The type of request
+ * @param requestDescription The description of the request
+ */
+ public Request(final RequestType requestType, final String requestDescription) {
+ this.requestType = Objects.requireNonNull(requestType);
+ this.requestDescription = Objects.requireNonNull(requestDescription);
+ }
+
+ /**
+ * Get a description of the request
+ *
+ * @return A human readable description of the request
+ */
+ public String getRequestDescription() {
+ return requestDescription;
+ }
+
+ /**
+ * Get the type of this request, used by each person in the chain of command to see if they should
+ * or can handle this particular request
+ *
+ * @return The request type
+ */
+ public RequestType getRequestType() {
+ return requestType;
+ }
+
+ /**
+ * Mark the request as handled
+ */
+ public void markHandled() {
+ this.handled = true;
+ }
+
+ /**
+ * Indicates if this request is handled or not
+ *
+ * @return true when the request is handled, false if not
+ */
+ public boolean isHandled() {
+ return this.handled;
+ }
+
+ @Override
+ public String toString() {
+ return getRequestDescription();
+ }
+
+}
diff --git a/chain/src/main/java/com/iluwatar/chain/RequestHandler.java b/chain/src/main/java/com/iluwatar/chain/RequestHandler.java
index dbb8b10a6..78d68e5dc 100644
--- a/chain/src/main/java/com/iluwatar/chain/RequestHandler.java
+++ b/chain/src/main/java/com/iluwatar/chain/RequestHandler.java
@@ -1,23 +1,53 @@
-package com.iluwatar.chain;
-
-public abstract class RequestHandler {
-
- private RequestHandler next;
-
- public RequestHandler(RequestHandler next) {
- this.next = next;
- }
-
- public void handleRequest(Request req) {
- if (next != null) {
- next.handleRequest(req);
- }
- }
-
- protected void printHandling(Request req) {
- System.out.println(this + " handling request \"" + req + "\"");
- }
-
- @Override
- public abstract String toString();
-}
+/**
+ * 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.chain;
+
+/**
+ *
+ * RequestHandler
+ *
+ */
+public abstract class RequestHandler {
+
+ private RequestHandler next;
+
+ public RequestHandler(RequestHandler next) {
+ this.next = next;
+ }
+
+ /**
+ * Request handler
+ */
+ public void handleRequest(Request req) {
+ if (next != null) {
+ next.handleRequest(req);
+ }
+ }
+
+ protected void printHandling(Request req) {
+ System.out.println(this + " handling request \"" + req + "\"");
+ }
+
+ @Override
+ public abstract String toString();
+}
diff --git a/chain/src/main/java/com/iluwatar/chain/RequestType.java b/chain/src/main/java/com/iluwatar/chain/RequestType.java
index 21727535e..ff6dcff4d 100644
--- a/chain/src/main/java/com/iluwatar/chain/RequestType.java
+++ b/chain/src/main/java/com/iluwatar/chain/RequestType.java
@@ -1,7 +1,34 @@
-package com.iluwatar.chain;
-
-public enum RequestType {
-
- DEFEND_CASTLE, TORTURE_PRISONER, COLLECT_TAX
-
-}
+/**
+ * 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.chain;
+
+/**
+ *
+ * RequestType enumeration
+ *
+ */
+public enum RequestType {
+
+ DEFEND_CASTLE, TORTURE_PRISONER, COLLECT_TAX
+
+}
diff --git a/chain/src/test/java/com/iluwatar/chain/AppTest.java b/chain/src/test/java/com/iluwatar/chain/AppTest.java
index 5edba69bb..93a8a4096 100644
--- a/chain/src/test/java/com/iluwatar/chain/AppTest.java
+++ b/chain/src/test/java/com/iluwatar/chain/AppTest.java
@@ -1,14 +1,39 @@
-package com.iluwatar.chain;
-
-import org.junit.Test;
-
-import com.iluwatar.chain.App;
-
-public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
-}
+/**
+ * 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.chain;
+
+import org.junit.Test;
+
+/**
+ *
+ * Application test
+ *
+ */
+public class AppTest {
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/chain/src/test/java/com/iluwatar/chain/OrcKingTest.java b/chain/src/test/java/com/iluwatar/chain/OrcKingTest.java
new file mode 100644
index 000000000..be3650613
--- /dev/null
+++ b/chain/src/test/java/com/iluwatar/chain/OrcKingTest.java
@@ -0,0 +1,59 @@
+/**
+ * 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.chain;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Date: 12/6/15 - 9:29 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class OrcKingTest {
+
+ /**
+ * All possible requests
+ */
+ private static final Request[] REQUESTS = new Request[]{
+ new Request(RequestType.DEFEND_CASTLE, "Don't let the barbarians enter my castle!!"),
+ new Request(RequestType.TORTURE_PRISONER, "Don't just stand there, tickle him!"),
+ new Request(RequestType.COLLECT_TAX, "Don't steal, the King hates competition ..."),
+ };
+
+ @Test
+ public void testMakeRequest() throws Exception {
+ final OrcKing king = new OrcKing();
+
+ for (final Request request : REQUESTS) {
+ king.makeRequest(request);
+ assertTrue(
+ "Expected all requests from King to be handled, but [" + request + "] was not!",
+ request.isHandled()
+ );
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/checkstyle-suppressions.xml b/checkstyle-suppressions.xml
new file mode 100644
index 000000000..60de4a697
--- /dev/null
+++ b/checkstyle-suppressions.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
diff --git a/checkstyle.xml b/checkstyle.xml
new file mode 100644
index 000000000..19b6d2ec4
--- /dev/null
+++ b/checkstyle.xml
@@ -0,0 +1,196 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/command/README.md b/command/README.md
new file mode 100644
index 000000000..a5478394c
--- /dev/null
+++ b/command/README.md
@@ -0,0 +1,46 @@
+---
+layout: pattern
+title: Command
+folder: command
+permalink: /patterns/command/
+categories: Behavioral
+tags:
+ - Java
+ - Gang Of Four
+ - Difficulty-Intermediate
+ - Functional
+---
+
+## Also known as
+Action, Transaction
+
+## Intent
+Encapsulate a request as an object, thereby letting you
+parameterize clients with different requests, queue or log requests, and
+support undoable operations.
+
+
+
+## Applicability
+Use the Command pattern when you want to
+
+* parameterize objects by an action to perform. You can express such parameterization in a procedural language with a callback function, that is, a function that's registered somewhere to be called at a later point. Commands are an object-oriented replacement for callbacks.
+* specify, queue, and execute requests at different times. A Command object can have a lifetime independent of the original request. If the receiver of a request can be represented in an address space-independent way, then you can transfer a command object for the request to a different process and fulfill the request there
+* support undo. The Command's execute operation can store state for reversing its effects in the command itself. The Command interface must have an added Unexecute operation that reverses the effects of a previous call to execute. Executed commands are stored in a history list. Unlimited-level undo and redo is achieved by traversing this list backwards and forwards calling unexecute and execute, respectively
+* support logging changes so that they can be reapplied in case of a system crash. By augmenting the Command interface with load and store operations, you can keep a persistent log of changes. Recovering from a crash involves reloading logged commands from disk and re-executing them with the execute operation
+* structure a system around high-level operations build on primitive operations. Such a structure is common in information systems that support transactions. A transaction encapsulates a set of changes to data. The Command pattern offers a way to model transactions. Commands have a common interface, letting you invoke all transactions the same way. The pattern also makes it easy to extend the system with new transactions
+
+## Typical Use Case
+
+* to keep a history of requests
+* implement callback functionality
+* implement the undo functionality
+
+## Real world examples
+
+* [java.lang.Runnable](http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html)
+* [Netflix Hystrix](https://github.com/Netflix/Hystrix/wiki)
+
+## Credits
+
+* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/command/pom.xml b/command/pom.xml
index 53a8e1914..a27a56e54 100644
--- a/command/pom.xml
+++ b/command/pom.xml
@@ -1,11 +1,35 @@
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
command
@@ -14,5 +38,10 @@
junit
test
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/command/src/main/java/com/iluwatar/command/App.java b/command/src/main/java/com/iluwatar/command/App.java
index 6d9df821c..93f9c376a 100644
--- a/command/src/main/java/com/iluwatar/command/App.java
+++ b/command/src/main/java/com/iluwatar/command/App.java
@@ -1,47 +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.command;
/**
*
- * In Command pattern actions are objects that can be executed and undone.
- *
- * Four terms always associated with the command pattern are command, receiver, invoker and client. A command
- * object (spell) knows about receiver (target) and invokes a method of the receiver. Values for parameters of
- * the receiver method are stored in the command. The receiver then does the work. An invoker object (wizard)
- * knows how to execute a command, and optionally does bookkeeping about the command execution. The invoker
- * does not know anything about a concrete command, it knows only about command interface. Both an invoker object
- * and several command objects are held by a client object (app). The client decides which commands to execute at
- * which points. To execute a command, it passes the command object to the invoker object.
- *
- * In other words, in this example the wizard casts spells on the goblin. The wizard keeps track of the previous
- * spells cast, so it is easy to undo them. In addition, the wizard keeps track of the spells undone, so they
- * can be redone.
+ * The Command pattern is a behavioral design pattern in which an object is used to encapsulate all
+ * information needed to perform an action or trigger an event at a later time. This information
+ * includes the method name, the object that owns the method and values for the method parameters.
+ *
+ * Four terms always associated with the command pattern are command, receiver, invoker and client.
+ * A command object (spell) knows about the receiver (target) and invokes a method of the receiver.
+ * Values for parameters of the receiver method are stored in the command. The receiver then does
+ * the work. An invoker object (wizard) knows how to execute a command, and optionally does
+ * bookkeeping about the command execution. The invoker does not know anything about a concrete
+ * command, it knows only about command interface. Both an invoker object and several command
+ * objects are held by a client object (app). The client decides which commands to execute at which
+ * points. To execute a command, it passes the command object to the invoker object.
+ *
+ * In other words, in this example the wizard casts spells on the goblin. The wizard keeps track of
+ * the previous spells cast, so it is easy to undo them. In addition, the wizard keeps track of the
+ * spells undone, so they can be redone.
*
*
*/
public class App {
- public static void main(String[] args) {
- Wizard wizard = new Wizard();
- Goblin goblin = new Goblin();
+ /**
+ * Program entry point
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ Wizard wizard = new Wizard();
+ Goblin goblin = new Goblin();
- goblin.printStatus();
+ goblin.printStatus();
- wizard.castSpell(new ShrinkSpell(), goblin);
- goblin.printStatus();
+ wizard.castSpell(new ShrinkSpell(), goblin);
+ goblin.printStatus();
- wizard.castSpell(new InvisibilitySpell(), goblin);
- goblin.printStatus();
+ wizard.castSpell(new InvisibilitySpell(), goblin);
+ goblin.printStatus();
- wizard.undoLastSpell();
- goblin.printStatus();
+ wizard.undoLastSpell();
+ goblin.printStatus();
- wizard.undoLastSpell();
- goblin.printStatus();
+ wizard.undoLastSpell();
+ goblin.printStatus();
- wizard.redoLastSpell();
- goblin.printStatus();
+ wizard.redoLastSpell();
+ goblin.printStatus();
- wizard.redoLastSpell();
- goblin.printStatus();
- }
+ wizard.redoLastSpell();
+ goblin.printStatus();
+ }
}
diff --git a/command/src/main/java/com/iluwatar/command/Command.java b/command/src/main/java/com/iluwatar/command/Command.java
index 9ffeed24d..c7b0c43bb 100644
--- a/command/src/main/java/com/iluwatar/command/Command.java
+++ b/command/src/main/java/com/iluwatar/command/Command.java
@@ -1,3 +1,25 @@
+/**
+ * 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.command;
/**
@@ -7,13 +29,13 @@ package com.iluwatar.command;
*/
public abstract class Command {
- public abstract void execute(Target target);
+ public abstract void execute(Target target);
- public abstract void undo();
+ public abstract void undo();
- public abstract void redo();
+ public abstract void redo();
- @Override
- public abstract String toString();
+ @Override
+ public abstract String toString();
}
diff --git a/command/src/main/java/com/iluwatar/command/Goblin.java b/command/src/main/java/com/iluwatar/command/Goblin.java
index 7d0804b0c..9e21cdefd 100644
--- a/command/src/main/java/com/iluwatar/command/Goblin.java
+++ b/command/src/main/java/com/iluwatar/command/Goblin.java
@@ -1,3 +1,25 @@
+/**
+ * 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.command;
/**
@@ -7,14 +29,14 @@ package com.iluwatar.command;
*/
public class Goblin extends Target {
- public Goblin() {
- setSize(Size.NORMAL);
- setVisibility(Visibility.VISIBLE);
- }
+ public Goblin() {
+ setSize(Size.NORMAL);
+ setVisibility(Visibility.VISIBLE);
+ }
- @Override
- public String toString() {
- return "Goblin";
- }
+ @Override
+ public String toString() {
+ return "Goblin";
+ }
}
diff --git a/command/src/main/java/com/iluwatar/command/InvisibilitySpell.java b/command/src/main/java/com/iluwatar/command/InvisibilitySpell.java
index b72c34cc2..9435e7245 100644
--- a/command/src/main/java/com/iluwatar/command/InvisibilitySpell.java
+++ b/command/src/main/java/com/iluwatar/command/InvisibilitySpell.java
@@ -1,3 +1,25 @@
+/**
+ * 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.command;
/**
@@ -7,30 +29,30 @@ package com.iluwatar.command;
*/
public class InvisibilitySpell extends Command {
- private Target target;
+ private Target target;
- @Override
- public void execute(Target target) {
- target.setVisibility(Visibility.INVISIBLE);
- this.target = target;
- }
+ @Override
+ public void execute(Target target) {
+ target.setVisibility(Visibility.INVISIBLE);
+ this.target = target;
+ }
- @Override
- public void undo() {
- if (target != null) {
- target.setVisibility(Visibility.VISIBLE);
- }
- }
+ @Override
+ public void undo() {
+ if (target != null) {
+ target.setVisibility(Visibility.VISIBLE);
+ }
+ }
- @Override
- public void redo() {
- if (target != null) {
- target.setVisibility(Visibility.INVISIBLE);
- }
- }
+ @Override
+ public void redo() {
+ if (target != null) {
+ target.setVisibility(Visibility.INVISIBLE);
+ }
+ }
- @Override
- public String toString() {
- return "Invisibility spell";
- }
+ @Override
+ public String toString() {
+ return "Invisibility spell";
+ }
}
diff --git a/command/src/main/java/com/iluwatar/command/ShrinkSpell.java b/command/src/main/java/com/iluwatar/command/ShrinkSpell.java
index f36438082..e88447353 100644
--- a/command/src/main/java/com/iluwatar/command/ShrinkSpell.java
+++ b/command/src/main/java/com/iluwatar/command/ShrinkSpell.java
@@ -1,3 +1,25 @@
+/**
+ * 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.command;
/**
@@ -7,32 +29,32 @@ package com.iluwatar.command;
*/
public class ShrinkSpell extends Command {
- private Size oldSize;
- private Target target;
+ private Size oldSize;
+ private Target target;
- @Override
- public void execute(Target target) {
- oldSize = target.getSize();
- target.setSize(Size.SMALL);
- this.target = target;
- }
+ @Override
+ public void execute(Target target) {
+ oldSize = target.getSize();
+ target.setSize(Size.SMALL);
+ this.target = target;
+ }
- @Override
- public void undo() {
- if (oldSize != null && target != null) {
- Size temp = target.getSize();
- target.setSize(oldSize);
- oldSize = temp;
- }
- }
+ @Override
+ public void undo() {
+ if (oldSize != null && target != null) {
+ Size temp = target.getSize();
+ target.setSize(oldSize);
+ oldSize = temp;
+ }
+ }
- @Override
- public void redo() {
- undo();
- }
+ @Override
+ public void redo() {
+ undo();
+ }
- @Override
- public String toString() {
- return "Shrink spell";
- }
+ @Override
+ public String toString() {
+ return "Shrink spell";
+ }
}
diff --git a/command/src/main/java/com/iluwatar/command/Size.java b/command/src/main/java/com/iluwatar/command/Size.java
index a9c20bd59..d33a19453 100644
--- a/command/src/main/java/com/iluwatar/command/Size.java
+++ b/command/src/main/java/com/iluwatar/command/Size.java
@@ -1,3 +1,25 @@
+/**
+ * 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.command;
/**
@@ -7,16 +29,16 @@ package com.iluwatar.command;
*/
public enum Size {
- SMALL("small"), NORMAL("normal"), LARGE("large"), UNDEFINED("");
-
- private String title;
+ SMALL("small"), NORMAL("normal"), LARGE("large"), UNDEFINED("");
- Size(String title) {
- this.title = title;
- }
+ private String title;
- @Override
- public String toString() {
- return title;
- }
+ Size(String title) {
+ this.title = title;
+ }
+
+ @Override
+ public String toString() {
+ return title;
+ }
}
diff --git a/command/src/main/java/com/iluwatar/command/Target.java b/command/src/main/java/com/iluwatar/command/Target.java
index 6ea2681d3..2e49ab663 100644
--- a/command/src/main/java/com/iluwatar/command/Target.java
+++ b/command/src/main/java/com/iluwatar/command/Target.java
@@ -1,3 +1,25 @@
+/**
+ * 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.command;
/**
@@ -7,32 +29,35 @@ package com.iluwatar.command;
*/
public abstract class Target {
- private Size size;
+ private Size size;
- private Visibility visibility;
+ private Visibility visibility;
- public Size getSize() {
- return size;
- }
+ public Size getSize() {
+ return size;
+ }
- public void setSize(Size size) {
- this.size = size;
- }
+ public void setSize(Size size) {
+ this.size = size;
+ }
- public Visibility getVisibility() {
- return visibility;
- }
+ public Visibility getVisibility() {
+ return visibility;
+ }
- public void setVisibility(Visibility visibility) {
- this.visibility = visibility;
- }
+ public void setVisibility(Visibility visibility) {
+ this.visibility = visibility;
+ }
- @Override
- public abstract String toString();
+ @Override
+ public abstract String toString();
- public void printStatus() {
- System.out.println(String.format("%s, [size=%s] [visibility=%s]", this,
- getSize(), getVisibility()));
- System.out.println();
- }
+ /**
+ * Print status
+ */
+ public void printStatus() {
+ System.out.println(String.format("%s, [size=%s] [visibility=%s]", this, getSize(),
+ getVisibility()));
+ System.out.println();
+ }
}
diff --git a/command/src/main/java/com/iluwatar/command/Visibility.java b/command/src/main/java/com/iluwatar/command/Visibility.java
index 3316ac9e3..4ab079d18 100644
--- a/command/src/main/java/com/iluwatar/command/Visibility.java
+++ b/command/src/main/java/com/iluwatar/command/Visibility.java
@@ -1,3 +1,25 @@
+/**
+ * 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.command;
/**
@@ -7,16 +29,16 @@ package com.iluwatar.command;
*/
public enum Visibility {
- VISIBLE("visible"), INVISIBLE("invisible"), UNDEFINED("");
+ VISIBLE("visible"), INVISIBLE("invisible"), UNDEFINED("");
- private String title;
+ private String title;
- Visibility(String title) {
- this.title = title;
- }
+ Visibility(String title) {
+ this.title = title;
+ }
- @Override
- public String toString() {
- return title;
- }
+ @Override
+ public String toString() {
+ return title;
+ }
}
diff --git a/command/src/main/java/com/iluwatar/command/Wizard.java b/command/src/main/java/com/iluwatar/command/Wizard.java
index 995b4441a..bd0ef85d4 100644
--- a/command/src/main/java/com/iluwatar/command/Wizard.java
+++ b/command/src/main/java/com/iluwatar/command/Wizard.java
@@ -1,3 +1,25 @@
+/**
+ * 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.command;
import java.util.Deque;
@@ -10,38 +32,46 @@ import java.util.LinkedList;
*/
public class Wizard {
- private Deque undoStack = new LinkedList<>();
- private Deque redoStack = new LinkedList<>();
+ private Deque undoStack = new LinkedList<>();
+ private Deque redoStack = new LinkedList<>();
- public Wizard() {
- }
+ public Wizard() {}
- public void castSpell(Command command, Target target) {
- System.out.println(this + " casts " + command + " at " + target);
- command.execute(target);
- undoStack.offerLast(command);
- }
+ /**
+ * Cast spell
+ */
+ public void castSpell(Command command, Target target) {
+ System.out.println(this + " casts " + command + " at " + target);
+ command.execute(target);
+ undoStack.offerLast(command);
+ }
- public void undoLastSpell() {
- if (!undoStack.isEmpty()) {
- Command previousSpell = undoStack.pollLast();
- redoStack.offerLast(previousSpell);
- System.out.println(this + " undoes " + previousSpell);
- previousSpell.undo();
- }
- }
+ /**
+ * Undo last spell
+ */
+ public void undoLastSpell() {
+ if (!undoStack.isEmpty()) {
+ Command previousSpell = undoStack.pollLast();
+ redoStack.offerLast(previousSpell);
+ System.out.println(this + " undoes " + previousSpell);
+ previousSpell.undo();
+ }
+ }
- public void redoLastSpell() {
- if (!redoStack.isEmpty()) {
- Command previousSpell = redoStack.pollLast();
- undoStack.offerLast(previousSpell);
- System.out.println(this + " redoes " + previousSpell);
- previousSpell.redo();
- }
- }
+ /**
+ * Redo last spell
+ */
+ public void redoLastSpell() {
+ if (!redoStack.isEmpty()) {
+ Command previousSpell = redoStack.pollLast();
+ undoStack.offerLast(previousSpell);
+ System.out.println(this + " redoes " + previousSpell);
+ previousSpell.redo();
+ }
+ }
- @Override
- public String toString() {
- return "Wizard";
- }
+ @Override
+ public String toString() {
+ return "Wizard";
+ }
}
diff --git a/command/src/test/java/com/iluwatar/command/AppTest.java b/command/src/test/java/com/iluwatar/command/AppTest.java
index 454f92b63..560594272 100644
--- a/command/src/test/java/com/iluwatar/command/AppTest.java
+++ b/command/src/test/java/com/iluwatar/command/AppTest.java
@@ -1,14 +1,38 @@
-package com.iluwatar.command;
-
-import org.junit.Test;
-
-import com.iluwatar.command.App;
-
-public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
-}
+/**
+ * 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.command;
+
+import org.junit.Test;
+
+import java.io.IOException;
+
+/**
+ * Tests that Command example runs without errors.
+ */
+public class AppTest {
+ @Test
+ public void test() throws IOException {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/command/src/test/java/com/iluwatar/command/CommandTest.java b/command/src/test/java/com/iluwatar/command/CommandTest.java
new file mode 100644
index 000000000..8201d50c6
--- /dev/null
+++ b/command/src/test/java/com/iluwatar/command/CommandTest.java
@@ -0,0 +1,93 @@
+/**
+ * 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.command;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+/**
+ * The Command pattern is a behavioral design pattern in which an object is used to encapsulate all
+ * information needed to perform an action or trigger an event at a later time. This information
+ * includes the method name, the object that owns the method and values for the method parameters.
+ *
+ * Four terms always associated with the command pattern are command, receiver, invoker and
+ * client. A command object (spell) knows about the receiver (target) and invokes a method of
+ * the receiver.Values for parameters of the receiver method are stored in the command. The receiver
+ * then does the work. An invoker object (wizard) knows how to execute a command, and optionally
+ * does bookkeeping about the command execution. The invoker does not know anything about a
+ * concrete command, it knows only about command interface. Both an invoker object and several
+ * command objects are held by a client object (app). The client decides which commands to execute
+ * at which points. To execute a command, it passes the command object to the invoker object.
+ */
+public class CommandTest {
+
+ private static final String GOBLIN = "Goblin";
+
+ /**
+ * This test verifies that when the wizard casts spells on the goblin. The wizard keeps track of
+ * the previous spells cast, so it is easy to undo them. In addition, it also verifies that the
+ * wizard keeps track of the spells undone, so they can be redone.
+ */
+ @Test
+ public void testCommand() {
+
+ Wizard wizard = new Wizard();
+ Goblin goblin = new Goblin();
+
+ wizard.castSpell(new ShrinkSpell(), goblin);
+ verifyGoblin(goblin, GOBLIN, Size.SMALL, Visibility.VISIBLE);
+
+ wizard.castSpell(new InvisibilitySpell(), goblin);
+ verifyGoblin(goblin, GOBLIN, Size.SMALL, Visibility.INVISIBLE);
+
+ wizard.undoLastSpell();
+ verifyGoblin(goblin, GOBLIN, Size.SMALL, Visibility.VISIBLE);
+
+ wizard.undoLastSpell();
+ verifyGoblin(goblin, GOBLIN, Size.NORMAL, Visibility.VISIBLE);
+
+ wizard.redoLastSpell();
+ verifyGoblin(goblin, GOBLIN, Size.SMALL, Visibility.VISIBLE);
+
+ wizard.redoLastSpell();
+ verifyGoblin(goblin, GOBLIN, Size.SMALL, Visibility.INVISIBLE);
+ }
+
+ /**
+ * This method asserts that the passed goblin object has the name as expectedName, size as
+ * expectedSize and visibility as expectedVisibility.
+ *
+ * @param goblin a goblin object whose state is to be verified against other parameters
+ * @param expectedName expectedName of the goblin
+ * @param expectedSize expected size of the goblin
+ * @param expectedVisibilty exepcted visibility of the goblin
+ */
+ private void verifyGoblin(Goblin goblin, String expectedName, Size expectedSize,
+ Visibility expectedVisibilty) {
+ assertEquals("Goblin's name must be same as expectedName", expectedName, goblin.toString());
+ assertEquals("Goblin's size must be same as expectedSize", expectedSize, goblin.getSize());
+ assertEquals("Goblin's visibility must be same as expectedVisibility", expectedVisibilty,
+ goblin.getVisibility());
+ }
+}
diff --git a/composite/README.md b/composite/README.md
new file mode 100644
index 000000000..8b980292d
--- /dev/null
+++ b/composite/README.md
@@ -0,0 +1,33 @@
+---
+layout: pattern
+title: Composite
+folder: composite
+permalink: /patterns/composite/
+categories: Structural
+tags:
+ - Java
+ - Gang Of Four
+ - Difficulty-Intermediate
+---
+
+## Intent
+Compose objects into tree structures to represent part-whole
+hierarchies. Composite lets clients treat individual objects and compositions
+of objects uniformly.
+
+
+
+## Applicability
+Use the Composite pattern when
+
+* you want to represent part-whole hierarchies of objects
+* you want clients to be able to ignore the difference between compositions of objects and individual objects. Clients will treat all objects in the composite structure uniformly
+
+## Real world examples
+
+* [java.awt.Container](http://docs.oracle.com/javase/8/docs/api/java/awt/Container.html) and [java.awt.Component](http://docs.oracle.com/javase/8/docs/api/java/awt/Component.html)
+* [Apache Wicket](https://github.com/apache/wicket) component tree, see [Component](https://github.com/apache/wicket/blob/91e154702ab1ff3481ef6cbb04c6044814b7e130/wicket-core/src/main/java/org/apache/wicket/Component.java) and [MarkupContainer](https://github.com/apache/wicket/blob/b60ec64d0b50a611a9549809c9ab216f0ffa3ae3/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java)
+
+## Credits
+
+* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/composite/pom.xml b/composite/pom.xml
index d8d7e4233..ace29d8d1 100644
--- a/composite/pom.xml
+++ b/composite/pom.xml
@@ -1,11 +1,35 @@
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
composite
diff --git a/composite/src/main/java/com/iluwatar/composite/App.java b/composite/src/main/java/com/iluwatar/composite/App.java
index 6dd62a552..cfe37876f 100644
--- a/composite/src/main/java/com/iluwatar/composite/App.java
+++ b/composite/src/main/java/com/iluwatar/composite/App.java
@@ -1,25 +1,56 @@
-package com.iluwatar.composite;
-
-/**
- *
- * With Composite we can treat tree hierarchies of objects with uniform
- * interface (LetterComposite). In this example we have sentences composed of
- * words composed of letters.
- *
- */
-public class App {
-
- public static void main(String[] args) {
- System.out.println("Message from the orcs: ");
-
- LetterComposite orcMessage = new Messenger().messageFromOrcs();
- orcMessage.print();
-
- System.out.println("\n");
-
- System.out.println("Message from the elves: ");
-
- LetterComposite elfMessage = new Messenger().messageFromElves();
- elfMessage.print();
- }
-}
+/**
+ * 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.composite;
+
+/**
+ * The Composite pattern is a partitioning design pattern. The Composite pattern describes that a
+ * group of objects is to be treated in the same way as a single instance of an object. The intent
+ * of a composite is to "compose" objects into tree structures to represent part-whole hierarchies.
+ * Implementing the Composite pattern lets clients treat individual objects and compositions
+ * uniformly.
+ *
+ * In this example we have sentences composed of words composed of letters. All of the objects can
+ * be treated through the same interface ({@link LetterComposite}).
+ *
+ */
+public class App {
+
+ /**
+ * Program entry point
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ System.out.println("Message from the orcs: ");
+
+ LetterComposite orcMessage = new Messenger().messageFromOrcs();
+ orcMessage.print();
+
+ System.out.println("\n");
+
+ System.out.println("Message from the elves: ");
+
+ LetterComposite elfMessage = new Messenger().messageFromElves();
+ elfMessage.print();
+ }
+}
diff --git a/composite/src/main/java/com/iluwatar/composite/Letter.java b/composite/src/main/java/com/iluwatar/composite/Letter.java
index 9df8b95f7..d6a4005d2 100644
--- a/composite/src/main/java/com/iluwatar/composite/Letter.java
+++ b/composite/src/main/java/com/iluwatar/composite/Letter.java
@@ -1,21 +1,47 @@
-package com.iluwatar.composite;
-
-public class Letter extends LetterComposite {
-
- private char c;
-
- public Letter(char c) {
- this.c = c;
- }
-
- @Override
- protected void printThisBefore() {
- System.out.print(c);
- }
-
- @Override
- protected void printThisAfter() {
- // nop
- }
-
-}
+/**
+ * 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.composite;
+
+/**
+ *
+ * Letter
+ *
+ */
+public class Letter extends LetterComposite {
+
+ private char c;
+
+ public Letter(char c) {
+ this.c = c;
+ }
+
+ @Override
+ protected void printThisBefore() {
+ System.out.print(c);
+ }
+
+ @Override
+ protected void printThisAfter() {
+ // nop
+ }
+}
diff --git a/composite/src/main/java/com/iluwatar/composite/LetterComposite.java b/composite/src/main/java/com/iluwatar/composite/LetterComposite.java
index e58d51b25..940562969 100644
--- a/composite/src/main/java/com/iluwatar/composite/LetterComposite.java
+++ b/composite/src/main/java/com/iluwatar/composite/LetterComposite.java
@@ -1,3 +1,25 @@
+/**
+ * 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.composite;
import java.util.ArrayList;
@@ -10,25 +32,28 @@ import java.util.List;
*/
public abstract class LetterComposite {
- private List children = new ArrayList();
+ private List children = new ArrayList<>();
- public void add(LetterComposite letter) {
- children.add(letter);
- }
+ public void add(LetterComposite letter) {
+ children.add(letter);
+ }
- public int count() {
- return children.size();
- }
+ public int count() {
+ return children.size();
+ }
- protected abstract void printThisBefore();
+ protected abstract void printThisBefore();
- protected abstract void printThisAfter();
+ protected abstract void printThisAfter();
- public void print() {
- printThisBefore();
- for (LetterComposite letter : children) {
- letter.print();
- }
- printThisAfter();
- }
+ /**
+ * Print
+ */
+ public void print() {
+ printThisBefore();
+ for (LetterComposite letter : children) {
+ letter.print();
+ }
+ printThisAfter();
+ }
}
diff --git a/composite/src/main/java/com/iluwatar/composite/Messenger.java b/composite/src/main/java/com/iluwatar/composite/Messenger.java
index a849408ca..3b758d680 100644
--- a/composite/src/main/java/com/iluwatar/composite/Messenger.java
+++ b/composite/src/main/java/com/iluwatar/composite/Messenger.java
@@ -1,53 +1,79 @@
-package com.iluwatar.composite;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-public class Messenger {
-
- LetterComposite messageFromOrcs() {
-
- List words = new ArrayList();
-
- words.add(new Word(Arrays.asList(new Letter('W'), new Letter('h'),
- new Letter('e'), new Letter('r'), new Letter('e'))));
- words.add(new Word(Arrays.asList(new Letter('t'), new Letter('h'),
- new Letter('e'), new Letter('r'), new Letter('e'))));
- words.add(new Word(Arrays.asList(new Letter('i'), new Letter('s'))));
- words.add(new Word(Arrays.asList(new Letter('a'))));
- words.add(new Word(Arrays.asList(new Letter('w'), new Letter('h'),
- new Letter('i'), new Letter('p'))));
- words.add(new Word(Arrays.asList(new Letter('t'), new Letter('h'),
- new Letter('e'), new Letter('r'), new Letter('e'))));
- words.add(new Word(Arrays.asList(new Letter('i'), new Letter('s'))));
- words.add(new Word(Arrays.asList(new Letter('a'))));
- words.add(new Word(Arrays.asList(new Letter('w'), new Letter('a'),
- new Letter('y'))));
-
- return new Sentence(words);
-
- }
-
- LetterComposite messageFromElves() {
-
- List words = new ArrayList();
-
- words.add(new Word(Arrays.asList(new Letter('M'), new Letter('u'),
- new Letter('c'), new Letter('h'))));
- words.add(new Word(Arrays.asList(new Letter('w'), new Letter('i'),
- new Letter('n'), new Letter('d'))));
- words.add(new Word(Arrays.asList(new Letter('p'), new Letter('o'),
- new Letter('u'), new Letter('r'), new Letter('s'))));
- words.add(new Word(Arrays.asList(new Letter('f'), new Letter('r'),
- new Letter('o'), new Letter('m'))));
- words.add(new Word(Arrays.asList(new Letter('y'), new Letter('o'),
- new Letter('u'), new Letter('r'))));
- words.add(new Word(Arrays.asList(new Letter('m'), new Letter('o'),
- new Letter('u'), new Letter('t'), new Letter('h'))));
-
- return new Sentence(words);
-
- }
-
-}
+/**
+ * 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.composite;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ *
+ * Messenger
+ *
+ */
+public class Messenger {
+
+ LetterComposite messageFromOrcs() {
+
+ List words = new ArrayList<>();
+
+ words.add(new Word(Arrays.asList(new Letter('W'), new Letter('h'), new Letter('e'), new Letter(
+ 'r'), new Letter('e'))));
+ words.add(new Word(Arrays.asList(new Letter('t'), new Letter('h'), new Letter('e'), new Letter(
+ 'r'), new Letter('e'))));
+ words.add(new Word(Arrays.asList(new Letter('i'), new Letter('s'))));
+ words.add(new Word(Arrays.asList(new Letter('a'))));
+ words.add(new Word(Arrays.asList(new Letter('w'), new Letter('h'), new Letter('i'), new Letter(
+ 'p'))));
+ words.add(new Word(Arrays.asList(new Letter('t'), new Letter('h'), new Letter('e'), new Letter(
+ 'r'), new Letter('e'))));
+ words.add(new Word(Arrays.asList(new Letter('i'), new Letter('s'))));
+ words.add(new Word(Arrays.asList(new Letter('a'))));
+ words.add(new Word(Arrays.asList(new Letter('w'), new Letter('a'), new Letter('y'))));
+
+ return new Sentence(words);
+
+ }
+
+ LetterComposite messageFromElves() {
+
+ List words = new ArrayList<>();
+
+ words.add(new Word(Arrays.asList(new Letter('M'), new Letter('u'), new Letter('c'), new Letter(
+ 'h'))));
+ words.add(new Word(Arrays.asList(new Letter('w'), new Letter('i'), new Letter('n'), new Letter(
+ 'd'))));
+ words.add(new Word(Arrays.asList(new Letter('p'), new Letter('o'), new Letter('u'), new Letter(
+ 'r'), new Letter('s'))));
+ words.add(new Word(Arrays.asList(new Letter('f'), new Letter('r'), new Letter('o'), new Letter(
+ 'm'))));
+ words.add(new Word(Arrays.asList(new Letter('y'), new Letter('o'), new Letter('u'), new Letter(
+ 'r'))));
+ words.add(new Word(Arrays.asList(new Letter('m'), new Letter('o'), new Letter('u'), new Letter(
+ 't'), new Letter('h'))));
+
+ return new Sentence(words);
+
+ }
+
+}
diff --git a/composite/src/main/java/com/iluwatar/composite/Sentence.java b/composite/src/main/java/com/iluwatar/composite/Sentence.java
index c83c520de..eea1d4b1d 100644
--- a/composite/src/main/java/com/iluwatar/composite/Sentence.java
+++ b/composite/src/main/java/com/iluwatar/composite/Sentence.java
@@ -1,23 +1,52 @@
-package com.iluwatar.composite;
-
-import java.util.List;
-
-public class Sentence extends LetterComposite {
-
- public Sentence(List words) {
- for (Word w : words) {
- this.add(w);
- }
- }
-
- @Override
- protected void printThisBefore() {
- // nop
- }
-
- @Override
- protected void printThisAfter() {
- System.out.print(".");
- }
-
-}
+/**
+ * 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.composite;
+
+import java.util.List;
+
+/**
+ *
+ * Sentence
+ *
+ */
+public class Sentence extends LetterComposite {
+
+ /**
+ * Constructor
+ */
+ public Sentence(List words) {
+ for (Word w : words) {
+ this.add(w);
+ }
+ }
+
+ @Override
+ protected void printThisBefore() {
+ // nop
+ }
+
+ @Override
+ protected void printThisAfter() {
+ System.out.print(".");
+ }
+}
diff --git a/composite/src/main/java/com/iluwatar/composite/Word.java b/composite/src/main/java/com/iluwatar/composite/Word.java
index 393cd2019..819f166dc 100644
--- a/composite/src/main/java/com/iluwatar/composite/Word.java
+++ b/composite/src/main/java/com/iluwatar/composite/Word.java
@@ -1,23 +1,52 @@
-package com.iluwatar.composite;
-
-import java.util.List;
-
-public class Word extends LetterComposite {
-
- public Word(List letters) {
- for (Letter l : letters) {
- this.add(l);
- }
- }
-
- @Override
- protected void printThisBefore() {
- System.out.print(" ");
- }
-
- @Override
- protected void printThisAfter() {
- // nop
- }
-
-}
+/**
+ * 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.composite;
+
+import java.util.List;
+
+/**
+ *
+ * Word
+ *
+ */
+public class Word extends LetterComposite {
+
+ /**
+ * Constructor
+ */
+ public Word(List letters) {
+ for (Letter l : letters) {
+ this.add(l);
+ }
+ }
+
+ @Override
+ protected void printThisBefore() {
+ System.out.print(" ");
+ }
+
+ @Override
+ protected void printThisAfter() {
+ // nop
+ }
+}
diff --git a/composite/src/test/java/com/iluwatar/composite/AppTest.java b/composite/src/test/java/com/iluwatar/composite/AppTest.java
index 5057efe68..336438a99 100644
--- a/composite/src/test/java/com/iluwatar/composite/AppTest.java
+++ b/composite/src/test/java/com/iluwatar/composite/AppTest.java
@@ -1,14 +1,39 @@
-package com.iluwatar.composite;
-
-import org.junit.Test;
-
-import com.iluwatar.composite.App;
-
-public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
-}
+/**
+ * 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.composite;
+
+import org.junit.Test;
+
+/**
+ *
+ * Application test
+ *
+ */
+public class AppTest {
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/composite/src/test/java/com/iluwatar/composite/MessengerTest.java b/composite/src/test/java/com/iluwatar/composite/MessengerTest.java
new file mode 100644
index 000000000..5f75ea017
--- /dev/null
+++ b/composite/src/test/java/com/iluwatar/composite/MessengerTest.java
@@ -0,0 +1,112 @@
+/**
+ * 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.composite;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Date: 12/11/15 - 8:12 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class MessengerTest {
+
+ /**
+ * The buffer used to capture every write to {@link System#out}
+ */
+ private ByteArrayOutputStream stdOutBuffer = new ByteArrayOutputStream();
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream realStdOut = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ this.stdOutBuffer = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(stdOutBuffer));
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(realStdOut);
+ }
+
+ /**
+ * Test the message from the orcs
+ */
+ @Test
+ public void testMessageFromOrcs() {
+ final Messenger messenger = new Messenger();
+ testMessage(
+ messenger.messageFromOrcs(),
+ "Where there is a whip there is a way."
+ );
+ }
+
+ /**
+ * Test the message from the elves
+ */
+ @Test
+ public void testMessageFromElves() {
+ final Messenger messenger = new Messenger();
+ testMessage(
+ messenger.messageFromElves(),
+ "Much wind pours from your mouth."
+ );
+ }
+
+ /**
+ * Test if the given composed message matches the expected message
+ *
+ * @param composedMessage The composed message, received from the messenger
+ * @param message The expected message
+ */
+ private void testMessage(final LetterComposite composedMessage, final String message) {
+ // Test is the composed message has the correct number of words
+ final String[] words = message.split(" ");
+ assertNotNull(composedMessage);
+ assertEquals(words.length, composedMessage.count());
+
+ // Print the message to the mocked stdOut ...
+ composedMessage.print();
+
+ // ... and verify if the message matches with the expected one
+ assertEquals(message, new String(this.stdOutBuffer.toByteArray()).trim());
+ }
+
+}
diff --git a/dao/README.md b/dao/README.md
new file mode 100644
index 000000000..785a1c362
--- /dev/null
+++ b/dao/README.md
@@ -0,0 +1,26 @@
+---
+layout: pattern
+title: Data Access Object
+folder: dao
+permalink: /patterns/dao/
+categories: Persistence Tier
+tags:
+ - Java
+ - Difficulty-Beginner
+---
+
+## Intent
+Object provides an abstract interface to some type of database or
+other persistence mechanism.
+
+
+
+## Applicability
+Use the Data Access Object in any of the following situations
+
+* when you want to consolidate how the data layer is accessed
+* when you want to avoid writing multiple data retrieval/persistence layers
+
+## Credits
+
+* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
diff --git a/dao/etc/dao.png b/dao/etc/dao.png
index 9fe34b976..452e72ba1 100644
Binary files a/dao/etc/dao.png and b/dao/etc/dao.png differ
diff --git a/dao/etc/dao.ucls b/dao/etc/dao.ucls
index bf11f18b3..0706837fc 100644
--- a/dao/etc/dao.ucls
+++ b/dao/etc/dao.ucls
@@ -1,45 +1,71 @@
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dao/pom.xml b/dao/pom.xml
index bfd35c727..f64eff8bc 100644
--- a/dao/pom.xml
+++ b/dao/pom.xml
@@ -1,18 +1,105 @@
-
+
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
dao
+
junit
junit
test
+
+ log4j
+ log4j
+
+
+ com.h2database
+ h2
+
+
+ de.bechte.junit
+ junit-hierarchicalcontextrunner
+
+
+ org.mockito
+ mockito-core
+
+
+
+
+
+
+
+
+ src/main/resources
+
+
+ src/main/resources
+
+ log4j.xml
+
+ ..
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 2.6
+
+
+ log4j.xml
+
+
+
+ true
+
+
+
+
+
+
+
diff --git a/dao/src/main/java/com/iluwatar/dao/App.java b/dao/src/main/java/com/iluwatar/dao/App.java
index dd96cf807..8a0c06739 100644
--- a/dao/src/main/java/com/iluwatar/dao/App.java
+++ b/dao/src/main/java/com/iluwatar/dao/App.java
@@ -1,47 +1,135 @@
-package com.iluwatar.dao;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- *
- * With the DAO pattern, we can use various method calls to retrieve/add/delete/update data without directly
- * interacting with the data. The below example demonstrates basic operations(CRUD): select, add, update, and delete.
- */
-public class App {
-
- public static void main(String[] args) {
-
- CustomerDaoImpl customerDao = new CustomerDaoImpl(generateSampleCustomers());
-
- System.out.println("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
- System.out.println("customerDao.getCusterById(2): " + customerDao.getCusterById(2));
-
- Customer customer = new Customer(4, "Dan", "Danson");
- customerDao.addCustomer(customer);
-
- System.out.println("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
-
- customer.setFirstName("Daniel");
- customer.setLastName("Danielson");
- customerDao.updateCustomer(customer);
-
- System.out.println("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
-
- customerDao.deleteCustomer(customer);
-
- System.out.println("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
- }
-
- public static List generateSampleCustomers() {
- Customer customer1 = new Customer(1, "Adam", "Adamson");
- Customer customer2 = new Customer(2, "Bob", "Bobson");
- Customer customer3 = new Customer(3, "Carl", "Carlson");
-
- List customers = new ArrayList();
- customers.add(customer1);
- customers.add(customer2);
- customers.add(customer3);
- return customers;
- }
-}
+/**
+ * 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.dao;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+import javax.sql.DataSource;
+
+import org.apache.log4j.Logger;
+import org.h2.jdbcx.JdbcDataSource;
+
+/**
+ * Data Access Object (DAO) is an object that provides an abstract interface to some type of
+ * database or other persistence mechanism. By mapping application calls to the persistence layer,
+ * DAO provide some specific data operations without exposing details of the database. This
+ * isolation supports the Single responsibility principle. It separates what data accesses the
+ * application needs, in terms of domain-specific objects and data types (the public interface of
+ * the DAO), from how these needs can be satisfied with a specific DBMS.
+ *
+ * With the DAO pattern, we can use various method calls to retrieve/add/delete/update data
+ * without directly interacting with the data source. The below example demonstrates basic CRUD
+ * operations: select, add, update, and delete.
+ *
+ *
+ */
+public class App {
+ private static final String DB_URL = "jdbc:h2:~/dao";
+ private static Logger log = Logger.getLogger(App.class);
+
+ /**
+ * Program entry point.
+ *
+ * @param args command line args.
+ * @throws Exception if any error occurs.
+ */
+ public static void main(final String[] args) throws Exception {
+ final CustomerDao inMemoryDao = new InMemoryCustomerDao();
+ performOperationsUsing(inMemoryDao);
+
+ final DataSource dataSource = createDataSource();
+ createSchema(dataSource);
+ final CustomerDao dbDao = new DbCustomerDao(dataSource);
+ performOperationsUsing(dbDao);
+ deleteSchema(dataSource);
+ }
+
+ private static void deleteSchema(DataSource dataSource) throws SQLException {
+ try (Connection connection = dataSource.getConnection();
+ Statement statement = connection.createStatement()) {
+ statement.execute(CustomerSchemaSql.DELETE_SCHEMA_SQL);
+ }
+ }
+
+ private static void createSchema(DataSource dataSource) throws SQLException {
+ try (Connection connection = dataSource.getConnection();
+ Statement statement = connection.createStatement()) {
+ statement.execute(CustomerSchemaSql.CREATE_SCHEMA_SQL);
+ }
+ }
+
+ private static DataSource createDataSource() {
+ JdbcDataSource dataSource = new JdbcDataSource();
+ dataSource.setURL(DB_URL);
+ return dataSource;
+ }
+
+ private static void performOperationsUsing(final CustomerDao customerDao) throws Exception {
+ addCustomers(customerDao);
+ log.info("customerDao.getAllCustomers(): ");
+ try (Stream customerStream = customerDao.getAll()) {
+ customerStream.forEach((customer) -> log.info(customer));
+ }
+ log.info("customerDao.getCustomerById(2): " + customerDao.getById(2));
+ final Customer customer = new Customer(4, "Dan", "Danson");
+ customerDao.add(customer);
+ log.info("customerDao.getAllCustomers(): " + customerDao.getAll());
+ customer.setFirstName("Daniel");
+ customer.setLastName("Danielson");
+ customerDao.update(customer);
+ log.info("customerDao.getAllCustomers(): ");
+ try (Stream customerStream = customerDao.getAll()) {
+ customerStream.forEach((cust) -> log.info(cust));
+ }
+ customerDao.delete(customer);
+ log.info("customerDao.getAllCustomers(): " + customerDao.getAll());
+ }
+
+ private static void addCustomers(CustomerDao customerDao) throws Exception {
+ for (Customer customer : generateSampleCustomers()) {
+ customerDao.add(customer);
+ }
+ }
+
+ /**
+ * Generate customers.
+ *
+ * @return list of customers.
+ */
+ public static List generateSampleCustomers() {
+ final Customer customer1 = new Customer(1, "Adam", "Adamson");
+ final Customer customer2 = new Customer(2, "Bob", "Bobson");
+ final Customer customer3 = new Customer(3, "Carl", "Carlson");
+ final List customers = new ArrayList<>();
+ customers.add(customer1);
+ customers.add(customer2);
+ customers.add(customer3);
+ return customers;
+ }
+}
diff --git a/dao/src/main/java/com/iluwatar/dao/Customer.java b/dao/src/main/java/com/iluwatar/dao/Customer.java
index 7900fee67..d6b512dd6 100644
--- a/dao/src/main/java/com/iluwatar/dao/Customer.java
+++ b/dao/src/main/java/com/iluwatar/dao/Customer.java
@@ -1,64 +1,93 @@
+/**
+ * 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.dao;
+/**
+ * A customer POJO that represents the data that will be read from the data source.
+ *
+ */
public class Customer {
- private int id;
- private String firstName;
- private String lastName;
- public Customer(int id, String firstName, String lastName) {
- this.id = id;
- this.firstName = firstName;
- this.lastName = lastName;
+ private int id;
+ private String firstName;
+ private String lastName;
+
+ /**
+ * Creates an instance of customer.
+ */
+ public Customer(final int id, final String firstName, final String lastName) {
+ this.id = id;
+ this.firstName = firstName;
+ this.lastName = lastName;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(final int id) {
+ this.id = id;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(final String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(final String lastName) {
+ this.lastName = lastName;
+ }
+
+ @Override
+ public String toString() {
+ return "Customer{" + "id=" + getId() + ", firstName='" + getFirstName() + '\'' + ", lastName='"
+ + getLastName() + '\'' + '}';
+ }
+
+ @Override
+ public boolean equals(final Object that) {
+ boolean isEqual = false;
+ if (this == that) {
+ isEqual = true;
+ } else if (that != null && getClass() == that.getClass()) {
+ final Customer customer = (Customer) that;
+ if (getId() == customer.getId()) {
+ isEqual = true;
+ }
}
+ return isEqual;
+ }
- public int getId() {
- return id;
- }
-
- public void setId(int id) {
- this.id = id;
- }
-
- public String getFirstName() {
- return firstName;
- }
-
- public void setFirstName(String firstName) {
- this.firstName = firstName;
- }
-
- public String getLastName() {
- return lastName;
- }
-
- public void setLastName(String lastName) {
- this.lastName = lastName;
- }
-
- @Override
- public String toString() {
- return "Customer{" +
- "id=" + id +
- ", firstName='" + firstName + '\'' +
- ", lastName='" + lastName + '\'' +
- '}';
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- Customer customer = (Customer) o;
-
- if (id != customer.id) return false;
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int result = id;
- return result;
- }
-}
\ No newline at end of file
+ @Override
+ public int hashCode() {
+ return getId();
+ }
+}
diff --git a/dao/src/main/java/com/iluwatar/dao/CustomerDao.java b/dao/src/main/java/com/iluwatar/dao/CustomerDao.java
index f201d945d..059a9e9f7 100644
--- a/dao/src/main/java/com/iluwatar/dao/CustomerDao.java
+++ b/dao/src/main/java/com/iluwatar/dao/CustomerDao.java
@@ -1,11 +1,81 @@
+/**
+ * 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.dao;
-import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
+/**
+ * In an application the Data Access Object (DAO) is a part of Data access layer. It is an object
+ * that provides an interface to some type of persistence mechanism. By mapping application calls
+ * to the persistence layer, DAO provides some specific data operations without exposing details
+ * of the database. This isolation supports the Single responsibility principle. It separates what
+ * data accesses the application needs, in terms of domain-specific objects and data types
+ * (the public interface of the DAO), from how these needs can be satisfied with a specific DBMS,
+ * database schema, etc.
+ *
+ * Any change in the way data is stored and retrieved will not change the client code as the
+ * client will be using interface and need not worry about exact source.
+ *
+ * @see InMemoryCustomerDao
+ * @see DbCustomerDao
+ */
public interface CustomerDao {
- public List getAllCustomers();
- public Customer getCusterById(int id);
- public void addCustomer(Customer customer);
- public void updateCustomer(Customer customer);
- public void deleteCustomer(Customer customer);
-}
\ No newline at end of file
+
+ /**
+ * @return all the customers as a stream. The stream may be lazily or eagerly evaluated based
+ * on the implementation. The stream must be closed after use.
+ * @throws Exception if any error occurs.
+ */
+ Stream getAll() throws Exception;
+
+ /**
+ * @param id unique identifier of the customer.
+ * @return an optional with customer if a customer with unique identifier id
+ * exists, empty optional otherwise.
+ * @throws Exception if any error occurs.
+ */
+ Optional getById(int id) throws Exception;
+
+ /**
+ * @param customer the customer to be added.
+ * @return true if customer is successfully added, false if customer already exists.
+ * @throws Exception if any error occurs.
+ */
+ boolean add(Customer customer) throws Exception;
+
+ /**
+ * @param customer the customer to be updated.
+ * @return true if customer exists and is successfully updated, false otherwise.
+ * @throws Exception if any error occurs.
+ */
+ boolean update(Customer customer) throws Exception;
+
+ /**
+ * @param customer the customer to be deleted.
+ * @return true if customer exists and is successfully deleted, false otherwise.
+ * @throws Exception if any error occurs.
+ */
+ boolean delete(Customer customer) throws Exception;
+}
diff --git a/dao/src/main/java/com/iluwatar/dao/CustomerDaoImpl.java b/dao/src/main/java/com/iluwatar/dao/CustomerDaoImpl.java
deleted file mode 100644
index ff5332798..000000000
--- a/dao/src/main/java/com/iluwatar/dao/CustomerDaoImpl.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.iluwatar.dao;
-
-import java.util.List;
-
-/**
- * The data access object (DAO) is an object that provides an abstract interface to some type of database or other persistence mechanism.
- * By mapping application calls to the persistence layer, DAO provide some specific data operations without exposing details of the database.
- * This isolation supports the Single responsibility principle. It separates what data accesses the application needs, in terms of
- * domain-specific objects and data types (the public interface of the DAO), from how these needs can be satisfied with a specific DBMS,
- * database schema, etc.
- */
-public class CustomerDaoImpl implements CustomerDao {
-
- // Represents the DB structure for our example so we don't have to managed it ourselves
- // Note: Normally this would be in the form of an actual database and not part of the Dao Impl.
- private List customers;
-
- public CustomerDaoImpl(List customers) {
- this.customers = customers;
- }
-
- @Override
- public List getAllCustomers() {
- return customers;
- }
-
- @Override
- public Customer getCusterById(int id) {
- for (int i = 0; i < customers.size(); i++) {
- if (customers.get(i).getId() == id) {
- return customers.get(i);
- }
- }
- // No customer found
- return null;
- }
-
- @Override
- public void addCustomer(Customer customer) {
- customers.add(customer);
- }
-
-
- @Override
- public void updateCustomer(Customer customer) {
- if (customers.contains(customer)) {
- customers.set(customers.indexOf(customer), customer);
- }
- }
-
- @Override
- public void deleteCustomer(Customer customer) {
- customers.remove(customer);
- }
-}
\ No newline at end of file
diff --git a/dao/src/main/java/com/iluwatar/dao/CustomerSchemaSql.java b/dao/src/main/java/com/iluwatar/dao/CustomerSchemaSql.java
new file mode 100644
index 000000000..860826abf
--- /dev/null
+++ b/dao/src/main/java/com/iluwatar/dao/CustomerSchemaSql.java
@@ -0,0 +1,31 @@
+/**
+ * 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.dao;
+
+public interface CustomerSchemaSql {
+
+ String CREATE_SCHEMA_SQL = "CREATE TABLE CUSTOMERS (ID NUMBER, FNAME VARCHAR(100), "
+ + "LNAME VARCHAR(100))";
+
+ String DELETE_SCHEMA_SQL = "DROP TABLE CUSTOMERS";
+}
diff --git a/dao/src/main/java/com/iluwatar/dao/DbCustomerDao.java b/dao/src/main/java/com/iluwatar/dao/DbCustomerDao.java
new file mode 100644
index 000000000..622b5b1f0
--- /dev/null
+++ b/dao/src/main/java/com/iluwatar/dao/DbCustomerDao.java
@@ -0,0 +1,183 @@
+/**
+ * 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.dao;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Optional;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Consumer;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import javax.sql.DataSource;
+
+/**
+ * An implementation of {@link CustomerDao} that persists customers in RDBMS.
+ *
+ */
+public class DbCustomerDao implements CustomerDao {
+
+ private final DataSource dataSource;
+
+ /**
+ * Creates an instance of {@link DbCustomerDao} which uses provided dataSource
+ * to store and retrieve customer information.
+ *
+ * @param dataSource a non-null dataSource.
+ */
+ public DbCustomerDao(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ /**
+ * @return a lazily populated stream of customers. Note the stream returned must be closed to
+ * free all the acquired resources. The stream keeps an open connection to the database till
+ * it is complete or is closed manually.
+ */
+ @Override
+ public Stream getAll() throws Exception {
+
+ Connection connection;
+ try {
+ connection = getConnection();
+ PreparedStatement statement = connection.prepareStatement("SELECT * FROM CUSTOMERS");
+ ResultSet resultSet = statement.executeQuery();
+ return StreamSupport.stream(new Spliterators.AbstractSpliterator(Long.MAX_VALUE,
+ Spliterator.ORDERED) {
+
+ @Override
+ public boolean tryAdvance(Consumer super Customer> action) {
+ try {
+ if (!resultSet.next()) {
+ return false;
+ }
+ action.accept(createCustomer(resultSet));
+ return true;
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }, false).onClose(() -> mutedClose(connection));
+ } catch (SQLException e) {
+ throw new Exception(e.getMessage(), e);
+ }
+ }
+
+ private Connection getConnection() throws SQLException {
+ return dataSource.getConnection();
+ }
+
+ private void mutedClose(Connection connection) {
+ try {
+ connection.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private Customer createCustomer(ResultSet resultSet) throws SQLException {
+ return new Customer(resultSet.getInt("ID"),
+ resultSet.getString("FNAME"),
+ resultSet.getString("LNAME"));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Optional getById(int id) throws Exception {
+ try (Connection connection = getConnection();
+ PreparedStatement statement =
+ connection.prepareStatement("SELECT * FROM CUSTOMERS WHERE ID = ?")) {
+
+ statement.setInt(1, id);
+ ResultSet resultSet = statement.executeQuery();
+ if (resultSet.next()) {
+ return Optional.of(createCustomer(resultSet));
+ } else {
+ return Optional.empty();
+ }
+ } catch (SQLException ex) {
+ throw new Exception(ex.getMessage(), ex);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean add(Customer customer) throws Exception {
+ if (getById(customer.getId()).isPresent()) {
+ return false;
+ }
+
+ try (Connection connection = getConnection();
+ PreparedStatement statement =
+ connection.prepareStatement("INSERT INTO CUSTOMERS VALUES (?,?,?)")) {
+ statement.setInt(1, customer.getId());
+ statement.setString(2, customer.getFirstName());
+ statement.setString(3, customer.getLastName());
+ statement.execute();
+ return true;
+ } catch (SQLException ex) {
+ throw new Exception(ex.getMessage(), ex);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean update(Customer customer) throws Exception {
+ try (Connection connection = getConnection();
+ PreparedStatement statement =
+ connection.prepareStatement("UPDATE CUSTOMERS SET FNAME = ?, LNAME = ? WHERE ID = ?")) {
+ statement.setString(1, customer.getFirstName());
+ statement.setString(2, customer.getLastName());
+ statement.setInt(3, customer.getId());
+ return statement.executeUpdate() > 0;
+ } catch (SQLException ex) {
+ throw new Exception(ex.getMessage(), ex);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean delete(Customer customer) throws Exception {
+ try (Connection connection = getConnection();
+ PreparedStatement statement =
+ connection.prepareStatement("DELETE FROM CUSTOMERS WHERE ID = ?")) {
+ statement.setInt(1, customer.getId());
+ return statement.executeUpdate() > 0;
+ } catch (SQLException ex) {
+ throw new Exception(ex.getMessage(), ex);
+ }
+ }
+}
diff --git a/dao/src/main/java/com/iluwatar/dao/InMemoryCustomerDao.java b/dao/src/main/java/com/iluwatar/dao/InMemoryCustomerDao.java
new file mode 100644
index 000000000..15c63d1de
--- /dev/null
+++ b/dao/src/main/java/com/iluwatar/dao/InMemoryCustomerDao.java
@@ -0,0 +1,73 @@
+/**
+ * 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.dao;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+/**
+ * An in memory implementation of {@link CustomerDao}, which stores the customers in JVM memory
+ * and data is lost when the application exits.
+ *
+ * This implementation is useful as temporary database or for testing.
+ */
+public class InMemoryCustomerDao implements CustomerDao {
+
+ private Map idToCustomer = new HashMap<>();
+
+ /**
+ * An eagerly evaluated stream of customers stored in memory.
+ */
+ @Override
+ public Stream getAll() {
+ return idToCustomer.values().stream();
+ }
+
+ @Override
+ public Optional getById(final int id) {
+ return Optional.ofNullable(idToCustomer.get(id));
+ }
+
+ @Override
+ public boolean add(final Customer customer) {
+ if (getById(customer.getId()).isPresent()) {
+ return false;
+ }
+
+ idToCustomer.put(customer.getId(), customer);
+ return true;
+ }
+
+ @Override
+ public boolean update(final Customer customer) {
+ return idToCustomer.replace(customer.getId(), customer) != null;
+ }
+
+ @Override
+ public boolean delete(final Customer customer) {
+ return idToCustomer.remove(customer.getId()) != null;
+ }
+}
diff --git a/dao/src/main/resources/log4j.xml b/dao/src/main/resources/log4j.xml
new file mode 100644
index 000000000..b591c17e1
--- /dev/null
+++ b/dao/src/main/resources/log4j.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dao/src/test/java/com/iluwatar/dao/AppTest.java b/dao/src/test/java/com/iluwatar/dao/AppTest.java
index d45e0ef18..169fc046e 100644
--- a/dao/src/test/java/com/iluwatar/dao/AppTest.java
+++ b/dao/src/test/java/com/iluwatar/dao/AppTest.java
@@ -1,14 +1,37 @@
-package com.iluwatar.dao;
-
-import org.junit.Test;
-
-import com.iluwatar.dao.App;
-
-public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
-}
+/**
+ * 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.dao;
+
+import org.junit.Test;
+
+/**
+ * Tests that DAO example runs without errors.
+ */
+public class AppTest {
+ @Test
+ public void test() throws Exception {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/dao/src/test/java/com/iluwatar/dao/CustomerTest.java b/dao/src/test/java/com/iluwatar/dao/CustomerTest.java
new file mode 100644
index 000000000..6a02fd6be
--- /dev/null
+++ b/dao/src/test/java/com/iluwatar/dao/CustomerTest.java
@@ -0,0 +1,97 @@
+/**
+ * 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.dao;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class CustomerTest {
+
+ private Customer customer;
+ private static final int ID = 1;
+ private static final String FIRSTNAME = "Winston";
+ private static final String LASTNAME = "Churchill";
+
+ @Before
+ public void setUp() {
+ customer = new Customer(ID, FIRSTNAME, LASTNAME);
+ }
+
+ @Test
+ public void getAndSetId() {
+ final int newId = 2;
+ customer.setId(newId);
+ assertEquals(newId, customer.getId());
+ }
+
+ @Test
+ public void getAndSetFirstname() {
+ final String newFirstname = "Bill";
+ customer.setFirstName(newFirstname);
+ assertEquals(newFirstname, customer.getFirstName());
+ }
+
+ @Test
+ public void getAndSetLastname() {
+ final String newLastname = "Clinton";
+ customer.setLastName(newLastname);
+ assertEquals(newLastname, customer.getLastName());
+ }
+
+ @Test
+ public void notEqualWithDifferentId() {
+ final int newId = 2;
+ final Customer otherCustomer = new Customer(newId, FIRSTNAME, LASTNAME);
+ assertNotEquals(customer, otherCustomer);
+ assertNotEquals(customer.hashCode(), otherCustomer.hashCode());
+ }
+
+ @Test
+ public void equalsWithSameObjectValues() {
+ final Customer otherCustomer = new Customer(ID, FIRSTNAME, LASTNAME);
+ assertEquals(customer, otherCustomer);
+ assertEquals(customer.hashCode(), otherCustomer.hashCode());
+ }
+
+ @Test
+ public void equalsWithSameObjects() {
+ assertEquals(customer, customer);
+ assertEquals(customer.hashCode(), customer.hashCode());
+ }
+
+ @Test
+ public void testToString() {
+ final StringBuffer buffer = new StringBuffer();
+ buffer.append("Customer{id=")
+ .append("" + customer.getId())
+ .append(", firstName='")
+ .append(customer.getFirstName())
+ .append("\', lastName='")
+ .append(customer.getLastName() + "\'}");
+ assertEquals(buffer.toString(), customer.toString());
+ }
+}
diff --git a/dao/src/test/java/com/iluwatar/dao/DbCustomerDaoTest.java b/dao/src/test/java/com/iluwatar/dao/DbCustomerDaoTest.java
new file mode 100644
index 000000000..ac69699df
--- /dev/null
+++ b/dao/src/test/java/com/iluwatar/dao/DbCustomerDaoTest.java
@@ -0,0 +1,269 @@
+/**
+ * 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.dao;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.stream.Stream;
+
+import javax.sql.DataSource;
+
+import org.h2.jdbcx.JdbcDataSource;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+import de.bechte.junit.runners.context.HierarchicalContextRunner;
+
+/**
+ * Tests {@link DbCustomerDao}.
+ */
+@RunWith(HierarchicalContextRunner.class)
+public class DbCustomerDaoTest {
+
+ private static final String DB_URL = "jdbc:h2:~/dao";
+ private DbCustomerDao dao;
+ private Customer existingCustomer = new Customer(1, "Freddy", "Krueger");
+
+ /**
+ * Creates customers schema.
+ * @throws SQLException if there is any error while creating schema.
+ */
+ @Before
+ public void createSchema() throws SQLException {
+ try (Connection connection = DriverManager.getConnection(DB_URL);
+ Statement statement = connection.createStatement()) {
+ statement.execute(CustomerSchemaSql.CREATE_SCHEMA_SQL);
+ }
+ }
+
+ /**
+ * Represents the scenario where DB connectivity is present.
+ */
+ public class ConnectionSuccess {
+
+ /**
+ * Setup for connection success scenario.
+ * @throws Exception if any error occurs.
+ */
+ @Before
+ public void setUp() throws Exception {
+ JdbcDataSource dataSource = new JdbcDataSource();
+ dataSource.setURL(DB_URL);
+ dao = new DbCustomerDao(dataSource);
+ boolean result = dao.add(existingCustomer);
+ assertTrue(result);
+ }
+
+ /**
+ * Represents the scenario when DAO operations are being performed on a non existing customer.
+ */
+ public class NonExistingCustomer {
+
+ @Test
+ public void addingShouldResultInSuccess() throws Exception {
+ try (Stream allCustomers = dao.getAll()) {
+ assumeTrue(allCustomers.count() == 1);
+ }
+
+ final Customer nonExistingCustomer = new Customer(2, "Robert", "Englund");
+ boolean result = dao.add(nonExistingCustomer);
+ assertTrue(result);
+
+ assertCustomerCountIs(2);
+ assertEquals(nonExistingCustomer, dao.getById(nonExistingCustomer.getId()).get());
+ }
+
+ @Test
+ public void deletionShouldBeFailureAndNotAffectExistingCustomers() throws Exception {
+ final Customer nonExistingCustomer = new Customer(2, "Robert", "Englund");
+ boolean result = dao.delete(nonExistingCustomer);
+
+ assertFalse(result);
+ assertCustomerCountIs(1);
+ }
+
+ @Test
+ public void updationShouldBeFailureAndNotAffectExistingCustomers() throws Exception {
+ final int nonExistingId = getNonExistingCustomerId();
+ final String newFirstname = "Douglas";
+ final String newLastname = "MacArthur";
+ final Customer customer = new Customer(nonExistingId, newFirstname, newLastname);
+ boolean result = dao.update(customer);
+
+ assertFalse(result);
+ assertFalse(dao.getById(nonExistingId).isPresent());
+ }
+
+ @Test
+ public void retrieveShouldReturnNoCustomer() throws Exception {
+ assertFalse(dao.getById(getNonExistingCustomerId()).isPresent());
+ }
+ }
+
+ /**
+ * Represents a scenario where DAO operations are being performed on an already existing
+ * customer.
+ *
+ */
+ public class ExistingCustomer {
+
+ @Test
+ public void addingShouldResultInFailureAndNotAffectExistingCustomers() throws Exception {
+ Customer existingCustomer = new Customer(1, "Freddy", "Krueger");
+
+ boolean result = dao.add(existingCustomer);
+
+ assertFalse(result);
+ assertCustomerCountIs(1);
+ assertEquals(existingCustomer, dao.getById(existingCustomer.getId()).get());
+ }
+
+ @Test
+ public void deletionShouldBeSuccessAndCustomerShouldBeNonAccessible() throws Exception {
+ boolean result = dao.delete(existingCustomer);
+
+ assertTrue(result);
+ assertCustomerCountIs(0);
+ assertFalse(dao.getById(existingCustomer.getId()).isPresent());
+ }
+
+ @Test
+ public void updationShouldBeSuccessAndAccessingTheSameCustomerShouldReturnUpdatedInformation() throws Exception {
+ final String newFirstname = "Bernard";
+ final String newLastname = "Montgomery";
+ final Customer customer = new Customer(existingCustomer.getId(), newFirstname, newLastname);
+ boolean result = dao.update(customer);
+
+ assertTrue(result);
+
+ final Customer cust = dao.getById(existingCustomer.getId()).get();
+ assertEquals(newFirstname, cust.getFirstName());
+ assertEquals(newLastname, cust.getLastName());
+ }
+ }
+ }
+
+ /**
+ * Represents a scenario where DB connectivity is not present due to network issue, or
+ * DB service unavailable.
+ *
+ */
+ public class ConnectivityIssue {
+
+ private static final String EXCEPTION_CAUSE = "Connection not available";
+ @Rule public ExpectedException exception = ExpectedException.none();
+
+ /**
+ * setup a connection failure scenario.
+ * @throws SQLException if any error occurs.
+ */
+ @Before
+ public void setUp() throws SQLException {
+ dao = new DbCustomerDao(mockedDatasource());
+ exception.expect(Exception.class);
+ exception.expectMessage(EXCEPTION_CAUSE);
+ }
+
+ private DataSource mockedDatasource() throws SQLException {
+ DataSource mockedDataSource = mock(DataSource.class);
+ Connection mockedConnection = mock(Connection.class);
+ SQLException exception = new SQLException(EXCEPTION_CAUSE);
+ doThrow(exception).when(mockedConnection).prepareStatement(Mockito.anyString());
+ doReturn(mockedConnection).when(mockedDataSource).getConnection();
+ return mockedDataSource;
+ }
+
+ @Test
+ public void addingACustomerFailsWithExceptionAsFeedbackToClient() throws Exception {
+ dao.add(new Customer(2, "Bernard", "Montgomery"));
+ }
+
+ @Test
+ public void deletingACustomerFailsWithExceptionAsFeedbackToTheClient() throws Exception {
+ dao.delete(existingCustomer);
+ }
+
+ @Test
+ public void updatingACustomerFailsWithFeedbackToTheClient() throws Exception {
+ final String newFirstname = "Bernard";
+ final String newLastname = "Montgomery";
+
+ dao.update(new Customer(existingCustomer.getId(), newFirstname, newLastname));
+ }
+
+ @Test
+ public void retrievingACustomerByIdFailsWithExceptionAsFeedbackToClient() throws Exception {
+ dao.getById(existingCustomer.getId());
+ }
+
+ @Test
+ public void retrievingAllCustomersFailsWithExceptionAsFeedbackToClient() throws Exception {
+ dao.getAll();
+ }
+
+ }
+
+ /**
+ * Delete customer schema for fresh setup per test.
+ * @throws SQLException if any error occurs.
+ */
+ @After
+ public void deleteSchema() throws SQLException {
+ try (Connection connection = DriverManager.getConnection(DB_URL);
+ Statement statement = connection.createStatement()) {
+ statement.execute(CustomerSchemaSql.DELETE_SCHEMA_SQL);
+ }
+ }
+
+ private void assertCustomerCountIs(int count) throws Exception {
+ try (Stream allCustomers = dao.getAll()) {
+ assertTrue(allCustomers.count() == count);
+ }
+ }
+
+
+ /**
+ * An arbitrary number which does not correspond to an active Customer id.
+ *
+ * @return an int of a customer id which doesn't exist
+ */
+ private int getNonExistingCustomerId() {
+ return 999;
+ }
+}
diff --git a/dao/src/test/java/com/iluwatar/dao/InMemoryCustomerDaoTest.java b/dao/src/test/java/com/iluwatar/dao/InMemoryCustomerDaoTest.java
new file mode 100644
index 000000000..65a087b9b
--- /dev/null
+++ b/dao/src/test/java/com/iluwatar/dao/InMemoryCustomerDaoTest.java
@@ -0,0 +1,164 @@
+/**
+ * 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.dao;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
+
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import de.bechte.junit.runners.context.HierarchicalContextRunner;
+
+/**
+ * Tests {@link InMemoryCustomerDao}.
+ */
+@RunWith(HierarchicalContextRunner.class)
+public class InMemoryCustomerDaoTest {
+
+ private InMemoryCustomerDao dao;
+ private static final Customer CUSTOMER = new Customer(1, "Freddy", "Krueger");
+
+ @Before
+ public void setUp() {
+ dao = new InMemoryCustomerDao();
+ assertTrue(dao.add(CUSTOMER));
+ }
+
+ /**
+ * Represents the scenario when the DAO operations are being performed on a non existent
+ * customer.
+ */
+ public class NonExistingCustomer {
+
+ @Test
+ public void addingShouldResultInSuccess() throws Exception {
+ try (Stream allCustomers = dao.getAll()) {
+ assumeTrue(allCustomers.count() == 1);
+ }
+
+ final Customer nonExistingCustomer = new Customer(2, "Robert", "Englund");
+ boolean result = dao.add(nonExistingCustomer);
+ assertTrue(result);
+
+ assertCustomerCountIs(2);
+ assertEquals(nonExistingCustomer, dao.getById(nonExistingCustomer.getId()).get());
+ }
+
+ @Test
+ public void deletionShouldBeFailureAndNotAffectExistingCustomers() throws Exception {
+ final Customer nonExistingCustomer = new Customer(2, "Robert", "Englund");
+ boolean result = dao.delete(nonExistingCustomer);
+
+ assertFalse(result);
+ assertCustomerCountIs(1);
+ }
+
+ @Test
+ public void updationShouldBeFailureAndNotAffectExistingCustomers() throws Exception {
+ final int nonExistingId = getNonExistingCustomerId();
+ final String newFirstname = "Douglas";
+ final String newLastname = "MacArthur";
+ final Customer customer = new Customer(nonExistingId, newFirstname, newLastname);
+ boolean result = dao.update(customer);
+
+ assertFalse(result);
+ assertFalse(dao.getById(nonExistingId).isPresent());
+ }
+
+ @Test
+ public void retrieveShouldReturnNoCustomer() throws Exception {
+ assertFalse(dao.getById(getNonExistingCustomerId()).isPresent());
+ }
+ }
+
+ /**
+ * Represents the scenario when the DAO operations are being performed on an already existing
+ * customer.
+ */
+ public class ExistingCustomer {
+
+ @Test
+ public void addingShouldResultInFailureAndNotAffectExistingCustomers() throws Exception {
+ boolean result = dao.add(CUSTOMER);
+
+ assertFalse(result);
+ assertCustomerCountIs(1);
+ assertEquals(CUSTOMER, dao.getById(CUSTOMER.getId()).get());
+ }
+
+ @Test
+ public void deletionShouldBeSuccessAndCustomerShouldBeNonAccessible() throws Exception {
+ boolean result = dao.delete(CUSTOMER);
+
+ assertTrue(result);
+ assertCustomerCountIs(0);
+ assertFalse(dao.getById(CUSTOMER.getId()).isPresent());
+ }
+
+ @Test
+ public void updationShouldBeSuccessAndAccessingTheSameCustomerShouldReturnUpdatedInformation() throws Exception {
+ final String newFirstname = "Bernard";
+ final String newLastname = "Montgomery";
+ final Customer customer = new Customer(CUSTOMER.getId(), newFirstname, newLastname);
+ boolean result = dao.update(customer);
+
+ assertTrue(result);
+
+ final Customer cust = dao.getById(CUSTOMER.getId()).get();
+ assertEquals(newFirstname, cust.getFirstName());
+ assertEquals(newLastname, cust.getLastName());
+ }
+
+ @Test
+ public void retriveShouldReturnTheCustomer() {
+ Optional optionalCustomer = dao.getById(CUSTOMER.getId());
+
+ assertTrue(optionalCustomer.isPresent());
+ assertEquals(CUSTOMER, optionalCustomer.get());
+ }
+ }
+
+ /**
+ * An arbitrary number which does not correspond to an active Customer id.
+ *
+ * @return an int of a customer id which doesn't exist
+ */
+ private int getNonExistingCustomerId() {
+ return 999;
+ }
+
+ private void assertCustomerCountIs(int count) throws Exception {
+ try (Stream allCustomers = dao.getAll()) {
+ assertTrue(allCustomers.count() == count);
+ }
+ }
+}
diff --git a/data-mapper/etc/data-mapper.png b/data-mapper/etc/data-mapper.png
new file mode 100644
index 000000000..bcda8054a
Binary files /dev/null and b/data-mapper/etc/data-mapper.png differ
diff --git a/data-mapper/etc/data-mapper.ucls b/data-mapper/etc/data-mapper.ucls
new file mode 100644
index 000000000..2467983ce
--- /dev/null
+++ b/data-mapper/etc/data-mapper.ucls
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/data-mapper/index.md b/data-mapper/index.md
new file mode 100644
index 000000000..075e8eece
--- /dev/null
+++ b/data-mapper/index.md
@@ -0,0 +1,25 @@
+---
+layout: pattern
+title: Data Mapper
+folder: data-mapper
+permalink: /patterns/data-mapper/
+categories: Persistence Tier
+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
+
+
+
+## Applicability
+Use the Data Mapper in any of the following situations
+
+* when you want to decouple data objects from DB access layer
+* when you want to write multiple data retrieval/persistence implementations
+
+## Credits
+
+* [Data Mapper](http://richard.jp.leguen.ca/tutoring/soen343-f2010/tutorials/implementing-data-mapper/)
diff --git a/data-mapper/pom.xml b/data-mapper/pom.xml
new file mode 100644
index 000000000..7d1b83469
--- /dev/null
+++ b/data-mapper/pom.xml
@@ -0,0 +1,45 @@
+
+
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.13.0-SNAPSHOT
+
+ data-mapper
+
+
+ junit
+ junit
+ test
+
+
+ log4j
+ log4j
+
+
+
diff --git a/data-mapper/src/main/java/com/iluwatar/datamapper/App.java b/data-mapper/src/main/java/com/iluwatar/datamapper/App.java
new file mode 100644
index 000000000..5fcd0d9ea
--- /dev/null
+++ b/data-mapper/src/main/java/com/iluwatar/datamapper/App.java
@@ -0,0 +1,77 @@
+/**
+ * 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.datamapper;
+
+import java.util.Optional;
+
+import org.apache.log4j.Logger;
+
+/**
+ * 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 below example demonstrates basic CRUD operations: Create, Read, Update, and Delete.
+ *
+ */
+public final class App {
+
+ private static Logger log = Logger.getLogger(App.class);
+
+ /**
+ * Program entry point.
+ *
+ * @param args command line args.
+ */
+ public static void main(final String... args) {
+
+ /* Create new data mapper for type 'first' */
+ final StudentDataMapper mapper = new StudentDataMapperImpl();
+
+ /* Create new student */
+ Student student = new Student(1, "Adam", 'A');
+
+ /* Add student in respectibe store */
+ mapper.insert(student);
+
+ log.debug("App.main(), student : " + student + ", is inserted");
+
+ /* Find this student */
+ final Optional studentToBeFound = mapper.find(student.getStudentId());
+
+ log.debug("App.main(), student : " + studentToBeFound + ", is searched");
+
+ /* Update existing student object */
+ student = new Student(student.getStudentId(), "AdamUpdated", 'A');
+
+ /* Update student in respectibe db */
+ mapper.update(student);
+
+ log.debug("App.main(), student : " + student + ", is updated");
+ log.debug("App.main(), student : " + student + ", is going to be deleted");
+
+ /* Delete student in db */
+ mapper.delete(student);
+ }
+
+ private App() {}
+}
diff --git a/data-mapper/src/main/java/com/iluwatar/datamapper/DataMapperException.java b/data-mapper/src/main/java/com/iluwatar/datamapper/DataMapperException.java
new file mode 100644
index 000000000..a6995b06d
--- /dev/null
+++ b/data-mapper/src/main/java/com/iluwatar/datamapper/DataMapperException.java
@@ -0,0 +1,42 @@
+/**
+ * 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.datamapper;
+
+/**
+ * Using Runtime Exception for avoiding dependancy on implementation exceptions. This helps in
+ * decoupling.
+ *
+ * @author amit.dixit
+ *
+ */
+public final class DataMapperException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs a new runtime exception with the specified detail message. The cause is not
+ * initialized, and may subsequently be initialized by a call to {@link #initCause}.
+ *
+ * @param message the detail message. The detail message is saved for later retrieval by the
+ * {@link #getMessage()} method.
+ */
+ public DataMapperException(final String message) {
+ super(message);
+ }
+}
diff --git a/data-mapper/src/main/java/com/iluwatar/datamapper/Student.java b/data-mapper/src/main/java/com/iluwatar/datamapper/Student.java
new file mode 100644
index 000000000..0164533c8
--- /dev/null
+++ b/data-mapper/src/main/java/com/iluwatar/datamapper/Student.java
@@ -0,0 +1,139 @@
+/**
+ * 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.datamapper;
+
+
+import java.io.Serializable;
+
+public final class Student implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private int studentId;
+ private String name;
+ private char grade;
+
+
+ /**
+ * Use this constructor to create a Student with all details
+ *
+ * @param studentId as unique student id
+ * @param name as student name
+ * @param grade as respective grade of student
+ */
+ public Student(final int studentId, final String name, final char grade) {
+ super();
+
+ this.studentId = studentId;
+ this.name = name;
+ this.grade = grade;
+ }
+
+ /**
+ *
+ * @return the student id
+ */
+ public int getStudentId() {
+ return studentId;
+ }
+
+ /**
+ *
+ * @param studentId as unique student id
+ */
+ public void setStudentId(final int studentId) {
+ this.studentId = studentId;
+ }
+
+ /**
+ *
+ * @return name of student
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ *
+ * @param name as 'name' of student
+ */
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ /**
+ *
+ * @return grade of student
+ */
+ public char getGrade() {
+ return grade;
+ }
+
+ /**
+ *
+ * @param grade as 'grade of student'
+ */
+ public void setGrade(final char grade) {
+ this.grade = grade;
+ }
+
+ /**
+ *
+ */
+ @Override
+ public boolean equals(final Object inputObject) {
+
+ boolean isEqual = false;
+
+ /* Check if both objects are same */
+ if (this == inputObject) {
+
+ isEqual = true;
+ } else if (inputObject != null && getClass() == inputObject.getClass()) {
+
+ final Student inputStudent = (Student) inputObject;
+
+ /* If student id matched */
+ if (this.getStudentId() == inputStudent.getStudentId()) {
+
+ isEqual = true;
+ }
+ }
+
+ return isEqual;
+ }
+
+ /**
+ *
+ */
+ @Override
+ public int hashCode() {
+
+ /* Student id is assumed to be unique */
+ return this.getStudentId();
+ }
+
+ /**
+ *
+ */
+ @Override
+ public String toString() {
+ return "Student [studentId=" + studentId + ", name=" + name + ", grade=" + grade + "]";
+ }
+}
diff --git a/data-mapper/src/main/java/com/iluwatar/datamapper/StudentDataMapper.java b/data-mapper/src/main/java/com/iluwatar/datamapper/StudentDataMapper.java
new file mode 100644
index 000000000..40f0c5c72
--- /dev/null
+++ b/data-mapper/src/main/java/com/iluwatar/datamapper/StudentDataMapper.java
@@ -0,0 +1,32 @@
+/**
+ * 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.datamapper;
+
+import java.util.Optional;
+
+public interface StudentDataMapper {
+
+ Optional find(int studentId);
+
+ void insert(Student student) throws DataMapperException;
+
+ void update(Student student) throws DataMapperException;
+
+ void delete(Student student) throws DataMapperException;
+}
diff --git a/data-mapper/src/main/java/com/iluwatar/datamapper/StudentDataMapperImpl.java b/data-mapper/src/main/java/com/iluwatar/datamapper/StudentDataMapperImpl.java
new file mode 100644
index 000000000..7ecd9e7f8
--- /dev/null
+++ b/data-mapper/src/main/java/com/iluwatar/datamapper/StudentDataMapperImpl.java
@@ -0,0 +1,102 @@
+/**
+ * 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.datamapper;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+public final class StudentDataMapperImpl implements StudentDataMapper {
+
+ /* Note: Normally this would be in the form of an actual database */
+ private List students = new ArrayList<>();
+
+ @Override
+ public Optional find(int studentId) {
+
+ /* Compare with existing students */
+ for (final Student student : this.getStudents()) {
+
+ /* Check if student is found */
+ if (student.getStudentId() == studentId) {
+
+ return Optional.of(student);
+ }
+ }
+
+ /* Return empty value */
+ return Optional.empty();
+ }
+
+ @Override
+ public void update(Student studentToBeUpdated) throws DataMapperException {
+
+
+ /* Check with existing students */
+ if (this.getStudents().contains(studentToBeUpdated)) {
+
+ /* Get the index of student in list */
+ final int index = this.getStudents().indexOf(studentToBeUpdated);
+
+ /* Update the student in list */
+ this.getStudents().set(index, studentToBeUpdated);
+
+ } else {
+
+ /* Throw user error after wrapping in a runtime exception */
+ throw new DataMapperException("Student [" + studentToBeUpdated.getName() + "] is not found");
+ }
+ }
+
+ @Override
+ public void insert(Student studentToBeInserted) throws DataMapperException {
+
+ /* Check with existing students */
+ if (!this.getStudents().contains(studentToBeInserted)) {
+
+ /* Add student in list */
+ this.getStudents().add(studentToBeInserted);
+
+ } else {
+
+ /* Throw user error after wrapping in a runtime exception */
+ throw new DataMapperException("Student already [" + studentToBeInserted.getName() + "] exists");
+ }
+ }
+
+ @Override
+ public void delete(Student studentToBeDeleted) throws DataMapperException {
+
+ /* Check with existing students */
+ if (this.getStudents().contains(studentToBeDeleted)) {
+
+ /* Delete the student from list */
+ this.getStudents().remove(studentToBeDeleted);
+
+ } else {
+
+ /* Throw user error after wrapping in a runtime exception */
+ throw new DataMapperException("Student [" + studentToBeDeleted.getName() + "] is not found");
+ }
+ }
+
+ public List getStudents() {
+ return this.students;
+ }
+}
diff --git a/data-mapper/src/main/resources/log4j.xml b/data-mapper/src/main/resources/log4j.xml
new file mode 100644
index 000000000..b591c17e1
--- /dev/null
+++ b/data-mapper/src/main/resources/log4j.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/data-mapper/src/test/java/com/iluwatar/datamapper/AppTest.java b/data-mapper/src/test/java/com/iluwatar/datamapper/AppTest.java
new file mode 100644
index 000000000..f2858100e
--- /dev/null
+++ b/data-mapper/src/test/java/com/iluwatar/datamapper/AppTest.java
@@ -0,0 +1,34 @@
+/**
+ * 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.datamapper;
+
+import com.iluwatar.datamapper.App;
+import org.junit.Test;
+
+/**
+ * Tests that Data-Mapper example runs without errors.
+ */
+public final class AppTest {
+
+ @Test
+ public void test() {
+ final String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/data-mapper/src/test/java/com/iluwatar/datamapper/DataMapperTest.java b/data-mapper/src/test/java/com/iluwatar/datamapper/DataMapperTest.java
new file mode 100644
index 000000000..17f4d3922
--- /dev/null
+++ b/data-mapper/src/test/java/com/iluwatar/datamapper/DataMapperTest.java
@@ -0,0 +1,73 @@
+/**
+ * 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.datamapper;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import com.iluwatar.datamapper.Student;
+import com.iluwatar.datamapper.StudentDataMapper;
+import com.iluwatar.datamapper.StudentDataMapperImpl;
+
+/**
+ * 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.
+ *
+ */
+public class DataMapperTest {
+
+ /**
+ * This test verify that first data mapper is able to perform all CRUD operations on Student
+ */
+ @Test
+ public void testFirstDataMapper() {
+
+ /* Create new data mapper of first type */
+ final StudentDataMapper mapper = new StudentDataMapperImpl();
+
+ /* Create new student */
+ Student student = new Student(1, "Adam", 'A');
+
+ /* Add student in respectibe db */
+ mapper.insert(student);
+
+ /* Check if student is added in db */
+ assertEquals(student.getStudentId(), mapper.find(student.getStudentId()).get().getStudentId());
+
+ /* Update existing student object */
+ student = new Student(student.getStudentId(), "AdamUpdated", 'A');
+
+ /* Update student in respectibe db */
+ mapper.update(student);
+
+ /* Check if student is updated in db */
+ assertEquals(mapper.find(student.getStudentId()).get().getName(), "AdamUpdated");
+
+ /* Delete student in db */
+ mapper.delete(student);
+
+ /* Result should be false */
+ assertEquals(false, mapper.find(student.getStudentId()).isPresent());
+ }
+}
diff --git a/data-mapper/src/test/java/com/iluwatar/datamapper/StudentTest.java b/data-mapper/src/test/java/com/iluwatar/datamapper/StudentTest.java
new file mode 100644
index 000000000..a3c0e46c1
--- /dev/null
+++ b/data-mapper/src/test/java/com/iluwatar/datamapper/StudentTest.java
@@ -0,0 +1,51 @@
+/**
+ * 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.datamapper;
+
+import org.junit.Test;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+public final class StudentTest {
+
+ @Test
+ /**
+ * This API tests the equality behaviour of Student object
+ * Object Equality should work as per logic defined in equals method
+ *
+ * @throws Exception if any execution error during test
+ */
+ public void testEquality() throws Exception {
+
+ /* Create some students */
+ final Student firstStudent = new Student(1, "Adam", 'A');
+ final Student secondStudent = new Student(2, "Donald", 'B');
+ final Student secondSameStudent = new Student(2, "Donald", 'B');
+ final Student firstSameStudent = firstStudent;
+
+ /* Check equals functionality: should return 'true' */
+ assertTrue(firstStudent.equals(firstSameStudent));
+
+ /* Check equals functionality: should return 'false' */
+ assertFalse(firstStudent.equals(secondStudent));
+
+ /* Check equals functionality: should return 'true' */
+ assertTrue(secondStudent.equals(secondSameStudent));
+ }
+}
diff --git a/decorator/README.md b/decorator/README.md
new file mode 100644
index 000000000..63795114c
--- /dev/null
+++ b/decorator/README.md
@@ -0,0 +1,34 @@
+---
+layout: pattern
+title: Decorator
+folder: decorator
+permalink: /patterns/decorator/
+categories: Structural
+tags:
+ - Java
+ - Gang Of Four
+ - Difficulty-Beginner
+---
+
+## Also known as
+Wrapper
+
+## Intent
+Attach additional responsibilities to an object dynamically.
+Decorators provide a flexible alternative to subclassing for extending
+functionality.
+
+
+
+## Applicability
+Use Decorator
+
+* to add responsibilities to individual objects dynamically and transparently, that is, without affecting other objects
+* for responsibilities that can be withdrawn
+* when extension by subclassing is impractical. Sometimes a large number of independent extensions are possible and would produce an explosion of subclasses to support every combination. Or a class definition may be hidden or otherwise unavailable for subclassing
+
+## Credits
+
+* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
+* [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](http://www.amazon.com/Functional-Programming-Java-Harnessing-Expressions/dp/1937785467/ref=sr_1_1)
+* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
diff --git a/decorator/etc/decorator.png b/decorator/etc/decorator.png
index 1e4bfdac2..47a87b20b 100644
Binary files a/decorator/etc/decorator.png and b/decorator/etc/decorator.png differ
diff --git a/decorator/etc/decorator.ucls b/decorator/etc/decorator.ucls
index 7adb8c3a6..a5353d4ec 100644
--- a/decorator/etc/decorator.ucls
+++ b/decorator/etc/decorator.ucls
@@ -1,18 +1,18 @@
-
+
-
+
-
-
+
+
@@ -21,29 +21,46 @@
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
+
+
+
+
+
+
diff --git a/decorator/etc/decorator_1.png b/decorator/etc/decorator_1.png
deleted file mode 100644
index 5a7afe2d1..000000000
Binary files a/decorator/etc/decorator_1.png and /dev/null differ
diff --git a/decorator/pom.xml b/decorator/pom.xml
index ab15cde08..7ba2a4ee8 100644
--- a/decorator/pom.xml
+++ b/decorator/pom.xml
@@ -1,11 +1,35 @@
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
decorator
@@ -14,5 +38,10 @@
junit
test
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/decorator/src/main/java/com/iluwatar/decorator/App.java b/decorator/src/main/java/com/iluwatar/decorator/App.java
index f424f51b9..bdc574fbc 100644
--- a/decorator/src/main/java/com/iluwatar/decorator/App.java
+++ b/decorator/src/main/java/com/iluwatar/decorator/App.java
@@ -1,29 +1,60 @@
-package com.iluwatar.decorator;
-
-/**
- *
- * Decorator pattern is more flexible alternative to subclassing. The decorator
- * class implements the same interface as the target and uses composition to
- * "decorate" calls to the target.
- *
- * Using decorator pattern it is possible to change class behavior during
- * runtime, as the example shows.
- *
- */
-public class App {
-
- public static void main(String[] args) {
-
- // simple troll
- System.out.println("A simple looking troll approaches.");
- Hostile troll = new Troll();
- troll.attack();
- troll.fleeBattle();
-
- // change the behavior of the simple troll by adding a decorator
- System.out.println("\nA smart looking troll surprises you.");
- Hostile smart = new SmartTroll(troll);
- smart.attack();
- smart.fleeBattle();
- }
-}
+/**
+ * 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.decorator;
+
+/**
+ *
+ * The Decorator pattern is a more flexible alternative to subclassing. The Decorator class
+ * implements the same interface as the target and uses composition to "decorate" calls to the
+ * target. Using the Decorator pattern it is possible to change the behavior of the class during
+ * runtime.
+ *
+ * In this example we show how the simple {@link Troll} first attacks and then flees the battle.
+ * Then we decorate the {@link Troll} with a {@link SmartHostile} and perform the attack again. You
+ * can see how the behavior changes after the decoration.
+ *
+ */
+public class App {
+
+ /**
+ * Program entry point
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+
+ // simple troll
+ System.out.println("A simple looking troll approaches.");
+ Hostile troll = new Troll();
+ troll.attack();
+ troll.fleeBattle();
+ System.out.printf("Simple troll power %d.\n", troll.getAttackPower());
+
+ // change the behavior of the simple troll by adding a decorator
+ System.out.println("\nA smart looking troll surprises you.");
+ Hostile smart = new SmartHostile(troll);
+ smart.attack();
+ smart.fleeBattle();
+ System.out.printf("Smart troll power %d.\n", smart.getAttackPower());
+ }
+}
diff --git a/decorator/src/main/java/com/iluwatar/decorator/Hostile.java b/decorator/src/main/java/com/iluwatar/decorator/Hostile.java
index 4df751cca..d3414c9dd 100644
--- a/decorator/src/main/java/com/iluwatar/decorator/Hostile.java
+++ b/decorator/src/main/java/com/iluwatar/decorator/Hostile.java
@@ -1,3 +1,25 @@
+/**
+ * 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.decorator;
/**
@@ -7,8 +29,10 @@ package com.iluwatar.decorator;
*/
public interface Hostile {
- void attack();
+ void attack();
- void fleeBattle();
+ int getAttackPower();
+
+ void fleeBattle();
}
diff --git a/decorator/src/main/java/com/iluwatar/decorator/SmartHostile.java b/decorator/src/main/java/com/iluwatar/decorator/SmartHostile.java
new file mode 100644
index 000000000..3b4b86276
--- /dev/null
+++ b/decorator/src/main/java/com/iluwatar/decorator/SmartHostile.java
@@ -0,0 +1,56 @@
+/**
+ * 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.decorator;
+
+/**
+ * SmartHostile is a decorator for {@link Hostile} objects. The calls to the {@link Hostile} interface
+ * are intercepted and decorated. Finally the calls are delegated to the decorated {@link Hostile}
+ * object.
+ *
+ */
+public class SmartHostile implements Hostile {
+
+ private Hostile decorated;
+
+ public SmartHostile(Hostile decorated) {
+ this.decorated = decorated;
+ }
+
+ @Override
+ public void attack() {
+ System.out.println("It throws a rock at you!");
+ decorated.attack();
+ }
+
+ @Override
+ public int getAttackPower() {
+ // decorated hostile's power + 20 because it is smart
+ return decorated.getAttackPower() + 20;
+ }
+
+ @Override
+ public void fleeBattle() {
+ System.out.println("It calls for help!");
+ decorated.fleeBattle();
+ }
+}
diff --git a/decorator/src/main/java/com/iluwatar/decorator/SmartTroll.java b/decorator/src/main/java/com/iluwatar/decorator/SmartTroll.java
deleted file mode 100644
index 9baa729f3..000000000
--- a/decorator/src/main/java/com/iluwatar/decorator/SmartTroll.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.iluwatar.decorator;
-
-/**
- * SmartTroll is a decorator for Hostile objects.
- * The calls to the Hostile interface are intercepted
- * and decorated. Finally the calls are delegated
- * to the decorated Hostile object.
- *
- */
-public class SmartTroll implements Hostile {
-
- private Hostile decorated;
-
- public SmartTroll(Hostile decorated) {
- this.decorated = decorated;
- }
-
- @Override
- public void attack() {
- System.out.println("The troll throws a rock at you!");
- decorated.attack();
- }
-
- @Override
- public void fleeBattle() {
- System.out.println("The troll calls for help!");
- decorated.fleeBattle();
- }
-
-}
diff --git a/decorator/src/main/java/com/iluwatar/decorator/Troll.java b/decorator/src/main/java/com/iluwatar/decorator/Troll.java
index 8d6cd0aa5..628adda4b 100644
--- a/decorator/src/main/java/com/iluwatar/decorator/Troll.java
+++ b/decorator/src/main/java/com/iluwatar/decorator/Troll.java
@@ -1,18 +1,46 @@
-package com.iluwatar.decorator;
-
-/**
- *
- * Troll implements Hostile interface directly.
- *
- */
-public class Troll implements Hostile {
-
- public void attack() {
- System.out.println("The troll swings at you with a club!");
- }
-
- public void fleeBattle() {
- System.out.println("The troll shrieks in horror and runs away!");
- }
-
-}
+/**
+ * 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.decorator;
+
+/**
+ *
+ * Troll implements {@link Hostile} interface directly.
+ *
+ */
+public class Troll implements Hostile {
+
+ @Override
+ public void attack() {
+ System.out.println("The troll swings at you with a club!");
+ }
+
+ @Override
+ public int getAttackPower() {
+ return 10;
+ }
+
+ @Override
+ public void fleeBattle() {
+ System.out.println("The troll shrieks in horror and runs away!");
+ }
+}
diff --git a/decorator/src/test/java/com/iluwatar/decorator/AppTest.java b/decorator/src/test/java/com/iluwatar/decorator/AppTest.java
index 28776c930..747144c6d 100644
--- a/decorator/src/test/java/com/iluwatar/decorator/AppTest.java
+++ b/decorator/src/test/java/com/iluwatar/decorator/AppTest.java
@@ -1,14 +1,39 @@
-package com.iluwatar.decorator;
-
-import org.junit.Test;
-
-import com.iluwatar.decorator.App;
-
-public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
-}
+/**
+ * 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.decorator;
+
+import org.junit.Test;
+
+/**
+ *
+ * Application test
+ *
+ */
+public class AppTest {
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/decorator/src/test/java/com/iluwatar/decorator/SmartHostileTest.java b/decorator/src/test/java/com/iluwatar/decorator/SmartHostileTest.java
new file mode 100644
index 000000000..6432d4e90
--- /dev/null
+++ b/decorator/src/test/java/com/iluwatar/decorator/SmartHostileTest.java
@@ -0,0 +1,58 @@
+/**
+ * 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.decorator;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.*;
+import static org.mockito.internal.verification.VerificationModeFactory.times;
+
+/**
+ * Date: 12/7/15 - 7:47 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SmartHostileTest {
+
+ @Test
+ public void testSmartHostile() throws Exception {
+ // Create a normal troll first, but make sure we can spy on it later on.
+ final Hostile simpleTroll = spy(new Troll());
+
+ // Now we want to decorate the troll to make it smarter ...
+ final Hostile smartTroll = new SmartHostile(simpleTroll);
+ assertEquals(30, smartTroll.getAttackPower());
+ verify(simpleTroll, times(1)).getAttackPower();
+
+ // Check if the smart troll actions are delegated to the decorated troll
+ smartTroll.attack();
+ verify(simpleTroll, times(1)).attack();
+
+ smartTroll.fleeBattle();
+ verify(simpleTroll, times(1)).fleeBattle();
+ verifyNoMoreInteractions(simpleTroll);
+
+ }
+
+}
diff --git a/decorator/src/test/java/com/iluwatar/decorator/TrollTest.java b/decorator/src/test/java/com/iluwatar/decorator/TrollTest.java
new file mode 100644
index 000000000..84b0f6d20
--- /dev/null
+++ b/decorator/src/test/java/com/iluwatar/decorator/TrollTest.java
@@ -0,0 +1,84 @@
+/**
+ * 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.decorator;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.PrintStream;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.*;
+import static org.mockito.internal.verification.VerificationModeFactory.times;
+
+/**
+ * Date: 12/7/15 - 7:26 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class TrollTest {
+
+ /**
+ * The mocked standard out stream, required since the actions don't have any influence on other
+ * objects, except for writing to the std-out using {@link System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ @Test
+ public void testTrollActions() throws Exception {
+ final Troll troll = new Troll();
+ assertEquals(10, troll.getAttackPower());
+
+ troll.attack();
+ verify(this.stdOutMock, times(1)).println(eq("The troll swings at you with a club!"));
+
+ troll.fleeBattle();
+ verify(this.stdOutMock, times(1)).println(eq("The troll shrieks in horror and runs away!"));
+
+ verifyNoMoreInteractions(this.stdOutMock);
+ }
+
+}
\ No newline at end of file
diff --git a/delegation/README.md b/delegation/README.md
new file mode 100644
index 000000000..e5c0c6376
--- /dev/null
+++ b/delegation/README.md
@@ -0,0 +1,30 @@
+---
+layout: pattern
+title: Delegation
+folder: delegation
+permalink: /patterns/delegation/
+categories: Behavioral
+tags:
+ - Java
+ - Difficulty-Beginner
+---
+
+## Also known as
+Proxy Pattern
+
+## Intent
+It is a technique where an object expresses certain behavior to the outside but in
+reality delegates responsibility for implementing that behaviour to an associated object.
+
+
+
+## Applicability
+Use the Delegate pattern in order to achieve the following
+
+* Reduce the coupling of methods to their class
+* Components that behave identically, but realize that this situation can change in the future.
+
+## Credits
+
+* [Delegate Pattern: Wikipedia ](https://en.wikipedia.org/wiki/Delegation_pattern)
+* [Proxy Pattern: Wikipedia ](https://en.wikipedia.org/wiki/Proxy_pattern)
diff --git a/delegation/etc/delegation.png b/delegation/etc/delegation.png
new file mode 100644
index 000000000..375ef4d6b
Binary files /dev/null and b/delegation/etc/delegation.png differ
diff --git a/delegation/etc/delegation.ucls b/delegation/etc/delegation.ucls
new file mode 100644
index 000000000..e3ce08873
--- /dev/null
+++ b/delegation/etc/delegation.ucls
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/delegation/pom.xml b/delegation/pom.xml
new file mode 100644
index 000000000..2fca225b8
--- /dev/null
+++ b/delegation/pom.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+ java-design-patterns
+ com.iluwatar
+ 1.13.0-SNAPSHOT
+
+ 4.0.0
+
+ delegation
+
+
+
+ junit
+ junit
+ test
+
+
+ com.github.stefanbirkner
+ system-rules
+ test
+
+
+
\ No newline at end of file
diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/App.java b/delegation/src/main/java/com/iluwatar/delegation/simple/App.java
new file mode 100644
index 000000000..1940e7ae2
--- /dev/null
+++ b/delegation/src/main/java/com/iluwatar/delegation/simple/App.java
@@ -0,0 +1,60 @@
+/**
+ * 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.delegation.simple;
+
+import com.iluwatar.delegation.simple.printers.CanonPrinter;
+import com.iluwatar.delegation.simple.printers.EpsonPrinter;
+import com.iluwatar.delegation.simple.printers.HpPrinter;
+
+/**
+ * The delegate pattern provides a mechanism to abstract away the implementation and control of the desired action.
+ * The class being called in this case {@link PrinterController} is not responsible for the actual desired action,
+ * but is actually delegated to a helper class either {@link CanonPrinter}, {@link EpsonPrinter} or {@link HpPrinter}.
+ * The consumer does not have or require knowledge of the actual class carrying out the action, only the
+ * container on which they are calling.
+ *
+ * In this example the delegates are {@link EpsonPrinter}, {@link HpPrinter} and {@link CanonPrinter} they all implement
+ * {@link Printer}. The {@link PrinterController} class also implements {@link Printer}. However neither provide the
+ * functionality of {@link Printer} by printing to the screen, they actually call upon the instance of {@link Printer}
+ * that they were instantiated with. Therefore delegating the behaviour to another class.
+ */
+public class App {
+
+ public static final String MESSAGE_TO_PRINT = "hello world";
+
+ /**
+ * Program entry point
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ PrinterController hpPrinterController = new PrinterController(new HpPrinter());
+ PrinterController canonPrinterController = new PrinterController(new CanonPrinter());
+ PrinterController epsonPrinterController = new PrinterController(new EpsonPrinter());
+
+ hpPrinterController.print(MESSAGE_TO_PRINT);
+ canonPrinterController.print(MESSAGE_TO_PRINT);
+ epsonPrinterController.print(MESSAGE_TO_PRINT);
+ }
+
+}
diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/Printer.java b/delegation/src/main/java/com/iluwatar/delegation/simple/Printer.java
new file mode 100644
index 000000000..a25f0fba3
--- /dev/null
+++ b/delegation/src/main/java/com/iluwatar/delegation/simple/Printer.java
@@ -0,0 +1,45 @@
+/**
+ * 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.delegation.simple;
+
+import com.iluwatar.delegation.simple.printers.CanonPrinter;
+import com.iluwatar.delegation.simple.printers.EpsonPrinter;
+import com.iluwatar.delegation.simple.printers.HpPrinter;
+
+/**
+ * Interface that both the Controller and the Delegate will implement.
+ *
+ * @see CanonPrinter
+ * @see EpsonPrinter
+ * @see HpPrinter
+ */
+public interface Printer {
+
+ /**
+ * Method that takes a String to print to the screen. This will be implemented on both the
+ * controller and the delegate allowing the controller to call the same method on the delegate class.
+ *
+ * @param message to be printed to the screen
+ */
+ void print(final String message);
+}
diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/PrinterController.java b/delegation/src/main/java/com/iluwatar/delegation/simple/PrinterController.java
new file mode 100644
index 000000000..8a4f20dd2
--- /dev/null
+++ b/delegation/src/main/java/com/iluwatar/delegation/simple/PrinterController.java
@@ -0,0 +1,45 @@
+/**
+ * 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.delegation.simple;
+
+public class PrinterController implements Printer {
+
+ private final Printer printer;
+
+ public PrinterController(Printer printer) {
+ this.printer = printer;
+ }
+
+ /**
+ * This method is implemented from {@link Printer} however instead on providing an
+ * implementation, it instead calls upon the class passed through the constructor. This is the delegate,
+ * hence the pattern. Therefore meaning that the caller does not care of the implementing class only the owning
+ * controller.
+ *
+ * @param message to be printed to the screen
+ */
+ @Override
+ public void print(String message) {
+ printer.print(message);
+ }
+}
diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/printers/CanonPrinter.java b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/CanonPrinter.java
new file mode 100644
index 000000000..5e3966d85
--- /dev/null
+++ b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/CanonPrinter.java
@@ -0,0 +1,43 @@
+/**
+ * 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.delegation.simple.printers;
+
+import com.iluwatar.delegation.simple.Printer;
+
+/**
+ * Specialised Implementation of {@link Printer} for a Canon Printer, in
+ * this case the message to be printed is appended to "Canon Printer : "
+ *
+ * @see Printer
+ */
+public class CanonPrinter implements Printer {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void print(String message) {
+ System.out.print("Canon Printer : " + message);
+ }
+
+}
diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/printers/EpsonPrinter.java b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/EpsonPrinter.java
new file mode 100644
index 000000000..d37fbf613
--- /dev/null
+++ b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/EpsonPrinter.java
@@ -0,0 +1,43 @@
+/**
+ * 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.delegation.simple.printers;
+
+import com.iluwatar.delegation.simple.Printer;
+
+/**
+ * Specialised Implementation of {@link Printer} for a Epson Printer, in
+ * this case the message to be printed is appended to "Epson Printer : "
+ *
+ * @see Printer
+ */
+public class EpsonPrinter implements Printer {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void print(String message) {
+ System.out.print("Epson Printer : " + message);
+ }
+
+}
diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/printers/HpPrinter.java b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/HpPrinter.java
new file mode 100644
index 000000000..f81debf62
--- /dev/null
+++ b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/HpPrinter.java
@@ -0,0 +1,43 @@
+/**
+ * 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.delegation.simple.printers;
+
+import com.iluwatar.delegation.simple.Printer;
+
+/**
+ * Specialised Implementation of {@link Printer} for a HP Printer, in
+ * this case the message to be printed is appended to "HP Printer : "
+ *
+ * @see Printer
+ */
+public class HpPrinter implements Printer {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void print(String message) {
+ System.out.print("HP Printer : " + message);
+ }
+
+}
diff --git a/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.java b/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.java
new file mode 100644
index 000000000..63e469a59
--- /dev/null
+++ b/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.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.delegation.simple;
+
+import org.junit.Test;
+
+public class AppTest {
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
+
+}
diff --git a/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java b/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java
new file mode 100644
index 000000000..6a19c9a1a
--- /dev/null
+++ b/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.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.delegation.simple;
+
+import com.iluwatar.delegation.simple.printers.CanonPrinter;
+import com.iluwatar.delegation.simple.printers.EpsonPrinter;
+import com.iluwatar.delegation.simple.printers.HpPrinter;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.SystemOutRule;
+
+import static org.junit.Assert.assertEquals;
+
+public class DelegateTest {
+
+ private static final String MESSAGE = "Test Message Printed";
+
+ @Rule
+ public final SystemOutRule systemOutRule = new SystemOutRule().enableLog();
+
+ @Test
+ public void testCanonPrinter() throws Exception {
+ PrinterController printerController = new PrinterController(new CanonPrinter());
+ printerController.print(MESSAGE);
+
+ assertEquals("Canon Printer : Test Message Printed", systemOutRule.getLog());
+ }
+
+ @Test
+ public void testHpPrinter() throws Exception {
+ PrinterController printerController = new PrinterController(new HpPrinter());
+ printerController.print(MESSAGE);
+
+ assertEquals("HP Printer : Test Message Printed", systemOutRule.getLog());
+ }
+
+ @Test
+ public void testEpsonPrinter() throws Exception {
+ PrinterController printerController = new PrinterController(new EpsonPrinter());
+ printerController.print(MESSAGE);
+
+ assertEquals("Epson Printer : Test Message Printed", systemOutRule.getLog());
+ }
+
+}
diff --git a/dependency-injection/README.md b/dependency-injection/README.md
new file mode 100644
index 000000000..735f589b1
--- /dev/null
+++ b/dependency-injection/README.md
@@ -0,0 +1,26 @@
+---
+layout: pattern
+title: Dependency Injection
+folder: dependency-injection
+permalink: /patterns/dependency-injection/
+categories: Behavioral
+tags:
+ - Java
+ - Difficulty-Beginner
+---
+
+## Intent
+Dependency Injection is a software design pattern in which one or
+more dependencies (or services) are injected, or passed by reference, into a
+dependent object (or client) and are made part of the client's state. The
+pattern separates the creation of a client's dependencies from its own
+behavior, which allows program designs to be loosely coupled and to follow the
+inversion of control and single responsibility principles.
+
+
+
+## Applicability
+Use the Dependency Injection pattern when
+
+* when you need to remove knowledge of concrete implementation from object
+* to enable unit testing of classes in isolation using mock objects or stubs
diff --git a/dependency-injection/pom.xml b/dependency-injection/pom.xml
index 813030b51..3472da240 100644
--- a/dependency-injection/pom.xml
+++ b/dependency-injection/pom.xml
@@ -1,11 +1,35 @@
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
dependency-injection
@@ -13,6 +37,11 @@
junit
junit
test
+
+
+ org.mockito
+ mockito-core
+ test
com.google.inject
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedWizard.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedWizard.java
new file mode 100644
index 000000000..4eeaccdea
--- /dev/null
+++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/AdvancedWizard.java
@@ -0,0 +1,43 @@
+/**
+ * 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.dependency.injection;
+
+/**
+ *
+ * AdvancedWizard implements inversion of control. It depends on abstraction that can be injected
+ * through its constructor.
+ *
+ */
+public class AdvancedWizard implements Wizard {
+
+ private Tobacco tobacco;
+
+ public AdvancedWizard(Tobacco tobacco) {
+ this.tobacco = tobacco;
+ }
+
+ @Override
+ public void smoke() {
+ tobacco.smoke(this);
+ }
+}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/App.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/App.java
new file mode 100644
index 000000000..faf2a6a43
--- /dev/null
+++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/App.java
@@ -0,0 +1,67 @@
+/**
+ * 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.dependency.injection;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+/**
+ *
+ * Dependency Injection pattern deals with how objects handle their dependencies. The pattern
+ * implements so called inversion of control principle. Inversion of control has two specific rules:
+ * - High-level modules should not depend on low-level modules. Both should depend on abstractions.
+ * - Abstractions should not depend on details. Details should depend on abstractions.
+ *
+ * In this example we show you three different wizards. The first one ({@link SimpleWizard}) is a
+ * naive implementation violating the inversion of control principle. It depends directly on a
+ * concrete implementation which cannot be changed.
+ *
+ * The second wizard ({@link AdvancedWizard}) is more flexible. It does not depend on any concrete
+ * implementation but abstraction. It utilizes Dependency Injection pattern allowing its
+ * {@link Tobacco} dependency to be injected through its constructor. This way, handling the
+ * dependency is no longer the wizard's responsibility. It is resolved outside the wizard class.
+ *
+ * The third example takes the pattern a step further. It uses Guice framework for Dependency
+ * Injection. {@link TobaccoModule} binds a concrete implementation to abstraction. Injector is then
+ * used to create {@link GuiceWizard} object with correct dependencies.
+ *
+ */
+public class App {
+
+ /**
+ * Program entry point
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ SimpleWizard simpleWizard = new SimpleWizard();
+ simpleWizard.smoke();
+
+ AdvancedWizard advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco());
+ advancedWizard.smoke();
+
+ Injector injector = Guice.createInjector(new TobaccoModule());
+ GuiceWizard guiceWizard = injector.getInstance(GuiceWizard.class);
+ guiceWizard.smoke();
+ }
+}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/GuiceWizard.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/GuiceWizard.java
new file mode 100644
index 000000000..6e3baee5a
--- /dev/null
+++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/GuiceWizard.java
@@ -0,0 +1,46 @@
+/**
+ * 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.dependency.injection;
+
+import javax.inject.Inject;
+
+/**
+ *
+ * GuiceWizard implements inversion of control. Its dependencies are injected through its
+ * constructor by Guice framework.
+ *
+ */
+public class GuiceWizard implements Wizard {
+
+ private Tobacco tobacco;
+
+ @Inject
+ public GuiceWizard(Tobacco tobacco) {
+ this.tobacco = tobacco;
+ }
+
+ @Override
+ public void smoke() {
+ tobacco.smoke(this);
+ }
+}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/OldTobyTobacco.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/OldTobyTobacco.java
new file mode 100644
index 000000000..523be1d37
--- /dev/null
+++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/OldTobyTobacco.java
@@ -0,0 +1,31 @@
+/**
+ * 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.dependency.injection;
+
+/**
+ *
+ * OldTobyTobacco concrete {@link Tobacco} implementation
+ *
+ */
+public class OldTobyTobacco extends Tobacco {
+}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/RivendellTobacco.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/RivendellTobacco.java
new file mode 100644
index 000000000..18691a161
--- /dev/null
+++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/RivendellTobacco.java
@@ -0,0 +1,31 @@
+/**
+ * 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.dependency.injection;
+
+/**
+ *
+ * RivendellTobacco concrete {@link Tobacco} implementation
+ *
+ */
+public class RivendellTobacco extends Tobacco {
+}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/SecondBreakfastTobacco.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/SecondBreakfastTobacco.java
new file mode 100644
index 000000000..57565daf0
--- /dev/null
+++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/SecondBreakfastTobacco.java
@@ -0,0 +1,31 @@
+/**
+ * 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.dependency.injection;
+
+/**
+ *
+ * SecondBreakfastTobacco concrete {@link Tobacco} implementation
+ *
+ */
+public class SecondBreakfastTobacco extends Tobacco {
+}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/SimpleWizard.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/SimpleWizard.java
new file mode 100644
index 000000000..6928fe7fe
--- /dev/null
+++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/SimpleWizard.java
@@ -0,0 +1,38 @@
+/**
+ * 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.dependency.injection;
+
+/**
+ *
+ * Naive Wizard implementation violating the inversion of control principle. It should depend on
+ * abstraction instead.
+ *
+ */
+public class SimpleWizard implements Wizard {
+
+ private OldTobyTobacco tobacco = new OldTobyTobacco();
+
+ public void smoke() {
+ tobacco.smoke(this);
+ }
+}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/Tobacco.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/Tobacco.java
new file mode 100644
index 000000000..74a564ab5
--- /dev/null
+++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/Tobacco.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.dependency.injection;
+
+/**
+ *
+ * Tobacco abstraction
+ *
+ */
+public abstract class Tobacco {
+
+ public void smoke(Wizard wizard) {
+ System.out.println(String.format("%s smoking %s", wizard.getClass().getSimpleName(), this
+ .getClass().getSimpleName()));
+ }
+}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/TobaccoModule.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/TobaccoModule.java
new file mode 100644
index 000000000..b8d4df676
--- /dev/null
+++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/TobaccoModule.java
@@ -0,0 +1,38 @@
+/**
+ * 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.dependency.injection;
+
+import com.google.inject.AbstractModule;
+
+/**
+ *
+ * Guice module for binding certain concrete {@link Tobacco} implementation.
+ *
+ */
+public class TobaccoModule extends AbstractModule {
+
+ @Override
+ protected void configure() {
+ bind(Tobacco.class).to(RivendellTobacco.class);
+ }
+}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependency/injection/Wizard.java b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/Wizard.java
new file mode 100644
index 000000000..a5d4d68e0
--- /dev/null
+++ b/dependency-injection/src/main/java/com/iluwatar/dependency/injection/Wizard.java
@@ -0,0 +1,34 @@
+/**
+ * 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.dependency.injection;
+
+/**
+ *
+ * Wizard interface
+ *
+ */
+public interface Wizard {
+
+ void smoke();
+
+}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/AdvancedWizard.java b/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/AdvancedWizard.java
deleted file mode 100644
index 5c4b12eef..000000000
--- a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/AdvancedWizard.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.iluwatar.dependencyinjection;
-
-/**
- *
- * AdvancedWizard implements inversion of control.
- * It depends on abstraction that can be injected through
- * its constructor.
- *
- */
-public class AdvancedWizard implements Wizard {
-
- private Tobacco tobacco;
-
- public AdvancedWizard(Tobacco tobacco) {
- this.tobacco = tobacco;
- }
-
- @Override
- public void smoke() {
- tobacco.smoke(this);
- }
-}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/App.java b/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/App.java
deleted file mode 100644
index 907eaaa9d..000000000
--- a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/App.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package com.iluwatar.dependencyinjection;
-
-import com.google.inject.Guice;
-import com.google.inject.Injector;
-
-/**
- *
- * Dependency Injection pattern deals with how objects handle their dependencies. The pattern
- * implements so called inversion of control principle. Inversion of control has two specific rules:
- * - High-level modules should not depend on low-level modules. Both should depend on abstractions.
- * - Abstractions should not depend on details. Details should depend on abstractions.
- *
- * In this example we show you three different wizards. The first one (SimpleWizard) is a naive
- * implementation violating the inversion of control principle. It depends directly on a concrete
- * implementation which cannot be changed.
- *
- * The second wizard (AdvancedWizard) is more flexible. It does not depend on any concrete implementation
- * but abstraction. It utilizes Dependency Injection pattern allowing its Tobacco dependency to be
- * injected through its constructor. This way, handling the dependency is no longer the wizard's
- * responsibility. It is resolved outside the wizard class.
- *
- * The third example takes the pattern a step further. It uses Guice framework for Dependency Injection.
- * TobaccoModule binds a concrete implementation to abstraction. Injector is then used to create
- * GuiceWizard object with correct dependencies.
- *
- */
-public class App {
-
- public static void main( String[] args ) {
- SimpleWizard simpleWizard = new SimpleWizard();
- simpleWizard.smoke();
-
- AdvancedWizard advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco());
- advancedWizard.smoke();
-
- Injector injector = Guice.createInjector(new TobaccoModule());
- GuiceWizard guiceWizard = injector.getInstance(GuiceWizard.class);
- guiceWizard.smoke();
- }
-}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/GuiceWizard.java b/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/GuiceWizard.java
deleted file mode 100644
index dbbd0a144..000000000
--- a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/GuiceWizard.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.iluwatar.dependencyinjection;
-
-import javax.inject.Inject;
-
-/**
- *
- * GuiceWizard implements inversion of control.
- * Its dependencies are injected through its constructor
- * by Guice framework.
- *
- */
-public class GuiceWizard implements Wizard {
-
- private Tobacco tobacco;
-
- @Inject
- public GuiceWizard(Tobacco tobacco) {
- this.tobacco = tobacco;
- }
-
- @Override
- public void smoke() {
- tobacco.smoke(this);
- }
-}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/OldTobyTobacco.java b/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/OldTobyTobacco.java
deleted file mode 100644
index 6ebe44033..000000000
--- a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/OldTobyTobacco.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.iluwatar.dependencyinjection;
-
-/**
- *
- * OldTobyTobacco concrete Tobacco implementation
- *
- */
-public class OldTobyTobacco extends Tobacco {
-}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/RivendellTobacco.java b/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/RivendellTobacco.java
deleted file mode 100644
index 08bebfac0..000000000
--- a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/RivendellTobacco.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.iluwatar.dependencyinjection;
-
-/**
- *
- * RivendellTobacco concrete Tobacco implementation
- *
- */
-public class RivendellTobacco extends Tobacco {
-}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/SecondBreakfastTobacco.java b/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/SecondBreakfastTobacco.java
deleted file mode 100644
index d0831a34a..000000000
--- a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/SecondBreakfastTobacco.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.iluwatar.dependencyinjection;
-
-/**
- *
- * SecondBreakfastTobacco concrete Tobacco implementation
- *
- */
-public class SecondBreakfastTobacco extends Tobacco {
-}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/SimpleWizard.java b/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/SimpleWizard.java
deleted file mode 100644
index 18031d840..000000000
--- a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/SimpleWizard.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.iluwatar.dependencyinjection;
-
-/**
- *
- * Naive Wizard implementation violating the inversion of control principle.
- * It should depend on abstraction instead.
- *
- */
-public class SimpleWizard implements Wizard {
-
- private OldTobyTobacco tobacco = new OldTobyTobacco();
-
- public void smoke() {
- tobacco.smoke(this);
- }
-}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/Tobacco.java b/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/Tobacco.java
deleted file mode 100644
index a10f648c9..000000000
--- a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/Tobacco.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.iluwatar.dependencyinjection;
-
-/**
- *
- * Tobacco abstraction
- *
- */
-public abstract class Tobacco {
-
- public void smoke(Wizard wizard) {
- System.out.println(String.format("%s smoking %s", wizard.getClass().getSimpleName(), this.getClass().getSimpleName()));
- }
-}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/TobaccoModule.java b/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/TobaccoModule.java
deleted file mode 100644
index 3a687e8fd..000000000
--- a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/TobaccoModule.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.iluwatar.dependencyinjection;
-
-import com.google.inject.AbstractModule;
-
-/**
- *
- * Guice module for binding certain concrete Tobacco implementation.
- *
- */
-public class TobaccoModule extends AbstractModule {
-
- @Override
- protected void configure() {
- bind(Tobacco.class).to(RivendellTobacco.class);
- }
-}
diff --git a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/Wizard.java b/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/Wizard.java
deleted file mode 100644
index e133265ca..000000000
--- a/dependency-injection/src/main/java/com/iluwatar/dependencyinjection/Wizard.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.iluwatar.dependencyinjection;
-
-/**
- *
- * Wizard interface
- *
- */
-public interface Wizard {
-
- void smoke();
-
-}
diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedWizardTest.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedWizardTest.java
new file mode 100644
index 000000000..d1f5e574c
--- /dev/null
+++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AdvancedWizardTest.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.dependency.injection;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/10/15 - 8:40 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class AdvancedWizardTest extends StdOutTest {
+
+ /**
+ * Test if the {@link AdvancedWizard} smokes whatever instance of {@link Tobacco} is passed to him
+ * through the constructor parameter
+ */
+ @Test
+ public void testSmokeEveryThing() throws Exception {
+
+ final Tobacco[] tobaccos = {
+ new OldTobyTobacco(), new RivendellTobacco(), new SecondBreakfastTobacco()
+ };
+
+ for (final Tobacco tobacco : tobaccos) {
+ final AdvancedWizard advancedWizard = new AdvancedWizard(tobacco);
+ advancedWizard.smoke();
+
+ // Verify if the wizard is smoking the correct tobacco ...
+ verify(getStdOutMock(), times(1)).println("AdvancedWizard smoking " + tobacco.getClass().getSimpleName());
+
+ // ... and nothing else is happening.
+ verifyNoMoreInteractions(getStdOutMock());
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AppTest.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AppTest.java
new file mode 100644
index 000000000..2003933ac
--- /dev/null
+++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AppTest.java
@@ -0,0 +1,39 @@
+/**
+ * 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.dependency.injection;
+
+import org.junit.Test;
+
+/**
+ *
+ * Application test
+ *
+ */
+public class AppTest {
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/GuiceWizardTest.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/GuiceWizardTest.java
new file mode 100644
index 000000000..1d3d679df
--- /dev/null
+++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/GuiceWizardTest.java
@@ -0,0 +1,100 @@
+/**
+ * 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.dependency.injection;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/10/15 - 8:57 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class GuiceWizardTest extends StdOutTest {
+
+ /**
+ * Test if the {@link GuiceWizard} smokes whatever instance of {@link Tobacco} is passed to him
+ * through the constructor parameter
+ */
+ @Test
+ public void testSmokeEveryThingThroughConstructor() throws Exception {
+
+ final Tobacco[] tobaccos = {
+ new OldTobyTobacco(), new RivendellTobacco(), new SecondBreakfastTobacco()
+ };
+
+ for (final Tobacco tobacco : tobaccos) {
+ final GuiceWizard guiceWizard = new GuiceWizard(tobacco);
+ guiceWizard.smoke();
+
+ // Verify if the wizard is smoking the correct tobacco ...
+ verify(getStdOutMock(), times(1)).println("GuiceWizard smoking " + tobacco.getClass().getSimpleName());
+
+ // ... and nothing else is happening.
+ verifyNoMoreInteractions(getStdOutMock());
+ }
+
+ }
+
+ /**
+ * Test if the {@link GuiceWizard} smokes whatever instance of {@link Tobacco} is passed to him
+ * through the Guice google inject framework
+ */
+ @Test
+ public void testSmokeEveryThingThroughInjectionFramework() throws Exception {
+
+ @SuppressWarnings("unchecked")
+ final Class extends Tobacco>[] tobaccos = new Class[]{
+ OldTobyTobacco.class, RivendellTobacco.class, SecondBreakfastTobacco.class
+ };
+
+ for (final Class extends Tobacco> tobaccoClass : tobaccos) {
+ // Configure the tobacco in the injection framework ...
+ final Injector injector = Guice.createInjector(new AbstractModule() {
+ @Override
+ protected void configure() {
+ bind(Tobacco.class).to(tobaccoClass);
+ }
+ });
+
+ // ... and create a new wizard with it
+ final GuiceWizard guiceWizard = injector.getInstance(GuiceWizard.class);
+ guiceWizard.smoke();
+
+ // Verify if the wizard is smoking the correct tobacco ...
+ verify(getStdOutMock(), times(1)).println("GuiceWizard smoking " + tobaccoClass.getSimpleName());
+
+ // ... and nothing else is happening.
+ verifyNoMoreInteractions(getStdOutMock());
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/SimpleWizardTest.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/SimpleWizardTest.java
new file mode 100644
index 000000000..e5a856e8d
--- /dev/null
+++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/SimpleWizardTest.java
@@ -0,0 +1,48 @@
+/**
+ * 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.dependency.injection;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.*;
+
+/**
+ * Date: 12/10/15 - 8:26 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SimpleWizardTest extends StdOutTest {
+
+ /**
+ * Test if the {@link SimpleWizard} does the only thing it can do: Smoke it's {@link
+ * OldTobyTobacco}
+ */
+ @Test
+ public void testSmoke() {
+ final SimpleWizard simpleWizard = new SimpleWizard();
+ simpleWizard.smoke();
+ verify(getStdOutMock(), times(1)).println("SimpleWizard smoking OldTobyTobacco");
+ verifyNoMoreInteractions(getStdOutMock());
+ }
+
+}
\ No newline at end of file
diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/StdOutTest.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/StdOutTest.java
new file mode 100644
index 000000000..57272c511
--- /dev/null
+++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/StdOutTest.java
@@ -0,0 +1,75 @@
+/**
+ * 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.dependency.injection;
+
+import org.junit.After;
+import org.junit.Before;
+
+import java.io.PrintStream;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * Date: 12/10/15 - 8:37 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class StdOutTest {
+
+ /**
+ * The mocked standard out {@link PrintStream}, required since the actions of the wizard don't
+ * have any influence on any other accessible objects, except for writing to std-out using {@link
+ * System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * Get the mocked stdOut {@link PrintStream}
+ *
+ * @return The stdOut print stream mock, renewed before each test
+ */
+ final PrintStream getStdOutMock() {
+ return this.stdOutMock;
+ }
+}
diff --git a/dependency-injection/src/test/java/com/iluwatar/dependencyinjection/AppTest.java b/dependency-injection/src/test/java/com/iluwatar/dependencyinjection/AppTest.java
deleted file mode 100644
index a8944c490..000000000
--- a/dependency-injection/src/test/java/com/iluwatar/dependencyinjection/AppTest.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.iluwatar.dependencyinjection;
-
-import org.junit.Test;
-
-import com.iluwatar.dependencyinjection.App;
-
-public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
-}
diff --git a/double-checked-locking/README.md b/double-checked-locking/README.md
new file mode 100644
index 000000000..da1fdd1a2
--- /dev/null
+++ b/double-checked-locking/README.md
@@ -0,0 +1,25 @@
+---
+layout: pattern
+title: Double Checked Locking
+folder: double-checked-locking
+permalink: /patterns/double-checked-locking/
+categories: Concurrency
+tags:
+ - Java
+ - Difficulty-Beginner
+ - Idiom
+---
+
+## Intent
+Reduce the overhead of acquiring a lock by first testing the
+locking criterion (the "lock hint") without actually acquiring the lock. Only
+if the locking criterion check indicates that locking is required does the
+actual locking logic proceed.
+
+
+
+## Applicability
+Use the Double Checked Locking pattern when
+
+* there is a concurrent access in object creation, e.g. singleton, where you want to create single instance of the same class and checking if it's null or not maybe not be enough when there are two or more threads that checks if instance is null or not.
+* there is a concurrent access on a method where method's behaviour changes according to the some constraints and these constraint change within this method.
diff --git a/double-checked-locking/etc/double-checked-locking.ucls b/double-checked-locking/etc/double-checked-locking.ucls
index 43bfbfb78..3ec179228 100644
--- a/double-checked-locking/etc/double-checked-locking.ucls
+++ b/double-checked-locking/etc/double-checked-locking.ucls
@@ -1,8 +1,8 @@
-
-
-
-
+
+
+
+
+
+
diff --git a/double-checked-locking/pom.xml b/double-checked-locking/pom.xml
index 8103cf986..239bcf870 100644
--- a/double-checked-locking/pom.xml
+++ b/double-checked-locking/pom.xml
@@ -1,9 +1,33 @@
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
double-checked-locking
@@ -12,5 +36,10 @@
junit
test
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/App.java b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/App.java
new file mode 100644
index 000000000..98309e181
--- /dev/null
+++ b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/App.java
@@ -0,0 +1,64 @@
+/**
+ * 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.doublechecked.locking;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/**
+ *
+ * Double Checked Locking is a concurrency design pattern used to reduce the overhead of acquiring a
+ * lock by first testing the locking criterion (the "lock hint") without actually acquiring the
+ * lock. Only if the locking criterion check indicates that locking is required does the actual
+ * locking logic proceed.
+ *
+ * In {@link Inventory} we store the items with a given size. However, we do not store more items
+ * than the inventory size. To address concurrent access problems we use double checked locking to
+ * add item to inventory. In this method, the thread which gets the lock first adds the item.
+ *
+ */
+public class App {
+
+ /**
+ * Program entry point
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ final Inventory inventory = new Inventory(1000);
+ ExecutorService executorService = Executors.newFixedThreadPool(3);
+ for (int i = 0; i < 3; i++) {
+ executorService.execute(() -> {
+ while (inventory.addItem(new Item())) {};
+ });
+ }
+
+ executorService.shutdown();
+ try {
+ executorService.awaitTermination(5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ System.out.println("Error waiting for ExecutorService shutdown");
+ }
+ }
+}
diff --git a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Inventory.java b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Inventory.java
new file mode 100644
index 000000000..176203a44
--- /dev/null
+++ b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Inventory.java
@@ -0,0 +1,80 @@
+/**
+ * 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.doublechecked.locking;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ *
+ * Inventory
+ *
+ */
+public class Inventory {
+
+ private final int inventorySize;
+ private final List- items;
+ private final Lock lock;
+
+ /**
+ * Constructor
+ */
+ public Inventory(int inventorySize) {
+ this.inventorySize = inventorySize;
+ this.items = new ArrayList<>(inventorySize);
+ this.lock = new ReentrantLock();
+ }
+
+ /**
+ * Add item
+ */
+ public boolean addItem(Item item) {
+ if (items.size() < inventorySize) {
+ lock.lock();
+ try {
+ if (items.size() < inventorySize) {
+ items.add(item);
+ System.out.println(Thread.currentThread() + ": items.size()=" + items.size()
+ + ", inventorySize=" + inventorySize);
+ return true;
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get all the items in the inventory
+ *
+ * @return All the items of the inventory, as an unmodifiable list
+ */
+ public final List
- getItems() {
+ return Collections.unmodifiableList(items);
+ }
+
+}
diff --git a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Item.java b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Item.java
new file mode 100644
index 000000000..c805022ab
--- /dev/null
+++ b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Item.java
@@ -0,0 +1,31 @@
+/**
+ * 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.doublechecked.locking;
+
+/**
+ *
+ * Item
+ *
+ */
+public class Item {
+}
diff --git a/double-checked-locking/src/main/java/com/iluwatar/doublecheckedlocking/App.java b/double-checked-locking/src/main/java/com/iluwatar/doublecheckedlocking/App.java
deleted file mode 100644
index 863f20882..000000000
--- a/double-checked-locking/src/main/java/com/iluwatar/doublecheckedlocking/App.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.iluwatar.doublecheckedlocking;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-/**
- *
- * In Inventory we store the items with a given size. However, we do not store
- * more items than the inventory size. To address concurrent access problems we
- * use double checked locking to add item to inventory. In this method, the
- * thread which gets the lock first adds the item.
- */
-public class App {
-
- public static void main(String[] args) {
- final Inventory inventory = new Inventory(1000);
- ExecutorService executorService = Executors.newFixedThreadPool(3);
- for (int i = 0; i < 3; i++) {
- executorService.execute(new Runnable() {
- @Override
- public void run() {
- while (inventory.addItem(new Item()))
- ;
- }
- });
- }
- }
-}
diff --git a/double-checked-locking/src/main/java/com/iluwatar/doublecheckedlocking/Inventory.java b/double-checked-locking/src/main/java/com/iluwatar/doublecheckedlocking/Inventory.java
deleted file mode 100644
index 368be2f9a..000000000
--- a/double-checked-locking/src/main/java/com/iluwatar/doublecheckedlocking/Inventory.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.iluwatar.doublecheckedlocking;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-public class Inventory {
-
- private int inventorySize;
- private List
- items;
- private Lock lock = new ReentrantLock();
-
- public Inventory(int inventorySize) {
- this.inventorySize = inventorySize;
- this.items = new ArrayList
- (inventorySize);
- }
-
- public boolean addItem(Item item) {
- if (items.size() < inventorySize) {
- lock.lock();
- try {
- if (items.size() < inventorySize) {
- items.add(item);
- System.out.println(Thread.currentThread());
- return true;
- }
- } finally {
- lock.unlock();
- }
- }
- return false;
- }
-
-}
diff --git a/double-checked-locking/src/main/java/com/iluwatar/doublecheckedlocking/Item.java b/double-checked-locking/src/main/java/com/iluwatar/doublecheckedlocking/Item.java
deleted file mode 100644
index bca41c51e..000000000
--- a/double-checked-locking/src/main/java/com/iluwatar/doublecheckedlocking/Item.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package com.iluwatar.doublecheckedlocking;
-
-public class Item {
- String name;
- int level;
-}
diff --git a/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/AppTest.java b/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/AppTest.java
new file mode 100644
index 000000000..748c66c6a
--- /dev/null
+++ b/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/AppTest.java
@@ -0,0 +1,39 @@
+/**
+ * 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.doublechecked.locking;
+
+import org.junit.Test;
+
+/**
+ *
+ * Application test
+ *
+ */
+public class AppTest {
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/InventoryTest.java b/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/InventoryTest.java
new file mode 100644
index 000000000..485c9573e
--- /dev/null
+++ b/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/InventoryTest.java
@@ -0,0 +1,132 @@
+/**
+ * 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.doublechecked.locking;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import java.io.PrintStream;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.TestCase.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/10/15 - 9:34 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class InventoryTest {
+
+ /**
+ * The mocked standard out {@link PrintStream}, used to verify a steady increasing size of the
+ * {@link Inventory} while adding items from multiple threads concurrently
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * The number of threads used to stress test the locking of the {@link Inventory#addItem(Item)}
+ * method
+ */
+ private static final int THREAD_COUNT = 8;
+
+ /**
+ * The maximum number of {@link Item}s allowed in the {@link Inventory}
+ */
+ private static final int INVENTORY_SIZE = 1000;
+
+ /**
+ * Concurrently add multiple items to the inventory, and check if the items were added in order by
+ * checking the stdOut for continuous growth of the inventory. When 'items.size()=xx' shows up out
+ * of order, it means that the locking is not ok, increasing the risk of going over the inventory
+ * item limit.
+ */
+ @Test(timeout = 10000)
+ public void testAddItem() throws Exception {
+ // Create a new inventory with a limit of 1000 items and put some load on the add method
+ final Inventory inventory = new Inventory(INVENTORY_SIZE);
+ final ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);
+ for (int i = 0; i < THREAD_COUNT; i++) {
+ executorService.execute(() -> {
+ while (inventory.addItem(new Item())) {};
+ });
+ }
+
+ // Wait until all threads have finished
+ executorService.shutdown();
+ executorService.awaitTermination(5, TimeUnit.SECONDS);
+
+ // Check the number of items in the inventory. It should not have exceeded the allowed maximum
+ final List
- items = inventory.getItems();
+ assertNotNull(items);
+ assertEquals(INVENTORY_SIZE, items.size());
+
+ // Capture all stdOut messages ...
+ final ArgumentCaptor
stdOutCaptor = ArgumentCaptor.forClass(String.class);
+ verify(this.stdOutMock, times(INVENTORY_SIZE)).println(stdOutCaptor.capture());
+
+ // ... verify if we got all 1000
+ final List values = stdOutCaptor.getAllValues();
+ assertEquals(INVENTORY_SIZE, values.size());
+
+ // ... and check if the inventory size is increasing continuously
+ for (int i = 0; i < values.size(); i++) {
+ assertNotNull(values.get(i));
+ assertTrue(values.get(i).contains("items.size()=" + (i + 1)));
+ }
+
+ verifyNoMoreInteractions(this.stdOutMock);
+ }
+
+}
\ No newline at end of file
diff --git a/double-checked-locking/src/test/java/com/iluwatar/doublecheckedlocking/AppTest.java b/double-checked-locking/src/test/java/com/iluwatar/doublecheckedlocking/AppTest.java
deleted file mode 100644
index ca3d82871..000000000
--- a/double-checked-locking/src/test/java/com/iluwatar/doublecheckedlocking/AppTest.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.iluwatar.doublecheckedlocking;
-
-import org.junit.Test;
-
-import com.iluwatar.doublecheckedlocking.App;
-
-public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
-}
diff --git a/double-dispatch/README.md b/double-dispatch/README.md
new file mode 100644
index 000000000..ae87208a2
--- /dev/null
+++ b/double-dispatch/README.md
@@ -0,0 +1,26 @@
+---
+layout: pattern
+title: Double Dispatch
+folder: double-dispatch
+permalink: /patterns/double-dispatch/
+categories: Other
+tags:
+ - Java
+ - Difficulty-Intermediate
+ - Idiom
+---
+
+## Intent
+Double Dispatch pattern is a way to create maintainable dynamic
+behavior based on receiver and parameter types.
+
+
+
+## Applicability
+Use the Double Dispatch pattern when
+
+* the dynamic behavior is not defined only based on receiving object's type but also on the receiving method's parameter type.
+
+## Real world examples
+
+* [ObjectOutputStream](https://docs.oracle.com/javase/8/docs/api/java/io/ObjectOutputStream.html)
diff --git a/double-dispatch/pom.xml b/double-dispatch/pom.xml
index 40356e018..4f31b2e7e 100644
--- a/double-dispatch/pom.xml
+++ b/double-dispatch/pom.xml
@@ -1,11 +1,35 @@
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
double-dispatch
@@ -14,5 +38,10 @@
junit
test
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/App.java b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/App.java
index fa799ecfc..40a0485a5 100644
--- a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/App.java
+++ b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/App.java
@@ -1,3 +1,25 @@
+/**
+ * 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.doubledispatch;
import java.util.ArrayList;
@@ -5,42 +27,50 @@ import java.util.List;
/**
*
- * When a message with a parameter is sent to an object, the resultant behaviour is defined by the
- * implementation of that method in the receiver. Sometimes the behaviour must also be determined
- * by the type of the parameter.
- *
- * One way to implement this would be to create multiple instanceof-checks for the methods parameter.
- * However, this creates a maintenance issue. When new types are added we would also need to change
- * the method's implementation and add a new instanceof-check. This violates the single responsibility
- * principle - a class should have only one reason to change.
- *
- * Instead of the instanceof-checks a better way is to make another virtual call on the parameter
- * object. This way new functionality can be easily added without the need to modify existing
- * implementation (open-closed principle).
- *
- * In this example we have hierarchy of objects (GameObject) that can collide to each other. Each
- * object has its own coordinates which are checked against the other objects' coordinates. If
- * there is an overlap, then the objects collide utilizing the Double Dispatch pattern.
+ * When a message with a parameter is sent to an object, the resultant behaviour is defined by the implementation of
+ * that method in the receiver. Sometimes the behaviour must also be determined by the type of the parameter.
+ *
+ * One way to implement this would be to create multiple instanceof-checks for the methods parameter. However, this
+ * creates a maintenance issue. When new types are added we would also need to change the method's implementation and
+ * add a new instanceof-check. This violates the single responsibility principle - a class should have only one reason
+ * to change.
+ *
+ * Instead of the instanceof-checks a better way is to make another virtual call on the parameter object. This way new
+ * functionality can be easily added without the need to modify existing implementation (open-closed principle).
+ *
+ * In this example we have hierarchy of objects ({@link GameObject}) that can collide to each other. Each object has its
+ * own coordinates which are checked against the other objects' coordinates. If there is an overlap, then the objects
+ * collide utilizing the Double Dispatch pattern.
*
*/
public class App {
-
- public static void main( String[] args ) {
- // initialize game objects and print their status
- List objects = new ArrayList<>();
- objects.add(new FlamingAsteroid(0, 0, 5, 5));
- objects.add(new SpaceStationMir(1, 1, 2, 2));
- objects.add(new Meteoroid(10, 10, 15, 15));
- objects.add(new SpaceStationIss(12, 12, 14, 14));
- objects.stream().forEach(o -> System.out.println(o));
- System.out.println("");
-
- // collision check
- objects.stream().forEach(o1 -> objects.stream().forEach(o2 -> { if (o1 != o2 && o1.intersectsWith(o2)) o1.collision(o2); } ));
- System.out.println("");
-
- // output eventual object statuses
- objects.stream().forEach(o -> System.out.println(o));
- System.out.println("");
- }
+
+ /**
+ * Program entry point
+ *
+ * @param args
+ * command line args
+ */
+ public static void main(String[] args) {
+ // initialize game objects and print their status
+ List objects = new ArrayList<>();
+ objects.add(new FlamingAsteroid(0, 0, 5, 5));
+ objects.add(new SpaceStationMir(1, 1, 2, 2));
+ objects.add(new Meteoroid(10, 10, 15, 15));
+ objects.add(new SpaceStationIss(12, 12, 14, 14));
+ objects.stream().forEach(o -> System.out.println(o));
+ System.out.println("");
+
+ // collision check
+ objects.stream().forEach(o1 -> objects.stream().forEach(o2 -> {
+ if (o1 != o2 && o1.intersectsWith(o2)) {
+ o1.collision(o2);
+ }
+ }));
+ System.out.println("");
+
+ // output eventual object statuses
+ objects.stream().forEach(o -> System.out.println(o));
+ System.out.println("");
+ }
}
diff --git a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/FlamingAsteroid.java b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/FlamingAsteroid.java
index 73b633e5b..6cff89f58 100644
--- a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/FlamingAsteroid.java
+++ b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/FlamingAsteroid.java
@@ -1,3 +1,25 @@
+/**
+ * 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.doubledispatch;
/**
@@ -7,13 +29,13 @@ package com.iluwatar.doubledispatch;
*/
public class FlamingAsteroid extends Meteoroid {
- public FlamingAsteroid(int left, int top, int right, int bottom) {
- super(left, top, right, bottom);
- setOnFire(true);
- }
+ public FlamingAsteroid(int left, int top, int right, int bottom) {
+ super(left, top, right, bottom);
+ setOnFire(true);
+ }
- @Override
- public void collision(GameObject gameObject) {
- gameObject.collisionResolve(this);
- }
+ @Override
+ public void collision(GameObject gameObject) {
+ gameObject.collisionResolve(this);
+ }
}
diff --git a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/GameObject.java b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/GameObject.java
index afe05e9b2..fea0cdfd1 100644
--- a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/GameObject.java
+++ b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/GameObject.java
@@ -1,49 +1,70 @@
+/**
+ * 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.doubledispatch;
/**
*
- * Game objects have coordinates and some
- * other status information.
+ * Game objects have coordinates and some other status information.
*
*/
public abstract class GameObject extends Rectangle {
-
- private boolean damaged;
- private boolean onFire;
-
- public GameObject(int left, int top, int right, int bottom) {
- super(left, top, right, bottom);
- }
-
- @Override
- public String toString() {
- return String.format("%s at %s damaged=%b onFire=%b", this.getClass().getSimpleName(),
- super.toString(), isDamaged(), isOnFire());
- }
-
- public boolean isOnFire() {
- return onFire;
- }
-
- public void setOnFire(boolean onFire) {
- this.onFire = onFire;
- }
-
- public boolean isDamaged() {
- return damaged;
- }
-
- public void setDamaged(boolean damaged) {
- this.damaged = damaged;
- }
-
- public abstract void collision(GameObject gameObject);
-
- public abstract void collisionResolve(FlamingAsteroid asteroid);
- public abstract void collisionResolve(Meteoroid meteoroid);
+ private boolean damaged;
+ private boolean onFire;
- public abstract void collisionResolve(SpaceStationMir mir);
+ public GameObject(int left, int top, int right, int bottom) {
+ super(left, top, right, bottom);
+ }
- public abstract void collisionResolve(SpaceStationIss iss);
+ @Override
+ public String toString() {
+ return String.format("%s at %s damaged=%b onFire=%b", this.getClass().getSimpleName(),
+ super.toString(), isDamaged(), isOnFire());
+ }
+
+ public boolean isOnFire() {
+ return onFire;
+ }
+
+ public void setOnFire(boolean onFire) {
+ this.onFire = onFire;
+ }
+
+ public boolean isDamaged() {
+ return damaged;
+ }
+
+ public void setDamaged(boolean damaged) {
+ this.damaged = damaged;
+ }
+
+ public abstract void collision(GameObject gameObject);
+
+ public abstract void collisionResolve(FlamingAsteroid asteroid);
+
+ public abstract void collisionResolve(Meteoroid meteoroid);
+
+ public abstract void collisionResolve(SpaceStationMir mir);
+
+ public abstract void collisionResolve(SpaceStationIss iss);
}
diff --git a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Meteoroid.java b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Meteoroid.java
index fb59c49b4..cc68a85ec 100644
--- a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Meteoroid.java
+++ b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Meteoroid.java
@@ -1,3 +1,25 @@
+/**
+ * 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.doubledispatch;
/**
@@ -7,32 +29,36 @@ package com.iluwatar.doubledispatch;
*/
public class Meteoroid extends GameObject {
- public Meteoroid(int left, int top, int right, int bottom) {
- super(left, top, right, bottom);
- }
+ public Meteoroid(int left, int top, int right, int bottom) {
+ super(left, top, right, bottom);
+ }
- @Override
- public void collision(GameObject gameObject) {
- gameObject.collisionResolve(this);
- }
+ @Override
+ public void collision(GameObject gameObject) {
+ gameObject.collisionResolve(this);
+ }
- @Override
- public void collisionResolve(FlamingAsteroid asteroid) {
- System.out.println(String.format("%s hits %s.", asteroid.getClass().getSimpleName(), this.getClass().getSimpleName()));
- }
+ @Override
+ public void collisionResolve(FlamingAsteroid asteroid) {
+ System.out.println(String.format("%s hits %s.", asteroid.getClass().getSimpleName(), this
+ .getClass().getSimpleName()));
+ }
- @Override
- public void collisionResolve(Meteoroid meteoroid) {
- System.out.println(String.format("%s hits %s.", meteoroid.getClass().getSimpleName(), this.getClass().getSimpleName()));
- }
+ @Override
+ public void collisionResolve(Meteoroid meteoroid) {
+ System.out.println(String.format("%s hits %s.", meteoroid.getClass().getSimpleName(), this
+ .getClass().getSimpleName()));
+ }
- @Override
- public void collisionResolve(SpaceStationMir mir) {
- System.out.println(String.format("%s hits %s.", mir.getClass().getSimpleName(), this.getClass().getSimpleName()));
- }
+ @Override
+ public void collisionResolve(SpaceStationMir mir) {
+ System.out.println(String.format("%s hits %s.", mir.getClass().getSimpleName(), this.getClass()
+ .getSimpleName()));
+ }
- @Override
- public void collisionResolve(SpaceStationIss iss) {
- System.out.println(String.format("%s hits %s.", iss.getClass().getSimpleName(), this.getClass().getSimpleName()));
- }
+ @Override
+ public void collisionResolve(SpaceStationIss iss) {
+ System.out.println(String.format("%s hits %s.", iss.getClass().getSimpleName(), this.getClass()
+ .getSimpleName()));
+ }
}
diff --git a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Rectangle.java b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Rectangle.java
index 12aca0056..496bb8769 100644
--- a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Rectangle.java
+++ b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Rectangle.java
@@ -1,44 +1,72 @@
+/**
+ * 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.doubledispatch;
/**
*
- * Rectangle has coordinates and can be checked for overlap against
- * other Rectangles.
+ * Rectangle has coordinates and can be checked for overlap against other Rectangles.
*
*/
public class Rectangle {
- private int left;
- private int top;
- private int right;
- private int bottom;
+ private int left;
+ private int top;
+ private int right;
+ private int bottom;
- public Rectangle(int left, int top, int right, int bottom) {
- this.left = left;
- this.top = top;
- this.right = right;
- this.bottom = bottom;
- }
-
- public int getLeft() {
- return left;
- }
- public int getTop() {
- return top;
- }
- public int getRight() {
- return right;
- }
- public int getBottom() {
- return bottom;
- }
-
- boolean intersectsWith(Rectangle r) {
- return !(r.getLeft() > getRight() || r.getRight() < getLeft() || r.getTop() > getBottom() || r.getBottom() < getTop());
- }
-
- @Override
- public String toString() {
- return String.format("[%d,%d,%d,%d]", getLeft(), getTop(), getRight(), getBottom());
- }
+ /**
+ * Constructor
+ */
+ public Rectangle(int left, int top, int right, int bottom) {
+ this.left = left;
+ this.top = top;
+ this.right = right;
+ this.bottom = bottom;
+ }
+
+ public int getLeft() {
+ return left;
+ }
+
+ public int getTop() {
+ return top;
+ }
+
+ public int getRight() {
+ return right;
+ }
+
+ public int getBottom() {
+ return bottom;
+ }
+
+ boolean intersectsWith(Rectangle r) {
+ return !(r.getLeft() > getRight() || r.getRight() < getLeft() || r.getTop() > getBottom() || r
+ .getBottom() < getTop());
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[%d,%d,%d,%d]", getLeft(), getTop(), getRight(), getBottom());
+ }
}
diff --git a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/SpaceStationIss.java b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/SpaceStationIss.java
index 50eae3df8..1150fc60b 100644
--- a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/SpaceStationIss.java
+++ b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/SpaceStationIss.java
@@ -1,3 +1,25 @@
+/**
+ * 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.doubledispatch;
/**
@@ -7,12 +29,12 @@ package com.iluwatar.doubledispatch;
*/
public class SpaceStationIss extends SpaceStationMir {
- public SpaceStationIss(int left, int top, int right, int bottom) {
- super(left, top, right, bottom);
- }
+ public SpaceStationIss(int left, int top, int right, int bottom) {
+ super(left, top, right, bottom);
+ }
- @Override
- public void collision(GameObject gameObject) {
- gameObject.collisionResolve(this);
- }
+ @Override
+ public void collision(GameObject gameObject) {
+ gameObject.collisionResolve(this);
+ }
}
diff --git a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/SpaceStationMir.java b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/SpaceStationMir.java
index 059b41271..e7a55d0ee 100644
--- a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/SpaceStationMir.java
+++ b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/SpaceStationMir.java
@@ -1,3 +1,25 @@
+/**
+ * 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.doubledispatch;
/**
@@ -7,45 +29,42 @@ package com.iluwatar.doubledispatch;
*/
public class SpaceStationMir extends GameObject {
- public SpaceStationMir(int left, int top, int right, int bottom) {
- super(left, top, right, bottom);
- }
+ public SpaceStationMir(int left, int top, int right, int bottom) {
+ super(left, top, right, bottom);
+ }
- @Override
- public void collision(GameObject gameObject) {
- gameObject.collisionResolve(this);
- }
+ @Override
+ public void collision(GameObject gameObject) {
+ gameObject.collisionResolve(this);
+ }
- @Override
- public void collisionResolve(FlamingAsteroid asteroid) {
- System.out.println(String.format("%s hits %s. %s is damaged! %s is set on fire!",
- asteroid.getClass().getSimpleName(), this.getClass().getSimpleName(),
- this.getClass().getSimpleName(), this.getClass().getSimpleName()));
- setDamaged(true);
- setOnFire(true);
- }
+ @Override
+ public void collisionResolve(FlamingAsteroid asteroid) {
+ System.out.println(String.format("%s hits %s. %s is damaged! %s is set on fire!", asteroid
+ .getClass().getSimpleName(), this.getClass().getSimpleName(), this.getClass()
+ .getSimpleName(), this.getClass().getSimpleName()));
+ setDamaged(true);
+ setOnFire(true);
+ }
- @Override
- public void collisionResolve(Meteoroid meteoroid) {
- System.out.println(String.format("%s hits %s. %s is damaged!",
- meteoroid.getClass().getSimpleName(), this.getClass().getSimpleName(),
- this.getClass().getSimpleName()));
- setDamaged(true);
- }
+ @Override
+ public void collisionResolve(Meteoroid meteoroid) {
+ System.out.println(String.format("%s hits %s. %s is damaged!", meteoroid.getClass()
+ .getSimpleName(), this.getClass().getSimpleName(), this.getClass().getSimpleName()));
+ setDamaged(true);
+ }
- @Override
- public void collisionResolve(SpaceStationMir mir) {
- System.out.println(String.format("%s hits %s. %s is damaged!",
- mir.getClass().getSimpleName(), this.getClass().getSimpleName(),
- this.getClass().getSimpleName()));
- setDamaged(true);
- }
+ @Override
+ public void collisionResolve(SpaceStationMir mir) {
+ System.out.println(String.format("%s hits %s. %s is damaged!", mir.getClass().getSimpleName(),
+ this.getClass().getSimpleName(), this.getClass().getSimpleName()));
+ setDamaged(true);
+ }
- @Override
- public void collisionResolve(SpaceStationIss iss) {
- System.out.println(String.format("%s hits %s. %s is damaged!",
- iss.getClass().getSimpleName(), this.getClass().getSimpleName(),
- this.getClass().getSimpleName()));
- setDamaged(true);
- }
+ @Override
+ public void collisionResolve(SpaceStationIss iss) {
+ System.out.println(String.format("%s hits %s. %s is damaged!", iss.getClass().getSimpleName(),
+ this.getClass().getSimpleName(), this.getClass().getSimpleName()));
+ setDamaged(true);
+ }
}
diff --git a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/AppTest.java b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/AppTest.java
index 892772e09..c1a6aa690 100644
--- a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/AppTest.java
+++ b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/AppTest.java
@@ -1,14 +1,39 @@
+/**
+ * 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.doubledispatch;
import org.junit.Test;
-import com.iluwatar.doubledispatch.App;
-
+/**
+ *
+ * Application test
+ *
+ */
public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
}
diff --git a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/CollisionTest.java b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/CollisionTest.java
new file mode 100644
index 000000000..dbc8fc55e
--- /dev/null
+++ b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/CollisionTest.java
@@ -0,0 +1,158 @@
+/**
+ * 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.doubledispatch;
+
+import org.junit.After;
+import org.junit.Before;
+
+import java.io.PrintStream;
+import java.util.Objects;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/10/15 - 8:37 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class CollisionTest {
+
+ /**
+ * The mocked standard out {@link PrintStream}, required if some of the actions on the tested
+ * object don't have a direct influence on any other accessible objects, except for writing to
+ * std-out using {@link System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * Get the mocked stdOut {@link PrintStream}
+ *
+ * @return The stdOut print stream mock, renewed before each test
+ */
+ final PrintStream getStdOutMock() {
+ return this.stdOutMock;
+ }
+
+ /**
+ * Get the tested object
+ *
+ * @return The tested object, should never return 'null'
+ */
+ abstract O getTestedObject();
+
+ /**
+ * Collide the tested item with the other given item and verify if the damage and fire state is as
+ * expected
+ *
+ * @param other The other object we have to collide with
+ * @param otherDamaged Indicates if the other object should be damaged after the collision
+ * @param otherOnFire Indicates if the other object should be burning after the collision
+ * @param thisDamaged Indicates if the test object should be damaged after the collision
+ * @param thisOnFire Indicates if the other object should be burning after the collision
+ * @param description The expected description of the collision
+ */
+ void testCollision(final GameObject other, final boolean otherDamaged, final boolean otherOnFire,
+ final boolean thisDamaged, final boolean thisOnFire, final String description) {
+
+ Objects.requireNonNull(other);
+ Objects.requireNonNull(getTestedObject());
+
+ final O tested = getTestedObject();
+
+ tested.collision(other);
+
+ verify(getStdOutMock(), times(1)).println(description);
+ verifyNoMoreInteractions(getStdOutMock());
+
+ testOnFire(other, tested, otherOnFire);
+ testDamaged(other, tested, otherDamaged);
+
+ testOnFire(tested, other, thisOnFire);
+ testDamaged(tested, other, thisDamaged);
+
+ }
+
+ /**
+ * Test if the fire state of the target matches the expected state after colliding with the given
+ * object
+ *
+ * @param target The target object
+ * @param other The other object
+ * @param expectTargetOnFire The expected state of fire on the target object
+ */
+ private void testOnFire(final GameObject target, final GameObject other, final boolean expectTargetOnFire) {
+ final String targetName = target.getClass().getSimpleName();
+ final String otherName = other.getClass().getSimpleName();
+
+ final String errorMessage = expectTargetOnFire
+ ? "Expected [" + targetName + "] to be on fire after colliding with [" + otherName + "] but it was not!"
+ : "Expected [" + targetName + "] not to be on fire after colliding with [" + otherName + "] but it was!";
+
+ assertEquals(errorMessage, expectTargetOnFire, target.isOnFire());
+ }
+
+ /**
+ * Test if the damage state of the target matches the expected state after colliding with the
+ * given object
+ *
+ * @param target The target object
+ * @param other The other object
+ * @param expectedDamage The expected state of damage on the target object
+ */
+ private void testDamaged(final GameObject target, final GameObject other, final boolean expectedDamage) {
+ final String targetName = target.getClass().getSimpleName();
+ final String otherName = other.getClass().getSimpleName();
+
+ final String errorMessage = expectedDamage
+ ? "Expected [" + targetName + "] to be damaged after colliding with [" + otherName + "] but it was not!"
+ : "Expected [" + targetName + "] not to be damaged after colliding with [" + otherName + "] but it was!";
+
+ assertEquals(errorMessage, expectedDamage, target.isDamaged());
+ }
+
+}
diff --git a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/FlamingAsteroidTest.java b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/FlamingAsteroidTest.java
new file mode 100644
index 000000000..31a16f093
--- /dev/null
+++ b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/FlamingAsteroidTest.java
@@ -0,0 +1,110 @@
+/**
+ * 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.doubledispatch;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Date: 12/10/15 - 11:31 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class FlamingAsteroidTest extends CollisionTest {
+
+ @Override
+ final FlamingAsteroid getTestedObject() {
+ return new FlamingAsteroid(1, 2, 3, 4);
+ }
+
+ /**
+ * Test the constructor parameters
+ */
+ @Test
+ public void testConstructor() {
+ final FlamingAsteroid asteroid = new FlamingAsteroid(1, 2, 3, 4);
+ assertEquals(1, asteroid.getLeft());
+ assertEquals(2, asteroid.getTop());
+ assertEquals(3, asteroid.getRight());
+ assertEquals(4, asteroid.getBottom());
+ assertTrue(asteroid.isOnFire());
+ assertFalse(asteroid.isDamaged());
+ assertEquals("FlamingAsteroid at [1,2,3,4] damaged=false onFire=true", asteroid.toString());
+ }
+
+ /**
+ * Test what happens we collide with an asteroid
+ */
+ @Test
+ public void testCollideFlamingAsteroid() {
+ testCollision(
+ new FlamingAsteroid(1, 2, 3, 4),
+ false, true,
+ false, true,
+ "FlamingAsteroid hits FlamingAsteroid."
+ );
+ }
+
+ /**
+ * Test what happens we collide with an meteoroid
+ */
+ @Test
+ public void testCollideMeteoroid() {
+ testCollision(
+ new Meteoroid(1, 1, 3, 4),
+ false, false,
+ false, true,
+ "FlamingAsteroid hits Meteoroid."
+ );
+ }
+
+ /**
+ * Test what happens we collide with ISS
+ */
+ @Test
+ public void testCollideSpaceStationIss() {
+ testCollision(
+ new SpaceStationIss(1, 1, 3, 4),
+ true, true,
+ false, true,
+ "FlamingAsteroid hits SpaceStationIss. SpaceStationIss is damaged! SpaceStationIss is set on fire!"
+ );
+ }
+
+ /**
+ * Test what happens we collide with MIR
+ */
+ @Test
+ public void testCollideSpaceStationMir() {
+ testCollision(
+ new SpaceStationMir(1, 1, 3, 4),
+ true, true,
+ false, true,
+ "FlamingAsteroid hits SpaceStationMir. SpaceStationMir is damaged! SpaceStationMir is set on fire!"
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/MeteoroidTest.java b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/MeteoroidTest.java
new file mode 100644
index 000000000..147fe430a
--- /dev/null
+++ b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/MeteoroidTest.java
@@ -0,0 +1,109 @@
+/**
+ * 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.doubledispatch;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+/**
+ * Date: 12/10/15 - 11:31 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class MeteoroidTest extends CollisionTest {
+
+ @Override
+ final Meteoroid getTestedObject() {
+ return new Meteoroid(1, 2, 3, 4);
+ }
+
+ /**
+ * Test the constructor parameters
+ */
+ @Test
+ public void testConstructor() {
+ final Meteoroid meteoroid = new Meteoroid(1, 2, 3, 4);
+ assertEquals(1, meteoroid.getLeft());
+ assertEquals(2, meteoroid.getTop());
+ assertEquals(3, meteoroid.getRight());
+ assertEquals(4, meteoroid.getBottom());
+ assertFalse(meteoroid.isOnFire());
+ assertFalse(meteoroid.isDamaged());
+ assertEquals("Meteoroid at [1,2,3,4] damaged=false onFire=false", meteoroid.toString());
+ }
+
+ /**
+ * Test what happens we collide with an asteroid
+ */
+ @Test
+ public void testCollideFlamingAsteroid() {
+ testCollision(
+ new FlamingAsteroid(1, 1, 3, 4),
+ false, true,
+ false, false,
+ "Meteoroid hits FlamingAsteroid."
+ );
+ }
+
+ /**
+ * Test what happens we collide with an meteoroid
+ */
+ @Test
+ public void testCollideMeteoroid() {
+ testCollision(
+ new Meteoroid(1, 1, 3, 4),
+ false, false,
+ false, false,
+ "Meteoroid hits Meteoroid."
+ );
+ }
+
+ /**
+ * Test what happens we collide with ISS
+ */
+ @Test
+ public void testCollideSpaceStationIss() {
+ testCollision(
+ new SpaceStationIss(1, 1, 3, 4),
+ true, false,
+ false, false,
+ "Meteoroid hits SpaceStationIss. SpaceStationIss is damaged!"
+ );
+ }
+
+ /**
+ * Test what happens we collide with MIR
+ */
+ @Test
+ public void testCollideSpaceStationMir() {
+ testCollision(
+ new SpaceStationMir(1, 1, 3, 4),
+ true, false,
+ false, false,
+ "Meteoroid hits SpaceStationMir. SpaceStationMir is damaged!"
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/RectangleTest.java b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/RectangleTest.java
index bb8aa954e..b7c0dbd2e 100644
--- a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/RectangleTest.java
+++ b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/RectangleTest.java
@@ -1,22 +1,69 @@
+/**
+ * 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.doubledispatch;
-import org.junit.Assert;
import org.junit.Test;
-import com.iluwatar.doubledispatch.Rectangle;
+import static junit.framework.TestCase.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
/**
- *
* Unit test for Rectangle
- *
*/
public class RectangleTest {
- @Test
- public void test() {
- Assert.assertTrue(new Rectangle(0,0,1,1).intersectsWith(new Rectangle(0,0,1,1)));
- Assert.assertTrue(new Rectangle(0,0,1,1).intersectsWith(new Rectangle(-1,-5,7,8)));
- Assert.assertFalse(new Rectangle(0,0,1,1).intersectsWith(new Rectangle(2,2,3,3)));
- Assert.assertFalse(new Rectangle(0,0,1,1).intersectsWith(new Rectangle(-2,-2,-1,-1)));
- }
+ /**
+ * Test if the values passed through the constructor matches the values fetched from the getters
+ */
+ @Test
+ public void testConstructor() {
+ final Rectangle rectangle = new Rectangle(1, 2, 3, 4);
+ assertEquals(1, rectangle.getLeft());
+ assertEquals(2, rectangle.getTop());
+ assertEquals(3, rectangle.getRight());
+ assertEquals(4, rectangle.getBottom());
+ }
+
+ /**
+ * Test if the values passed through the constructor matches the values in the {@link
+ * #toString()}
+ */
+ @Test
+ public void testToString() throws Exception {
+ final Rectangle rectangle = new Rectangle(1, 2, 3, 4);
+ assertEquals("[1,2,3,4]", rectangle.toString());
+ }
+
+ /**
+ * Test if the {@link Rectangle} class can detect if it intersects with another rectangle.
+ */
+ @Test
+ public void testIntersection() {
+ assertTrue(new Rectangle(0, 0, 1, 1).intersectsWith(new Rectangle(0, 0, 1, 1)));
+ assertTrue(new Rectangle(0, 0, 1, 1).intersectsWith(new Rectangle(-1, -5, 7, 8)));
+ assertFalse(new Rectangle(0, 0, 1, 1).intersectsWith(new Rectangle(2, 2, 3, 3)));
+ assertFalse(new Rectangle(0, 0, 1, 1).intersectsWith(new Rectangle(-2, -2, -1, -1)));
+ }
+
}
diff --git a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/SpaceStationIssTest.java b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/SpaceStationIssTest.java
new file mode 100644
index 000000000..d06f84b22
--- /dev/null
+++ b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/SpaceStationIssTest.java
@@ -0,0 +1,109 @@
+/**
+ * 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.doubledispatch;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+/**
+ * Date: 12/10/15 - 11:31 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SpaceStationIssTest extends CollisionTest {
+
+ @Override
+ final SpaceStationIss getTestedObject() {
+ return new SpaceStationIss(1, 2, 3, 4);
+ }
+
+ /**
+ * Test the constructor parameters
+ */
+ @Test
+ public void testConstructor() {
+ final SpaceStationIss iss = new SpaceStationIss(1, 2, 3, 4);
+ assertEquals(1, iss.getLeft());
+ assertEquals(2, iss.getTop());
+ assertEquals(3, iss.getRight());
+ assertEquals(4, iss.getBottom());
+ assertFalse(iss.isOnFire());
+ assertFalse(iss.isDamaged());
+ assertEquals("SpaceStationIss at [1,2,3,4] damaged=false onFire=false", iss.toString());
+ }
+
+ /**
+ * Test what happens we collide with an asteroid
+ */
+ @Test
+ public void testCollideFlamingAsteroid() {
+ testCollision(
+ new FlamingAsteroid(1, 1, 3, 4),
+ false, true,
+ false, false,
+ "SpaceStationIss hits FlamingAsteroid."
+ );
+ }
+
+ /**
+ * Test what happens we collide with an meteoroid
+ */
+ @Test
+ public void testCollideMeteoroid() {
+ testCollision(
+ new Meteoroid(1, 1, 3, 4),
+ false, false,
+ false, false,
+ "SpaceStationIss hits Meteoroid."
+ );
+ }
+
+ /**
+ * Test what happens we collide with ISS
+ */
+ @Test
+ public void testCollideSpaceStationIss() {
+ testCollision(
+ new SpaceStationIss(1, 1, 3, 4),
+ true, false,
+ false, false,
+ "SpaceStationIss hits SpaceStationIss. SpaceStationIss is damaged!"
+ );
+ }
+
+ /**
+ * Test what happens we collide with MIR
+ */
+ @Test
+ public void testCollideSpaceStationMir() {
+ testCollision(
+ new SpaceStationMir(1, 1, 3, 4),
+ true, false,
+ false, false,
+ "SpaceStationIss hits SpaceStationMir. SpaceStationMir is damaged!"
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/SpaceStationMirTest.java b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/SpaceStationMirTest.java
new file mode 100644
index 000000000..c107aed8b
--- /dev/null
+++ b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/SpaceStationMirTest.java
@@ -0,0 +1,109 @@
+/**
+ * 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.doubledispatch;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+/**
+ * Date: 12/10/15 - 11:31 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SpaceStationMirTest extends CollisionTest {
+
+ @Override
+ final SpaceStationMir getTestedObject() {
+ return new SpaceStationMir(1, 2, 3, 4);
+ }
+
+ /**
+ * Test the constructor parameters
+ */
+ @Test
+ public void testConstructor() {
+ final SpaceStationMir mir = new SpaceStationMir(1, 2, 3, 4);
+ assertEquals(1, mir.getLeft());
+ assertEquals(2, mir.getTop());
+ assertEquals(3, mir.getRight());
+ assertEquals(4, mir.getBottom());
+ assertFalse(mir.isOnFire());
+ assertFalse(mir.isDamaged());
+ assertEquals("SpaceStationMir at [1,2,3,4] damaged=false onFire=false", mir.toString());
+ }
+
+ /**
+ * Test what happens we collide with an asteroid
+ */
+ @Test
+ public void testCollideFlamingAsteroid() {
+ testCollision(
+ new FlamingAsteroid(1, 1, 3, 4),
+ false, true,
+ false, false,
+ "SpaceStationMir hits FlamingAsteroid."
+ );
+ }
+
+ /**
+ * Test what happens we collide with an meteoroid
+ */
+ @Test
+ public void testCollideMeteoroid() {
+ testCollision(
+ new Meteoroid(1, 1, 3, 4),
+ false, false,
+ false, false,
+ "SpaceStationMir hits Meteoroid."
+ );
+ }
+
+ /**
+ * Test what happens we collide with ISS
+ */
+ @Test
+ public void testCollideSpaceStationIss() {
+ testCollision(
+ new SpaceStationIss(1, 1, 3, 4),
+ true, false,
+ false, false,
+ "SpaceStationMir hits SpaceStationIss. SpaceStationIss is damaged!"
+ );
+ }
+
+ /**
+ * Test what happens we collide with MIR
+ */
+ @Test
+ public void testCollideSpaceStationMir() {
+ testCollision(
+ new SpaceStationMir(1, 1, 3, 4),
+ true, false,
+ false, false,
+ "SpaceStationMir hits SpaceStationMir. SpaceStationMir is damaged!"
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/event-aggregator/README.md b/event-aggregator/README.md
new file mode 100644
index 000000000..ac07869e7
--- /dev/null
+++ b/event-aggregator/README.md
@@ -0,0 +1,34 @@
+---
+layout: pattern
+title: Event Aggregator
+folder: event-aggregator
+permalink: /patterns/event-aggregator/
+categories: Structural
+tags:
+ - Java
+ - Difficulty-Beginner
+ - Reactive
+---
+
+## Intent
+A system with lots of objects can lead to complexities when a
+client wants to subscribe to events. The client has to find and register for
+each object individually, if each object has multiple events then each event
+requires a separate subscription. An Event Aggregator acts as a single source
+of events for many objects. It registers for all the events of the many objects
+allowing clients to register with just the aggregator.
+
+
+
+## Applicability
+Use the Event Aggregator pattern when
+
+* Event Aggregator is a good choice when you have lots of objects that are
+ potential event sources. Rather than have the observer deal with registering
+ with them all, you can centralize the registration logic to the Event
+ Aggregator. As well as simplifying registration, a Event Aggregator also
+ simplifies the memory management issues in using observers.
+
+## Credits
+
+* [Martin Fowler - Event Aggregator](http://martinfowler.com/eaaDev/EventAggregator.html)
diff --git a/event-aggregator/pom.xml b/event-aggregator/pom.xml
index 910d6a35e..b7de6e01b 100644
--- a/event-aggregator/pom.xml
+++ b/event-aggregator/pom.xml
@@ -1,10 +1,34 @@
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
event-aggregator
@@ -13,5 +37,10 @@
junit
test
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/App.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/App.java
new file mode 100644
index 000000000..879355b65
--- /dev/null
+++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/App.java
@@ -0,0 +1,66 @@
+/**
+ * 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.event.aggregator;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * A system with lots of objects can lead to complexities when a client wants to subscribe to
+ * events. The client has to find and register for each object individually, if each object has
+ * multiple events then each event requires a separate subscription.
+ *
+ * An Event Aggregator acts as a single source of events for many objects. It registers for all the
+ * events of the many objects allowing clients to register with just the aggregator.
+ *
+ * In the example {@link LordBaelish}, {@link LordVarys} and {@link Scout} deliver events to
+ * {@link KingsHand}. {@link KingsHand}, the event aggregator, then delivers the events to
+ * {@link KingJoffrey}.
+ *
+ */
+public class App {
+
+ /**
+ * Program entry point
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+
+ KingJoffrey kingJoffrey = new KingJoffrey();
+ KingsHand kingsHand = new KingsHand(kingJoffrey);
+
+ List emitters = new ArrayList<>();
+ emitters.add(kingsHand);
+ emitters.add(new LordBaelish(kingsHand));
+ emitters.add(new LordVarys(kingsHand));
+ emitters.add(new Scout(kingsHand));
+
+ for (Weekday day : Weekday.values()) {
+ for (EventEmitter emitter : emitters) {
+ emitter.timePasses(day);
+ }
+ }
+ }
+}
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Event.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Event.java
new file mode 100644
index 000000000..7397530ef
--- /dev/null
+++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Event.java
@@ -0,0 +1,44 @@
+/**
+ * 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.event.aggregator;
+
+/**
+ *
+ * Event enumeration.
+ *
+ */
+public enum Event {
+
+ STARK_SIGHTED("Stark sighted"), WARSHIPS_APPROACHING("Warships approaching"), TRAITOR_DETECTED(
+ "Traitor detected");
+
+ private String description;
+
+ Event(String description) {
+ this.description = description;
+ }
+
+ public String toString() {
+ return description;
+ }
+}
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/EventEmitter.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/EventEmitter.java
new file mode 100644
index 000000000..b34235df5
--- /dev/null
+++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/EventEmitter.java
@@ -0,0 +1,57 @@
+/**
+ * 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.event.aggregator;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ *
+ * EventEmitter is the base class for event producers that can be observed.
+ *
+ */
+public abstract class EventEmitter {
+
+ private List observers;
+
+ public EventEmitter() {
+ observers = new LinkedList<>();
+ }
+
+ public EventEmitter(EventObserver obs) {
+ this();
+ registerObserver(obs);
+ }
+
+ public final void registerObserver(EventObserver obs) {
+ observers.add(obs);
+ }
+
+ protected void notifyObservers(Event e) {
+ for (EventObserver obs : observers) {
+ obs.onEvent(e);
+ }
+ }
+
+ public abstract void timePasses(Weekday day);
+}
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/EventObserver.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/EventObserver.java
new file mode 100644
index 000000000..020f23284
--- /dev/null
+++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/EventObserver.java
@@ -0,0 +1,34 @@
+/**
+ * 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.event.aggregator;
+
+/**
+ *
+ * Observers of events implement this interface.
+ *
+ */
+public interface EventObserver {
+
+ void onEvent(Event e);
+
+}
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/KingJoffrey.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/KingJoffrey.java
new file mode 100644
index 000000000..fdda59693
--- /dev/null
+++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/KingJoffrey.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.event.aggregator;
+
+/**
+ *
+ * KingJoffrey observes events from {@link KingsHand}.
+ *
+ */
+public class KingJoffrey implements EventObserver {
+
+ @Override
+ public void onEvent(Event e) {
+ System.out.println("Received event from the King's Hand: " + e.toString());
+ }
+}
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/KingsHand.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/KingsHand.java
new file mode 100644
index 000000000..32c8d98d6
--- /dev/null
+++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/KingsHand.java
@@ -0,0 +1,49 @@
+/**
+ * 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.event.aggregator;
+
+/**
+ *
+ * KingsHand observes events from multiple sources and delivers them to listeners.
+ *
+ */
+public class KingsHand extends EventEmitter implements EventObserver {
+
+ public KingsHand() {
+ super();
+ }
+
+ public KingsHand(EventObserver obs) {
+ super(obs);
+ }
+
+ @Override
+ public void onEvent(Event e) {
+ notifyObservers(e);
+ }
+
+ @Override
+ public void timePasses(Weekday day) {
+ // NOP
+ }
+}
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/LordBaelish.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/LordBaelish.java
new file mode 100644
index 000000000..2fdfeada9
--- /dev/null
+++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/LordBaelish.java
@@ -0,0 +1,46 @@
+/**
+ * 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.event.aggregator;
+
+/**
+ *
+ * LordBaelish produces events.
+ *
+ */
+public class LordBaelish extends EventEmitter {
+
+ public LordBaelish() {
+ super();
+ }
+
+ public LordBaelish(EventObserver obs) {
+ super(obs);
+ }
+
+ @Override
+ public void timePasses(Weekday day) {
+ if (day.equals(Weekday.FRIDAY)) {
+ notifyObservers(Event.STARK_SIGHTED);
+ }
+ }
+}
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/LordVarys.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/LordVarys.java
new file mode 100644
index 000000000..b22708d63
--- /dev/null
+++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/LordVarys.java
@@ -0,0 +1,46 @@
+/**
+ * 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.event.aggregator;
+
+/**
+ *
+ * LordVarys produces events.
+ *
+ */
+public class LordVarys extends EventEmitter {
+
+ public LordVarys() {
+ super();
+ }
+
+ public LordVarys(EventObserver obs) {
+ super(obs);
+ }
+
+ @Override
+ public void timePasses(Weekday day) {
+ if (day.equals(Weekday.SATURDAY)) {
+ notifyObservers(Event.TRAITOR_DETECTED);
+ }
+ }
+}
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Scout.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Scout.java
new file mode 100644
index 000000000..3b0945367
--- /dev/null
+++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Scout.java
@@ -0,0 +1,46 @@
+/**
+ * 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.event.aggregator;
+
+/**
+ *
+ * Scout produces events.
+ *
+ */
+public class Scout extends EventEmitter {
+
+ public Scout() {
+ super();
+ }
+
+ public Scout(EventObserver obs) {
+ super(obs);
+ }
+
+ @Override
+ public void timePasses(Weekday day) {
+ if (day.equals(Weekday.TUESDAY)) {
+ notifyObservers(Event.WARSHIPS_APPROACHING);
+ }
+ }
+}
diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Weekday.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Weekday.java
new file mode 100644
index 000000000..d6f10ce22
--- /dev/null
+++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/Weekday.java
@@ -0,0 +1,44 @@
+/**
+ * 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.event.aggregator;
+
+/**
+ *
+ * Weekday enumeration
+ *
+ */
+public enum Weekday {
+
+ MONDAY("Monday"), TUESDAY("Tuesday"), WEDNESDAY("Wednesday"), THURSDAY("Thursday"), FRIDAY(
+ "Friday"), SATURDAY("Saturday"), SUNDAY("Sunday");
+
+ private String description;
+
+ Weekday(String description) {
+ this.description = description;
+ }
+
+ public String toString() {
+ return description;
+ }
+}
diff --git a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/App.java b/event-aggregator/src/main/java/com/iluwatar/eventaggregator/App.java
deleted file mode 100644
index 1b13dfdaa..000000000
--- a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/App.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.iluwatar.eventaggregator;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- *
- * The Event Aggregator pattern channels events from multiple objects
- * into a single object to simplify registration for clients.
- *
- * In the example LordBaelish, LordVarys and Scout deliver events to
- * KingsHand. KingsHand, the event aggregator, then delivers the events
- * to KingJoffrey.
- *
- */
-public class App {
-
- public static void main(String[] args) {
-
- KingJoffrey kingJoffrey = new KingJoffrey();
- KingsHand kingsHand = new KingsHand(kingJoffrey);
-
- List emitters = new ArrayList<>();
- emitters.add(kingsHand);
- emitters.add(new LordBaelish(kingsHand));
- emitters.add(new LordVarys(kingsHand));
- emitters.add(new Scout(kingsHand));
-
- for (Weekday day: Weekday.values()) {
- for (EventEmitter emitter: emitters) {
- emitter.timePasses(day);
- }
- }
- }
-}
diff --git a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/Event.java b/event-aggregator/src/main/java/com/iluwatar/eventaggregator/Event.java
deleted file mode 100644
index fbceeb01d..000000000
--- a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/Event.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.iluwatar.eventaggregator;
-
-/**
- *
- * Event enumeration.
- *
- */
-public enum Event {
-
- STARK_SIGHTED("Stark sighted"), WARSHIPS_APPROACHING("Warships approaching"), TRAITOR_DETECTED("Traitor detected");
-
- private String description;
-
- Event(String description) {
- this.description = description;
- }
-
- public String toString() {
- return description;
- }
-}
diff --git a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/EventEmitter.java b/event-aggregator/src/main/java/com/iluwatar/eventaggregator/EventEmitter.java
deleted file mode 100644
index 88c23178f..000000000
--- a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/EventEmitter.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package com.iluwatar.eventaggregator;
-
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- *
- * EventEmitter is the base class for event producers that can be observed.
- *
- */
-public abstract class EventEmitter {
-
- private List observers;
-
- public EventEmitter() {
- observers = new LinkedList<>();
- }
-
- public EventEmitter(EventObserver obs) {
- this();
- registerObserver(obs);
- }
-
- public void registerObserver(EventObserver obs) {
- observers.add(obs);
- }
-
- protected void notifyObservers(Event e) {
- for (EventObserver obs: observers) {
- obs.onEvent(e);
- }
- }
-
- public abstract void timePasses(Weekday day);
-}
diff --git a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/EventObserver.java b/event-aggregator/src/main/java/com/iluwatar/eventaggregator/EventObserver.java
deleted file mode 100644
index c3dc54a47..000000000
--- a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/EventObserver.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.iluwatar.eventaggregator;
-
-/**
- *
- * Observers of events implement this interface.
- *
- */
-public interface EventObserver {
-
- void onEvent(Event e);
-
-}
diff --git a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/KingJoffrey.java b/event-aggregator/src/main/java/com/iluwatar/eventaggregator/KingJoffrey.java
deleted file mode 100644
index 642dfc787..000000000
--- a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/KingJoffrey.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.iluwatar.eventaggregator;
-
-/**
- *
- * KingJoffrey observes events from KingsHand.
- *
- */
-public class KingJoffrey implements EventObserver {
-
- @Override
- public void onEvent(Event e) {
- System.out.println("Received event from the King's Hand: " + e.toString());
- }
-}
diff --git a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/KingsHand.java b/event-aggregator/src/main/java/com/iluwatar/eventaggregator/KingsHand.java
deleted file mode 100644
index 2b8e1e769..000000000
--- a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/KingsHand.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.iluwatar.eventaggregator;
-
-/**
- *
- * KingsHand observes events from multiple sources and delivers them
- * to listeners.
- *
- */
-public class KingsHand extends EventEmitter implements EventObserver {
-
- public KingsHand() {
- super();
- }
-
- public KingsHand(EventObserver obs) {
- super(obs);
- }
-
- @Override
- public void onEvent(Event e) {
- notifyObservers(e);
- }
-
- @Override
- public void timePasses(Weekday day) {
- // NOP
- }
-}
diff --git a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/LordBaelish.java b/event-aggregator/src/main/java/com/iluwatar/eventaggregator/LordBaelish.java
deleted file mode 100644
index e3f0223a1..000000000
--- a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/LordBaelish.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.iluwatar.eventaggregator;
-
-/**
- *
- * LordBaelish produces events.
- *
- */
-public class LordBaelish extends EventEmitter {
-
- public LordBaelish() {
- super();
- }
-
- public LordBaelish(EventObserver obs) {
- super(obs);
- }
-
- @Override
- public void timePasses(Weekday day) {
- if (day.equals(Weekday.FRIDAY)) {
- notifyObservers(Event.STARK_SIGHTED);
- }
- }
-}
diff --git a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/LordVarys.java b/event-aggregator/src/main/java/com/iluwatar/eventaggregator/LordVarys.java
deleted file mode 100644
index 0afaaf150..000000000
--- a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/LordVarys.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.iluwatar.eventaggregator;
-
-/**
- *
- * LordVarys produces events.
- *
- */
-public class LordVarys extends EventEmitter {
-
- public LordVarys() {
- super();
- }
-
- public LordVarys(EventObserver obs) {
- super(obs);
- }
-
- @Override
- public void timePasses(Weekday day) {
- if (day.equals(Weekday.SATURDAY)) {
- notifyObservers(Event.TRAITOR_DETECTED);
- }
- }
-}
diff --git a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/Scout.java b/event-aggregator/src/main/java/com/iluwatar/eventaggregator/Scout.java
deleted file mode 100644
index 6376182b7..000000000
--- a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/Scout.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.iluwatar.eventaggregator;
-
-/**
- *
- * Scout produces events.
- *
- */
-public class Scout extends EventEmitter {
-
- public Scout() {
- super();
- }
-
- public Scout(EventObserver obs) {
- super(obs);
- }
-
- @Override
- public void timePasses(Weekday day) {
- if (day.equals(Weekday.TUESDAY)) {
- notifyObservers(Event.WARSHIPS_APPROACHING);
- }
- }
-}
diff --git a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/Weekday.java b/event-aggregator/src/main/java/com/iluwatar/eventaggregator/Weekday.java
deleted file mode 100644
index b62cbb106..000000000
--- a/event-aggregator/src/main/java/com/iluwatar/eventaggregator/Weekday.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.iluwatar.eventaggregator;
-
-public enum Weekday {
-
- MONDAY("Monday"), TUESDAY("Tuesday"), WEDNESDAY("Wednesday"), THURSDAY("Thursday"), FRIDAY("Friday"), SATURDAY("Saturday"), SUNDAY("Sunday");
-
- private String description;
-
- Weekday(String description) {
- this.description = description;
- }
-
- public String toString() {
- return description;
- }
-}
diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/AppTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/AppTest.java
new file mode 100644
index 000000000..2330e1f1e
--- /dev/null
+++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/AppTest.java
@@ -0,0 +1,39 @@
+/**
+ * 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.event.aggregator;
+
+import org.junit.Test;
+
+/**
+ *
+ * Application test
+ *
+ */
+public class AppTest {
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/EventEmitterTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/EventEmitterTest.java
new file mode 100644
index 000000000..63fc31a1f
--- /dev/null
+++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/EventEmitterTest.java
@@ -0,0 +1,155 @@
+/**
+ * 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.event.aggregator;
+
+import org.junit.Test;
+
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/12/15 - 10:58 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class EventEmitterTest {
+
+ /**
+ * Factory used to create a new instance of the test object with a default observer
+ */
+ private final Function factoryWithDefaultObserver;
+
+ /**
+ * Factory used to create a new instance of the test object without passing a default observer
+ */
+ private final Supplier factoryWithoutDefaultObserver;
+
+ /**
+ * The day of the week an event is expected
+ */
+ private final Weekday specialDay;
+
+ /**
+ * The expected event, emitted on the special day
+ */
+ private final Event event;
+
+ /**
+ * Create a new event emitter test, using the given test object factories, special day and event
+ */
+ EventEmitterTest(final Weekday specialDay, final Event event,
+ final Function factoryWithDefaultObserver,
+ final Supplier factoryWithoutDefaultObserver) {
+
+ this.specialDay = specialDay;
+ this.event = event;
+ this.factoryWithDefaultObserver = Objects.requireNonNull(factoryWithDefaultObserver);
+ this.factoryWithoutDefaultObserver = Objects.requireNonNull(factoryWithoutDefaultObserver);
+ }
+
+ /**
+ * Go over every day of the month, and check if the event is emitted on the given day. This test
+ * is executed twice, once without a default emitter and once with
+ */
+ @Test
+ public void testAllDays() {
+ testAllDaysWithoutDefaultObserver(specialDay, event);
+ testAllDaysWithDefaultObserver(specialDay, event);
+ }
+
+ /**
+ * Pass each week of the day, day by day to the event emitter and verify of the given observers
+ * received the correct event on the special day.
+ *
+ * @param specialDay The special day on which an event is emitted
+ * @param event The expected event emitted by the test object
+ * @param emitter The event emitter
+ * @param observers The registered observer mocks
+ */
+ private void testAllDays(final Weekday specialDay, final Event event, final E emitter,
+ final EventObserver... observers) {
+
+ for (final Weekday weekday : Weekday.values()) {
+ // Pass each week of the day, day by day to the event emitter
+ emitter.timePasses(weekday);
+
+ if (weekday == specialDay) {
+ // On a special day, every observer should have received the event
+ for (final EventObserver observer : observers) {
+ verify(observer, times(1)).onEvent(eq(event));
+ }
+ } else {
+ // On any other normal day, the observers should have received nothing at all
+ verifyZeroInteractions(observers);
+ }
+ }
+
+ // The observers should not have received any additional events after the week
+ verifyNoMoreInteractions(observers);
+ }
+
+ /**
+ * Go over every day of the month, and check if the event is emitted on the given day. Use an
+ * event emitter without a default observer
+ *
+ * @param specialDay The special day on which an event is emitted
+ * @param event The expected event emitted by the test object
+ */
+ private void testAllDaysWithoutDefaultObserver(final Weekday specialDay, final Event event) {
+ final EventObserver observer1 = mock(EventObserver.class);
+ final EventObserver observer2 = mock(EventObserver.class);
+
+ final E emitter = this.factoryWithoutDefaultObserver.get();
+ emitter.registerObserver(observer1);
+ emitter.registerObserver(observer2);
+
+ testAllDays(specialDay, event, emitter, observer1, observer2);
+ }
+
+ /**
+ * Go over every day of the month, and check if the event is emitted on the given day.
+ *
+ * @param specialDay The special day on which an event is emitted
+ * @param event The expected event emitted by the test object
+ */
+ private void testAllDaysWithDefaultObserver(final Weekday specialDay, final Event event) {
+ final EventObserver defaultObserver = mock(EventObserver.class);
+ final EventObserver observer1 = mock(EventObserver.class);
+ final EventObserver observer2 = mock(EventObserver.class);
+
+ final E emitter = this.factoryWithDefaultObserver.apply(defaultObserver);
+ emitter.registerObserver(observer1);
+ emitter.registerObserver(observer2);
+
+ testAllDays(specialDay, event, emitter, defaultObserver, observer1, observer2);
+ }
+
+}
diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/EventTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/EventTest.java
new file mode 100644
index 000000000..33d1796e9
--- /dev/null
+++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/EventTest.java
@@ -0,0 +1,49 @@
+/**
+ * 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.event.aggregator;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Date: 12/12/15 - 2:52 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class EventTest {
+
+ /**
+ * Verify if every event has a non-null, non-empty description
+ */
+ @Test
+ public void testToString() {
+ for (final Event event : Event.values()) {
+ final String toString = event.toString();
+ assertNotNull(toString);
+ assertFalse(toString.trim().isEmpty());
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingJoffreyTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingJoffreyTest.java
new file mode 100644
index 000000000..3e0028ac4
--- /dev/null
+++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingJoffreyTest.java
@@ -0,0 +1,89 @@
+/**
+ * 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.event.aggregator;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.PrintStream;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/12/15 - 3:04 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class KingJoffreyTest {
+
+ /**
+ * The mocked standard out {@link PrintStream}, required since {@link KingJoffrey} does nothing
+ * except for writing to std-out using {@link System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * Test if {@link KingJoffrey} tells us what event he received
+ */
+ @Test
+ public void testOnEvent() {
+ final KingJoffrey kingJoffrey = new KingJoffrey();
+
+ for (final Event event : Event.values()) {
+ verifyZeroInteractions(this.stdOutMock);
+ kingJoffrey.onEvent(event);
+
+ final String expectedMessage = "Received event from the King's Hand: " + event.toString();
+ verify(this.stdOutMock, times(1)).println(expectedMessage);
+ verifyNoMoreInteractions(this.stdOutMock);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingsHandTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingsHandTest.java
new file mode 100644
index 000000000..93116a071
--- /dev/null
+++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingsHandTest.java
@@ -0,0 +1,70 @@
+/**
+ * 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.event.aggregator;
+
+import org.junit.Test;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/12/15 - 10:57 AM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class KingsHandTest extends EventEmitterTest {
+
+ /**
+ * Create a new test instance, using the correct object factory
+ */
+ public KingsHandTest() {
+ super(null, null, KingsHand::new, KingsHand::new);
+ }
+
+ /**
+ * The {@link KingsHand} is both an {@link EventEmitter} as an {@link EventObserver} so verify if every
+ * event received is passed up to it's superior, in most cases {@link KingJoffrey} but now just a
+ * mocked observer.
+ */
+ @Test
+ public void testPassThrough() throws Exception {
+ final EventObserver observer = mock(EventObserver.class);
+ final KingsHand kingsHand = new KingsHand(observer);
+
+ // The kings hand should not pass any events before he received one
+ verifyZeroInteractions(observer);
+
+ // Verify if each event is passed on to the observer, nothing less, nothing more.
+ for (final Event event : Event.values()) {
+ kingsHand.onEvent(event);
+ verify(observer, times(1)).onEvent(eq(event));
+ verifyNoMoreInteractions(observer);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/LordBaelishTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/LordBaelishTest.java
new file mode 100644
index 000000000..2432e7b40
--- /dev/null
+++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/LordBaelishTest.java
@@ -0,0 +1,39 @@
+/**
+ * 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.event.aggregator;
+
+/**
+ * Date: 12/12/15 - 10:57 AM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class LordBaelishTest extends EventEmitterTest {
+
+ /**
+ * Create a new test instance, using the correct object factory
+ */
+ public LordBaelishTest() {
+ super(Weekday.FRIDAY, Event.STARK_SIGHTED, LordBaelish::new, LordBaelish::new);
+ }
+
+}
\ No newline at end of file
diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/LordVarysTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/LordVarysTest.java
new file mode 100644
index 000000000..d65c3f8e6
--- /dev/null
+++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/LordVarysTest.java
@@ -0,0 +1,39 @@
+/**
+ * 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.event.aggregator;
+
+/**
+ * Date: 12/12/15 - 10:57 AM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class LordVarysTest extends EventEmitterTest {
+
+ /**
+ * Create a new test instance, using the correct object factory
+ */
+ public LordVarysTest() {
+ super(Weekday.SATURDAY, Event.TRAITOR_DETECTED, LordVarys::new, LordVarys::new);
+ }
+
+}
\ No newline at end of file
diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/ScoutTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/ScoutTest.java
new file mode 100644
index 000000000..701323485
--- /dev/null
+++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/ScoutTest.java
@@ -0,0 +1,39 @@
+/**
+ * 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.event.aggregator;
+
+/**
+ * Date: 12/12/15 - 10:57 AM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class ScoutTest extends EventEmitterTest {
+
+ /**
+ * Create a new test instance, using the correct object factory
+ */
+ public ScoutTest() {
+ super(Weekday.TUESDAY, Event.WARSHIPS_APPROACHING, Scout::new, Scout::new);
+ }
+
+}
\ No newline at end of file
diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/WeekdayTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/WeekdayTest.java
new file mode 100644
index 000000000..1e91aab74
--- /dev/null
+++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/WeekdayTest.java
@@ -0,0 +1,46 @@
+/**
+ * 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.event.aggregator;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Date: 12/12/15 - 2:12 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class WeekdayTest {
+
+ @Test
+ public void testToString() throws Exception {
+ for (final Weekday weekday : Weekday.values()) {
+ final String toString = weekday.toString();
+ assertNotNull(toString);
+ assertEquals(weekday.name(), toString.toUpperCase());
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/event-aggregator/src/test/java/com/iluwatar/eventaggregator/AppTest.java b/event-aggregator/src/test/java/com/iluwatar/eventaggregator/AppTest.java
deleted file mode 100644
index 42710f378..000000000
--- a/event-aggregator/src/test/java/com/iluwatar/eventaggregator/AppTest.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package com.iluwatar.eventaggregator;
-import org.junit.Test;
-
-import com.iluwatar.eventaggregator.App;
-
-public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
-}
diff --git a/event-driven-architecture/README.md b/event-driven-architecture/README.md
new file mode 100644
index 000000000..843e4c268
--- /dev/null
+++ b/event-driven-architecture/README.md
@@ -0,0 +1,37 @@
+---
+layout: pattern
+title: Event Driven Architecture
+folder: event-driven-architecture
+permalink: /patterns/event-driven-architecture/
+categories: Architectural
+tags:
+ - Java
+ - Difficulty-Intermediate
+ - Reactive
+---
+
+## Intent
+Send and notify state changes of your objects to other applications using an Event-driven Architecture.
+
+
+
+## Applicability
+Use an Event-driven architecture when
+
+* you want to create a loosely coupled system
+* you want to build a more responsive system
+* you want a system that is easier to extend
+
+## Real world examples
+
+* SendGrid, an email API, sends events whenever an email is processed, delivered, opened etc... (https://sendgrid.com/docs/API_Reference/Webhooks/event.html)
+* Chargify, a billing API, exposes payment activity through various events (https://docs.chargify.com/api-events)
+* Amazon's AWS Lambda, lets you execute code in response to events such as changes to Amazon S3 buckets, updates to an Amazon DynamoDB table, or custom events generated by your applications or devices. (https://aws.amazon.com/lambda)
+* MySQL runs triggers based on events such as inserts and update events happening on database tables.
+
+## Credits
+
+* [Event-driven architecture - Wikipedia](http://www.computerweekly.com/feature/Write-through-write-around-write-back-Cache-explained)
+* [Fundamental Components of an Event-Driven Architecture](http://giocc.com/fundamental-components-of-an-event-driven-architecture.html)
+* [Real World Applications/Event Driven Applications](https://wiki.haskell.org/Real_World_Applications/Event_Driven_Applications)
+* [Event-driven architecture definition](http://searchsoa.techtarget.com/definition/event-driven-architecture)
diff --git a/event-driven-architecture/etc/eda.png b/event-driven-architecture/etc/eda.png
new file mode 100644
index 000000000..743726451
Binary files /dev/null and b/event-driven-architecture/etc/eda.png differ
diff --git a/event-driven-architecture/etc/eda.ucls b/event-driven-architecture/etc/eda.ucls
new file mode 100644
index 000000000..776bedc81
--- /dev/null
+++ b/event-driven-architecture/etc/eda.ucls
@@ -0,0 +1,184 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/event-driven-architecture/pom.xml b/event-driven-architecture/pom.xml
new file mode 100644
index 000000000..99ed39891
--- /dev/null
+++ b/event-driven-architecture/pom.xml
@@ -0,0 +1,52 @@
+
+
+
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.13.0-SNAPSHOT
+
+
+ event-driven-architecture
+
+
+
+ junit
+ junit
+ test
+
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
\ No newline at end of file
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/App.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/App.java
new file mode 100644
index 000000000..866b3c9e9
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/App.java
@@ -0,0 +1,64 @@
+/**
+ * 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.eda;
+
+import com.iluwatar.eda.event.UserCreatedEvent;
+import com.iluwatar.eda.event.UserUpdatedEvent;
+import com.iluwatar.eda.framework.Event;
+import com.iluwatar.eda.framework.EventDispatcher;
+import com.iluwatar.eda.handler.UserCreatedEventHandler;
+import com.iluwatar.eda.handler.UserUpdatedEventHandler;
+import com.iluwatar.eda.model.User;
+
+/**
+ * An event-driven architecture (EDA) is a framework that orchestrates behavior around the
+ * production, detection and consumption of events as well as the responses they evoke. An event is
+ * any identifiable occurrence that has significance for system hardware or software.
The
+ * example below uses an {@link EventDispatcher} to link/register {@link Event} objects to their
+ * respective handlers once an {@link Event} is dispatched, it's respective handler is invoked and
+ * the {@link Event} is handled accordingly.
+ *
+ */
+public class App {
+
+ /**
+ * Once the {@link EventDispatcher} is initialised, handlers related to specific events have to be
+ * made known to the dispatcher by registering them. In this case the {@link UserCreatedEvent} is
+ * bound to the UserCreatedEventHandler, whilst the {@link UserUpdatedEvent} is bound to the
+ * {@link UserUpdatedEventHandler}. The dispatcher can now be called to dispatch specific events.
+ * When a user is saved, the {@link UserCreatedEvent} can be dispatched.
+ * On the other hand, when a user is updated, {@link UserUpdatedEvent} can be dispatched.
+ *
+ */
+ public static void main(String[] args) {
+
+ EventDispatcher dispatcher = new EventDispatcher();
+ dispatcher.registerHandler(UserCreatedEvent.class, new UserCreatedEventHandler());
+ dispatcher.registerHandler(UserUpdatedEvent.class, new UserUpdatedEventHandler());
+
+ User user = new User("iluwatar");
+ dispatcher.dispatch(new UserCreatedEvent(user));
+ dispatcher.dispatch(new UserUpdatedEvent(user));
+ }
+
+}
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/event/AbstractEvent.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/AbstractEvent.java
new file mode 100644
index 000000000..54a916c7b
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/AbstractEvent.java
@@ -0,0 +1,49 @@
+/**
+ * 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.eda.event;
+
+import com.iluwatar.eda.framework.EventDispatcher;
+import com.iluwatar.eda.framework.Event;
+
+/**
+ * The {@link AbstractEvent} class serves as a base class for defining custom events happening with your
+ * system. In this example we have two types of events defined.
+ *
+ * {@link UserCreatedEvent} - used when a user is created
+ * {@link UserUpdatedEvent} - used when a user is updated
+ *
+ * Events can be distinguished using the {@link #getType() getType} method.
+ */
+public abstract class AbstractEvent implements Event {
+
+ /**
+ * Returns the event type as a {@link Class} object
+ * In this example, this method is used by the {@link EventDispatcher} to
+ * dispatch events depending on their type.
+ *
+ * @return the AbstractEvent type as a {@link Class}.
+ */
+ public Class extends Event> getType() {
+ return getClass();
+ }
+}
\ No newline at end of file
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserCreatedEvent.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserCreatedEvent.java
new file mode 100644
index 000000000..717ed1a9d
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserCreatedEvent.java
@@ -0,0 +1,43 @@
+/**
+ * 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.eda.event;
+
+import com.iluwatar.eda.model.User;
+
+/**
+ * The {@link UserCreatedEvent} should should be dispatched whenever a user has been created.
+ * This class can be extended to contain details about the user has been created. In this example,
+ * the entire {@link User} object is passed on as data with the event.
+ */
+public class UserCreatedEvent extends AbstractEvent {
+
+ private User user;
+
+ public UserCreatedEvent(User user) {
+ this.user = user;
+ }
+
+ public User getUser() {
+ return user;
+ }
+}
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserUpdatedEvent.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserUpdatedEvent.java
new file mode 100644
index 000000000..9646957dc
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserUpdatedEvent.java
@@ -0,0 +1,43 @@
+/**
+ * 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.eda.event;
+
+import com.iluwatar.eda.model.User;
+
+/**
+ * The {@link UserUpdatedEvent} should should be dispatched whenever a user has been updated.
+ * This class can be extended to contain details about the user has been updated. In this example,
+ * the entire {@link User} object is passed on as data with the event.
+ */
+public class UserUpdatedEvent extends AbstractEvent {
+
+ private User user;
+
+ public UserUpdatedEvent(User user) {
+ this.user = user;
+ }
+
+ public User getUser() {
+ return user;
+ }
+}
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Event.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Event.java
new file mode 100644
index 000000000..c63d2746f
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Event.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.eda.framework;
+
+/**
+ * A {@link Event} is an object with a specific type that is associated
+ * to a specific {@link Handler}.
+ */
+public interface Event {
+
+ /**
+ * Returns the message type as a {@link Class} object. In this example the message type is
+ * used to handle events by their type.
+ * @return the message type as a {@link Class}.
+ */
+ Class extends Event> getType();
+}
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/EventDispatcher.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/EventDispatcher.java
new file mode 100644
index 000000000..9f8e29315
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/EventDispatcher.java
@@ -0,0 +1,64 @@
+/**
+ * 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.eda.framework;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Handles the routing of {@link Event} messages to associated handlers.
+ * A {@link HashMap} is used to store the association between events and their respective handlers.
+ */
+public class EventDispatcher {
+
+ private Map, Handler extends Event>> handlers;
+
+ public EventDispatcher() {
+ handlers = new HashMap<>();
+ }
+
+ /**
+ * Links an {@link Event} to a specific {@link Handler}.
+ *
+ * @param eventType The {@link Event} to be registered
+ * @param handler The {@link Handler} that will be handling the {@link Event}
+ */
+ public void registerHandler(Class eventType,
+ Handler handler) {
+ handlers.put(eventType, handler);
+ }
+
+ /**
+ * Dispatches an {@link Event} depending on it's type.
+ *
+ * @param event The {@link Event} to be dispatched
+ */
+ @SuppressWarnings("unchecked")
+ public void dispatch(E event) {
+ Handler handler = (Handler) handlers.get(event.getClass());
+ if (handler != null) {
+ handler.onEvent(event);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Handler.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Handler.java
new file mode 100644
index 000000000..44bdab6dc
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Handler.java
@@ -0,0 +1,38 @@
+/**
+ * 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.eda.framework;
+
+/**
+ * This interface can be implemented to handle different types of messages.
+ * Every handler is responsible for a single of type message
+ */
+public interface Handler {
+
+ /**
+ * The onEvent method should implement and handle behavior related to the event.
+ * This can be as simple as calling another service to handle the event on publishing the event on
+ * a queue to be consumed by other sub systems.
+ * @param event the {@link Event} object to be handled.
+ */
+ void onEvent(E event);
+}
\ No newline at end of file
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserCreatedEventHandler.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserCreatedEventHandler.java
new file mode 100644
index 000000000..3ef4e8255
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserCreatedEventHandler.java
@@ -0,0 +1,40 @@
+/**
+ * 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.eda.handler;
+
+import com.iluwatar.eda.event.UserCreatedEvent;
+import com.iluwatar.eda.framework.Handler;
+
+/**
+ * Handles the {@link UserCreatedEvent} message.
+ */
+public class UserCreatedEventHandler implements Handler {
+
+ @Override
+ public void onEvent(UserCreatedEvent event) {
+
+ System.out.println(String.format(
+ "User '%s' has been Created!", event.getUser().getUsername()));
+ }
+
+}
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserUpdatedEventHandler.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserUpdatedEventHandler.java
new file mode 100644
index 000000000..0311d5781
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserUpdatedEventHandler.java
@@ -0,0 +1,39 @@
+/**
+ * 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.eda.handler;
+
+import com.iluwatar.eda.event.UserUpdatedEvent;
+import com.iluwatar.eda.framework.Handler;
+
+/**
+ * Handles the {@link UserUpdatedEvent} message.
+ */
+public class UserUpdatedEventHandler implements Handler {
+
+ @Override
+ public void onEvent(UserUpdatedEvent event) {
+
+ System.out.println(String.format(
+ "User '%s' has been Updated!", event.getUser().getUsername()));
+ }
+}
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/model/User.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/model/User.java
new file mode 100644
index 000000000..82ef960de
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/model/User.java
@@ -0,0 +1,43 @@
+/**
+ * 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.eda.model;
+
+import com.iluwatar.eda.event.UserCreatedEvent;
+import com.iluwatar.eda.event.UserUpdatedEvent;
+
+/**
+ * This {@link User} class is a basic pojo used to demonstrate user data sent along with
+ * the {@link UserCreatedEvent} and {@link UserUpdatedEvent} events.
+ */
+public class User {
+
+ private String username;
+
+ public User(String username) {
+ this.username = username;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+}
diff --git a/event-driven-architecture/src/test/java/com/iluwatar/eda/AppTest.java b/event-driven-architecture/src/test/java/com/iluwatar/eda/AppTest.java
new file mode 100644
index 000000000..603d0a61b
--- /dev/null
+++ b/event-driven-architecture/src/test/java/com/iluwatar/eda/AppTest.java
@@ -0,0 +1,38 @@
+/**
+ * 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.eda;
+
+import org.junit.Test;
+
+import java.io.IOException;
+
+/**
+ * Tests that Event Driven Architecture example runs without errors.
+ */
+public class AppTest {
+ @Test
+ public void test() throws IOException {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/event-driven-architecture/src/test/java/com/iluwatar/eda/event/UserCreatedEventTest.java b/event-driven-architecture/src/test/java/com/iluwatar/eda/event/UserCreatedEventTest.java
new file mode 100644
index 000000000..b9074faf2
--- /dev/null
+++ b/event-driven-architecture/src/test/java/com/iluwatar/eda/event/UserCreatedEventTest.java
@@ -0,0 +1,46 @@
+/**
+ * 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.eda.event;
+
+import com.iluwatar.eda.model.User;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * {@link UserCreatedEventTest} tests and verifies {@link AbstractEvent} behaviour.
+ */
+public class UserCreatedEventTest {
+
+ /**
+ * This unit test should correctly return the {@link AbstractEvent} class type when calling the
+ * {@link AbstractEvent#getType() getType} method.
+ */
+ @Test
+ public void testGetEventType() {
+ User user = new User("iluwatar");
+ UserCreatedEvent userCreatedEvent = new UserCreatedEvent(user);
+ assertEquals(UserCreatedEvent.class, userCreatedEvent.getType());
+ }
+}
diff --git a/event-driven-architecture/src/test/java/com/iluwatar/eda/framework/EventDispatcherTest.java b/event-driven-architecture/src/test/java/com/iluwatar/eda/framework/EventDispatcherTest.java
new file mode 100644
index 000000000..21956afec
--- /dev/null
+++ b/event-driven-architecture/src/test/java/com/iluwatar/eda/framework/EventDispatcherTest.java
@@ -0,0 +1,70 @@
+/**
+ * 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.eda.framework;
+
+import com.iluwatar.eda.event.UserCreatedEvent;
+import com.iluwatar.eda.event.UserUpdatedEvent;
+import com.iluwatar.eda.handler.UserCreatedEventHandler;
+import com.iluwatar.eda.handler.UserUpdatedEventHandler;
+import com.iluwatar.eda.model.User;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Event Dispatcher unit tests to assert and verify correct event dispatcher behaviour
+ */
+public class EventDispatcherTest {
+
+ /**
+ * This unit test should register events and event handlers correctly with the event dispatcher
+ * and events should be dispatched accordingly.
+ */
+ @Test
+ public void testEventDriverPattern() {
+
+ EventDispatcher dispatcher = spy(new EventDispatcher());
+ UserCreatedEventHandler userCreatedEventHandler = spy(new UserCreatedEventHandler());
+ UserUpdatedEventHandler userUpdatedEventHandler = spy(new UserUpdatedEventHandler());
+ dispatcher.registerHandler(UserCreatedEvent.class, userCreatedEventHandler);
+ dispatcher.registerHandler(UserUpdatedEvent.class, userUpdatedEventHandler);
+
+ User user = new User("iluwatar");
+
+ UserCreatedEvent userCreatedEvent = new UserCreatedEvent(user);
+ UserUpdatedEvent userUpdatedEvent = new UserUpdatedEvent(user);
+
+ //fire a userCreatedEvent and verify that userCreatedEventHandler has been invoked.
+ dispatcher.dispatch(userCreatedEvent);
+ verify(userCreatedEventHandler).onEvent(userCreatedEvent);
+ verify(dispatcher).dispatch(userCreatedEvent);
+
+ //fire a userCreatedEvent and verify that userUpdatedEventHandler has been invoked.
+ dispatcher.dispatch(userUpdatedEvent);
+ verify(userUpdatedEventHandler).onEvent(userUpdatedEvent);
+ verify(dispatcher).dispatch(userUpdatedEvent);
+ }
+
+}
diff --git a/exclude-pmd.properties b/exclude-pmd.properties
new file mode 100644
index 000000000..aeda4353d
--- /dev/null
+++ b/exclude-pmd.properties
@@ -0,0 +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.
+#
+
+com.iluwatar.servicelayer.common.BaseEntity=UnusedPrivateField
+com.iluwatar.doublechecked.locking.App=EmptyStatementNotInLoop,EmptyWhileStmt
+com.iluwatar.doublechecked.locking.InventoryTest=EmptyStatementNotInLoop,EmptyWhileStmt
diff --git a/execute-around/README.md b/execute-around/README.md
new file mode 100644
index 000000000..f669f18ff
--- /dev/null
+++ b/execute-around/README.md
@@ -0,0 +1,27 @@
+---
+layout: pattern
+title: Execute Around
+folder: execute-around
+permalink: /patterns/execute-around/
+categories: Other
+tags:
+ - Java
+ - Difficulty-Beginner
+ - Idiom
+---
+
+## Intent
+Execute Around idiom frees the user from certain actions that
+should always be executed before and after the business method. A good example
+of this is resource allocation and deallocation leaving the user to specify
+only what to do with the resource.
+
+
+
+## Applicability
+Use the Execute Around idiom when
+
+* you use an API that requires methods to be called in pairs such as open/close or allocate/deallocate.
+
+## Credits
+* [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](http://www.amazon.com/Functional-Programming-Java-Harnessing-Expressions/dp/1937785467/ref=sr_1_1)
diff --git a/execute-around/pom.xml b/execute-around/pom.xml
index 1782caf88..60bb6d0ab 100644
--- a/execute-around/pom.xml
+++ b/execute-around/pom.xml
@@ -1,11 +1,35 @@
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
execute-around
diff --git a/execute-around/src/main/java/com/iluwatar/execute/around/App.java b/execute-around/src/main/java/com/iluwatar/execute/around/App.java
new file mode 100644
index 000000000..f8ccebdcf
--- /dev/null
+++ b/execute-around/src/main/java/com/iluwatar/execute/around/App.java
@@ -0,0 +1,55 @@
+/**
+ * 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.execute.around;
+
+import java.io.FileWriter;
+import java.io.IOException;
+
+/**
+ * The Execute Around idiom specifies some code to be executed before and after a method. Typically
+ * the idiom is used when the API has methods to be executed in pairs, such as resource
+ * allocation/deallocation or lock acquisition/release.
+ *
+ * In this example, we have {@link SimpleFileWriter} class that opens and closes the file for the
+ * user. The user specifies only what to do with the file by providing the {@link FileWriterAction}
+ * implementation.
+ *
+ */
+public class App {
+
+ /**
+ * Program entry point
+ */
+ public static void main(String[] args) throws IOException {
+
+ new SimpleFileWriter("testfile.txt", new FileWriterAction() {
+
+ @Override
+ public void writeFile(FileWriter writer) throws IOException {
+ writer.write("Hello");
+ writer.append(" ");
+ writer.append("there!");
+ }
+ });
+ }
+}
diff --git a/execute-around/src/main/java/com/iluwatar/execute/around/FileWriterAction.java b/execute-around/src/main/java/com/iluwatar/execute/around/FileWriterAction.java
new file mode 100644
index 000000000..159786134
--- /dev/null
+++ b/execute-around/src/main/java/com/iluwatar/execute/around/FileWriterAction.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.execute.around;
+
+import java.io.FileWriter;
+import java.io.IOException;
+
+/**
+ *
+ * Interface for specifying what to do with the file resource.
+ *
+ */
+public interface FileWriterAction {
+
+ void writeFile(FileWriter writer) throws IOException;
+
+}
diff --git a/execute-around/src/main/java/com/iluwatar/execute/around/SimpleFileWriter.java b/execute-around/src/main/java/com/iluwatar/execute/around/SimpleFileWriter.java
new file mode 100644
index 000000000..111bad73e
--- /dev/null
+++ b/execute-around/src/main/java/com/iluwatar/execute/around/SimpleFileWriter.java
@@ -0,0 +1,47 @@
+/**
+ * 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.execute.around;
+
+import java.io.FileWriter;
+import java.io.IOException;
+
+/**
+ *
+ * SimpleFileWriter handles opening and closing file for the user. The user only has to specify what
+ * to do with the file resource through {@link FileWriterAction} parameter.
+ *
+ */
+public class SimpleFileWriter {
+
+ /**
+ * Constructor
+ */
+ public SimpleFileWriter(String filename, FileWriterAction action) throws IOException {
+ FileWriter writer = new FileWriter(filename);
+ try {
+ action.writeFile(writer);
+ } finally {
+ writer.close();
+ }
+ }
+}
diff --git a/execute-around/src/main/java/com/iluwatar/executearound/App.java b/execute-around/src/main/java/com/iluwatar/executearound/App.java
deleted file mode 100644
index 783693fac..000000000
--- a/execute-around/src/main/java/com/iluwatar/executearound/App.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.iluwatar.executearound;
-
-import java.io.FileWriter;
-import java.io.IOException;
-
-/**
- * The Execute Around idiom specifies some code to be executed before and after
- * a method. Typically the idiom is used when the API has methods to be executed in
- * pairs, such as resource allocation/deallocation or lock acquisition/release.
- *
- * In this example, we have SimpleFileWriter class that opens and closes the file
- * for the user. The user specifies only what to do with the file by providing the
- * FileWriterAction implementation.
- *
- */
-public class App {
-
- public static void main( String[] args ) throws IOException {
-
- new SimpleFileWriter("testfile.txt", new FileWriterAction() {
-
- @Override
- public void writeFile(FileWriter writer) throws IOException {
- writer.write("Hello");
- writer.append(" ");
- writer.append("there!");
- }
- });
- }
-}
diff --git a/execute-around/src/main/java/com/iluwatar/executearound/FileWriterAction.java b/execute-around/src/main/java/com/iluwatar/executearound/FileWriterAction.java
deleted file mode 100644
index 12eea7f66..000000000
--- a/execute-around/src/main/java/com/iluwatar/executearound/FileWriterAction.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.iluwatar.executearound;
-
-import java.io.FileWriter;
-import java.io.IOException;
-
-/**
- *
- * Interface for specifying what to do with the file resource.
- *
- */
-public interface FileWriterAction {
-
- void writeFile(FileWriter writer) throws IOException;
-
-}
diff --git a/execute-around/src/main/java/com/iluwatar/executearound/SimpleFileWriter.java b/execute-around/src/main/java/com/iluwatar/executearound/SimpleFileWriter.java
deleted file mode 100644
index ee7f23360..000000000
--- a/execute-around/src/main/java/com/iluwatar/executearound/SimpleFileWriter.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.iluwatar.executearound;
-
-import java.io.FileWriter;
-import java.io.IOException;
-
-/**
- *
- * SimpleFileWriter handles opening and closing file for the user. The user
- * only has to specify what to do with the file resource through FileWriterAction
- * parameter.
- *
- */
-public class SimpleFileWriter {
-
- public SimpleFileWriter(String filename, FileWriterAction action) throws IOException {
- FileWriter writer = new FileWriter(filename);
- try {
- action.writeFile(writer);
- } finally {
- writer.close();
- }
- }
-}
diff --git a/execute-around/src/test/java/com/iluwatar/execute/around/AppTest.java b/execute-around/src/test/java/com/iluwatar/execute/around/AppTest.java
new file mode 100644
index 000000000..b74f53a25
--- /dev/null
+++ b/execute-around/src/test/java/com/iluwatar/execute/around/AppTest.java
@@ -0,0 +1,51 @@
+/**
+ * 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.execute.around;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ *
+ * Tests execute-around example.
+ *
+ */
+public class AppTest {
+
+ @Test
+ public void test() throws IOException {
+ String[] args = {};
+ App.main(args);
+ }
+
+ @Before
+ @After
+ public void cleanup() {
+ File file = new File("testfile.txt");
+ file.delete();
+ }
+}
diff --git a/execute-around/src/test/java/com/iluwatar/execute/around/SimpleFileWriterTest.java b/execute-around/src/test/java/com/iluwatar/execute/around/SimpleFileWriterTest.java
new file mode 100644
index 000000000..abad14935
--- /dev/null
+++ b/execute-around/src/test/java/com/iluwatar/execute/around/SimpleFileWriterTest.java
@@ -0,0 +1,96 @@
+/**
+ * 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.execute.around;
+
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Date: 12/12/15 - 3:21 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SimpleFileWriterTest {
+
+ /**
+ * Create a temporary folder, used to generate files in during this test
+ */
+ @Rule
+ public final TemporaryFolder testFolder = new TemporaryFolder();
+
+ /**
+ * Verify if the given writer is not 'null'
+ */
+ @Test
+ public void testWriterNotNull() throws Exception {
+ final File temporaryFile = this.testFolder.newFile();
+ new SimpleFileWriter(temporaryFile.getPath(), Assert::assertNotNull);
+ }
+
+ /**
+ * Test if the {@link SimpleFileWriter} creates a file if it doesn't exist
+ */
+ @Test
+ public void testNonExistentFile() throws Exception {
+ final File nonExistingFile = new File(this.testFolder.getRoot(), "non-existing-file");
+ assertFalse(nonExistingFile.exists());
+
+ new SimpleFileWriter(nonExistingFile.getPath(), Assert::assertNotNull);
+ assertTrue(nonExistingFile.exists());
+ }
+
+ /**
+ * Test if the data written to the file writer actually gets in the file
+ */
+ @Test
+ public void testActualWrite() throws Exception {
+ final String testMessage = "Test message";
+
+ final File temporaryFile = this.testFolder.newFile();
+ assertTrue(temporaryFile.exists());
+
+ new SimpleFileWriter(temporaryFile.getPath(), writer -> writer.write(testMessage));
+ assertTrue(Files.lines(temporaryFile.toPath()).allMatch(testMessage::equals));
+ }
+
+ /**
+ * Verify if an {@link IOException} during the write ripples through
+ */
+ @Test(expected = IOException.class)
+ public void testIoException() throws Exception {
+ final File temporaryFile = this.testFolder.newFile();
+ new SimpleFileWriter(temporaryFile.getPath(), writer -> {
+ throw new IOException("");
+ });
+ }
+
+}
diff --git a/execute-around/src/test/java/com/iluwatar/executearound/AppTest.java b/execute-around/src/test/java/com/iluwatar/executearound/AppTest.java
deleted file mode 100644
index 263595cd8..000000000
--- a/execute-around/src/test/java/com/iluwatar/executearound/AppTest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package com.iluwatar.executearound;
-
-import java.io.File;
-import java.io.IOException;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.iluwatar.executearound.App;
-
-/**
- *
- * Tests execute-around example.
- *
- */
-public class AppTest {
-
- @Test
- public void test() throws IOException {
- String[] args = {};
- App.main(args);
- }
-
- @Before
- @After
- public void cleanup() {
- File file = new File("testfile.txt");
- file.delete();
- }
-}
diff --git a/facade/README.md b/facade/README.md
new file mode 100644
index 000000000..c416552c7
--- /dev/null
+++ b/facade/README.md
@@ -0,0 +1,28 @@
+---
+layout: pattern
+title: Facade
+folder: facade
+permalink: /patterns/facade/
+categories: Structural
+tags:
+ - Java
+ - Gang Of Four
+ - Difficulty-Beginner
+---
+
+## Intent
+Provide a unified interface to a set of interfaces in a subsystem.
+Facade defines a higher-level interface that makes the subsystem easier to use.
+
+
+
+## Applicability
+Use the Facade pattern when
+
+* you want to provide a simple interface to a complex subsystem. Subsystems often get more complex as they evolve. Most patterns, when applied, result in more and smaller classes. This makes the subsystem more reusable and easier to customize, but it also becomes harder to use for clients that don't need to customize it. A facade can provide a simple default view of the subsystem that is good enough for most clients. Only clients needing more customizability will need to look beyond the facade.
+* there are many dependencies between clients and the implementation classes of an abstraction. Introduce a facade to decouple the subsystem from clients and other subsystems, thereby promoting subsystem independence and portability.
+* you want to layer your subsystems. Use a facade to define an entry point to each subsystem level. If subsystems are dependent, the you can simplify the dependencies between them by making them communicate with each other solely through their facades
+
+## Credits
+
+* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/facade/pom.xml b/facade/pom.xml
index b80538341..e0e0f4a4d 100644
--- a/facade/pom.xml
+++ b/facade/pom.xml
@@ -1,11 +1,35 @@
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
facade
@@ -14,5 +38,10 @@
junit
test
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/facade/src/main/java/com/iluwatar/facade/App.java b/facade/src/main/java/com/iluwatar/facade/App.java
index 09d5d1a0b..242bfc9c4 100644
--- a/facade/src/main/java/com/iluwatar/facade/App.java
+++ b/facade/src/main/java/com/iluwatar/facade/App.java
@@ -1,17 +1,51 @@
-package com.iluwatar.facade;
-
-/**
- *
- * Facade (DwarvenGoldmineFacade) provides simpler interface to subsystem.
- * http://en.wikipedia.org/wiki/Facade_pattern
- *
- */
-public class App {
-
- public static void main(String[] args) {
- DwarvenGoldmineFacade facade = new DwarvenGoldmineFacade();
- facade.startNewDay();
- facade.digOutGold();
- facade.endDay();
- }
-}
+/**
+ * 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.facade;
+
+/**
+ *
+ * The Facade design pattern is often used when a system is very complex or difficult to understand
+ * because the system has a large number of interdependent classes or its source code is
+ * unavailable. This pattern hides the complexities of the larger system and provides a simpler
+ * interface to the client. It typically involves a single wrapper class which contains a set of
+ * members required by client. These members access the system on behalf of the facade client and
+ * hide the implementation details.
+ *
+ * In this example the Facade is ({@link DwarvenGoldmineFacade}) and it provides a simpler interface
+ * to the goldmine subsystem.
+ *
+ */
+public class App {
+
+ /**
+ * Program entry point
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ DwarvenGoldmineFacade facade = new DwarvenGoldmineFacade();
+ facade.startNewDay();
+ facade.digOutGold();
+ facade.endDay();
+ }
+}
diff --git a/facade/src/main/java/com/iluwatar/facade/DwarvenCartOperator.java b/facade/src/main/java/com/iluwatar/facade/DwarvenCartOperator.java
index 7c33fd267..bdc839f57 100644
--- a/facade/src/main/java/com/iluwatar/facade/DwarvenCartOperator.java
+++ b/facade/src/main/java/com/iluwatar/facade/DwarvenCartOperator.java
@@ -1,3 +1,25 @@
+/**
+ * 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.facade;
/**
@@ -7,14 +29,13 @@ package com.iluwatar.facade;
*/
public class DwarvenCartOperator extends DwarvenMineWorker {
- @Override
- public void work() {
- System.out.println(name() + " moves gold chunks out of the mine.");
- }
-
- @Override
- public String name() {
- return "Dwarf cart operator";
- }
+ @Override
+ public void work() {
+ System.out.println(name() + " moves gold chunks out of the mine.");
+ }
+ @Override
+ public String name() {
+ return "Dwarf cart operator";
+ }
}
diff --git a/facade/src/main/java/com/iluwatar/facade/DwarvenGoldDigger.java b/facade/src/main/java/com/iluwatar/facade/DwarvenGoldDigger.java
index b503889b7..54fa821f4 100644
--- a/facade/src/main/java/com/iluwatar/facade/DwarvenGoldDigger.java
+++ b/facade/src/main/java/com/iluwatar/facade/DwarvenGoldDigger.java
@@ -1,3 +1,25 @@
+/**
+ * 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.facade;
/**
@@ -7,14 +29,13 @@ package com.iluwatar.facade;
*/
public class DwarvenGoldDigger extends DwarvenMineWorker {
- @Override
- public void work() {
- System.out.println(name() + " digs for gold.");
- }
-
- @Override
- public String name() {
- return "Dwarf gold digger";
- }
+ @Override
+ public void work() {
+ System.out.println(name() + " digs for gold.");
+ }
+ @Override
+ public String name() {
+ return "Dwarf gold digger";
+ }
}
diff --git a/facade/src/main/java/com/iluwatar/facade/DwarvenGoldmineFacade.java b/facade/src/main/java/com/iluwatar/facade/DwarvenGoldmineFacade.java
index 83a989fa7..4f6e3be4c 100644
--- a/facade/src/main/java/com/iluwatar/facade/DwarvenGoldmineFacade.java
+++ b/facade/src/main/java/com/iluwatar/facade/DwarvenGoldmineFacade.java
@@ -1,3 +1,25 @@
+/**
+ * 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.facade;
import java.util.ArrayList;
@@ -6,40 +28,42 @@ import java.util.List;
/**
*
- * DwarvenGoldmineFacade provides a single interface
- * through which users can operate the subsystems.
+ * DwarvenGoldmineFacade provides a single interface through which users can operate the subsystems.
*
- * This makes the goldmine easier to operate and
- * cuts the dependencies from the goldmine user to
- * the subsystems.
+ * This makes the goldmine easier to operate and cuts the dependencies from the goldmine user to the
+ * subsystems.
*
*/
public class DwarvenGoldmineFacade {
- private final List workers;
+ private final List workers;
- public DwarvenGoldmineFacade() {
- workers = new ArrayList<>();
- workers.add(new DwarvenGoldDigger());
- workers.add(new DwarvenCartOperator());
- workers.add(new DwarvenTunnelDigger());
- }
+ /**
+ * Constructor
+ */
+ public DwarvenGoldmineFacade() {
+ workers = new ArrayList<>();
+ workers.add(new DwarvenGoldDigger());
+ workers.add(new DwarvenCartOperator());
+ workers.add(new DwarvenTunnelDigger());
+ }
- public void startNewDay() {
- makeActions(workers, DwarvenMineWorker.Action.WAKE_UP, DwarvenMineWorker.Action.GO_TO_MINE);
- }
+ public void startNewDay() {
+ makeActions(workers, DwarvenMineWorker.Action.WAKE_UP, DwarvenMineWorker.Action.GO_TO_MINE);
+ }
- public void digOutGold() {
- makeActions(workers, DwarvenMineWorker.Action.WORK);
- }
+ public void digOutGold() {
+ makeActions(workers, DwarvenMineWorker.Action.WORK);
+ }
- public void endDay() {
- makeActions(workers, DwarvenMineWorker.Action.GO_HOME, DwarvenMineWorker.Action.GO_TO_SLEEP);
- }
+ public void endDay() {
+ makeActions(workers, DwarvenMineWorker.Action.GO_HOME, DwarvenMineWorker.Action.GO_TO_SLEEP);
+ }
- private void makeActions(Collection workers, DwarvenMineWorker.Action... actions) {
- for (DwarvenMineWorker worker : workers) {
- worker.action(actions);
- }
+ private static void makeActions(Collection workers,
+ DwarvenMineWorker.Action... actions) {
+ for (DwarvenMineWorker worker : workers) {
+ worker.action(actions);
}
+ }
}
diff --git a/facade/src/main/java/com/iluwatar/facade/DwarvenMineWorker.java b/facade/src/main/java/com/iluwatar/facade/DwarvenMineWorker.java
index 3dd51f907..f27054c53 100644
--- a/facade/src/main/java/com/iluwatar/facade/DwarvenMineWorker.java
+++ b/facade/src/main/java/com/iluwatar/facade/DwarvenMineWorker.java
@@ -1,3 +1,25 @@
+/**
+ * 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.facade;
/**
@@ -7,56 +29,59 @@ package com.iluwatar.facade;
*/
public abstract class DwarvenMineWorker {
- public void goToSleep() {
- System.out.println(name() + " goes to sleep.");
- }
+ public void goToSleep() {
+ System.out.println(name() + " goes to sleep.");
+ }
- public void wakeUp() {
- System.out.println(name() + " wakes up.");
- }
+ public void wakeUp() {
+ System.out.println(name() + " wakes up.");
+ }
- public void goHome() {
- System.out.println(name() + " goes home.");
- }
+ public void goHome() {
+ System.out.println(name() + " goes home.");
+ }
- public void goToMine() {
- System.out.println(name() + " goes to the mine.");
- }
+ public void goToMine() {
+ System.out.println(name() + " goes to the mine.");
+ }
- private void action(Action action) {
- switch (action) {
- case GO_TO_SLEEP:
- goToSleep();
- break;
- case WAKE_UP:
- wakeUp();
- break;
- case GO_HOME:
- goHome();
- break;
- case GO_TO_MINE:
- goToMine();
- break;
- case WORK:
- work();
- break;
- default:
- System.out.println("Undefined action");
- break;
- }
+ private void action(Action action) {
+ switch (action) {
+ case GO_TO_SLEEP:
+ goToSleep();
+ break;
+ case WAKE_UP:
+ wakeUp();
+ break;
+ case GO_HOME:
+ goHome();
+ break;
+ case GO_TO_MINE:
+ goToMine();
+ break;
+ case WORK:
+ work();
+ break;
+ default:
+ System.out.println("Undefined action");
+ break;
}
+ }
- public void action(Action... actions) {
- for (Action action : actions) {
- action(action);
- }
+ /**
+ * Perform actions
+ */
+ public void action(Action... actions) {
+ for (Action action : actions) {
+ action(action);
}
+ }
- public abstract void work();
+ public abstract void work();
- public abstract String name();
+ public abstract String name();
- static enum Action {
- GO_TO_SLEEP, WAKE_UP, GO_HOME, GO_TO_MINE, WORK
- }
+ static enum Action {
+ GO_TO_SLEEP, WAKE_UP, GO_HOME, GO_TO_MINE, WORK
+ }
}
diff --git a/facade/src/main/java/com/iluwatar/facade/DwarvenTunnelDigger.java b/facade/src/main/java/com/iluwatar/facade/DwarvenTunnelDigger.java
index 05fe02fb6..74d8b89cc 100644
--- a/facade/src/main/java/com/iluwatar/facade/DwarvenTunnelDigger.java
+++ b/facade/src/main/java/com/iluwatar/facade/DwarvenTunnelDigger.java
@@ -1,3 +1,25 @@
+/**
+ * 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.facade;
/**
@@ -7,14 +29,13 @@ package com.iluwatar.facade;
*/
public class DwarvenTunnelDigger extends DwarvenMineWorker {
- @Override
- public void work() {
- System.out.println(name() + " creates another promising tunnel.");
- }
-
- @Override
- public String name() {
- return "Dwarven tunnel digger";
- }
+ @Override
+ public void work() {
+ System.out.println(name() + " creates another promising tunnel.");
+ }
+ @Override
+ public String name() {
+ return "Dwarven tunnel digger";
+ }
}
diff --git a/facade/src/test/java/com/iluwatar/facade/AppTest.java b/facade/src/test/java/com/iluwatar/facade/AppTest.java
index b32b16bb1..115fcc405 100644
--- a/facade/src/test/java/com/iluwatar/facade/AppTest.java
+++ b/facade/src/test/java/com/iluwatar/facade/AppTest.java
@@ -1,14 +1,39 @@
-package com.iluwatar.facade;
-
-import org.junit.Test;
-
-import com.iluwatar.facade.App;
-
-public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
-}
+/**
+ * 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.facade;
+
+import org.junit.Test;
+
+/**
+ *
+ * Application test
+ *
+ */
+public class AppTest {
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java b/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java
new file mode 100644
index 000000000..4a3b218e2
--- /dev/null
+++ b/facade/src/test/java/com/iluwatar/facade/DwarvenGoldmineFacadeTest.java
@@ -0,0 +1,125 @@
+/**
+ * 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.facade;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.PrintStream;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.internal.verification.VerificationModeFactory.times;
+
+/**
+ * Date: 12/9/15 - 9:40 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class DwarvenGoldmineFacadeTest {
+
+ /**
+ * The mocked standard out {@link PrintStream}, required since the actions on the gold mine facade
+ * don't have any influence on any other accessible objects, except for writing to std-out using
+ * {@link System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * Test a complete day cycle in the gold mine by executing all three different steps: {@link
+ * DwarvenGoldmineFacade#startNewDay()}, {@link DwarvenGoldmineFacade#digOutGold()} and {@link
+ * DwarvenGoldmineFacade#endDay()}.
+ *
+ * See if the workers are doing what's expected from them on each step.
+ */
+ @Test
+ public void testFullWorkDay() {
+ final DwarvenGoldmineFacade goldMine = new DwarvenGoldmineFacade();
+ goldMine.startNewDay();
+
+ // On the start of a day, all workers should wake up ...
+ verify(this.stdOutMock, times(1)).println(eq("Dwarf gold digger wakes up."));
+ verify(this.stdOutMock, times(1)).println(eq("Dwarf cart operator wakes up."));
+ verify(this.stdOutMock, times(1)).println(eq("Dwarven tunnel digger wakes up."));
+
+ // ... and go to the mine
+ verify(this.stdOutMock, times(1)).println(eq("Dwarf gold digger goes to the mine."));
+ verify(this.stdOutMock, times(1)).println(eq("Dwarf cart operator goes to the mine."));
+ verify(this.stdOutMock, times(1)).println(eq("Dwarven tunnel digger goes to the mine."));
+
+ // No other actions were invoked, so the workers shouldn't have done (printed) anything else
+ verifyNoMoreInteractions(this.stdOutMock);
+
+ // Now do some actual work, start digging gold!
+ goldMine.digOutGold();
+
+ // Since we gave the dig command, every worker should be doing it's job ...
+ verify(this.stdOutMock, times(1)).println(eq("Dwarf gold digger digs for gold."));
+ verify(this.stdOutMock, times(1)).println(eq("Dwarf cart operator moves gold chunks out of the mine."));
+ verify(this.stdOutMock, times(1)).println(eq("Dwarven tunnel digger creates another promising tunnel."));
+
+ // Again, they shouldn't be doing anything else.
+ verifyNoMoreInteractions(this.stdOutMock);
+
+ // Enough gold, lets end the day.
+ goldMine.endDay();
+
+ // Check if the workers go home ...
+ verify(this.stdOutMock, times(1)).println(eq("Dwarf gold digger goes home."));
+ verify(this.stdOutMock, times(1)).println(eq("Dwarf cart operator goes home."));
+ verify(this.stdOutMock, times(1)).println(eq("Dwarven tunnel digger goes home."));
+
+ // ... and go to sleep. We need well rested workers the next day :)
+ verify(this.stdOutMock, times(1)).println(eq("Dwarf gold digger goes to sleep."));
+ verify(this.stdOutMock, times(1)).println(eq("Dwarf cart operator goes to sleep."));
+ verify(this.stdOutMock, times(1)).println(eq("Dwarven tunnel digger goes to sleep."));
+
+ // Every worker should be sleeping now, no other actions allowed
+ verifyNoMoreInteractions(this.stdOutMock);
+ }
+
+}
diff --git a/factory-kit/README.md b/factory-kit/README.md
new file mode 100644
index 000000000..c25701047
--- /dev/null
+++ b/factory-kit/README.md
@@ -0,0 +1,28 @@
+---
+layout: pattern
+title: Factory Kit
+folder: factory-kit
+permalink: /patterns/factory-kit/
+categories: Creational
+tags:
+ - Java
+ - Difficulty-Beginner
+ - Functional
+---
+
+## Intent
+Define a factory of immutable content with separated builder and factory interfaces.
+
+
+
+## Applicability
+Use the Factory Kit pattern when
+
+* a class can't anticipate the class of objects it must create
+* you just want a new instance of a custom builder instead of the global one
+* you explicitly want to define types of objects, that factory can build
+* you want a separated builder and creator interface
+
+## Credits
+
+* [Design Pattern Reloaded by Remi Forax: ](https://www.youtube.com/watch?v=-k2X7guaArU)
diff --git a/factory-kit/etc/factory-kit.png b/factory-kit/etc/factory-kit.png
new file mode 100644
index 000000000..7093193cb
Binary files /dev/null and b/factory-kit/etc/factory-kit.png differ
diff --git a/factory-kit/etc/factory-kit.ucls b/factory-kit/etc/factory-kit.ucls
new file mode 100644
index 000000000..403fb7e27
--- /dev/null
+++ b/factory-kit/etc/factory-kit.ucls
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/factory-kit/pom.xml b/factory-kit/pom.xml
new file mode 100644
index 000000000..6c936de5c
--- /dev/null
+++ b/factory-kit/pom.xml
@@ -0,0 +1,48 @@
+
+
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.13.0-SNAPSHOT
+
+ factory-kit
+
+
+ junit
+ junit
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
\ No newline at end of file
diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/App.java b/factory-kit/src/main/java/com/iluwatar/factorykit/App.java
new file mode 100644
index 000000000..f27bee170
--- /dev/null
+++ b/factory-kit/src/main/java/com/iluwatar/factorykit/App.java
@@ -0,0 +1,54 @@
+/**
+ * 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.factorykit;
+
+/**
+ * Factory-kit is a creational pattern which defines a factory of immutable content
+ * with separated builder and factory interfaces to deal with the problem of
+ * creating one of the objects specified directly in the factory-kit instance.
+ *
+ *
+ * In the given example {@link WeaponFactory} represents the factory-kit, that contains
+ * four {@link Builder}s for creating new objects of
+ * the classes implementing {@link Weapon} interface.
+ * Each of them can be called with {@link WeaponFactory#create(WeaponType)} method, with
+ * an input representing an instance of {@link WeaponType} that needs to
+ * be mapped explicitly with desired class type in the factory instance.
+ */
+public class App {
+ /**
+ * Program entry point.
+ *
+ * @param args @param args command line args
+ */
+ public static void main(String[] args) {
+ WeaponFactory factory = WeaponFactory.factory(builder -> {
+ builder.add(WeaponType.SWORD, Sword::new);
+ builder.add(WeaponType.AXE, Axe::new);
+ builder.add(WeaponType.SPEAR, Spear::new);
+ builder.add(WeaponType.BOW, Bow::new);
+ });
+ Weapon axe = factory.create(WeaponType.AXE);
+ System.out.println(axe);
+ }
+}
diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/Axe.java b/factory-kit/src/main/java/com/iluwatar/factorykit/Axe.java
new file mode 100644
index 000000000..826a1f9ec
--- /dev/null
+++ b/factory-kit/src/main/java/com/iluwatar/factorykit/Axe.java
@@ -0,0 +1,30 @@
+/**
+ * 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.factorykit;
+
+public class Axe implements Weapon {
+ @Override
+ public String toString() {
+ return "Axe";
+ }
+}
diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/Bow.java b/factory-kit/src/main/java/com/iluwatar/factorykit/Bow.java
new file mode 100644
index 000000000..5aa952c3d
--- /dev/null
+++ b/factory-kit/src/main/java/com/iluwatar/factorykit/Bow.java
@@ -0,0 +1,30 @@
+/**
+ * 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.factorykit;
+
+public class Bow implements Weapon {
+ @Override
+ public String toString() {
+ return "Bow";
+ }
+}
diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/Builder.java b/factory-kit/src/main/java/com/iluwatar/factorykit/Builder.java
new file mode 100644
index 000000000..1049c7b6f
--- /dev/null
+++ b/factory-kit/src/main/java/com/iluwatar/factorykit/Builder.java
@@ -0,0 +1,32 @@
+/**
+ * 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.factorykit;
+
+import java.util.function.Supplier;
+
+/**
+ * Functional interface that allows adding builder with name to the factory.
+ */
+public interface Builder {
+ void add(WeaponType name, Supplier supplier);
+}
diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/Spear.java b/factory-kit/src/main/java/com/iluwatar/factorykit/Spear.java
new file mode 100644
index 000000000..c32811e8c
--- /dev/null
+++ b/factory-kit/src/main/java/com/iluwatar/factorykit/Spear.java
@@ -0,0 +1,30 @@
+/**
+ * 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.factorykit;
+
+public class Spear implements Weapon {
+ @Override
+ public String toString() {
+ return "Spear";
+ }
+}
diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/Sword.java b/factory-kit/src/main/java/com/iluwatar/factorykit/Sword.java
new file mode 100644
index 000000000..208cd6bbb
--- /dev/null
+++ b/factory-kit/src/main/java/com/iluwatar/factorykit/Sword.java
@@ -0,0 +1,30 @@
+/**
+ * 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.factorykit;
+
+public class Sword implements Weapon {
+ @Override
+ public String toString() {
+ return "Sword";
+ }
+}
diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/Weapon.java b/factory-kit/src/main/java/com/iluwatar/factorykit/Weapon.java
new file mode 100644
index 000000000..3d668e352
--- /dev/null
+++ b/factory-kit/src/main/java/com/iluwatar/factorykit/Weapon.java
@@ -0,0 +1,29 @@
+/**
+ * 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.factorykit;
+
+/**
+ * Interface representing weapon.
+ */
+public interface Weapon {
+}
diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/WeaponFactory.java b/factory-kit/src/main/java/com/iluwatar/factorykit/WeaponFactory.java
new file mode 100644
index 000000000..80a6fd9d3
--- /dev/null
+++ b/factory-kit/src/main/java/com/iluwatar/factorykit/WeaponFactory.java
@@ -0,0 +1,55 @@
+/**
+ * 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.factorykit;
+
+import java.util.HashMap;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * Functional interface, an example of the factory-kit design pattern.
+ * Instance created locally gives an opportunity to strictly define
+ * which objects types the instance of a factory will be able to create.
+ * Factory is a placeholder for {@link Builder}s
+ * with {@link WeaponFactory#create(WeaponType)} method to initialize new objects.
+ */
+public interface WeaponFactory {
+
+ /**
+ * Creates an instance of the given type.
+ * @param name representing enum of an object type to be created.
+ * @return new instance of a requested class implementing {@link Weapon} interface.
+ */
+ Weapon create(WeaponType name);
+
+ /**
+ * Creates factory - placeholder for specified {@link Builder}s.
+ * @param consumer for the new builder to the factory.
+ * @return factory with specified {@link Builder}s
+ */
+ static WeaponFactory factory(Consumer consumer) {
+ HashMap> map = new HashMap<>();
+ consumer.accept(map::put);
+ return name -> map.get(name).get();
+ }
+}
diff --git a/factory-kit/src/main/java/com/iluwatar/factorykit/WeaponType.java b/factory-kit/src/main/java/com/iluwatar/factorykit/WeaponType.java
new file mode 100644
index 000000000..283f252de
--- /dev/null
+++ b/factory-kit/src/main/java/com/iluwatar/factorykit/WeaponType.java
@@ -0,0 +1,30 @@
+/**
+ * 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.factorykit;
+
+/**
+ * Enumerates {@link Weapon} types
+ */
+public enum WeaponType {
+ SWORD, AXE, BOW, SPEAR
+}
diff --git a/factory-kit/src/test/java/com/iluwatar/factorykit/app/AppTest.java b/factory-kit/src/test/java/com/iluwatar/factorykit/app/AppTest.java
new file mode 100644
index 000000000..036326d97
--- /dev/null
+++ b/factory-kit/src/test/java/com/iluwatar/factorykit/app/AppTest.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.factorykit.app;
+
+import com.iluwatar.factorykit.App;
+import org.junit.Test;
+
+public class AppTest {
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
+}
+
diff --git a/factory-kit/src/test/java/com/iluwatar/factorykit/factorykit/FactoryKitTest.java b/factory-kit/src/test/java/com/iluwatar/factorykit/factorykit/FactoryKitTest.java
new file mode 100644
index 000000000..c57bee3e3
--- /dev/null
+++ b/factory-kit/src/test/java/com/iluwatar/factorykit/factorykit/FactoryKitTest.java
@@ -0,0 +1,81 @@
+/**
+ * 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.factorykit.factorykit;
+
+import com.iluwatar.factorykit.*;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+
+public class FactoryKitTest {
+
+ private WeaponFactory factory;
+
+ @Before
+ public void init() {
+ factory = WeaponFactory.factory(builder -> {
+ builder.add(WeaponType.SPEAR, Spear::new);
+ builder.add(WeaponType.AXE, Axe::new);
+ builder.add(WeaponType.SWORD, Sword::new);
+ });
+ }
+
+ /**
+ * Testing {@link WeaponFactory} to produce a SPEAR asserting that the Weapon is an instance of {@link Spear}
+ */
+ @Test
+ public void testSpearWeapon() {
+ Weapon weapon = factory.create(WeaponType.SPEAR);
+ verifyWeapon(weapon, Spear.class);
+ }
+
+ /**
+ * Testing {@link WeaponFactory} to produce a AXE asserting that the Weapon is an instance of {@link Axe}
+ */
+ @Test
+ public void testAxeWeapon() {
+ Weapon weapon = factory.create(WeaponType.AXE);
+ verifyWeapon(weapon, Axe.class);
+ }
+
+
+ /**
+ * Testing {@link WeaponFactory} to produce a SWORD asserting that the Weapon is an instance of {@link Sword}
+ */
+ @Test
+ public void testWeapon() {
+ Weapon weapon = factory.create(WeaponType.SWORD);
+ verifyWeapon(weapon, Sword.class);
+ }
+
+ /**
+ * This method asserts that the weapon object that is passed is an instance of the clazz
+ *
+ * @param weapon weapon object which is to be verified
+ * @param clazz expected class of the weapon
+ */
+ private void verifyWeapon(Weapon weapon, Class clazz) {
+ assertTrue("Weapon must be an object of: " + clazz.getName(), clazz.isInstance(weapon));
+ }
+}
diff --git a/factory-method/README.md b/factory-method/README.md
new file mode 100644
index 000000000..05549cf4f
--- /dev/null
+++ b/factory-method/README.md
@@ -0,0 +1,38 @@
+---
+layout: pattern
+title: Factory Method
+folder: factory-method
+permalink: /patterns/factory-method/
+categories: Creational
+tags:
+ - Java
+ - Difficulty-Beginner
+ - Gang Of Four
+---
+
+## Also known as
+Virtual Constructor
+
+## Intent
+Define an interface for creating an object, but let subclasses
+decide which class to instantiate. Factory Method lets a class defer
+instantiation to subclasses.
+
+
+
+## Applicability
+Use the Factory Method pattern when
+
+* a class can't anticipate the class of objects it must create
+* a class wants its subclasses to specify the objects it creates
+* classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate
+
+## Known uses
+
+* java.util.Calendar
+* java.util.ResourceBundle
+* java.text.NumberFormat#getInstance()
+
+## Credits
+
+* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/factory-method/etc/factory-method.ucls b/factory-method/etc/factory-method.ucls
index 6f270fd18..562437995 100644
--- a/factory-method/etc/factory-method.ucls
+++ b/factory-method/etc/factory-method.ucls
@@ -1,8 +1,8 @@
-
-
+
@@ -20,8 +21,9 @@
-
+
@@ -29,8 +31,8 @@
-
+
@@ -38,8 +40,8 @@
-
+
@@ -47,8 +49,8 @@
-
+
@@ -56,8 +58,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/factory-method/pom.xml b/factory-method/pom.xml
index 9f4c79c15..5081ecf99 100644
--- a/factory-method/pom.xml
+++ b/factory-method/pom.xml
@@ -1,11 +1,35 @@
+
4.0.0
com.iluwatar
java-design-patterns
- 1.1.0
+ 1.13.0-SNAPSHOT
factory-method
@@ -14,5 +38,10 @@
junit
test
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/App.java b/factory-method/src/main/java/com/iluwatar/factory/method/App.java
new file mode 100644
index 000000000..cd7a6e6e7
--- /dev/null
+++ b/factory-method/src/main/java/com/iluwatar/factory/method/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.factory.method;
+
+/**
+ *
+ * The Factory Method is a creational design pattern which uses factory methods to deal with the
+ * problem of creating objects without specifying the exact class of object that will be created.
+ * This is done by creating objects via calling a factory method either specified in an interface
+ * and implemented by child classes, or implemented in a base class and optionally overridden by
+ * derived classes—rather than by calling a constructor.
+ *
+ * In this Factory Method example we have an interface ({@link Blacksmith}) with a method for
+ * creating objects ({@link Blacksmith#manufactureWeapon}). The concrete subclasses (
+ * {@link OrcBlacksmith}, {@link ElfBlacksmith}) then override the method to produce objects of
+ * their liking.
+ *
+ */
+public class App {
+
+ private final Blacksmith blacksmith;
+
+ /**
+ * Creates an instance of App
which will use blacksmith
to manufacture
+ * the weapons for war.
+ * App
is unaware which concrete implementation of {@link Blacksmith} it is using.
+ * The decision of which blacksmith implementation to use may depend on configuration, or
+ * the type of rival in war.
+ * @param blacksmith a non-null implementation of blacksmith
+ */
+ public App(Blacksmith blacksmith) {
+ this.blacksmith = blacksmith;
+ }
+
+ /**
+ * Program entry point
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ // Lets go to war with Orc weapons
+ App app = new App(new OrcBlacksmith());
+ app.manufactureWeapons();
+
+ // Lets go to war with Elf weapons
+ app = new App(new ElfBlacksmith());
+ app.manufactureWeapons();
+ }
+
+ private void manufactureWeapons() {
+ Weapon weapon;
+ weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
+ System.out.println(weapon);
+ weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
+ System.out.println(weapon);
+ }
+}
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/Blacksmith.java b/factory-method/src/main/java/com/iluwatar/factory/method/Blacksmith.java
new file mode 100644
index 000000000..9d90bebbc
--- /dev/null
+++ b/factory-method/src/main/java/com/iluwatar/factory/method/Blacksmith.java
@@ -0,0 +1,34 @@
+/**
+ * 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.factory.method;
+
+/**
+ *
+ * The interface containing method for producing objects.
+ *
+ */
+public interface Blacksmith {
+
+ Weapon manufactureWeapon(WeaponType weaponType);
+
+}
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/ElfBlacksmith.java b/factory-method/src/main/java/com/iluwatar/factory/method/ElfBlacksmith.java
new file mode 100644
index 000000000..52844691f
--- /dev/null
+++ b/factory-method/src/main/java/com/iluwatar/factory/method/ElfBlacksmith.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.factory.method;
+
+/**
+ *
+ * Concrete subclass for creating new objects.
+ *
+ */
+public class ElfBlacksmith implements Blacksmith {
+
+ public Weapon manufactureWeapon(WeaponType weaponType) {
+ return new ElfWeapon(weaponType);
+ }
+
+}
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/ElfWeapon.java b/factory-method/src/main/java/com/iluwatar/factory/method/ElfWeapon.java
new file mode 100644
index 000000000..c06674d49
--- /dev/null
+++ b/factory-method/src/main/java/com/iluwatar/factory/method/ElfWeapon.java
@@ -0,0 +1,45 @@
+/**
+ * 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.factory.method;
+
+/**
+ * ElfWeapon.
+ */
+public class ElfWeapon implements Weapon {
+
+ private WeaponType weaponType;
+
+ public ElfWeapon(WeaponType weaponType) {
+ this.weaponType = weaponType;
+ }
+
+ @Override
+ public String toString() {
+ return "Elven " + weaponType;
+ }
+
+ @Override
+ public WeaponType getWeaponType() {
+ return weaponType;
+ }
+}
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/OrcBlacksmith.java b/factory-method/src/main/java/com/iluwatar/factory/method/OrcBlacksmith.java
new file mode 100644
index 000000000..75247f4a2
--- /dev/null
+++ b/factory-method/src/main/java/com/iluwatar/factory/method/OrcBlacksmith.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.factory.method;
+
+/**
+ *
+ * Concrete subclass for creating new objects.
+ *
+ */
+public class OrcBlacksmith implements Blacksmith {
+
+ public Weapon manufactureWeapon(WeaponType weaponType) {
+ return new OrcWeapon(weaponType);
+ }
+}
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/OrcWeapon.java b/factory-method/src/main/java/com/iluwatar/factory/method/OrcWeapon.java
new file mode 100644
index 000000000..abae770ed
--- /dev/null
+++ b/factory-method/src/main/java/com/iluwatar/factory/method/OrcWeapon.java
@@ -0,0 +1,45 @@
+/**
+ * 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.factory.method;
+
+/**
+ * OrcWeapon.
+ */
+public class OrcWeapon implements Weapon {
+
+ private WeaponType weaponType;
+
+ public OrcWeapon(WeaponType weaponType) {
+ this.weaponType = weaponType;
+ }
+
+ @Override
+ public String toString() {
+ return "Orcish " + weaponType;
+ }
+
+ @Override
+ public WeaponType getWeaponType() {
+ return weaponType;
+ }
+}
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/Weapon.java b/factory-method/src/main/java/com/iluwatar/factory/method/Weapon.java
new file mode 100644
index 000000000..d9c8cac0c
--- /dev/null
+++ b/factory-method/src/main/java/com/iluwatar/factory/method/Weapon.java
@@ -0,0 +1,32 @@
+/**
+ * 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.factory.method;
+
+/**
+ * Weapon interface.
+ */
+public interface Weapon {
+
+ WeaponType getWeaponType();
+
+}
diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/WeaponType.java b/factory-method/src/main/java/com/iluwatar/factory/method/WeaponType.java
new file mode 100644
index 000000000..34921ae5c
--- /dev/null
+++ b/factory-method/src/main/java/com/iluwatar/factory/method/WeaponType.java
@@ -0,0 +1,44 @@
+/**
+ * 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.factory.method;
+
+/**
+ *
+ * WeaponType enumeration
+ *
+ */
+public enum WeaponType {
+
+ SHORT_SWORD("short sword"), SPEAR("spear"), AXE("axe"), UNDEFINED("");
+
+ private String title;
+
+ WeaponType(String title) {
+ this.title = title;
+ }
+
+ @Override
+ public String toString() {
+ return title;
+ }
+}
diff --git a/factory-method/src/main/java/com/iluwatar/factorymethod/App.java b/factory-method/src/main/java/com/iluwatar/factorymethod/App.java
deleted file mode 100644
index 90d14dfb0..000000000
--- a/factory-method/src/main/java/com/iluwatar/factorymethod/App.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.iluwatar.factorymethod;
-
-/**
- *
- * In Factory Method we have an interface (Blacksmith) with a method for
- * creating objects (manufactureWeapon). The concrete subclasses (OrcBlacksmith,
- * ElfBlacksmith) then override the method to produce objects of their liking.
- *
- */
-public class App {
-
- public static void main(String[] args) {
- Blacksmith blacksmith;
- Weapon weapon;
-
- blacksmith = new OrcBlacksmith();
- weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
- System.out.println(weapon);
- weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
- System.out.println(weapon);
-
- blacksmith = new ElfBlacksmith();
- weapon = blacksmith.manufactureWeapon(WeaponType.SHORT_SWORD);
- System.out.println(weapon);
- weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
- System.out.println(weapon);
- }
-}
diff --git a/factory-method/src/main/java/com/iluwatar/factorymethod/Blacksmith.java b/factory-method/src/main/java/com/iluwatar/factorymethod/Blacksmith.java
deleted file mode 100644
index b18a5c6df..000000000
--- a/factory-method/src/main/java/com/iluwatar/factorymethod/Blacksmith.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.iluwatar.factorymethod;
-
-/**
- *
- * The interface containing method for producing objects.
- *
- */
-public interface Blacksmith {
-
- Weapon manufactureWeapon(WeaponType weaponType);
-
-}
diff --git a/factory-method/src/main/java/com/iluwatar/factorymethod/ElfBlacksmith.java b/factory-method/src/main/java/com/iluwatar/factorymethod/ElfBlacksmith.java
deleted file mode 100644
index 21c6aacdf..000000000
--- a/factory-method/src/main/java/com/iluwatar/factorymethod/ElfBlacksmith.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.iluwatar.factorymethod;
-
-/**
- *
- * Concrete subclass for creating new objects.
- *
- */
-public class ElfBlacksmith implements Blacksmith {
-
- public Weapon manufactureWeapon(WeaponType weaponType) {
- return new ElfWeapon(weaponType);
- }
-
-}
diff --git a/factory-method/src/main/java/com/iluwatar/factorymethod/ElfWeapon.java b/factory-method/src/main/java/com/iluwatar/factorymethod/ElfWeapon.java
deleted file mode 100644
index 7e90f3b38..000000000
--- a/factory-method/src/main/java/com/iluwatar/factorymethod/ElfWeapon.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.iluwatar.factorymethod;
-
-public class ElfWeapon implements Weapon {
-
- private WeaponType weaponType;
-
- public ElfWeapon(WeaponType weaponType) {
- this.weaponType = weaponType;
- }
-
- @Override
- public String toString() {
- return "Elven " + weaponType;
- }
-
-}
diff --git a/factory-method/src/main/java/com/iluwatar/factorymethod/OrcBlacksmith.java b/factory-method/src/main/java/com/iluwatar/factorymethod/OrcBlacksmith.java
deleted file mode 100644
index 297dd6b98..000000000
--- a/factory-method/src/main/java/com/iluwatar/factorymethod/OrcBlacksmith.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.iluwatar.factorymethod;
-
-/**
- *
- * Concrete subclass for creating new objects.
- *
- */
-public class OrcBlacksmith implements Blacksmith {
-
- public Weapon manufactureWeapon(WeaponType weaponType) {
- return new OrcWeapon(weaponType);
- }
-
-}
diff --git a/factory-method/src/main/java/com/iluwatar/factorymethod/OrcWeapon.java b/factory-method/src/main/java/com/iluwatar/factorymethod/OrcWeapon.java
deleted file mode 100644
index 2d7b19adb..000000000
--- a/factory-method/src/main/java/com/iluwatar/factorymethod/OrcWeapon.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package com.iluwatar.factorymethod;
-
-public class OrcWeapon implements Weapon {
-
- private WeaponType weaponType;
-
- public OrcWeapon(WeaponType weaponType) {
- this.weaponType = weaponType;
- }
-
- @Override
- public String toString() {
- return "Orcish " + weaponType;
- }
-
-}
diff --git a/factory-method/src/main/java/com/iluwatar/factorymethod/Weapon.java b/factory-method/src/main/java/com/iluwatar/factorymethod/Weapon.java
deleted file mode 100644
index 3a9346d03..000000000
--- a/factory-method/src/main/java/com/iluwatar/factorymethod/Weapon.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package com.iluwatar.factorymethod;
-
-public interface Weapon {
-
-}
diff --git a/factory-method/src/main/java/com/iluwatar/factorymethod/WeaponType.java b/factory-method/src/main/java/com/iluwatar/factorymethod/WeaponType.java
deleted file mode 100644
index 45e1f82de..000000000
--- a/factory-method/src/main/java/com/iluwatar/factorymethod/WeaponType.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.iluwatar.factorymethod;
-
-public enum WeaponType {
-
- SHORT_SWORD("short sword"), SPEAR("spear"), AXE("axe"), UNDEFINED("");
-
- private String title;
-
- WeaponType(String title) {
- this.title = title;
- }
-
- @Override
- public String toString() {
- return title;
- }
-}
diff --git a/factory-method/src/test/java/com/iluwatar/factory/method/AppTest.java b/factory-method/src/test/java/com/iluwatar/factory/method/AppTest.java
new file mode 100644
index 000000000..818ee96cd
--- /dev/null
+++ b/factory-method/src/test/java/com/iluwatar/factory/method/AppTest.java
@@ -0,0 +1,38 @@
+/**
+ * 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.factory.method;
+
+import org.junit.Test;
+
+import java.io.IOException;
+
+/**
+ * Tests that Factory Method example runs without errors.
+ */
+public class AppTest {
+ @Test
+ public void test() throws IOException {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/factory-method/src/test/java/com/iluwatar/factory/method/FactoryMethodTest.java b/factory-method/src/test/java/com/iluwatar/factory/method/FactoryMethodTest.java
new file mode 100644
index 000000000..2f8d1c9bb
--- /dev/null
+++ b/factory-method/src/test/java/com/iluwatar/factory/method/FactoryMethodTest.java
@@ -0,0 +1,101 @@
+/**
+ * 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.factory.method;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+/**
+ * The Factory Method is a creational design pattern which uses factory methods to deal with the
+ * problem of creating objects without specifying the exact class of object that will be created.
+ * This is done by creating objects via calling a factory method either specified in an interface
+ * and implemented by child classes, or implemented in a base class and optionally overridden by
+ * derived classes—rather than by calling a constructor.
+ *
+ *
Factory produces the object of its liking.
+ * The weapon {@link Weapon} manufactured by the
+ * blacksmith depends on the kind of factory implementation it is referring to.
+ *
+ */
+public class FactoryMethodTest {
+
+ /**
+ * Testing {@link OrcBlacksmith} to produce a SPEAR asserting that the Weapon is an instance
+ * of {@link OrcWeapon}.
+ */
+ @Test
+ public void testOrcBlacksmithWithSpear() {
+ Blacksmith blacksmith = new OrcBlacksmith();
+ Weapon weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
+ verifyWeapon(weapon, WeaponType.SPEAR, OrcWeapon.class);
+ }
+
+ /**
+ * Testing {@link OrcBlacksmith} to produce a AXE asserting that the Weapon is an instance
+ * of {@link OrcWeapon}.
+ */
+ @Test
+ public void testOrcBlacksmithWithAxe() {
+ Blacksmith blacksmith = new OrcBlacksmith();
+ Weapon weapon = blacksmith.manufactureWeapon(WeaponType.AXE);
+ verifyWeapon(weapon, WeaponType.AXE, OrcWeapon.class);
+ }
+
+ /**
+ * Testing {@link ElfBlacksmith} to produce a SHORT_SWORD asserting that the Weapon is an
+ * instance of {@link ElfWeapon}.
+ */
+ @Test
+ public void testElfBlacksmithWithShortSword() {
+ Blacksmith blacksmith = new ElfBlacksmith();
+ Weapon weapon = blacksmith.manufactureWeapon(WeaponType.SHORT_SWORD);
+ verifyWeapon(weapon, WeaponType.SHORT_SWORD, ElfWeapon.class);
+ }
+
+ /**
+ * Testing {@link ElfBlacksmith} to produce a SPEAR asserting that the Weapon is an instance
+ * of {@link ElfWeapon}.
+ */
+ @Test
+ public void testElfBlacksmithWithSpear() {
+ Blacksmith blacksmith = new ElfBlacksmith();
+ Weapon weapon = blacksmith.manufactureWeapon(WeaponType.SPEAR);
+ verifyWeapon(weapon, WeaponType.SPEAR, ElfWeapon.class);
+ }
+
+ /**
+ * This method asserts that the weapon object that is passed is an instance of the clazz and the
+ * weapon is of type expectedWeaponType.
+ *
+ * @param weapon weapon object which is to be verified
+ * @param expectedWeaponType expected WeaponType of the weapon
+ * @param clazz expected class of the weapon
+ */
+ private void verifyWeapon(Weapon weapon, WeaponType expectedWeaponType, Class> clazz) {
+ assertTrue("Weapon must be an object of: " + clazz.getName(), clazz.isInstance(weapon));
+ assertEquals("Weapon must be of weaponType: " + clazz.getName(), expectedWeaponType,
+ weapon.getWeaponType());
+ }
+}
diff --git a/factory-method/src/test/java/com/iluwatar/factorymethod/AppTest.java b/factory-method/src/test/java/com/iluwatar/factorymethod/AppTest.java
deleted file mode 100644
index 0abf55c2d..000000000
--- a/factory-method/src/test/java/com/iluwatar/factorymethod/AppTest.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.iluwatar.factorymethod;
-
-import org.junit.Test;
-
-import com.iluwatar.factorymethod.App;
-
-public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
-}
diff --git a/faq.md b/faq.md
new file mode 100644
index 000000000..69f7b795e
--- /dev/null
+++ b/faq.md
@@ -0,0 +1,67 @@
+---
+layout: page
+title: FAQ
+permalink: /faq/
+icon: fa-question
+page-index: 1
+---
+
+### Q1: What is the difference between State and Strategy patterns? {#Q1}
+
+While the implementation is similar they solve different problems. The State
+pattern deals with what state an object is in - it encapsulates state-dependent
+behavior.
+The Strategy pattern deals with how an object performs a certain task - it
+encapsulates an algorithm.
+
+### Q2: What is the difference between Strategy and Template Method patterns? {#Q2}
+
+In Template Method the algorithm is chosen at compile time via inheritance.
+With Strategy pattern the algorithm is chosen at runtime via composition.
+
+### Q3: What is the difference between Proxy and Decorator patterns? {#Q3}
+
+The difference is the intent of the patterns. While Proxy controls access to
+the object Decorator is used to add responsibilities to the object.
+
+### Q4: What is the difference between Chain of Responsibility and Intercepting Filter patterns? {#Q4}
+
+While the implementations look similar there are differences. The Chain of
+Responsibility forms a chain of request processors and the processors are then
+executed one by one until the correct processor is found. In Intercepting
+Filter the chain is constructed from filters and the whole chain is always
+executed.
+
+### Q5: What is the difference between Visitor and Double Dispatch patterns? {#Q5}
+
+The Visitor pattern is a means of adding a new operation to existing classes.
+Double dispatch is a means of dispatching function calls with respect to two
+polymorphic types, rather than a single polymorphic type, which is what
+languages like C++ and Java _do not_ support directly.
+
+### Q6: What are the differences between Flyweight and Object Pool patterns? {#Q6}
+
+They differ in the way they are used.
+
+Pooled objects can simultaneously be used by a single "client" only. For that,
+a pooled object must be checked out from the pool, then it can be used by a
+client, and then the client must return the object back to the pool. Multiple
+instances of identical objects may exist, up to the maximal capacity of the
+pool.
+
+In contrast, a Flyweight object is singleton, and it can be used simultaneously
+by multiple clients.
+
+As for concurrent access, pooled objects can be mutable and they usually don't
+need to be thread safe, as typically, only one thread is going to use a
+specific instance at the same time. Flyweight must either be immutable (the
+best option), or implement thread safety.
+
+As for performance and scalability, pools can become bottlenecks, if all the
+pooled objects are in use and more clients need them, threads will become
+blocked waiting for available object from the pool. This is not the case with
+Flyweight.
+
+### Q7: What are the differences between FluentInterface and Builder patterns? {#Q7}
+
+Fluent interfaces are sometimes confused with the Builder pattern, because they share method chaining and a fluent usage. However, fluent interfaces are not primarily used to create shared (mutable) objects, but to configure complex objects without having to respecify the target object on every property change.
diff --git a/feature-toggle/README.md b/feature-toggle/README.md
new file mode 100644
index 000000000..51747ac09
--- /dev/null
+++ b/feature-toggle/README.md
@@ -0,0 +1,32 @@
+---
+layout: pattern
+title: Feature Toggle
+folder: feature-toggle
+permalink: /patterns/feature-toggle/
+categories: Behavioral
+tags:
+ - Java
+ - Difficulty-Beginner
+---
+
+## Also known as
+Feature Flag
+
+## Intent
+Used to switch code execution paths based on properties or groupings. Allowing new features to be released, tested
+and rolled out. Allowing switching back to the older feature quickly if needed. It should be noted that this pattern,
+can easily introduce code complexity. There is also cause for concern that the old feature that the toggle is eventually
+going to phase out is never removed, causing redundant code smells and increased maintainability.
+
+
+
+## Applicability
+Use the Feature Toogle pattern when
+
+* Giving different features to different users.
+* Rolling out a new feature incrementally.
+* Switching between development and production environments.
+
+## Credits
+
+* [Martin Fowler 29 October 2010 (2010-10-29).](http://martinfowler.com/bliki/FeatureToggle.html)
\ No newline at end of file
diff --git a/feature-toggle/etc/feature-toggle.png b/feature-toggle/etc/feature-toggle.png
new file mode 100644
index 000000000..5c118e57e
Binary files /dev/null and b/feature-toggle/etc/feature-toggle.png differ
diff --git a/feature-toggle/etc/feature-toggle.ucls b/feature-toggle/etc/feature-toggle.ucls
new file mode 100644
index 000000000..538d3f416
--- /dev/null
+++ b/feature-toggle/etc/feature-toggle.ucls
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/feature-toggle/pom.xml b/feature-toggle/pom.xml
new file mode 100644
index 000000000..78c182af9
--- /dev/null
+++ b/feature-toggle/pom.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+ java-design-patterns
+ com.iluwatar
+ 1.13.0-SNAPSHOT
+
+ 4.0.0
+
+ feature-toggle
+
+
+
+
+ junit
+ junit
+ test
+
+
+
+
\ No newline at end of file
diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/App.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/App.java
new file mode 100644
index 000000000..debe99580
--- /dev/null
+++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/App.java
@@ -0,0 +1,96 @@
+/**
+ * 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.featuretoggle;
+
+import com.iluwatar.featuretoggle.pattern.Service;
+import com.iluwatar.featuretoggle.pattern.propertiesversion.PropertiesFeatureToggleVersion;
+import com.iluwatar.featuretoggle.user.User;
+import com.iluwatar.featuretoggle.user.UserGroup;
+
+import java.util.Properties;
+
+/**
+ * The Feature Toggle pattern allows for complete code executions to be turned on or off with ease. This allows features
+ * to be controlled by either dynamic methods just as {@link User} information or by {@link Properties}. In the App
+ * below there are two examples. Firstly the {@link Properties} version of the feature toggle, where the enhanced
+ * version of the welcome message which is personalised is turned either on or off at instance creation. This method
+ * is not as dynamic as the {@link User} driven version where the feature of the personalised welcome message is
+ * dependant on the {@link UserGroup} the {@link User} is in. So if the user is a memeber of the
+ * {@link UserGroup#isPaid(User)} then they get an ehanced version of the welcome message.
+ *
+ * Note that this pattern can easily introduce code complexity, and if not kept in check can result in redundant
+ * unmaintained code within the codebase.
+ *
+ */
+public class App {
+
+ /**
+ * Block 1 shows the {@link PropertiesFeatureToggleVersion} being run with {@link Properties} setting the feature
+ * toggle to enabled.
+ *
+ * Block 2 shows the {@link PropertiesFeatureToggleVersion} being run with {@link Properties} setting the feature
+ * toggle to disabled. Notice the difference with the printed welcome message the username is not included.
+ *
+ * Block 3 shows the {@link com.iluwatar.featuretoggle.pattern.tieredversion.TieredFeatureToggleVersion} being
+ * set up with two users on who is on the free level, while the other is on the paid level. When the
+ * {@link Service#getWelcomeMessage(User)} is called with the paid {@link User} note that the welcome message
+ * contains their username, while the same service call with the free tier user is more generic. No username is
+ * printed.
+ *
+ * @see User
+ * @see UserGroup
+ * @see Service
+ * @see PropertiesFeatureToggleVersion
+ * @see com.iluwatar.featuretoggle.pattern.tieredversion.TieredFeatureToggleVersion;
+ */
+ public static void main(String[] args) {
+
+ final Properties properties = new Properties();
+ properties.put("enhancedWelcome", true);
+ Service service = new PropertiesFeatureToggleVersion(properties);
+ final String welcomeMessage = service.getWelcomeMessage(new User("Jamie No Code"));
+ System.out.println(welcomeMessage);
+
+ // ---------------------------------------------
+
+ final Properties turnedOff = new Properties();
+ turnedOff.put("enhancedWelcome", false);
+ Service turnedOffService = new PropertiesFeatureToggleVersion(turnedOff);
+ final String welcomeMessageturnedOff = turnedOffService.getWelcomeMessage(new User("Jamie No Code"));
+ System.out.println(welcomeMessageturnedOff);
+
+ // --------------------------------------------
+
+ final User paidUser = new User("Jamie Coder");
+ final User freeUser = new User("Alan Defect");
+
+ UserGroup.addUserToPaidGroup(paidUser);
+ UserGroup.addUserToFreeGroup(freeUser);
+
+ final String welcomeMessagePaidUser = service.getWelcomeMessage(paidUser);
+ final String welcomeMessageFreeUser = service.getWelcomeMessage(freeUser);
+ System.out.println(welcomeMessageFreeUser);
+ System.out.println(welcomeMessagePaidUser);
+ }
+}
diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/Service.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/Service.java
new file mode 100644
index 000000000..d2542b2b7
--- /dev/null
+++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/Service.java
@@ -0,0 +1,54 @@
+/**
+ * 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.featuretoggle.pattern;
+
+import com.iluwatar.featuretoggle.user.User;
+
+/**
+ * Simple interfaces to allow the calling of the method to generate the welcome message for a given user. While there is
+ * a helper method to gather the the status of the feature toggle. In some cases there is no need for the
+ * {@link Service#isEnhanced()} in {@link com.iluwatar.featuretoggle.pattern.tieredversion.TieredFeatureToggleVersion}
+ * where the toggle is determined by the actual {@link User}.
+ *
+ * @see com.iluwatar.featuretoggle.pattern.propertiesversion.PropertiesFeatureToggleVersion
+ * @see com.iluwatar.featuretoggle.pattern.tieredversion.TieredFeatureToggleVersion
+ * @see User
+ */
+public interface Service {
+
+ /**
+ * Generates a welcome message for the passed user.
+ *
+ * @param user the {@link User} to be used if the message is to be personalised.
+ * @return Generated {@link String} welcome message
+ */
+ String getWelcomeMessage(User user);
+
+ /**
+ * Returns if the welcome message to be displayed will be the enhanced version.
+ *
+ * @return Boolean {@value true} if enhanced.
+ */
+ boolean isEnhanced();
+
+}
diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersion.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersion.java
new file mode 100644
index 000000000..761d7d39a
--- /dev/null
+++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersion.java
@@ -0,0 +1,100 @@
+/**
+ * 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.featuretoggle.pattern.propertiesversion;
+
+import com.iluwatar.featuretoggle.pattern.Service;
+import com.iluwatar.featuretoggle.user.User;
+
+import java.util.Properties;
+
+/**
+ * This example of the Feature Toogle pattern is less dynamic version than
+ * {@link com.iluwatar.featuretoggle.pattern.tieredversion.TieredFeatureToggleVersion} where the feature is turned on
+ * or off at the time of creation of the service. This example uses simple Java {@link Properties} however it could as
+ * easily be done with an external configuration file loaded by Spring and so on. A good example of when to use this
+ * version of the feature toggle is when new features are being developed. So you could have a configuration property
+ * boolean named development or some sort of system environment variable.
+ *
+ * @see Service
+ * @see com.iluwatar.featuretoggle.pattern.tieredversion.TieredFeatureToggleVersion
+ * @see User
+ */
+public class PropertiesFeatureToggleVersion implements Service {
+
+ private boolean isEnhanced;
+
+ /**
+ * Creates an instance of {@link PropertiesFeatureToggleVersion} using the passed {@link Properties} to determine,
+ * the status of the feature toggle {@link PropertiesFeatureToggleVersion#isEnhanced()}. There is also some defensive
+ * code to ensure the {@link Properties} passed are as expected.
+ *
+ * @param properties {@link Properties} used to configure the service and toggle features.
+ * @throws IllegalArgumentException when the passed {@link Properties} is not as expected
+ * @see Properties
+ */
+ public PropertiesFeatureToggleVersion(final Properties properties) {
+ if (properties == null) {
+ throw new IllegalArgumentException("No Properties Provided.");
+ } else {
+ try {
+ isEnhanced = (boolean) properties.get("enhancedWelcome");
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Invalid Enhancement Settings Provided.");
+ }
+ }
+ }
+
+ /**
+ * Generate a welcome message based on the user being passed and the status of the feature toggle. If the enhanced
+ * version is enabled, then the message will be personalised with the name of the passed {@link User}. However if
+ * disabled then a generic version fo the message is returned.
+ *
+ * @param user the {@link User} to be displayed in the message if the enhanced version is enabled see
+ * {@link PropertiesFeatureToggleVersion#isEnhanced()}. If the enhanced version is enabled, then the
+ * message will be personalised with the name of the passed {@link User}. However if disabled then a
+ * generic version fo the message is returned.
+ * @return Resulting welcome message.
+ * @see User
+ */
+ @Override
+ public String getWelcomeMessage(final User user) {
+
+ if (isEnhanced()) {
+ return "Welcome " + user + ". You're using the enhanced welcome message.";
+ }
+
+ return "Welcome to the application.";
+ }
+
+ /**
+ * Method that checks if the welcome message to be returned is the enhanced venison or not. For this service it will
+ * see the value of the boolean that was set in the constructor
+ * {@link PropertiesFeatureToggleVersion#PropertiesFeatureToggleVersion(Properties)}
+ *
+ * @return Boolean value {@value true} if enhanced.
+ */
+ @Override
+ public boolean isEnhanced() {
+ return isEnhanced;
+ }
+}
diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/tieredversion/TieredFeatureToggleVersion.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/tieredversion/TieredFeatureToggleVersion.java
new file mode 100644
index 000000000..124c9533f
--- /dev/null
+++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/tieredversion/TieredFeatureToggleVersion.java
@@ -0,0 +1,75 @@
+/**
+ * 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.featuretoggle.pattern.tieredversion;
+
+import com.iluwatar.featuretoggle.pattern.Service;
+import com.iluwatar.featuretoggle.user.User;
+import com.iluwatar.featuretoggle.user.UserGroup;
+
+/**
+ * This example of the Feature Toogle pattern shows how it could be implemented based on a {@link User}. Therefore
+ * showing its use within a tiered application where the paying users get access to different content or
+ * better versions of features. So in this instance a {@link User} is passed in and if they are found to be
+ * on the {@link UserGroup#isPaid(User)} they are welcomed with a personalised message. While the other is more
+ * generic. However this pattern is limited to simple examples such as the one below.
+ *
+ * @see Service
+ * @see User
+ * @see com.iluwatar.featuretoggle.pattern.propertiesversion.PropertiesFeatureToggleVersion
+ * @see UserGroup
+ */
+public class TieredFeatureToggleVersion implements Service {
+
+ /**
+ * Generates a welcome message from the passed {@link User}. The resulting message depends on the group of the
+ * {@link User}. So if the {@link User} is in the {@link UserGroup#paidGroup} then the enhanced version of the
+ * welcome message will be returned where the username is displayed.
+ *
+ * @param user the {@link User} to generate the welcome message for, different messages are displayed if the user is
+ * in the {@link UserGroup#isPaid(User)} or {@link UserGroup#freeGroup}
+ * @return Resulting welcome message.
+ * @see User
+ * @see UserGroup
+ */
+ @Override
+ public String getWelcomeMessage(User user) {
+ if (UserGroup.isPaid(user)) {
+ return "You're amazing " + user + ". Thanks for paying for this awesome software.";
+ }
+
+ return "I suppose you can use this software.";
+ }
+
+ /**
+ * Method that checks if the welcome message to be returned is the enhanced version. For this instance as the logic
+ * is driven by the user group. This method is a little redundant. However can be used to show that there is an
+ * enhanced version available.
+ *
+ * @return Boolean value {@value true} if enhanced.
+ */
+ @Override
+ public boolean isEnhanced() {
+ return true;
+ }
+
+}
diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/User.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/User.java
new file mode 100644
index 000000000..ce7b54b7b
--- /dev/null
+++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/User.java
@@ -0,0 +1,49 @@
+/**
+ * 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.featuretoggle.user;
+
+/**
+ * Used to demonstrate the purpose of the feature toggle. This class actually has nothing to do with the pattern.
+ */
+public class User {
+
+ private String name;
+
+ /**
+ * Default Constructor setting the username.
+ *
+ * @param name {@link String} to represent the name of the user.
+ */
+ public User(String name) {
+ this.name = name;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @return The {@link String} representation of the User, in this case just return the name of the user.
+ */
+ @Override
+ public String toString() {
+ return name;
+ }
+}
diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/UserGroup.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/UserGroup.java
new file mode 100644
index 000000000..c9d9fd027
--- /dev/null
+++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/user/UserGroup.java
@@ -0,0 +1,84 @@
+/**
+ * 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.featuretoggle.user;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Contains the lists of users of different groups paid and free. Used to demonstrate the tiered example of feature
+ * toggle. Allowing certain features to be available to only certain groups of users.
+ *
+ * @see User
+ */
+public class UserGroup {
+
+ private static List freeGroup = new ArrayList<>();
+ private static List paidGroup = new ArrayList<>();
+
+
+ /**
+ * Add the passed {@link User} to the free user group list.
+ *
+ * @param user {@link User} to be added to the free group
+ * @throws IllegalArgumentException when user is already added to the paid group
+ * @see User
+ */
+ public static void addUserToFreeGroup(final User user) throws IllegalArgumentException {
+ if (paidGroup.contains(user)) {
+ throw new IllegalArgumentException("User all ready member of paid group.");
+ } else {
+ if (!freeGroup.contains(user)) {
+ freeGroup.add(user);
+ }
+ }
+ }
+
+ /**
+ * Add the passed {@link User} to the paid user group list.
+ *
+ * @param user {@link User} to be added to the paid group
+ * @throws IllegalArgumentException when the user is already added to the free group
+ * @see User
+ */
+ public static void addUserToPaidGroup(final User user) throws IllegalArgumentException {
+ if (freeGroup.contains(user)) {
+ throw new IllegalArgumentException("User all ready member of free group.");
+ } else {
+ if (!paidGroup.contains(user)) {
+ paidGroup.add(user);
+ }
+ }
+ }
+
+ /**
+ * Method to take a {@link User} to determine if the user is in the {@link UserGroup#paidGroup}.
+ *
+ * @param user {@link User} to check if they are in the {@link UserGroup#paidGroup}
+ *
+ * @return true if the {@link User} is in {@link UserGroup#paidGroup}
+ */
+ public static boolean isPaid(User user) {
+ return paidGroup.contains(user);
+ }
+}
diff --git a/feature-toggle/src/test/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersionTest.java b/feature-toggle/src/test/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersionTest.java
new file mode 100644
index 000000000..69afc9bb4
--- /dev/null
+++ b/feature-toggle/src/test/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersionTest.java
@@ -0,0 +1,69 @@
+/**
+ * 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.featuretoggle.pattern.propertiesversion;
+
+import com.iluwatar.featuretoggle.pattern.Service;
+import com.iluwatar.featuretoggle.user.User;
+import org.junit.Test;
+
+import java.util.Properties;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class PropertiesFeatureToggleVersionTest {
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNullPropertiesPassed() throws Exception {
+ new PropertiesFeatureToggleVersion(null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNonBooleanProperty() throws Exception {
+ final Properties properties = new Properties();
+ properties.setProperty("enhancedWelcome", "Something");
+ new PropertiesFeatureToggleVersion(properties);
+ }
+
+ @Test
+ public void testFeatureTurnedOn() throws Exception {
+ final Properties properties = new Properties();
+ properties.put("enhancedWelcome", true);
+ Service service = new PropertiesFeatureToggleVersion(properties);
+ assertTrue(service.isEnhanced());
+ final String welcomeMessage = service.getWelcomeMessage(new User("Jamie No Code"));
+ assertEquals("Welcome Jamie No Code. You're using the enhanced welcome message.", welcomeMessage);
+ }
+
+ @Test
+ public void testFeatureTurnedOff() throws Exception {
+ final Properties properties = new Properties();
+ properties.put("enhancedWelcome", false);
+ Service service = new PropertiesFeatureToggleVersion(properties);
+ assertFalse(service.isEnhanced());
+ final String welcomeMessage = service.getWelcomeMessage(new User("Jamie No Code"));
+ assertEquals("Welcome to the application.", welcomeMessage);
+ }
+}
\ No newline at end of file
diff --git a/feature-toggle/src/test/java/com/iluwatar/featuretoggle/pattern/tieredversion/TieredFeatureToggleVersionTest.java b/feature-toggle/src/test/java/com/iluwatar/featuretoggle/pattern/tieredversion/TieredFeatureToggleVersionTest.java
new file mode 100644
index 000000000..dca1d9b82
--- /dev/null
+++ b/feature-toggle/src/test/java/com/iluwatar/featuretoggle/pattern/tieredversion/TieredFeatureToggleVersionTest.java
@@ -0,0 +1,64 @@
+/**
+ * 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.featuretoggle.pattern.tieredversion;
+
+import com.iluwatar.featuretoggle.pattern.Service;
+import com.iluwatar.featuretoggle.user.User;
+import com.iluwatar.featuretoggle.user.UserGroup;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class TieredFeatureToggleVersionTest {
+
+ final User paidUser = new User("Jamie Coder");
+ final User freeUser = new User("Alan Defect");
+ final Service service = new TieredFeatureToggleVersion();
+
+ @Before
+ public void setUp() throws Exception {
+ UserGroup.addUserToPaidGroup(paidUser);
+ UserGroup.addUserToFreeGroup(freeUser);
+ }
+
+ @Test
+ public void testGetWelcomeMessageForPaidUser() throws Exception {
+ final String welcomeMessage = service.getWelcomeMessage(paidUser);
+ final String expected = "You're amazing Jamie Coder. Thanks for paying for this awesome software.";
+ assertEquals(expected, welcomeMessage);
+ }
+
+ @Test
+ public void testGetWelcomeMessageForFreeUser() throws Exception {
+ final String welcomeMessage = service.getWelcomeMessage(freeUser);
+ final String expected = "I suppose you can use this software.";
+ assertEquals(expected, welcomeMessage);
+ }
+
+ @Test
+ public void testIsEnhancedAlwaysTrueAsTiered() throws Exception {
+ assertTrue(service.isEnhanced());
+ }
+}
\ No newline at end of file
diff --git a/feature-toggle/src/test/java/com/iluwatar/featuretoggle/user/UserGroupTest.java b/feature-toggle/src/test/java/com/iluwatar/featuretoggle/user/UserGroupTest.java
new file mode 100644
index 000000000..6659815d3
--- /dev/null
+++ b/feature-toggle/src/test/java/com/iluwatar/featuretoggle/user/UserGroupTest.java
@@ -0,0 +1,59 @@
+/**
+ * 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.featuretoggle.user;
+
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class UserGroupTest {
+
+ @Test
+ public void testAddUserToFreeGroup() throws Exception {
+ User user = new User("Free User");
+ UserGroup.addUserToFreeGroup(user);
+ assertFalse(UserGroup.isPaid(user));
+ }
+
+ @Test
+ public void testAddUserToPaidGroup() throws Exception {
+ User user = new User("Paid User");
+ UserGroup.addUserToPaidGroup(user);
+ assertTrue(UserGroup.isPaid(user));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testAddUserToPaidWhenOnFree() throws Exception {
+ User user = new User("Paid User");
+ UserGroup.addUserToFreeGroup(user);
+ UserGroup.addUserToPaidGroup(user);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testAddUserToFreeWhenOnPaid() throws Exception {
+ User user = new User("Free User");
+ UserGroup.addUserToPaidGroup(user);
+ UserGroup.addUserToFreeGroup(user);
+ }
+}
\ No newline at end of file
diff --git a/fluentinterface/README.md b/fluentinterface/README.md
new file mode 100644
index 000000000..767792da7
--- /dev/null
+++ b/fluentinterface/README.md
@@ -0,0 +1,44 @@
+---
+layout: pattern
+title: Fluent Interface
+folder: fluentinterface
+permalink: /patterns/fluentinterface/
+categories: Other
+tags:
+ - Java
+ - Difficulty-Intermediate
+ - Functional
+---
+
+## Intent
+A fluent interface provides an easy-readable, flowing interface, that often mimics a domain specific language. Using this pattern results in code that can be read nearly as human language.
+
+## Implementation
+
+A fluent interface can be implemented using any of
+
+ * Method Chaining - calling a method returns some object on which further methods can be called.
+ * Static Factory Methods and Imports
+ * Named parameters - can be simulated in Java using static factory methods.
+
+
+
+## Applicability
+Use the Fluent Interface pattern when
+
+* you provide an API that would benefit from a DSL-like usage
+* you have objects that are difficult to configure or use
+
+## Real world examples
+
+* [Java 8 Stream API](http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html)
+* [Google Guava FluentInterable](https://github.com/google/guava/wiki/FunctionalExplained)
+* [JOOQ](http://www.jooq.org/doc/3.0/manual/getting-started/use-cases/jooq-as-a-standalone-sql-builder/)
+* [Mockito](http://mockito.org/)
+* [Java Hamcrest](http://code.google.com/p/hamcrest/wiki/Tutorial)
+
+## Credits
+
+* [Fluent Interface - Martin Fowler](http://www.martinfowler.com/bliki/FluentInterface.html)
+* [Evolutionary architecture and emergent design: Fluent interfaces - Neal Ford](http://www.ibm.com/developerworks/library/j-eaed14/)
+* [Internal DSL](http://www.infoq.com/articles/internal-dsls-java)
diff --git a/fluentinterface/etc/fluentinterface.png b/fluentinterface/etc/fluentinterface.png
new file mode 100644
index 000000000..611fec7c6
Binary files /dev/null and b/fluentinterface/etc/fluentinterface.png differ
diff --git a/fluentinterface/etc/fluentinterface.ucls b/fluentinterface/etc/fluentinterface.ucls
new file mode 100644
index 000000000..e30c45bb2
--- /dev/null
+++ b/fluentinterface/etc/fluentinterface.ucls
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/fluentinterface/pom.xml b/fluentinterface/pom.xml
new file mode 100644
index 000000000..ca5e115d0
--- /dev/null
+++ b/fluentinterface/pom.xml
@@ -0,0 +1,49 @@
+
+
+
+
+ java-design-patterns
+ com.iluwatar
+ 1.13.0-SNAPSHOT
+
+ 4.0.0
+
+ fluentinterface
+
+
+ junit
+ junit
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
\ No newline at end of file
diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java
new file mode 100644
index 000000000..1be2b1e70
--- /dev/null
+++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java
@@ -0,0 +1,131 @@
+/**
+ * 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.fluentinterface.app;
+
+import static java.lang.String.valueOf;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringJoiner;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import com.iluwatar.fluentinterface.fluentiterable.FluentIterable;
+import com.iluwatar.fluentinterface.fluentiterable.lazy.LazyFluentIterable;
+import com.iluwatar.fluentinterface.fluentiterable.simple.SimpleFluentIterable;
+
+/**
+ * The Fluent Interface pattern is useful when you want to provide an easy readable, flowing API.
+ * Those interfaces tend to mimic domain specific languages, so they can nearly be read as human
+ * languages.
+ *
+ * In this example two implementations of a {@link FluentIterable} interface are given. The
+ * {@link SimpleFluentIterable} evaluates eagerly and would be too costly for real world
+ * applications. The {@link LazyFluentIterable} is evaluated on termination. Their usage is
+ * demonstrated with a simple number list that is filtered, transformed and collected. The result is
+ * printed afterwards.
+ *
+ */
+public class App {
+
+ /**
+ * Program entry point
+ */
+ public static void main(String[] args) {
+
+ List integerList = new ArrayList<>();
+ integerList.addAll(Arrays.asList(1, -61, 14, -22, 18, -87, 6, 64, -82, 26, -98, 97, 45, 23, 2,
+ -68, 45));
+
+ prettyPrint("The initial list contains: ", integerList);
+
+ List firstFiveNegatives =
+ SimpleFluentIterable.fromCopyOf(integerList).filter(negatives()).first(3).asList();
+ prettyPrint("The first three negative values are: ", firstFiveNegatives);
+
+
+ List lastTwoPositives =
+ SimpleFluentIterable.fromCopyOf(integerList).filter(positives()).last(2).asList();
+ prettyPrint("The last two positive values are: ", lastTwoPositives);
+
+ SimpleFluentIterable
+ .fromCopyOf(integerList)
+ .filter(number -> number % 2 == 0)
+ .first()
+ .ifPresent(
+ evenNumber -> System.out.println(String.format("The first even number is: %d",
+ evenNumber)));
+
+
+ List transformedList =
+ SimpleFluentIterable.fromCopyOf(integerList).filter(negatives()).map(transformToString())
+ .asList();
+ prettyPrint("A string-mapped list of negative numbers contains: ", transformedList);
+
+
+ List lastTwoOfFirstFourStringMapped =
+ LazyFluentIterable.from(integerList).filter(positives()).first(4).last(2)
+ .map(number -> "String[" + valueOf(number) + "]").asList();
+ prettyPrint(
+ "The lazy list contains the last two of the first four positive numbers mapped to Strings: ",
+ lastTwoOfFirstFourStringMapped);
+
+ LazyFluentIterable
+ .from(integerList)
+ .filter(negatives())
+ .first(2)
+ .last()
+ .ifPresent(
+ lastOfFirstTwo -> System.out.println(String.format(
+ "The last of the first two negatives is: %d", lastOfFirstTwo)));
+ }
+
+ private static Function transformToString() {
+ return integer -> "String[" + valueOf(integer) + "]";
+ }
+
+ private static Predicate super Integer> negatives() {
+ return integer -> integer < 0;
+ }
+
+ private static Predicate super Integer> positives() {
+ return integer -> integer > 0;
+ }
+
+ private static void prettyPrint(String prefix, Iterable iterable) {
+ prettyPrint(", ", prefix, iterable);
+ }
+
+ private static void prettyPrint(String delimiter, String prefix,
+ Iterable iterable) {
+ StringJoiner joiner = new StringJoiner(delimiter, prefix, ".");
+ Iterator iterator = iterable.iterator();
+ while (iterator.hasNext()) {
+ joiner.add(iterator.next().toString());
+ }
+
+ System.out.println(joiner);
+ }
+}
diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/FluentIterable.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/FluentIterable.java
new file mode 100644
index 000000000..f6d7e2e2b
--- /dev/null
+++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/FluentIterable.java
@@ -0,0 +1,111 @@
+/**
+ * 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.fluentinterface.fluentiterable;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * The FluentIterable is a more convenient implementation of the common iterable interface based on
+ * the fluent interface design pattern. This interface defines common operations, but doesn't aim to
+ * be complete. It was inspired by Guava's com.google.common.collect.FluentIterable.
+ *
+ * @param is the class of objects the iterable contains
+ */
+public interface FluentIterable extends Iterable {
+
+ /**
+ * Filters the contents of Iterable using the given predicate, leaving only the ones which satisfy
+ * the predicate.
+ *
+ * @param predicate the condition to test with for the filtering. If the test is negative, the
+ * tested object is removed by the iterator.
+ * @return a filtered FluentIterable
+ */
+ FluentIterable filter(Predicate super E> predicate);
+
+ /**
+ * Returns an Optional containing the first element of this iterable if present, else returns
+ * Optional.empty().
+ *
+ * @return the first element after the iteration is evaluated
+ */
+ Optional first();
+
+ /**
+ * Evaluates the iteration and leaves only the count first elements.
+ *
+ * @return the first count elements as an Iterable
+ */
+ FluentIterable first(int count);
+
+ /**
+ * Evaluates the iteration and returns the last element. This is a terminating operation.
+ *
+ * @return the last element after the iteration is evaluated
+ */
+ Optional last();
+
+ /**
+ * Evaluates the iteration and leaves only the count last elements.
+ *
+ * @return the last counts elements as an Iterable
+ */
+ FluentIterable last(int count);
+
+ /**
+ * Transforms this FluentIterable into a new one containing objects of the type T.
+ *
+ * @param function a function that transforms an instance of E into an instance of T
+ * @param the target type of the transformation
+ * @return a new FluentIterable of the new type
+ */
+ FluentIterable map(Function super E, T> function);
+
+ /**
+ * Returns the contents of this Iterable as a List.
+ *
+ * @return a List representation of this Iterable
+ */
+ List asList();
+
+ /**
+ * Utility method that iterates over iterable and adds the contents to a list.
+ *
+ * @param iterable the iterable to collect
+ * @param the type of the objects to iterate
+ * @return a list with all objects of the given iterator
+ */
+ static List copyToList(Iterable iterable) {
+ List copy = new ArrayList<>();
+ Iterator iterator = iterable.iterator();
+ while (iterator.hasNext()) {
+ copy.add(iterator.next());
+ }
+ return copy;
+ }
+}
diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/DecoratingIterator.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/DecoratingIterator.java
new file mode 100644
index 000000000..07d7f5739
--- /dev/null
+++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/DecoratingIterator.java
@@ -0,0 +1,78 @@
+/**
+ * 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.fluentinterface.fluentiterable.lazy;
+
+import java.util.Iterator;
+
+/**
+ * This class is used to realize LazyFluentIterables. It decorates a given iterator. Does not
+ * support consecutive hasNext() calls.
+ */
+public abstract class DecoratingIterator implements Iterator {
+
+ protected final Iterator fromIterator;
+
+ private E next;
+
+ /**
+ * Creates an iterator that decorates the given iterator.
+ */
+ public DecoratingIterator(Iterator fromIterator) {
+ this.fromIterator = fromIterator;
+ }
+
+ /**
+ * Precomputes and saves the next element of the Iterable. null is considered as end of data.
+ *
+ * @return true if a next element is available
+ */
+ @Override
+ public final boolean hasNext() {
+ next = computeNext();
+ return next != null;
+ }
+
+ /**
+ * Returns the next element of the Iterable.
+ *
+ * @return the next element of the Iterable, or null if not present.
+ */
+ @Override
+ public final E next() {
+ if (next == null) {
+ return fromIterator.next();
+ } else {
+ final E result = next;
+ next = null;
+ return result;
+ }
+ }
+
+ /**
+ * Computes the next object of the Iterable. Can be implemented to realize custom behaviour for an
+ * iteration process. null is considered as end of data.
+ *
+ * @return the next element of the Iterable.
+ */
+ public abstract E computeNext();
+}
diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java
new file mode 100644
index 000000000..63247875c
--- /dev/null
+++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java
@@ -0,0 +1,249 @@
+/**
+ * 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.fluentinterface.fluentiterable.lazy;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import com.iluwatar.fluentinterface.fluentiterable.FluentIterable;
+
+/**
+ * This is a lazy implementation of the FluentIterable interface. It evaluates all chained
+ * operations when a terminating operation is applied.
+ *
+ * @param the type of the objects the iteration is about
+ */
+public class LazyFluentIterable implements FluentIterable {
+
+ private final Iterable iterable;
+
+ /**
+ * This constructor creates a new LazyFluentIterable. It wraps the given iterable.
+ *
+ * @param iterable the iterable this FluentIterable works on.
+ */
+ protected LazyFluentIterable(Iterable iterable) {
+ this.iterable = iterable;
+ }
+
+ /**
+ * This constructor can be used to implement anonymous subclasses of the LazyFluentIterable.
+ */
+ protected LazyFluentIterable() {
+ iterable = this;
+ }
+
+ /**
+ * Filters the contents of Iterable using the given predicate, leaving only the ones which satisfy
+ * the predicate.
+ *
+ * @param predicate the condition to test with for the filtering. If the test is negative, the
+ * tested object is removed by the iterator.
+ * @return a new FluentIterable object that decorates the source iterable
+ */
+ @Override
+ public FluentIterable filter(Predicate super E> predicate) {
+ return new LazyFluentIterable() {
+ @Override
+ public Iterator iterator() {
+ return new DecoratingIterator(iterable.iterator()) {
+ @Override
+ public E computeNext() {
+ while (fromIterator.hasNext()) {
+ E candidate = fromIterator.next();
+ if (predicate.test(candidate)) {
+ return candidate;
+ }
+ }
+
+ return null;
+ }
+ };
+ }
+ };
+ }
+
+ /**
+ * Can be used to collect objects from the iteration. Is a terminating operation.
+ *
+ * @return an Optional containing the first object of this Iterable
+ */
+ @Override
+ public Optional first() {
+ Iterator resultIterator = first(1).iterator();
+ return resultIterator.hasNext() ? Optional.of(resultIterator.next()) : Optional.empty();
+ }
+
+ /**
+ * Can be used to collect objects from the iteration.
+ *
+ * @param count defines the number of objects to return
+ * @return the same FluentIterable with a collection decimated to a maximum of 'count' first
+ * objects.
+ */
+ @Override
+ public FluentIterable first(int count) {
+ return new LazyFluentIterable() {
+ @Override
+ public Iterator iterator() {
+ return new DecoratingIterator(iterable.iterator()) {
+ int currentIndex;
+
+ @Override
+ public E computeNext() {
+ if (currentIndex < count && fromIterator.hasNext()) {
+ E candidate = fromIterator.next();
+ currentIndex++;
+ return candidate;
+ }
+ return null;
+ }
+ };
+ }
+ };
+ }
+
+ /**
+ * Can be used to collect objects from the iteration. Is a terminating operation.
+ *
+ * @return an Optional containing the last object of this Iterable
+ */
+ @Override
+ public Optional last() {
+ Iterator resultIterator = last(1).iterator();
+ return resultIterator.hasNext() ? Optional.of(resultIterator.next()) : Optional.empty();
+ }
+
+ /**
+ * Can be used to collect objects from the Iterable. Is a terminating operation. This operation is
+ * memory intensive, because the contents of this Iterable are collected into a List, when the
+ * next object is requested.
+ *
+ * @param count defines the number of objects to return
+ * @return the same FluentIterable with a collection decimated to a maximum of 'count' last
+ * objects
+ */
+ @Override
+ public FluentIterable last(int count) {
+ return new LazyFluentIterable() {
+ @Override
+ public Iterator iterator() {
+ return new DecoratingIterator(iterable.iterator()) {
+ private int stopIndex;
+ private int totalElementsCount;
+ private List list;
+ private int currentIndex;
+
+ @Override
+ public E computeNext() {
+ initialize();
+
+ E candidate = null;
+ while (currentIndex < stopIndex && fromIterator.hasNext()) {
+ currentIndex++;
+ fromIterator.next();
+ }
+ if (currentIndex >= stopIndex && fromIterator.hasNext()) {
+ candidate = fromIterator.next();
+ }
+ return candidate;
+ }
+
+ private void initialize() {
+ if (list == null) {
+ list = new ArrayList<>();
+ Iterator newIterator = iterable.iterator();
+ while (newIterator.hasNext()) {
+ list.add(newIterator.next());
+ }
+
+ totalElementsCount = list.size();
+ stopIndex = totalElementsCount - count;
+ }
+ }
+ };
+ }
+ };
+ }
+
+ /**
+ * Transforms this FluentIterable into a new one containing objects of the type T.
+ *
+ * @param function a function that transforms an instance of E into an instance of T
+ * @param the target type of the transformation
+ * @return a new FluentIterable of the new type
+ */
+ @Override
+ public FluentIterable map(Function super E, T> function) {
+ return new LazyFluentIterable() {
+ @Override
+ public Iterator iterator() {
+ return new DecoratingIterator(null) {
+ Iterator oldTypeIterator = iterable.iterator();
+
+ @Override
+ public T computeNext() {
+ if (oldTypeIterator.hasNext()) {
+ E candidate = oldTypeIterator.next();
+ return function.apply(candidate);
+ } else {
+ return null;
+ }
+ }
+ };
+ }
+ };
+ }
+
+ /**
+ * Collects all remaining objects of this iteration into a list.
+ *
+ * @return a list with all remaining objects of this iteration
+ */
+ @Override
+ public List asList() {
+ return FluentIterable.copyToList(iterable);
+ }
+
+ @Override
+ public Iterator iterator() {
+ return new DecoratingIterator(iterable.iterator()) {
+ @Override
+ public E computeNext() {
+ return fromIterator.hasNext() ? fromIterator.next() : null;
+ }
+ };
+ }
+
+ /**
+ * @return a FluentIterable from a given iterable. Calls the LazyFluentIterable constructor.
+ */
+ public static final FluentIterable from(Iterable iterable) {
+ return new LazyFluentIterable<>(iterable);
+ }
+
+}
diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/simple/SimpleFluentIterable.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/simple/SimpleFluentIterable.java
new file mode 100644
index 000000000..153f3faa5
--- /dev/null
+++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/simple/SimpleFluentIterable.java
@@ -0,0 +1,224 @@
+/**
+ * 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.fluentinterface.fluentiterable.simple;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.Spliterator;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+import com.iluwatar.fluentinterface.fluentiterable.FluentIterable;
+
+/**
+ * This is a simple implementation of the FluentIterable interface. It evaluates all chained
+ * operations eagerly. This implementation would be costly to be utilized in real applications.
+ *
+ * @param the type of the objects the iteration is about
+ */
+public class SimpleFluentIterable implements FluentIterable {
+
+ private final Iterable iterable;
+
+ /**
+ * This constructor creates a copy of a given iterable's contents.
+ *
+ * @param iterable the iterable this interface copies to work on.
+ */
+ protected SimpleFluentIterable(Iterable iterable) {
+ this.iterable = iterable;
+ }
+
+ /**
+ * Filters the contents of Iterable using the given predicate, leaving only the ones which satisfy
+ * the predicate.
+ *
+ * @param predicate the condition to test with for the filtering. If the test is negative, the
+ * tested object is removed by the iterator.
+ * @return the same FluentIterable with a filtered collection
+ */
+ @Override
+ public final FluentIterable filter(Predicate super E> predicate) {
+ Iterator iterator = iterator();
+ while (iterator.hasNext()) {
+ E nextElement = iterator.next();
+ if (!predicate.test(nextElement)) {
+ iterator.remove();
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Can be used to collect objects from the Iterable. Is a terminating operation.
+ *
+ * @return an option of the first object of the Iterable
+ */
+ @Override
+ public final Optional first() {
+ Iterator resultIterator = first(1).iterator();
+ return resultIterator.hasNext() ? Optional.of(resultIterator.next()) : Optional.empty();
+ }
+
+ /**
+ * Can be used to collect objects from the Iterable. Is a terminating operation.
+ *
+ * @param count defines the number of objects to return
+ * @return the same FluentIterable with a collection decimated to a maximum of 'count' first
+ * objects.
+ */
+ @Override
+ public final FluentIterable first(int count) {
+ Iterator iterator = iterator();
+ int currentCount = 0;
+ while (iterator.hasNext()) {
+ iterator.next();
+ if (currentCount >= count) {
+ iterator.remove();
+ }
+ currentCount++;
+ }
+ return this;
+ }
+
+ /**
+ * Can be used to collect objects from the Iterable. Is a terminating operation.
+ *
+ * @return an option of the last object of the Iterable
+ */
+ @Override
+ public final Optional last() {
+ List list = last(1).asList();
+ if (list.isEmpty()) {
+ return Optional.empty();
+ }
+ return Optional.of(list.get(0));
+ }
+
+ /**
+ * Can be used to collect objects from the Iterable. Is a terminating operation.
+ *
+ * @param count defines the number of objects to return
+ * @return the same FluentIterable with a collection decimated to a maximum of 'count' last
+ * objects
+ */
+ @Override
+ public final FluentIterable last(int count) {
+ int remainingElementsCount = getRemainingElementsCount();
+ Iterator iterator = iterator();
+ int currentIndex = 0;
+ while (iterator.hasNext()) {
+ iterator.next();
+ if (currentIndex < remainingElementsCount - count) {
+ iterator.remove();
+ }
+ currentIndex++;
+ }
+
+ return this;
+ }
+
+ /**
+ * Transforms this FluentIterable into a new one containing objects of the type T.
+ *
+ * @param function a function that transforms an instance of E into an instance of T
+ * @param the target type of the transformation
+ * @return a new FluentIterable of the new type
+ */
+ @Override
+ public final FluentIterable map(Function super E, T> function) {
+ List temporaryList = new ArrayList<>();
+ Iterator iterator = iterator();
+ while (iterator.hasNext()) {
+ temporaryList.add(function.apply(iterator.next()));
+ }
+ return from(temporaryList);
+ }
+
+ /**
+ * Collects all remaining objects of this Iterable into a list.
+ *
+ * @return a list with all remaining objects of this Iterable
+ */
+ @Override
+ public List asList() {
+ return toList(iterable.iterator());
+ }
+
+ /**
+ * @return a FluentIterable from a given iterable. Calls the SimpleFluentIterable constructor.
+ */
+ public static final FluentIterable from(Iterable iterable) {
+ return new SimpleFluentIterable<>(iterable);
+ }
+
+ public static final FluentIterable fromCopyOf(Iterable iterable) {
+ List copy = FluentIterable.copyToList(iterable);
+ return new SimpleFluentIterable<>(copy);
+ }
+
+ @Override
+ public Iterator iterator() {
+ return iterable.iterator();
+ }
+
+ @Override
+ public void forEach(Consumer super E> action) {
+ iterable.forEach(action);
+ }
+
+
+ @Override
+ public Spliterator spliterator() {
+ return iterable.spliterator();
+ }
+
+ /**
+ * @return the count of remaining objects of the current Iterable
+ */
+ public final int getRemainingElementsCount() {
+ int counter = 0;
+ Iterator iterator = iterator();
+ while (iterator.hasNext()) {
+ iterator.next();
+ counter++;
+ }
+ return counter;
+ }
+
+ /**
+ * Collects the remaining objects of the given iterator into a List.
+ *
+ * @return a new List with the remaining objects.
+ */
+ public static List toList(Iterator iterator) {
+ List copy = new ArrayList<>();
+ while (iterator.hasNext()) {
+ copy.add(iterator.next());
+ }
+ return copy;
+ }
+}
diff --git a/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java b/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java
new file mode 100644
index 000000000..5b750c604
--- /dev/null
+++ b/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java
@@ -0,0 +1,34 @@
+/**
+ * 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.fluentinterface.app;
+
+import org.junit.Test;
+
+public class AppTest {
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/fluentinterface/src/test/java/com/iluwatar/fluentinterface/fluentiterable/FluentIterableTest.java b/fluentinterface/src/test/java/com/iluwatar/fluentinterface/fluentiterable/FluentIterableTest.java
new file mode 100644
index 000000000..4037bed49
--- /dev/null
+++ b/fluentinterface/src/test/java/com/iluwatar/fluentinterface/fluentiterable/FluentIterableTest.java
@@ -0,0 +1,192 @@
+/**
+ * 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.fluentinterface.fluentiterable;
+
+import org.junit.Test;
+
+import java.util.*;
+import java.util.function.Consumer;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+/**
+ * Date: 12/12/15 - 7:00 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class FluentIterableTest {
+
+ /**
+ * Create a new {@link FluentIterable} from the given integers
+ *
+ * @param integers The integers
+ * @return The new iterable, use for testing
+ */
+ protected abstract FluentIterable createFluentIterable(final Iterable integers);
+
+ @Test
+ public void testFirst() throws Exception {
+ final List integers = Arrays.asList(1, 2, 3, 10, 9, 8);
+ final Optional first = createFluentIterable(integers).first();
+ assertNotNull(first);
+ assertTrue(first.isPresent());
+ assertEquals(integers.get(0), first.get());
+ }
+
+ @Test
+ public void testFirstEmptyCollection() throws Exception {
+ final List integers = Collections.emptyList();
+ final Optional first = createFluentIterable(integers).first();
+ assertNotNull(first);
+ assertFalse(first.isPresent());
+ }
+
+ @Test
+ public void testFirstCount() throws Exception {
+ final List integers = Arrays.asList(1, 2, 3, 10, 9, 8);
+ final List first4 = createFluentIterable(integers)
+ .first(4)
+ .asList();
+
+ assertNotNull(first4);
+ assertEquals(4, first4.size());
+
+ assertEquals(integers.get(0), first4.get(0));
+ assertEquals(integers.get(1), first4.get(1));
+ assertEquals(integers.get(2), first4.get(2));
+ assertEquals(integers.get(3), first4.get(3));
+ }
+
+ @Test
+ public void testFirstCountLessItems() throws Exception {
+ final List integers = Arrays.asList(1, 2, 3);
+ final List first4 = createFluentIterable(integers)
+ .first(4)
+ .asList();
+
+ assertNotNull(first4);
+ assertEquals(3, first4.size());
+
+ assertEquals(integers.get(0), first4.get(0));
+ assertEquals(integers.get(1), first4.get(1));
+ assertEquals(integers.get(2), first4.get(2));
+ }
+
+ @Test
+ public void testLast() throws Exception {
+ final List integers = Arrays.asList(1, 2, 3, 10, 9, 8);
+ final Optional last = createFluentIterable(integers).last();
+ assertNotNull(last);
+ assertTrue(last.isPresent());
+ assertEquals(integers.get(integers.size() - 1), last.get());
+ }
+
+ @Test
+ public void testLastEmptyCollection() throws Exception {
+ final List integers = Collections.emptyList();
+ final Optional