Adjust checkstyle rules. Make checkstyle fail the build when violations are found. Correct all current checkstyle violations.

This commit is contained in:
Ilkka Seppala 2015-12-25 23:49:28 +02:00
parent 9fbb085985
commit cec9a99410
167 changed files with 1242 additions and 969 deletions

View File

@ -1,20 +1,18 @@
package com.iluwatar.abstractfactory; package com.iluwatar.abstractfactory;
/** /**
* *
* The Abstract Factory pattern provides a way to encapsulate a group of individual factories that * The Abstract Factory pattern provides a way to encapsulate a group of individual factories that have a common theme
* have a common theme without specifying their concrete classes. In normal usage, the client * without specifying their concrete classes. In normal usage, the client software creates a concrete implementation of
* software creates a concrete implementation of the abstract factory and then uses the generic * the abstract factory and then uses the generic interface of the factory to create the concrete objects that are part
* interface of the factory to create the concrete objects that are part of the theme. The client * of the theme. The client does not know (or care) which concrete objects it gets from each of these internal
* does not know (or care) which concrete objects it gets from each of these internal factories, * factories, since it uses only the generic interfaces of their products. This pattern separates the details of
* since it uses only the generic interfaces of their products. This pattern separates the details * implementation of a set of objects from their general usage and relies on object composition, as object creation is
* of implementation of a set of objects from their general usage and relies on object composition, * implemented in methods exposed in the factory interface.
* as object creation is implemented in methods exposed in the factory interface.
* <p> * <p>
* The essence of the Abstract Factory pattern is a factory interface ({@link KingdomFactory}) and * The essence of the Abstract Factory pattern is a factory interface ({@link KingdomFactory}) and its implementations (
* its implementations ({@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses both * {@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses both concrete implementations to create a
* concrete implementations to create a king, a castle and an army. * king, a castle and an army.
* *
*/ */
public class App { public class App {
@ -23,11 +21,8 @@ public class App {
private Castle castle; private Castle castle;
private Army army; private Army army;
/** /**
* Creates kingdom * Creates kingdom
*
* @param factory
*/ */
public void createKingdom(final KingdomFactory factory) { public void createKingdom(final KingdomFactory factory) {
setKing(factory.createKing()); setKing(factory.createKing());
@ -47,14 +42,6 @@ public class App {
return factory.createKing(); return factory.createKing();
} }
Castle getCastle(final KingdomFactory factory) {
return factory.createCastle();
}
Army getArmy(final KingdomFactory factory) {
return factory.createArmy();
}
public King getKing() { public King getKing() {
return king; return king;
} }
@ -62,6 +49,10 @@ public class App {
private void setKing(final King king) { private void setKing(final King king) {
this.king = king; this.king = king;
} }
Castle getCastle(final KingdomFactory factory) {
return factory.createCastle();
}
public Castle getCastle() { public Castle getCastle() {
return castle; return castle;
@ -70,6 +61,10 @@ public class App {
private void setCastle(final Castle castle) { private void setCastle(final Castle castle) {
this.castle = castle; this.castle = castle;
} }
Army getArmy(final KingdomFactory factory) {
return factory.createArmy();
}
public Army getArmy() { public Army getArmy() {
return army; return army;
@ -79,32 +74,32 @@ public class App {
this.army = army; this.army = army;
} }
/** /**
* Program entry point * Program entry point
* *
* @param args command line args * @param args
* command line args
*/ */
public static void main(String[] args) { public static void main(String[] args) {
App app = new App(); App app = new App();
System.out.println("Elf Kingdom"); System.out.println("Elf Kingdom");
KingdomFactory elfKingdomFactory; KingdomFactory elfKingdomFactory;
elfKingdomFactory = app.getElfKingdomFactory(); elfKingdomFactory = app.getElfKingdomFactory();
app.createKingdom(elfKingdomFactory); app.createKingdom(elfKingdomFactory);
System.out.println(app.getArmy().getDescription()); System.out.println(app.getArmy().getDescription());
System.out.println(app.getCastle().getDescription()); System.out.println(app.getCastle().getDescription());
System.out.println(app.getKing().getDescription()); System.out.println(app.getKing().getDescription());
System.out.println("\nOrc Kingdom"); System.out.println("\nOrc Kingdom");
KingdomFactory orcKingdomFactory; KingdomFactory orcKingdomFactory;
orcKingdomFactory = app.getOrcKingdomFactory(); orcKingdomFactory = app.getOrcKingdomFactory();
app.createKingdom(orcKingdomFactory); app.createKingdom(orcKingdomFactory);
System.out.println(app.getArmy().getDescription()); System.out.println(app.getArmy().getDescription());
System.out.println(app.getCastle().getDescription()); System.out.println(app.getCastle().getDescription());
System.out.println(app.getKing().getDescription()); System.out.println(app.getKing().getDescription());
} }
} }

View File

@ -4,24 +4,23 @@ import java.util.concurrent.Callable;
/** /**
* This application demonstrates the async method invocation pattern. Key parts of the pattern are * This application demonstrates the async method invocation pattern. Key parts of the pattern are
* <code>AsyncResult</code> which is an intermediate container for an asynchronously evaluated * <code>AsyncResult</code> which is an intermediate container for an asynchronously evaluated value,
* value, <code>AsyncCallback</code> which can be provided to be executed on task completion and * <code>AsyncCallback</code> which can be provided to be executed on task completion and <code>AsyncExecutor</code>
* <code>AsyncExecutor</code> that manages the execution of the async tasks. * that manages the execution of the async tasks.
* <p> * <p>
* The main method shows example flow of async invocations. The main thread starts multiple tasks * The main method shows example flow of async invocations. The main thread starts multiple tasks with variable
* with variable durations and then continues its own work. When the main thread has done it's job * durations and then continues its own work. When the main thread has done it's job it collects the results of the
* it collects the results of the async tasks. Two of the tasks are handled with callbacks, meaning * async tasks. Two of the tasks are handled with callbacks, meaning the callbacks are executed immediately when the
* the callbacks are executed immediately when the tasks complete. * tasks complete.
* <p> * <p>
* Noteworthy difference of thread usage between the async results and callbacks is that the async * Noteworthy difference of thread usage between the async results and callbacks is that the async results are collected
* results are collected in the main thread but the callbacks are executed within the worker * in the main thread but the callbacks are executed within the worker threads. This should be noted when working with
* threads. This should be noted when working with thread pools. * thread pools.
* <p> * <p>
* Java provides its own implementations of async method invocation pattern. FutureTask, * Java provides its own implementations of async method invocation pattern. FutureTask, CompletableFuture and
* CompletableFuture and ExecutorService are the real world implementations of this pattern. But due * ExecutorService are the real world implementations of this pattern. But due to the nature of parallel programming,
* to the nature of parallel programming, the implementations are not trivial. This example does not * the implementations are not trivial. This example does not take all possible scenarios into account but rather
* take all possible scenarios into account but rather provides a simple version that helps to * provides a simple version that helps to understand the pattern.
* understand the pattern.
* *
* @see AsyncResult * @see AsyncResult
* @see AsyncCallback * @see AsyncCallback
@ -33,6 +32,9 @@ import java.util.concurrent.Callable;
*/ */
public class App { public class App {
/**
* Program entry point
*/
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
// construct a new executor that will run async tasks // construct a new executor that will run async tasks
AsyncExecutor executor = new ThreadAsyncExecutor(); AsyncExecutor executor = new ThreadAsyncExecutor();
@ -41,10 +43,8 @@ public class App {
AsyncResult<Integer> asyncResult1 = executor.startProcess(lazyval(10, 500)); AsyncResult<Integer> asyncResult1 = executor.startProcess(lazyval(10, 500));
AsyncResult<String> asyncResult2 = executor.startProcess(lazyval("test", 300)); AsyncResult<String> asyncResult2 = executor.startProcess(lazyval("test", 300));
AsyncResult<Long> asyncResult3 = executor.startProcess(lazyval(50L, 700)); AsyncResult<Long> asyncResult3 = executor.startProcess(lazyval(50L, 700));
AsyncResult<Integer> asyncResult4 = AsyncResult<Integer> asyncResult4 = executor.startProcess(lazyval(20, 400), callback("Callback result 4"));
executor.startProcess(lazyval(20, 400), callback("Callback result 4")); AsyncResult<String> asyncResult5 = executor.startProcess(lazyval("callback", 600), callback("Callback result 5"));
AsyncResult<String> 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 // 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 Thread.sleep(350); // Oh boy I'm working hard here
@ -66,8 +66,10 @@ public class App {
/** /**
* Creates a callable that lazily evaluates to given value with artificial delay. * Creates a callable that lazily evaluates to given value with artificial delay.
* *
* @param value value to evaluate * @param value
* @param delayMillis artificial delay in milliseconds * value to evaluate
* @param delayMillis
* artificial delay in milliseconds
* @return new callable for lazy evaluation * @return new callable for lazy evaluation
*/ */
private static <T> Callable<T> lazyval(T value, long delayMillis) { private static <T> Callable<T> lazyval(T value, long delayMillis) {
@ -81,7 +83,8 @@ public class App {
/** /**
* Creates a simple callback that logs the complete status of the async result. * Creates a simple callback that logs the complete status of the async result.
* *
* @param name callback name * @param name
* callback name
* @return new async callback * @return new async callback
*/ */
private static <T> AsyncCallback<T> callback(String name) { private static <T> AsyncCallback<T> callback(String name) {

View File

@ -5,8 +5,6 @@ import java.util.concurrent.ExecutionException;
/** /**
* *
* AsyncResult interface * AsyncResult interface
*
* @param <T>
*/ */
public interface AsyncResult<T> { public interface AsyncResult<T> {

View File

@ -29,13 +29,12 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
} catch (Exception ex) { } catch (Exception ex) {
result.setException(ex); result.setException(ex);
} }
}, "executor-" + idx.incrementAndGet()).start(); } , "executor-" + idx.incrementAndGet()).start();
return result; return result;
} }
@Override @Override
public <T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException, public <T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException, InterruptedException {
InterruptedException {
if (asyncResult.isCompleted()) { if (asyncResult.isCompleted()) {
return asyncResult.getValue(); return asyncResult.getValue();
} else { } else {
@ -45,9 +44,8 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
} }
/** /**
* Simple implementation of async result that allows completing it successfully with a value or * Simple implementation of async result that allows completing it successfully with a value or exceptionally with an
* exceptionally with an exception. A really simplified version from its real life cousins * exception. A really simplified version from its real life cousins FutureTask and CompletableFuture.
* FutureTask and CompletableFuture.
* *
* @see java.util.concurrent.FutureTask * @see java.util.concurrent.FutureTask
* @see java.util.concurrent.CompletableFuture * @see java.util.concurrent.CompletableFuture
@ -71,10 +69,11 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
} }
/** /**
* Sets the value from successful execution and executes callback if available. Notifies any * Sets the value from successful execution and executes callback if available. Notifies any thread waiting for
* thread waiting for completion. * completion.
* *
* @param value value of the evaluated task * @param value
* value of the evaluated task
*/ */
void setValue(T value) { void setValue(T value) {
this.value = value; this.value = value;
@ -86,10 +85,11 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
} }
/** /**
* Sets the exception from failed execution and executes callback if available. Notifies any * Sets the exception from failed execution and executes callback if available. Notifies any thread waiting for
* thread waiting for completion. * completion.
* *
* @param exception exception of the failed task * @param exception
* exception of the failed task
*/ */
void setException(Exception exception) { void setException(Exception exception) {
this.exception = exception; this.exception = exception;

View File

@ -55,8 +55,7 @@ public class ThreadAsyncExecutorTest {
} }
/** /**
* Test used to verify the happy path of * Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)}
* {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)}
*/ */
@Test(timeout = 3000) @Test(timeout = 3000)
public void testSuccessfulTaskWithCallback() throws Exception { public void testSuccessfulTaskWithCallback() throws Exception {
@ -77,8 +76,7 @@ public class ThreadAsyncExecutorTest {
verify(task, times(1)).call(); verify(task, times(1)).call();
// ... same for the callback, we expect our object // ... same for the callback, we expect our object
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
.forClass((Class) Optional.class);
verify(callback, times(1)).onComplete(eq(result), optionalCaptor.capture()); verify(callback, times(1)).onComplete(eq(result), optionalCaptor.capture());
final Optional<Exception> optionalException = optionalCaptor.getValue(); final Optional<Exception> optionalException = optionalCaptor.getValue();
@ -90,8 +88,8 @@ public class ThreadAsyncExecutorTest {
} }
/** /**
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a * Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a task takes a while
* task takes a while to execute * to execute
*/ */
@Test(timeout = 5000) @Test(timeout = 5000)
public void testLongRunningTaskWithoutCallback() throws Exception { public void testLongRunningTaskWithoutCallback() throws Exception {
@ -101,9 +99,9 @@ public class ThreadAsyncExecutorTest {
final Object result = new Object(); final Object result = new Object();
final Callable<Object> task = mock(Callable.class); final Callable<Object> task = mock(Callable.class);
when(task.call()).thenAnswer(i -> { when(task.call()).thenAnswer(i -> {
Thread.sleep(1500); Thread.sleep(1500);
return result; return result;
}); });
final AsyncResult<Object> asyncResult = executor.startProcess(task); final AsyncResult<Object> asyncResult = executor.startProcess(task);
assertNotNull(asyncResult); assertNotNull(asyncResult);
@ -111,8 +109,7 @@ public class ThreadAsyncExecutorTest {
try { try {
asyncResult.getValue(); asyncResult.getValue();
fail( fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
"Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
assertNotNull(e.getMessage()); assertNotNull(e.getMessage());
} }
@ -130,9 +127,8 @@ public class ThreadAsyncExecutorTest {
} }
/** /**
* Test used to verify the happy path of * Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when a task
* {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when a task takes a while to * takes a while to execute
* execute
*/ */
@Test(timeout = 5000) @Test(timeout = 5000)
public void testLongRunningTaskWithCallback() throws Exception { public void testLongRunningTaskWithCallback() throws Exception {
@ -142,9 +138,9 @@ public class ThreadAsyncExecutorTest {
final Object result = new Object(); final Object result = new Object();
final Callable<Object> task = mock(Callable.class); final Callable<Object> task = mock(Callable.class);
when(task.call()).thenAnswer(i -> { when(task.call()).thenAnswer(i -> {
Thread.sleep(1500); Thread.sleep(1500);
return result; return result;
}); });
final AsyncCallback<Object> callback = mock(AsyncCallback.class); final AsyncCallback<Object> callback = mock(AsyncCallback.class);
final AsyncResult<Object> asyncResult = executor.startProcess(task, callback); final AsyncResult<Object> asyncResult = executor.startProcess(task, callback);
@ -155,8 +151,7 @@ public class ThreadAsyncExecutorTest {
try { try {
asyncResult.getValue(); asyncResult.getValue();
fail( fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
"Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
assertNotNull(e.getMessage()); assertNotNull(e.getMessage());
} }
@ -164,8 +159,7 @@ public class ThreadAsyncExecutorTest {
// Our task should only execute once, but it can take a while ... // Our task should only execute once, but it can take a while ...
verify(task, timeout(3000).times(1)).call(); verify(task, timeout(3000).times(1)).call();
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
.forClass((Class) Optional.class);
verify(callback, timeout(3000).times(1)).onComplete(eq(result), optionalCaptor.capture()); verify(callback, timeout(3000).times(1)).onComplete(eq(result), optionalCaptor.capture());
final Optional<Exception> optionalException = optionalCaptor.getValue(); final Optional<Exception> optionalException = optionalCaptor.getValue();
@ -182,9 +176,8 @@ public class ThreadAsyncExecutorTest {
} }
/** /**
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a * Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a task takes a while
* task takes a while to execute, while waiting on the result using * to execute, while waiting on the result using {@link ThreadAsyncExecutor#endProcess(AsyncResult)}
* {@link ThreadAsyncExecutor#endProcess(AsyncResult)}
*/ */
@Test(timeout = 5000) @Test(timeout = 5000)
public void testEndProcess() throws Exception { public void testEndProcess() throws Exception {
@ -194,9 +187,9 @@ public class ThreadAsyncExecutorTest {
final Object result = new Object(); final Object result = new Object();
final Callable<Object> task = mock(Callable.class); final Callable<Object> task = mock(Callable.class);
when(task.call()).thenAnswer(i -> { when(task.call()).thenAnswer(i -> {
Thread.sleep(1500); Thread.sleep(1500);
return result; return result;
}); });
final AsyncResult<Object> asyncResult = executor.startProcess(task); final AsyncResult<Object> asyncResult = executor.startProcess(task);
assertNotNull(asyncResult); assertNotNull(asyncResult);
@ -204,8 +197,7 @@ public class ThreadAsyncExecutorTest {
try { try {
asyncResult.getValue(); asyncResult.getValue();
fail( fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
"Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
assertNotNull(e.getMessage()); assertNotNull(e.getMessage());
} }
@ -220,8 +212,7 @@ public class ThreadAsyncExecutorTest {
} }
/** /**
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable)} when * Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable)} when the callable is 'null'
* the callable is 'null'
*/ */
@Test(timeout = 3000) @Test(timeout = 3000)
public void testNullTask() throws Exception { public void testNullTask() throws Exception {
@ -229,8 +220,7 @@ public class ThreadAsyncExecutorTest {
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor(); final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
final AsyncResult<Object> asyncResult = executor.startProcess(null); final AsyncResult<Object> asyncResult = executor.startProcess(null);
assertNotNull("The AsyncResult should not be 'null', even though the task was 'null'.", assertNotNull("The AsyncResult should not be 'null', even though the task was 'null'.", asyncResult);
asyncResult);
asyncResult.await(); // Prevent timing issues, and wait until the result is available asyncResult.await(); // Prevent timing issues, and wait until the result is available
assertTrue(asyncResult.isCompleted()); assertTrue(asyncResult.isCompleted());
@ -246,9 +236,8 @@ public class ThreadAsyncExecutorTest {
} }
/** /**
* Test used to verify the behaviour of * Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when the
* {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when the callable is 'null', * callable is 'null', but the asynchronous callback is provided
* but the asynchronous callback is provided
*/ */
@Test(timeout = 3000) @Test(timeout = 3000)
public void testNullTaskWithCallback() throws Exception { public void testNullTaskWithCallback() throws Exception {
@ -257,13 +246,11 @@ public class ThreadAsyncExecutorTest {
final AsyncCallback<Object> callback = mock(AsyncCallback.class); final AsyncCallback<Object> callback = mock(AsyncCallback.class);
final AsyncResult<Object> asyncResult = executor.startProcess(null, callback); final AsyncResult<Object> asyncResult = executor.startProcess(null, callback);
assertNotNull("The AsyncResult should not be 'null', even though the task was 'null'.", assertNotNull("The AsyncResult should not be 'null', even though the task was 'null'.", asyncResult);
asyncResult);
asyncResult.await(); // Prevent timing issues, and wait until the result is available asyncResult.await(); // Prevent timing issues, and wait until the result is available
assertTrue(asyncResult.isCompleted()); assertTrue(asyncResult.isCompleted());
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
.forClass((Class) Optional.class);
verify(callback, times(1)).onComplete(Matchers.isNull(), optionalCaptor.capture()); verify(callback, times(1)).onComplete(Matchers.isNull(), optionalCaptor.capture());
final Optional<Exception> optionalException = optionalCaptor.getValue(); final Optional<Exception> optionalException = optionalCaptor.getValue();
@ -286,9 +273,8 @@ public class ThreadAsyncExecutorTest {
} }
/** /**
* Test used to verify the behaviour of * Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when both
* {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when both the callable and * the callable and the asynchronous callback are 'null'
* the asynchronous callback are 'null'
*/ */
@Test(timeout = 3000) @Test(timeout = 3000)
public void testNullTaskWithNullCallback() throws Exception { public void testNullTaskWithNullCallback() throws Exception {
@ -296,9 +282,7 @@ public class ThreadAsyncExecutorTest {
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor(); final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
final AsyncResult<Object> asyncResult = executor.startProcess(null, null); final AsyncResult<Object> asyncResult = executor.startProcess(null, null);
assertNotNull( assertNotNull("The AsyncResult should not be 'null', even though the task and callback were 'null'.", asyncResult);
"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 asyncResult.await(); // Prevent timing issues, and wait until the result is available
assertTrue(asyncResult.isCompleted()); assertTrue(asyncResult.isCompleted());

View File

@ -93,6 +93,9 @@ public class Hero {
private Armor armor; private Armor armor;
private Weapon weapon; private Weapon weapon;
/**
* Constructor
*/
public HeroBuilder(Profession profession, String name) { public HeroBuilder(Profession profession, String name) {
if (profession == null || name == null) { if (profession == null || name == null) {
throw new IllegalArgumentException("profession and name can not be null"); throw new IllegalArgumentException("profession and name can not be null");

View File

@ -5,20 +5,20 @@ package com.iluwatar.business.delegate;
*/ */
public class BusinessDelegate { public class BusinessDelegate {
private BusinessLookup lookupService; private BusinessLookup lookupService;
private BusinessService businessService; private BusinessService businessService;
private ServiceType serviceType; private ServiceType serviceType;
public void setLookupService(BusinessLookup businessLookup) { public void setLookupService(BusinessLookup businessLookup) {
this.lookupService = businessLookup; this.lookupService = businessLookup;
} }
public void setServiceType(ServiceType serviceType) { public void setServiceType(ServiceType serviceType) {
this.serviceType = serviceType; this.serviceType = serviceType;
} }
public void doTask() { public void doTask() {
businessService = lookupService.getBusinessService(serviceType); businessService = lookupService.getBusinessService(serviceType);
businessService.doProcessing(); businessService.doProcessing();
} }
} }

View File

@ -21,7 +21,7 @@ package com.iluwatar.caching;
* application data. The cache itself is implemented as an internal (Java) data structure. It adopts * 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 * 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 * 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 ( * 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 * {@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 * 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 * ({@link AppManager}) handles the transaction of data to-and-from the underlying data store
@ -43,7 +43,7 @@ public class App {
* @param args command line args * @param args command line args
*/ */
public static void main(String[] args) { public static void main(String[] args) {
AppManager.initDB(false); // VirtualDB (instead of MongoDB) was used in running the JUnit tests 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 // and the App class to avoid Maven compilation errors. Set flag to
// true to run the tests with MongoDB (provided that MongoDB is // true to run the tests with MongoDB (provided that MongoDB is
// installed and socket connection is open). // installed and socket connection is open).

View File

@ -21,18 +21,21 @@ public class AppManager {
* data storage or a simple Java data structure to (temporarily) store the data/objects during * data storage or a simple Java data structure to (temporarily) store the data/objects during
* runtime. * runtime.
*/ */
public static void initDB(boolean useMongoDB) { public static void initDb(boolean useMongoDb) {
if (useMongoDB) { if (useMongoDb) {
try { try {
DBManager.connect(); DbManager.connect();
} catch (ParseException e) { } catch (ParseException e) {
e.printStackTrace(); e.printStackTrace();
} }
} else { } else {
DBManager.createVirtualDB(); DbManager.createVirtualDb();
} }
} }
/**
* Initialize caching policy
*/
public static void initCachingPolicy(CachingPolicy policy) { public static void initCachingPolicy(CachingPolicy policy) {
cachingPolicy = policy; cachingPolicy = policy;
if (cachingPolicy == CachingPolicy.BEHIND) { if (cachingPolicy == CachingPolicy.BEHIND) {
@ -50,15 +53,21 @@ public class AppManager {
CacheStore.initCapacity(capacity); CacheStore.initCapacity(capacity);
} }
public static UserAccount find(String userID) { /**
* Find user account
*/
public static UserAccount find(String userId) {
if (cachingPolicy == CachingPolicy.THROUGH || cachingPolicy == CachingPolicy.AROUND) { if (cachingPolicy == CachingPolicy.THROUGH || cachingPolicy == CachingPolicy.AROUND) {
return CacheStore.readThrough(userID); return CacheStore.readThrough(userId);
} else if (cachingPolicy == CachingPolicy.BEHIND) { } else if (cachingPolicy == CachingPolicy.BEHIND) {
return CacheStore.readThroughWithWriteBackPolicy(userID); return CacheStore.readThroughWithWriteBackPolicy(userId);
} }
return null; return null;
} }
/**
* Save user account
*/
public static void save(UserAccount userAccount) { public static void save(UserAccount userAccount) {
if (cachingPolicy == CachingPolicy.THROUGH) { if (cachingPolicy == CachingPolicy.THROUGH) {
CacheStore.writeThrough(userAccount); CacheStore.writeThrough(userAccount);

View File

@ -9,73 +9,96 @@ import java.util.ArrayList;
*/ */
public class CacheStore { public class CacheStore {
static LRUCache cache = null; static LruCache cache = null;
/**
* Init cache capacity
*/
public static void initCapacity(int capacity) { public static void initCapacity(int capacity) {
if (null == cache) if (null == cache) {
cache = new LRUCache(capacity); cache = new LruCache(capacity);
else } else {
cache.setCapacity(capacity); cache.setCapacity(capacity);
}
} }
public static UserAccount readThrough(String userID) { /**
if (cache.contains(userID)) { * Get user account using read-through cache
*/
public static UserAccount readThrough(String userId) {
if (cache.contains(userId)) {
System.out.println("# Cache Hit!"); System.out.println("# Cache Hit!");
return cache.get(userID); return cache.get(userId);
} }
System.out.println("# Cache Miss!"); System.out.println("# Cache Miss!");
UserAccount userAccount = DBManager.readFromDB(userID); UserAccount userAccount = DbManager.readFromDb(userId);
cache.set(userID, userAccount); cache.set(userId, userAccount);
return userAccount; return userAccount;
} }
/**
* Get user account using write-through cache
*/
public static void writeThrough(UserAccount userAccount) { public static void writeThrough(UserAccount userAccount) {
if (cache.contains(userAccount.getUserID())) { if (cache.contains(userAccount.getUserId())) {
DBManager.updateDB(userAccount); DbManager.updateDb(userAccount);
} else { } else {
DBManager.writeToDB(userAccount); DbManager.writeToDb(userAccount);
} }
cache.set(userAccount.getUserID(), userAccount); cache.set(userAccount.getUserId(), userAccount);
} }
/**
* Get user account using write-around cache
*/
public static void writeAround(UserAccount userAccount) { public static void writeAround(UserAccount userAccount) {
if (cache.contains(userAccount.getUserID())) { if (cache.contains(userAccount.getUserId())) {
DBManager.updateDB(userAccount); DbManager.updateDb(userAccount);
cache.invalidate(userAccount.getUserID()); // Cache data has been updated -- remove older cache.invalidate(userAccount.getUserId()); // Cache data has been updated -- remove older
// version from cache. // version from cache.
} else { } else {
DBManager.writeToDB(userAccount); DbManager.writeToDb(userAccount);
} }
} }
public static UserAccount readThroughWithWriteBackPolicy(String userID) { /**
if (cache.contains(userID)) { * 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!"); System.out.println("# Cache Hit!");
return cache.get(userID); return cache.get(userId);
} }
System.out.println("# Cache Miss!"); System.out.println("# Cache Miss!");
UserAccount userAccount = DBManager.readFromDB(userID); UserAccount userAccount = DbManager.readFromDb(userId);
if (cache.isFull()) { if (cache.isFull()) {
System.out.println("# Cache is FULL! Writing LRU data to DB..."); System.out.println("# Cache is FULL! Writing LRU data to DB...");
UserAccount toBeWrittenToDB = cache.getLRUData(); UserAccount toBeWrittenToDb = cache.getLruData();
DBManager.upsertDB(toBeWrittenToDB); DbManager.upsertDb(toBeWrittenToDb);
} }
cache.set(userID, userAccount); cache.set(userId, userAccount);
return userAccount; return userAccount;
} }
/**
* Set user account
*/
public static void writeBehind(UserAccount userAccount) { public static void writeBehind(UserAccount userAccount) {
if (cache.isFull() && !cache.contains(userAccount.getUserID())) { if (cache.isFull() && !cache.contains(userAccount.getUserId())) {
System.out.println("# Cache is FULL! Writing LRU data to DB..."); System.out.println("# Cache is FULL! Writing LRU data to DB...");
UserAccount toBeWrittenToDB = cache.getLRUData(); UserAccount toBeWrittenToDb = cache.getLruData();
DBManager.upsertDB(toBeWrittenToDB); DbManager.upsertDb(toBeWrittenToDb);
} }
cache.set(userAccount.getUserID(), userAccount); cache.set(userAccount.getUserId(), userAccount);
} }
/**
* Clears cache
*/
public static void clearCache() { public static void clearCache() {
if (null != cache) if (null != cache) {
cache.clear(); cache.clear();
}
} }
/** /**
@ -83,14 +106,18 @@ public class CacheStore {
*/ */
public static void flushCache() { public static void flushCache() {
System.out.println("# flushCache..."); System.out.println("# flushCache...");
if (null == cache) if (null == cache) {
return; return;
}
ArrayList<UserAccount> listOfUserAccounts = cache.getCacheDataInListForm(); ArrayList<UserAccount> listOfUserAccounts = cache.getCacheDataInListForm();
for (UserAccount userAccount : listOfUserAccounts) { for (UserAccount userAccount : listOfUserAccounts) {
DBManager.upsertDB(userAccount); DbManager.upsertDb(userAccount);
} }
} }
/**
* Print user accounts
*/
public static String print() { public static String print() {
ArrayList<UserAccount> listOfUserAccounts = cache.getCacheDataInListForm(); ArrayList<UserAccount> listOfUserAccounts = cache.getCacheDataInListForm();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();

View File

@ -21,7 +21,7 @@ import com.mongodb.client.model.UpdateOptions;
* during runtime (createVirtualDB()).</p> * during runtime (createVirtualDB()).</p>
* *
*/ */
public class DBManager { public class DbManager {
private static MongoClient mongoClient; private static MongoClient mongoClient;
private static MongoDatabase db; private static MongoDatabase db;
@ -29,21 +29,31 @@ public class DBManager {
private static HashMap<String, UserAccount> virtualDB; private static HashMap<String, UserAccount> virtualDB;
public static void createVirtualDB() { /**
* Create DB
*/
public static void createVirtualDb() {
useMongoDB = false; useMongoDB = false;
virtualDB = new HashMap<String, UserAccount>(); virtualDB = new HashMap<String, UserAccount>();
} }
/**
* Connect to DB
*/
public static void connect() throws ParseException { public static void connect() throws ParseException {
useMongoDB = true; useMongoDB = true;
mongoClient = new MongoClient(); mongoClient = new MongoClient();
db = mongoClient.getDatabase("test"); db = mongoClient.getDatabase("test");
} }
public static UserAccount readFromDB(String userID) { /**
* Read user account from DB
*/
public static UserAccount readFromDb(String userId) {
if (!useMongoDB) { if (!useMongoDB) {
if (virtualDB.containsKey(userID)) if (virtualDB.containsKey(userId)) {
return virtualDB.get(userID); return virtualDB.get(userId);
}
return null; return null;
} }
if (null == db) { if (null == db) {
@ -54,18 +64,22 @@ public class DBManager {
} }
} }
FindIterable<Document> iterable = FindIterable<Document> iterable =
db.getCollection("user_accounts").find(new Document("userID", userID)); db.getCollection("user_accounts").find(new Document("userID", userId));
if (iterable == null) if (iterable == null) {
return null; return null;
}
Document doc = iterable.first(); Document doc = iterable.first();
UserAccount userAccount = UserAccount userAccount =
new UserAccount(userID, doc.getString("userName"), doc.getString("additionalInfo")); new UserAccount(userId, doc.getString("userName"), doc.getString("additionalInfo"));
return userAccount; return userAccount;
} }
public static void writeToDB(UserAccount userAccount) { /**
* Write user account to DB
*/
public static void writeToDb(UserAccount userAccount) {
if (!useMongoDB) { if (!useMongoDB) {
virtualDB.put(userAccount.getUserID(), userAccount); virtualDB.put(userAccount.getUserId(), userAccount);
return; return;
} }
if (null == db) { if (null == db) {
@ -76,13 +90,16 @@ public class DBManager {
} }
} }
db.getCollection("user_accounts").insertOne( db.getCollection("user_accounts").insertOne(
new Document("userID", userAccount.getUserID()).append("userName", new Document("userID", userAccount.getUserId()).append("userName",
userAccount.getUserName()).append("additionalInfo", userAccount.getAdditionalInfo())); userAccount.getUserName()).append("additionalInfo", userAccount.getAdditionalInfo()));
} }
public static void updateDB(UserAccount userAccount) { /**
* Update DB
*/
public static void updateDb(UserAccount userAccount) {
if (!useMongoDB) { if (!useMongoDB) {
virtualDB.put(userAccount.getUserID(), userAccount); virtualDB.put(userAccount.getUserId(), userAccount);
return; return;
} }
if (null == db) { if (null == db) {
@ -93,7 +110,7 @@ public class DBManager {
} }
} }
db.getCollection("user_accounts").updateOne( db.getCollection("user_accounts").updateOne(
new Document("userID", userAccount.getUserID()), new Document("userID", userAccount.getUserId()),
new Document("$set", new Document("userName", userAccount.getUserName()).append( new Document("$set", new Document("userName", userAccount.getUserName()).append(
"additionalInfo", userAccount.getAdditionalInfo()))); "additionalInfo", userAccount.getAdditionalInfo())));
} }
@ -102,9 +119,9 @@ public class DBManager {
* *
* Insert data into DB if it does not exist. Else, update it. * Insert data into DB if it does not exist. Else, update it.
*/ */
public static void upsertDB(UserAccount userAccount) { public static void upsertDb(UserAccount userAccount) {
if (!useMongoDB) { if (!useMongoDB) {
virtualDB.put(userAccount.getUserID(), userAccount); virtualDB.put(userAccount.getUserId(), userAccount);
return; return;
} }
if (null == db) { if (null == db) {
@ -115,8 +132,8 @@ public class DBManager {
} }
} }
db.getCollection("user_accounts").updateOne( db.getCollection("user_accounts").updateOne(
new Document("userID", userAccount.getUserID()), new Document("userID", userAccount.getUserId()),
new Document("$set", new Document("userID", userAccount.getUserID()).append("userName", new Document("$set", new Document("userID", userAccount.getUserId()).append("userName",
userAccount.getUserName()).append("additionalInfo", userAccount.getAdditionalInfo())), userAccount.getUserName()).append("additionalInfo", userAccount.getAdditionalInfo())),
new UpdateOptions().upsert(true)); new UpdateOptions().upsert(true));
} }

View File

@ -12,16 +12,16 @@ import java.util.HashMap;
* LRU data is always at the end of the list. * LRU data is always at the end of the list.
* *
*/ */
public class LRUCache { public class LruCache {
class Node { class Node {
String userID; String userId;
UserAccount userAccount; UserAccount userAccount;
Node previous; Node previous;
Node next; Node next;
public Node(String userID, UserAccount userAccount) { public Node(String userId, UserAccount userAccount) {
this.userID = userID; this.userId = userId;
this.userAccount = userAccount; this.userAccount = userAccount;
} }
} }
@ -31,13 +31,16 @@ public class LRUCache {
Node head = null; Node head = null;
Node end = null; Node end = null;
public LRUCache(int capacity) { public LruCache(int capacity) {
this.capacity = capacity; this.capacity = capacity;
} }
public UserAccount get(String userID) { /**
if (cache.containsKey(userID)) { * Get user account
Node node = cache.get(userID); */
public UserAccount get(String userId) {
if (cache.containsKey(userId)) {
Node node = cache.get(userId);
remove(node); remove(node);
setHead(node); setHead(node);
return node.userAccount; return node.userAccount;
@ -69,52 +72,63 @@ public class LRUCache {
public void setHead(Node node) { public void setHead(Node node) {
node.next = head; node.next = head;
node.previous = null; node.previous = null;
if (head != null) if (head != null) {
head.previous = node; head.previous = node;
}
head = node; head = node;
if (end == null) if (end == null) {
end = head; end = head;
}
} }
public void set(String userID, UserAccount userAccount) { /**
if (cache.containsKey(userID)) { * Set user account
Node old = cache.get(userID); */
public void set(String userId, UserAccount userAccount) {
if (cache.containsKey(userId)) {
Node old = cache.get(userId);
old.userAccount = userAccount; old.userAccount = userAccount;
remove(old); remove(old);
setHead(old); setHead(old);
} else { } else {
Node newNode = new Node(userID, userAccount); Node newNode = new Node(userId, userAccount);
if (cache.size() >= capacity) { if (cache.size() >= capacity) {
System.out.println("# Cache is FULL! Removing " + end.userID + " from cache..."); System.out.println("# Cache is FULL! Removing " + end.userId + " from cache...");
cache.remove(end.userID); // remove LRU data from cache. cache.remove(end.userId); // remove LRU data from cache.
remove(end); remove(end);
setHead(newNode); setHead(newNode);
} else { } else {
setHead(newNode); setHead(newNode);
} }
cache.put(userID, newNode); cache.put(userId, newNode);
} }
} }
public boolean contains(String userID) { public boolean contains(String userId) {
return cache.containsKey(userID); return cache.containsKey(userId);
} }
public void invalidate(String userID) { /**
System.out.println("# " + userID + " has been updated! Removing older version from cache..."); * Invalidate cache for user
Node toBeRemoved = cache.get(userID); */
public void invalidate(String userId) {
System.out.println("# " + userId + " has been updated! Removing older version from cache...");
Node toBeRemoved = cache.get(userId);
remove(toBeRemoved); remove(toBeRemoved);
cache.remove(userID); cache.remove(userId);
} }
public boolean isFull() { public boolean isFull() {
return cache.size() >= capacity; return cache.size() >= capacity;
} }
public UserAccount getLRUData() { public UserAccount getLruData() {
return end.userAccount; return end.userAccount;
} }
/**
* Clear cache
*/
public void clear() { public void clear() {
head = null; head = null;
end = null; end = null;
@ -135,6 +149,9 @@ public class LRUCache {
return listOfCacheData; return listOfCacheData;
} }
/**
* Set cache capacity
*/
public void setCapacity(int newCapacity) { public void setCapacity(int newCapacity) {
if (capacity > newCapacity) { if (capacity > newCapacity) {
clear(); // Behavior can be modified to accommodate for decrease in cache size. For now, we'll clear(); // Behavior can be modified to accommodate for decrease in cache size. For now, we'll

View File

@ -6,22 +6,25 @@ package com.iluwatar.caching;
* *
*/ */
public class UserAccount { public class UserAccount {
private String userID; private String userId;
private String userName; private String userName;
private String additionalInfo; private String additionalInfo;
public UserAccount(String userID, String userName, String additionalInfo) { /**
this.userID = userID; * Constructor
*/
public UserAccount(String userId, String userName, String additionalInfo) {
this.userId = userId;
this.userName = userName; this.userName = userName;
this.additionalInfo = additionalInfo; this.additionalInfo = additionalInfo;
} }
public String getUserID() { public String getUserId() {
return userID; return userId;
} }
public void setUserID(String userID) { public void setUserId(String userId) {
this.userID = userID; this.userId = userId;
} }
public String getUserName() { public String getUserName() {
@ -42,6 +45,6 @@ public class UserAccount {
@Override @Override
public String toString() { public String toString() {
return userID + ", " + userName + ", " + additionalInfo; return userId + ", " + userName + ", " + additionalInfo;
} }
} }

View File

@ -16,7 +16,7 @@ public class AppTest {
*/ */
@Before @Before
public void setUp() { public void setUp() {
AppManager.initDB(false); // VirtualDB (instead of MongoDB) was used in running the JUnit tests 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 // to avoid Maven compilation errors. Set flag to true to run the
// tests with MongoDB (provided that MongoDB is installed and socket // tests with MongoDB (provided that MongoDB is installed and socket
// connection is open). // connection is open).

View File

@ -9,6 +9,9 @@ package com.iluwatar.callback;
*/ */
public class App { public class App {
/**
* Program entry point
*/
public static void main(String[] args) { public static void main(String[] args) {
Task task = new SimpleTask(); Task task = new SimpleTask();
Callback callback = new Callback() { Callback callback = new Callback() {

View File

@ -7,6 +7,9 @@ package com.iluwatar.callback;
*/ */
public abstract class Task { public abstract class Task {
/**
* Execute with callback
*/
public final void executeWith(Callback callback) { public final void executeWith(Callback callback) {
execute(); execute();
if (callback != null) { if (callback != null) {

View File

@ -13,6 +13,9 @@ public abstract class RequestHandler {
this.next = next; this.next = next;
} }
/**
* Request handler
*/
public void handleRequest(Request req) { public void handleRequest(Request req) {
if (next != null) { if (next != null) {
next.handleRequest(req); next.handleRequest(req);

View File

@ -25,8 +25,10 @@
<module name="Checker"> <module name="Checker">
<property name="charset" value="UTF-8"/> <property name="charset" value="UTF-8"/>
<property name="fileExtensions" value="java, xml, properties"/>
<property name="severity" value="warning"/> <property name="severity" value="error"/>
<!-- Checks for whitespace --> <!-- Checks for whitespace -->
<!-- See http://checkstyle.sf.net/config_whitespace.html --> <!-- See http://checkstyle.sf.net/config_whitespace.html -->
@ -48,7 +50,7 @@
<property name="allowNonPrintableEscapes" value="true"/> <property name="allowNonPrintableEscapes" value="true"/>
</module> </module>
<module name="LineLength"> <module name="LineLength">
<property name="max" value="100"/> <property name="max" value="120"/>
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/> <property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
</module> </module>
<module name="AvoidStarImport"/> <module name="AvoidStarImport"/>
@ -61,7 +63,7 @@
</module> </module>
<module name="NeedBraces"/> <module name="NeedBraces"/>
<module name="LeftCurly"> <module name="LeftCurly">
<property name="maxLineLength" value="100"/> <property name="maxLineLength" value="120"/>
</module> </module>
<module name="RightCurly"/> <module name="RightCurly"/>
<module name="RightCurly"> <module name="RightCurly">
@ -86,9 +88,6 @@
<module name="FallThrough"/> <module name="FallThrough"/>
<module name="UpperEll"/> <module name="UpperEll"/>
<module name="ModifierOrder"/> <module name="ModifierOrder"/>
<module name="EmptyLineSeparator">
<property name="allowNoEmptyLineBetweenFields" value="true"/>
</module>
<module name="SeparatorWrap"> <module name="SeparatorWrap">
<property name="tokens" value="DOT"/> <property name="tokens" value="DOT"/>
<property name="option" value="nl"/> <property name="option" value="nl"/>
@ -97,42 +96,19 @@
<property name="tokens" value="COMMA"/> <property name="tokens" value="COMMA"/>
<property name="option" value="EOL"/> <property name="option" value="EOL"/>
</module> </module>
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/> <!-- Checks for Naming Conventions. -->
<message key="name.invalidPattern" <!-- See http://checkstyle.sf.net/config_naming.html -->
value="Package name ''{0}'' must match pattern ''{1}''."/> <module name="ConstantName"/>
</module> <module name="LocalFinalVariableName"/>
<module name="TypeName"> <module name="LocalVariableName"/>
<message key="name.invalidPattern" <module name="MemberName"/>
value="Type name ''{0}'' must match pattern ''{1}''."/> <module name="MethodName"/>
</module> <module name="PackageName"/>
<module name="MemberName"> <module name="ParameterName"/>
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/> <module name="StaticVariableName"/>
<message key="name.invalidPattern" <module name="TypeName"/>
value="Member name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ParameterName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
<message key="name.invalidPattern"
value="Parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="LocalVariableName">
<property name="tokens" value="VARIABLE_DEF"/>
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
<property name="allowOneCharVarInForLoop" value="true"/>
<message key="name.invalidPattern"
value="Local variable name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ClassTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Class type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="MethodTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Method type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="NoFinalizer"/> <module name="NoFinalizer"/>
<module name="GenericWhitespace"> <module name="GenericWhitespace">
<message key="ws.followed" <message key="ws.followed"
@ -157,14 +133,6 @@
<property name="allowedAbbreviationLength" value="1"/> <property name="allowedAbbreviationLength" value="1"/>
</module> </module>
<module name="OverloadMethodsDeclarationOrder"/> <module name="OverloadMethodsDeclarationOrder"/>
<module name="VariableDeclarationUsageDistance"/>
<module name="CustomImportOrder">
<property name="thirdPartyPackageRegExp" value=".*"/>
<property name="specialImportsRegExp" value="com.google"/>
<property name="sortImportsInGroupAlphabetically" value="true"/>
<property name="customImportOrderRules"
value="STATIC###SPECIAL_IMPORTS###THIRD_PARTY_PACKAGE###STANDARD_JAVA_PACKAGE"/>
</module>
<module name="MethodParamPad"/> <module name="MethodParamPad"/>
<module name="OperatorWrap"> <module name="OperatorWrap">
<property name="option" value="NL"/> <property name="option" value="NL"/>
@ -180,11 +148,6 @@
</module> </module>
<module name="NonEmptyAtclauseDescription"/> <module name="NonEmptyAtclauseDescription"/>
<module name="JavadocTagContinuationIndentation"/> <module name="JavadocTagContinuationIndentation"/>
<module name="SummaryJavadocCheck">
<property name="forbiddenSummaryFragments"
value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
</module>
<module name="JavadocParagraph"/>
<module name="AtclauseOrder"> <module name="AtclauseOrder">
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/> <property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
<property name="target" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/> <property name="target" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
@ -195,7 +158,7 @@
<property name="allowMissingThrowsTags" value="true"/> <property name="allowMissingThrowsTags" value="true"/>
<property name="allowMissingReturnTag" value="true"/> <property name="allowMissingReturnTag" value="true"/>
<property name="minLineCount" value="2"/> <property name="minLineCount" value="2"/>
<property name="allowedAnnotations" value="Override, Test"/> <property name="allowedAnnotations" value="Override, Test, Before, After, Parameters, Given, When, BeforeClass, AfterClass"/>
<property name="allowThrowsTagsForSubclasses" value="true"/> <property name="allowThrowsTagsForSubclasses" value="true"/>
</module> </module>
<module name="MethodName"> <module name="MethodName">

View File

@ -30,6 +30,9 @@ public abstract class Target {
@Override @Override
public abstract String toString(); public abstract String toString();
/**
* Print status
*/
public void printStatus() { public void printStatus() {
System.out.println(String.format("%s, [size=%s] [visibility=%s]", this, getSize(), System.out.println(String.format("%s, [size=%s] [visibility=%s]", this, getSize(),
getVisibility())); getVisibility()));

View File

@ -15,12 +15,18 @@ public class Wizard {
public Wizard() {} public Wizard() {}
/**
* Cast spell
*/
public void castSpell(Command command, Target target) { public void castSpell(Command command, Target target) {
System.out.println(this + " casts " + command + " at " + target); System.out.println(this + " casts " + command + " at " + target);
command.execute(target); command.execute(target);
undoStack.offerLast(command); undoStack.offerLast(command);
} }
/**
* Undo last spell
*/
public void undoLastSpell() { public void undoLastSpell() {
if (!undoStack.isEmpty()) { if (!undoStack.isEmpty()) {
Command previousSpell = undoStack.pollLast(); Command previousSpell = undoStack.pollLast();
@ -30,6 +36,9 @@ public class Wizard {
} }
} }
/**
* Redo last spell
*/
public void redoLastSpell() { public void redoLastSpell() {
if (!redoStack.isEmpty()) { if (!redoStack.isEmpty()) {
Command previousSpell = redoStack.pollLast(); Command previousSpell = redoStack.pollLast();

View File

@ -24,6 +24,9 @@ public abstract class LetterComposite {
protected abstract void printThisAfter(); protected abstract void printThisAfter();
/**
* Print
*/
public void print() { public void print() {
printThisBefore(); printThisBefore();
for (LetterComposite letter : children) { for (LetterComposite letter : children) {

View File

@ -9,6 +9,9 @@ import java.util.List;
*/ */
public class Sentence extends LetterComposite { public class Sentence extends LetterComposite {
/**
* Constructor
*/
public Sentence(List<Word> words) { public Sentence(List<Word> words) {
for (Word w : words) { for (Word w : words) {
this.add(w); this.add(w);

View File

@ -9,6 +9,9 @@ import java.util.List;
*/ */
public class Word extends LetterComposite { public class Word extends LetterComposite {
/**
* Constructor
*/
public Word(List<Letter> letters) { public Word(List<Letter> letters) {
for (Letter l : letters) { for (Letter l : letters) {
this.add(l); this.add(l);

View File

@ -21,7 +21,7 @@ import org.apache.log4j.Logger;
*/ */
public class App { public class App {
private static Logger LOGGER = Logger.getLogger(App.class); private static Logger log = Logger.getLogger(App.class);
/** /**
* Program entry point. * Program entry point.
@ -30,17 +30,17 @@ public class App {
*/ */
public static void main(final String[] args) { public static void main(final String[] args) {
final CustomerDaoImpl customerDao = new CustomerDaoImpl(generateSampleCustomers()); final CustomerDaoImpl customerDao = new CustomerDaoImpl(generateSampleCustomers());
LOGGER.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers()); log.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
LOGGER.info("customerDao.getCusterById(2): " + customerDao.getCustomerById(2)); log.info("customerDao.getCusterById(2): " + customerDao.getCustomerById(2));
final Customer customer = new Customer(4, "Dan", "Danson"); final Customer customer = new Customer(4, "Dan", "Danson");
customerDao.addCustomer(customer); customerDao.addCustomer(customer);
LOGGER.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers()); log.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
customer.setFirstName("Daniel"); customer.setFirstName("Daniel");
customer.setLastName("Danielson"); customer.setLastName("Danielson");
customerDao.updateCustomer(customer); customerDao.updateCustomer(customer);
LOGGER.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers()); log.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
customerDao.deleteCustomer(customer); customerDao.deleteCustomer(customer);
LOGGER.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers()); log.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
} }
/** /**

View File

@ -11,6 +11,9 @@ public class Customer {
private String firstName; private String firstName;
private String lastName; private String lastName;
/**
* Constructor
*/
public Customer(final int id, final String firstName, final String lastName) { public Customer(final int id, final String firstName, final String lastName) {
this.id = id; this.id = id;
this.firstName = firstName; this.firstName = firstName;
@ -54,8 +57,9 @@ public class Customer {
isEqual = true; isEqual = true;
} else if (o != null && (getClass() == o.getClass())) { } else if (o != null && (getClass() == o.getClass())) {
final Customer customer = (Customer) o; final Customer customer = (Customer) o;
if (getId() == customer.getId()) if (getId() == customer.getId()) {
isEqual = true; isEqual = true;
}
} }
return isEqual; return isEqual;
} }

View File

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration debug="true" <log4j:configuration debug="true"
xmlns:log4j='http://jakarta.apache.org/log4j/'> xmlns:log4j='http://jakarta.apache.org/log4j/'>
<appender name="console" class="org.apache.log4j.ConsoleAppender"> <appender name="console" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout"> <layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" /> <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
</layout> </layout>
</appender> </appender>
<root> <root>
<level value="INFO" /> <level value="INFO" />
<appender-ref ref="console" /> <appender-ref ref="console" />
</root> </root>
</log4j:configuration> </log4j:configuration>

View File

@ -28,7 +28,7 @@ public class App {
ExecutorService executorService = Executors.newFixedThreadPool(3); ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
executorService.execute(() -> { executorService.execute(() -> {
while (inventory.addItem(new Item())); while (inventory.addItem(new Item())) {};
}); });
} }

View File

@ -17,12 +17,18 @@ public class Inventory {
private final List<Item> items; private final List<Item> items;
private final Lock lock; private final Lock lock;
/**
* Constructor
*/
public Inventory(int inventorySize) { public Inventory(int inventorySize) {
this.inventorySize = inventorySize; this.inventorySize = inventorySize;
this.items = new ArrayList<>(inventorySize); this.items = new ArrayList<>(inventorySize);
this.lock = new ReentrantLock(); this.lock = new ReentrantLock();
} }
/**
* Add item
*/
public boolean addItem(Item item) { public boolean addItem(Item item) {
if (items.size() < inventorySize) { if (items.size() < inventorySize) {
lock.lock(); lock.lock();

View File

@ -77,8 +77,8 @@ public class InventoryTest {
final ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT); final ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);
for (int i = 0; i < THREAD_COUNT; i++) { for (int i = 0; i < THREAD_COUNT; i++) {
executorService.execute(() -> { executorService.execute(() -> {
while (inventory.addItem(new Item())) ; while (inventory.addItem(new Item())) {};
}); });
} }
// Wait until all threads have finished // Wait until all threads have finished

View File

@ -5,22 +5,20 @@ import java.util.List;
/** /**
* *
* When a message with a parameter is sent to an object, the resultant behaviour is defined by the * When a message with a parameter is sent to an object, the resultant behaviour is defined by the implementation of
* implementation of that method in the receiver. Sometimes the behaviour must also be determined by * that method in the receiver. Sometimes the behaviour must also be determined by the type of the parameter.
* the type of the parameter.
* <p> * <p>
* One way to implement this would be to create multiple instanceof-checks for the methods * One way to implement this would be to create multiple instanceof-checks for the methods parameter. However, this
* parameter. However, this creates a maintenance issue. When new types are added we would also need * creates a maintenance issue. When new types are added we would also need to change the method's implementation and
* to change the method's implementation and add a new instanceof-check. This violates the single * add a new instanceof-check. This violates the single responsibility principle - a class should have only one reason
* responsibility principle - a class should have only one reason to change. * to change.
* <p> * <p>
* Instead of the instanceof-checks a better way is to make another virtual call on the parameter * Instead of the instanceof-checks a better way is to make another virtual call on the parameter object. This way new
* object. This way new functionality can be easily added without the need to modify existing * functionality can be easily added without the need to modify existing implementation (open-closed principle).
* implementation (open-closed principle).
* <p> * <p>
* In this example we have hierarchy of objects ({@link GameObject}) that can collide to each other. * In this example we have hierarchy of objects ({@link GameObject}) that can collide to each other. Each object has its
* Each object has its own coordinates which are checked against the other objects' coordinates. If * own coordinates which are checked against the other objects' coordinates. If there is an overlap, then the objects
* there is an overlap, then the objects collide utilizing the Double Dispatch pattern. * collide utilizing the Double Dispatch pattern.
* *
*/ */
public class App { public class App {
@ -28,7 +26,8 @@ public class App {
/** /**
* Program entry point * Program entry point
* *
* @param args command line args * @param args
* command line args
*/ */
public static void main(String[] args) { public static void main(String[] args) {
// initialize game objects and print their status // initialize game objects and print their status
@ -42,8 +41,9 @@ public class App {
// collision check // collision check
objects.stream().forEach(o1 -> objects.stream().forEach(o2 -> { objects.stream().forEach(o1 -> objects.stream().forEach(o2 -> {
if (o1 != o2 && o1.intersectsWith(o2)) if (o1 != o2 && o1.intersectsWith(o2)) {
o1.collision(o2); o1.collision(o2);
}
})); }));
System.out.println(""); System.out.println("");

View File

@ -12,6 +12,9 @@ public class Rectangle {
private int right; private int right;
private int bottom; private int bottom;
/**
* Constructor
*/
public Rectangle(int left, int top, int right, int bottom) { public Rectangle(int left, int top, int right, int bottom) {
this.left = left; this.left = left;
this.top = top; this.top = top;

View File

@ -107,9 +107,9 @@ public abstract class CollisionTest<O extends GameObject> {
final String targetName = target.getClass().getSimpleName(); final String targetName = target.getClass().getSimpleName();
final String otherName = other.getClass().getSimpleName(); final String otherName = other.getClass().getSimpleName();
final String errorMessage = expectTargetOnFire ? final String errorMessage = expectTargetOnFire
"Expected [" + targetName + "] to be on fire after colliding with [" + otherName + "] but it was not!" : ? "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!"; : "Expected [" + targetName + "] not to be on fire after colliding with [" + otherName + "] but it was!";
assertEquals(errorMessage, expectTargetOnFire, target.isOnFire()); assertEquals(errorMessage, expectTargetOnFire, target.isOnFire());
} }
@ -126,9 +126,9 @@ public abstract class CollisionTest<O extends GameObject> {
final String targetName = target.getClass().getSimpleName(); final String targetName = target.getClass().getSimpleName();
final String otherName = other.getClass().getSimpleName(); final String otherName = other.getClass().getSimpleName();
final String errorMessage = expectedDamage ? final String errorMessage = expectedDamage
"Expected [" + targetName + "] to be damaged after colliding with [" + otherName + "] but it was not!" : ? "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!"; : "Expected [" + targetName + "] not to be damaged after colliding with [" + otherName + "] but it was!";
assertEquals(errorMessage, expectedDamage, target.isDamaged()); assertEquals(errorMessage, expectedDamage, target.isDamaged());
} }

View File

@ -63,6 +63,37 @@ public abstract class EventEmitterTest<E extends EventEmitter> {
testAllDaysWithDefaultObserver(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 * 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 * event emitter without a default observer
@ -99,35 +130,4 @@ public abstract class EventEmitterTest<E extends EventEmitter> {
testAllDays(specialDay, event, emitter, defaultObserver, observer1, observer2); testAllDays(specialDay, event, emitter, defaultObserver, observer1, observer2);
} }
/**
* 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);
}
} }

View File

@ -24,7 +24,7 @@ public class KingsHandTest extends EventEmitterTest<KingsHand> {
} }
/** /**
* The {@link KingsHand} is both an {@EventEmitter} as an {@link EventObserver} so verify if every * 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 * event received is passed up to it's superior, in most cases {@link KingJoffrey} but now just a
* mocked observer. * mocked observer.
*/ */

View File

@ -17,9 +17,6 @@ public class App {
/** /**
* Program entry point * Program entry point
*
* @param args command line args
* @throws IOException
*/ */
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {

View File

@ -11,6 +11,9 @@ import java.io.IOException;
*/ */
public class SimpleFileWriter { public class SimpleFileWriter {
/**
* Constructor
*/
public SimpleFileWriter(String filename, FileWriterAction action) throws IOException { public SimpleFileWriter(String filename, FileWriterAction action) throws IOException {
FileWriter writer = new FileWriter(filename); FileWriter writer = new FileWriter(filename);
try { try {

View File

@ -65,11 +65,11 @@ public class SimpleFileWriterTest {
* Verify if an {@link IOException} during the write ripples through * Verify if an {@link IOException} during the write ripples through
*/ */
@Test(expected = IOException.class) @Test(expected = IOException.class)
public void testIOException() throws Exception { public void testIoException() throws Exception {
final File temporaryFile = this.testFolder.newFile(); final File temporaryFile = this.testFolder.newFile();
new SimpleFileWriter(temporaryFile.getPath(), writer -> { new SimpleFileWriter(temporaryFile.getPath(), writer -> {
throw new IOException(""); throw new IOException("");
}); });
} }
} }

View File

@ -16,6 +16,9 @@ public class DwarvenGoldmineFacade {
private final List<DwarvenMineWorker> workers; private final List<DwarvenMineWorker> workers;
/**
* Constructor
*/
public DwarvenGoldmineFacade() { public DwarvenGoldmineFacade() {
workers = new ArrayList<>(); workers = new ArrayList<>();
workers.add(new DwarvenGoldDigger()); workers.add(new DwarvenGoldDigger());

View File

@ -46,6 +46,9 @@ public abstract class DwarvenMineWorker {
} }
} }
/**
* Perform actions
*/
public void action(Action... actions) { public void action(Action... actions) {
for (Action action : actions) { for (Action action : actions) {
action(action); action(action);

View File

@ -1,15 +1,19 @@
package com.iluwatar.fluentinterface.app; 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.FluentIterable;
import com.iluwatar.fluentinterface.fluentiterable.lazy.LazyFluentIterable; import com.iluwatar.fluentinterface.fluentiterable.lazy.LazyFluentIterable;
import com.iluwatar.fluentinterface.fluentiterable.simple.SimpleFluentIterable; import com.iluwatar.fluentinterface.fluentiterable.simple.SimpleFluentIterable;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import static java.lang.String.valueOf;
/** /**
* The Fluent Interface pattern is useful when you want to provide an easy readable, flowing API. * 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 * Those interfaces tend to mimic domain specific languages, so they can nearly be read as human
@ -24,6 +28,9 @@ import static java.lang.String.valueOf;
*/ */
public class App { public class App {
/**
* Program entry point
*/
public static void main(String[] args) { public static void main(String[] args) {
List<Integer> integerList = new ArrayList<>(); List<Integer> integerList = new ArrayList<>();

View File

@ -5,8 +5,6 @@ import java.util.Iterator;
/** /**
* This class is used to realize LazyFluentIterables. It decorates a given iterator. Does not * This class is used to realize LazyFluentIterables. It decorates a given iterator. Does not
* support consecutive hasNext() calls. * support consecutive hasNext() calls.
*
* @param <TYPE>
*/ */
public abstract class DecoratingIterator<TYPE> implements Iterator<TYPE> { public abstract class DecoratingIterator<TYPE> implements Iterator<TYPE> {
@ -16,8 +14,6 @@ public abstract class DecoratingIterator<TYPE> implements Iterator<TYPE> {
/** /**
* Creates an iterator that decorates the given iterator. * Creates an iterator that decorates the given iterator.
*
* @param fromIterator
*/ */
public DecoratingIterator(Iterator<TYPE> fromIterator) { public DecoratingIterator(Iterator<TYPE> fromIterator) {
this.fromIterator = fromIterator; this.fromIterator = fromIterator;

View File

@ -1,12 +1,16 @@
package com.iluwatar.fluentinterface.fluentiterable.simple; package com.iluwatar.fluentinterface.fluentiterable.simple;
import com.iluwatar.fluentinterface.fluentiterable.FluentIterable; import java.util.ArrayList;
import java.util.Iterator;
import java.util.*; import java.util.List;
import java.util.Optional;
import java.util.Spliterator;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import com.iluwatar.fluentinterface.fluentiterable.FluentIterable;
/** /**
* This is a simple implementation of the FluentIterable interface. It evaluates all chained * 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. * operations eagerly. This implementation would be costly to be utilized in real applications.

View File

@ -26,7 +26,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
public abstract class FluentIterableTest { public abstract class FluentIterableTest {
/** /**
* Create a new {@link FluentIterable<Integer>} from the given integers * Create a new {@link FluentIterable} from the given integers
* *
* @param integers The integers * @param integers The integers
* @return The new iterable, use for testing * @return The new iterable, use for testing

View File

@ -31,6 +31,9 @@ public class Dispatcher {
stores.add(store); stores.add(store);
} }
/**
* Menu item selected handler
*/
public void menuItemSelected(MenuItem menuItem) { public void menuItemSelected(MenuItem menuItem) {
dispatchAction(new MenuAction(menuItem)); dispatchAction(new MenuAction(menuItem));
switch (menuItem) { switch (menuItem) {

View File

@ -14,6 +14,9 @@ public class AlchemistShop {
private List<Potion> topShelf; private List<Potion> topShelf;
private List<Potion> bottomShelf; private List<Potion> bottomShelf;
/**
* Constructor
*/
public AlchemistShop() { public AlchemistShop() {
topShelf = new ArrayList<>(); topShelf = new ArrayList<>();
bottomShelf = new ArrayList<>(); bottomShelf = new ArrayList<>();
@ -58,6 +61,9 @@ public class AlchemistShop {
return Collections.unmodifiableList(this.bottomShelf); return Collections.unmodifiableList(this.bottomShelf);
} }
/**
* Enumerate potions
*/
public void enumerate() { public void enumerate() {
System.out.println("Enumerating top shelf potions\n"); System.out.println("Enumerating top shelf potions\n");

View File

@ -2,32 +2,34 @@ package com.iluwatar.front.controller;
/** /**
* *
* The Front Controller is a presentation tier pattern. Essentially it defines a * The Front Controller is a presentation tier pattern. Essentially it defines a controller that
* controller that handles all requests for a web site. * handles all requests for a web site.
* <p> * <p>
* The Front Controller pattern consolidates request handling through a single handler * The Front Controller pattern consolidates request handling through a single handler object (
* object ({@link FrontController}). This object can carry out the common the behavior such as * {@link FrontController}). This object can carry out the common the behavior such as
* authorization, request logging and routing requests to corresponding views. * authorization, request logging and routing requests to corresponding views.
* <p> * <p>
* Typically the requests are mapped to command objects ({@link Command}) which then display * Typically the requests are mapped to command objects ({@link Command}) which then display the
* the correct view ({@link View}). * correct view ({@link View}).
* <p> * <p>
* In this example we have implemented two views: {@link ArcherView} and {@link CatapultView}. These * In this example we have implemented two views: {@link ArcherView} and {@link CatapultView}. These
* are displayed by sending correct request to the {@link FrontController} object. For example, * are displayed by sending correct request to the {@link FrontController} object. For example, the
* the {@link ArcherView} gets displayed when {@link FrontController} receives request "Archer". When * {@link ArcherView} gets displayed when {@link FrontController} receives request "Archer". When
* the request is unknown, we display the error view ({@link ErrorView}). * the request is unknown, we display the error view ({@link ErrorView}).
* *
*/ */
public class App { public class App {
/** /**
* Program entry point * Program entry point
* @param args command line args *
*/ * @param args
public static void main(String[] args) { * command line args
FrontController controller = new FrontController(); */
controller.handleRequest("Archer"); public static void main(String[] args) {
controller.handleRequest("Catapult"); FrontController controller = new FrontController();
controller.handleRequest("foobar"); controller.handleRequest("Archer");
} controller.handleRequest("Catapult");
controller.handleRequest("foobar");
}
} }

View File

@ -7,9 +7,9 @@ package com.iluwatar.front.controller;
*/ */
public class ApplicationException extends RuntimeException { public class ApplicationException extends RuntimeException {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public ApplicationException(Throwable cause) { public ApplicationException(Throwable cause) {
super(cause); super(cause);
} }
} }

View File

@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
*/ */
public class ArcherCommand implements Command { public class ArcherCommand implements Command {
@Override @Override
public void process() { public void process() {
new ArcherView().display(); new ArcherView().display();
} }
} }

View File

@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
*/ */
public class ArcherView implements View { public class ArcherView implements View {
@Override @Override
public void display() { public void display() {
System.out.println("Displaying archers"); System.out.println("Displaying archers");
} }
} }

View File

@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
*/ */
public class CatapultCommand implements Command { public class CatapultCommand implements Command {
@Override @Override
public void process() { public void process() {
new CatapultView().display(); new CatapultView().display();
} }
} }

View File

@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
*/ */
public class CatapultView implements View { public class CatapultView implements View {
@Override @Override
public void display() { public void display() {
System.out.println("Displaying catapults"); System.out.println("Displaying catapults");
} }
} }

View File

@ -6,6 +6,6 @@ package com.iluwatar.front.controller;
* *
*/ */
public interface Command { public interface Command {
void process(); void process();
} }

View File

@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
*/ */
public class ErrorView implements View { public class ErrorView implements View {
@Override @Override
public void display() { public void display() {
System.out.println("Error 500"); System.out.println("Error 500");
} }
} }

View File

@ -2,33 +2,33 @@ package com.iluwatar.front.controller;
/** /**
* *
* FrontController is the handler class that takes in all the requests and * FrontController is the handler class that takes in all the requests and renders the correct
* renders the correct response. * response.
* *
*/ */
public class FrontController { public class FrontController {
public void handleRequest(String request) { public void handleRequest(String request) {
Command command = getCommand(request); Command command = getCommand(request);
command.process(); command.process();
} }
private Command getCommand(String request) { private Command getCommand(String request) {
Class commandClass = getCommandClass(request); Class commandClass = getCommandClass(request);
try { try {
return (Command) commandClass.newInstance(); return (Command) commandClass.newInstance();
} catch (Exception e) { } catch (Exception e) {
throw new ApplicationException(e); throw new ApplicationException(e);
} }
} }
private Class getCommandClass(String request) { private Class getCommandClass(String request) {
Class result; Class result;
try { try {
result = Class.forName("com.iluwatar.front.controller." + request + "Command"); result = Class.forName("com.iluwatar.front.controller." + request + "Command");
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
result = UnknownCommand.class; result = UnknownCommand.class;
} }
return result; return result;
} }
} }

View File

@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
*/ */
public class UnknownCommand implements Command { public class UnknownCommand implements Command {
@Override @Override
public void process() { public void process() {
new ErrorView().display(); new ErrorView().display();
} }
} }

View File

@ -7,5 +7,5 @@ package com.iluwatar.front.controller;
*/ */
public interface View { public interface View {
void display(); void display();
} }

View File

@ -10,10 +10,10 @@ import com.iluwatar.front.controller.App;
* *
*/ */
public class AppTest { public class AppTest {
@Test @Test
public void test() { public void test() {
String[] args = {}; String[] args = {};
App.main(args); App.main(args);
} }
} }

View File

@ -1,8 +1,8 @@
package com.iluwatar.front.controller; package com.iluwatar.front.controller;
import org.junit.Test; import static org.junit.Assert.assertSame;
import static org.junit.Assert.*; import org.junit.Test;
/** /**
* Date: 12/13/15 - 1:35 PM * Date: 12/13/15 - 1:35 PM

View File

@ -21,17 +21,15 @@ import java.util.concurrent.LinkedBlockingQueue;
* *
* <p> * <p>
* <i>APPLICABILITY</i> <br/> * <i>APPLICABILITY</i> <br/>
* <ul> * UNIX network subsystems - In operating systems network operations are carried out
* <li>UNIX network subsystems - In operating systems network operations are carried out * asynchronously with help of hardware level interrupts.<br/>
* asynchronously with help of hardware level interrupts.</li> * CORBA - At the asynchronous layer one thread is associated with each socket that is connected
* <li>CORBA - At the asynchronous layer one thread is associated with each socket that is connected
* to the client. Thread blocks waiting for CORBA requests from the client. On receiving request it * to the client. Thread blocks waiting for CORBA requests from the client. On receiving request it
* is inserted in the queuing layer which is then picked up by synchronous layer which processes the * is inserted in the queuing layer which is then picked up by synchronous layer which processes the
* request and sends response back to the client.</li> * request and sends response back to the client.<br/>
* <li>Android AsyncTask framework - Framework provides a way to execute long running blocking * Android AsyncTask framework - Framework provides a way to execute long running blocking
* calls, such as downloading a file, in background threads so that the UI thread remains free to * calls, such as downloading a file, in background threads so that the UI thread remains free to
* respond to user inputs.</i> * respond to user inputs.<br/>
* </ul>
* *
* <p> * <p>
* <i>IMPLEMENTATION</i> <br/> * <i>IMPLEMENTATION</i> <br/>
@ -121,6 +119,7 @@ public class App {
try { try {
Thread.sleep(i); Thread.sleep(i);
} catch (InterruptedException e) { } catch (InterruptedException e) {
System.out.println(e);
} }
return (i) * (i + 1) / 2; return (i) * (i + 1) / 2;
} }

View File

@ -14,7 +14,8 @@ public class AddressFilter extends AbstractFilter {
String result = super.execute(order); String result = super.execute(order);
if (order.getAddress() == null || order.getAddress().isEmpty()) { if (order.getAddress() == null || order.getAddress().isEmpty()) {
return result + "Invalid address! "; return result + "Invalid address! ";
} else } else {
return result; return result;
}
} }
} }

View File

@ -32,8 +32,12 @@ public class Client extends JFrame {
private JLabel jl; private JLabel jl;
private JTextField[] jtFields; private JTextField[] jtFields;
private JTextArea[] jtAreas; private JTextArea[] jtAreas;
private JButton clearButton, processButton; private JButton clearButton;
private JButton processButton;
/**
* Constructor
*/
public Client() { public Client() {
super("Client System"); super("Client System");
setDefaultCloseOperation(EXIT_ON_CLOSE); setDefaultCloseOperation(EXIT_ON_CLOSE);

View File

@ -11,30 +11,21 @@ public interface Filter {
/** /**
* Execute order processing filter. * Execute order processing filter.
*
* @param order
* @return empty string on success, otherwise error message.
*/ */
String execute(Order order); String execute(Order order);
/** /**
* Set next filter in chain after this. * Set next filter in chain after this.
*
* @param filter
*/ */
void setNext(Filter filter); void setNext(Filter filter);
/** /**
* Get next filter in chain after this. * Get next filter in chain after this.
*
* @return
*/ */
Filter getNext(); Filter getNext();
/** /**
* Get last filter in the chain. * Get last filter in the chain.
*
* @return
*/ */
Filter getLast(); Filter getLast();
} }

View File

@ -12,10 +12,16 @@ public class FilterChain {
private final Target target; private final Target target;
/**
* Constructor
*/
public FilterChain(Target target) { public FilterChain(Target target) {
this.target = target; this.target = target;
} }
/**
* Adds filter
*/
public void addFilter(Filter filter) { public void addFilter(Filter filter) {
if (chain == null) { if (chain == null) {
chain = filter; chain = filter;
@ -24,6 +30,9 @@ public class FilterChain {
} }
} }
/**
* Execute filter chain
*/
public String execute(Order order) { public String execute(Order order) {
if (chain != null) { if (chain != null) {
return chain.execute(order); return chain.execute(order);

View File

@ -14,6 +14,9 @@ public class Order {
public Order() {} public Order() {}
/**
* Constructor
*/
public Order(String name, String contactNumber, String address, String depositNumber, String order) { public Order(String name, String contactNumber, String address, String depositNumber, String order) {
this.name = name; this.name = name;
this.contactNumber = contactNumber; this.contactNumber = contactNumber;

View File

@ -29,6 +29,9 @@ public class Target extends JFrame {
private DefaultTableModel dtm; private DefaultTableModel dtm;
private JButton del; private JButton del;
/**
* Constructor
*/
public Target() { public Target() {
super("Order System"); super("Order System");
setDefaultCloseOperation(EXIT_ON_CLOSE); setDefaultCloseOperation(EXIT_ON_CLOSE);
@ -67,8 +70,9 @@ public class Target extends JFrame {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
int temp = jt.getSelectedRow(); int temp = jt.getSelectedRow();
if (temp == -1) if (temp == -1) {
return; return;
}
int temp2 = jt.getSelectedRowCount(); int temp2 = jt.getSelectedRowCount();
for (int i = 0; i < temp2; i++) { for (int i = 0; i < temp2; i++) {
dtm.removeRow(temp); dtm.removeRow(temp);

View File

@ -73,6 +73,9 @@ public class FilterTest {
private final Order order; private final Order order;
private final String result; private final String result;
/**
* Constructor
*/
public FilterTest(Filter filter, Order order, String result) { public FilterTest(Filter filter, Order order, String result) {
this.filter = filter; this.filter = filter;
this.order = order; this.order = order;

View File

@ -55,6 +55,9 @@ public class App {
return s.equals("+") || s.equals("-") || s.equals("*"); return s.equals("+") || s.equals("-") || s.equals("*");
} }
/**
* Get expression for string
*/
public static Expression getOperatorInstance(String s, Expression left, Expression right) { public static Expression getOperatorInstance(String s, Expression left, Expression right) {
switch (s) { switch (s) {
case "+": case "+":
@ -63,7 +66,8 @@ public class App {
return new MinusExpression(left, right); return new MinusExpression(left, right);
case "*": case "*":
return new MultiplyExpression(left, right); return new MultiplyExpression(left, right);
default:
return new MultiplyExpression(left, right);
} }
return null;
} }
} }

View File

@ -27,9 +27,9 @@ public abstract class ExpressionTest<E extends Expression> {
for (int i = -10; i < 10; i++) { for (int i = -10; i < 10; i++) {
for (int j = -10; j < 10; j++) { for (int j = -10; j < 10; j++) {
testData.add(new Object[]{ testData.add(new Object[]{
new NumberExpression(i), new NumberExpression(i),
new NumberExpression(j), new NumberExpression(j),
resultCalc.apply(i, j) resultCalc.apply(i, j)
}); });
} }
} }

View File

@ -20,28 +20,28 @@ public class App {
public static void main(String[] args) { public static void main(String[] args) {
TreasureChest chest = new TreasureChest(); TreasureChest chest = new TreasureChest();
ItemIterator ringIterator = chest.Iterator(ItemType.RING); ItemIterator ringIterator = chest.iterator(ItemType.RING);
while (ringIterator.hasNext()) { while (ringIterator.hasNext()) {
System.out.println(ringIterator.next()); System.out.println(ringIterator.next());
} }
System.out.println("----------"); System.out.println("----------");
ItemIterator potionIterator = chest.Iterator(ItemType.POTION); ItemIterator potionIterator = chest.iterator(ItemType.POTION);
while (potionIterator.hasNext()) { while (potionIterator.hasNext()) {
System.out.println(potionIterator.next()); System.out.println(potionIterator.next());
} }
System.out.println("----------"); System.out.println("----------");
ItemIterator weaponIterator = chest.Iterator(ItemType.WEAPON); ItemIterator weaponIterator = chest.iterator(ItemType.WEAPON);
while (weaponIterator.hasNext()) { while (weaponIterator.hasNext()) {
System.out.println(weaponIterator.next()); System.out.println(weaponIterator.next());
} }
System.out.println("----------"); System.out.println("----------");
ItemIterator it = chest.Iterator(ItemType.ANY); ItemIterator it = chest.iterator(ItemType.ANY);
while (it.hasNext()) { while (it.hasNext()) {
System.out.println(it.next()); System.out.println(it.next());
} }

View File

@ -12,6 +12,9 @@ public class TreasureChest {
private List<Item> items; private List<Item> items;
/**
* Constructor
*/
public TreasureChest() { public TreasureChest() {
items = new ArrayList<>(); items = new ArrayList<>();
items.add(new Item(ItemType.POTION, "Potion of courage")); items.add(new Item(ItemType.POTION, "Potion of courage"));
@ -26,10 +29,13 @@ public class TreasureChest {
items.add(new Item(ItemType.WEAPON, "Dagger of poison")); items.add(new Item(ItemType.WEAPON, "Dagger of poison"));
} }
ItemIterator Iterator(ItemType type) { ItemIterator iterator(ItemType itemType) {
return new TreasureChestItemIterator(this, type); return new TreasureChestItemIterator(this, itemType);
} }
/**
* Get all items
*/
public List<Item> getItems() { public List<Item> getItems() {
ArrayList<Item> list = new ArrayList<>(); ArrayList<Item> list = new ArrayList<>();
list.addAll(items); list.addAll(items);

View File

@ -13,6 +13,9 @@ public class TreasureChestItemIterator implements ItemIterator {
private int idx; private int idx;
private ItemType type; private ItemType type;
/**
* Constructor
*/
public TreasureChestItemIterator(TreasureChest chest, ItemType type) { public TreasureChestItemIterator(TreasureChest chest, ItemType type) {
this.chest = chest; this.chest = chest;
this.type = type; this.type = type;

View File

@ -60,7 +60,7 @@ public class TreasureChestTest {
@Test @Test
public void testIterator() { public void testIterator() {
final TreasureChest chest = new TreasureChest(); final TreasureChest chest = new TreasureChest();
final ItemIterator iterator = chest.Iterator(expectedItem.getType()); final ItemIterator iterator = chest.iterator(expectedItem.getType());
assertNotNull(iterator); assertNotNull(iterator);
while (iterator.hasNext()) { while (iterator.hasNext()) {

View File

@ -4,31 +4,31 @@ import java.util.Arrays;
/** /**
* *
* Layers is an architectural style where software responsibilities are divided among the different * Layers is an architectural style where software responsibilities are divided among the different layers of the
* layers of the application. * application.
* <p> * <p>
* This example demonstrates a traditional 3-layer architecture consisting of data access layer, * This example demonstrates a traditional 3-layer architecture consisting of data access layer, business layer and
* business layer and presentation layer. * presentation layer.
* <p> * <p>
* The data access layer is formed of Spring Data repositories <code>CakeDao</code>, * The data access layer is formed of Spring Data repositories <code>CakeDao</code>, <code>CakeToppingDao</code> and
* <code>CakeToppingDao</code> and <code>CakeLayerDao</code>. The repositories can be used for CRUD * <code>CakeLayerDao</code>. The repositories can be used for CRUD operations on cakes, cake toppings and cake layers
* operations on cakes, cake toppings and cake layers respectively. * respectively.
* <p> * <p>
* The business layer is built on top of the data access layer. <code>CakeBakingService</code> * The business layer is built on top of the data access layer. <code>CakeBakingService</code> offers methods to
* offers methods to retrieve available cake toppings and cake layers and baked cakes. Also the * retrieve available cake toppings and cake layers and baked cakes. Also the service is used to create new cakes out of
* service is used to create new cakes out of cake toppings and cake layers. * cake toppings and cake layers.
* <p> * <p>
* The presentation layer is built on the business layer and in this example it simply lists the * The presentation layer is built on the business layer and in this example it simply lists the cakes that have been
* cakes that have been baked. * baked.
* <p> * <p>
* We have applied so called strict layering which means that the layers can only access the classes * We have applied so called strict layering which means that the layers can only access the classes directly beneath
* directly beneath them. This leads the solution to create an additional set of DTOs ( * them. This leads the solution to create an additional set of DTOs ( <code>CakeInfo</code>,
* <code>CakeInfo</code>, <code>CakeToppingInfo</code>, <code>CakeLayerInfo</code>) to translate * <code>CakeToppingInfo</code>, <code>CakeLayerInfo</code>) to translate data between layers. In other words,
* data between layers. In other words, <code>CakeBakingService</code> cannot return entities ( * <code>CakeBakingService</code> cannot return entities ( <code>Cake</code>, <code>CakeTopping</code>,
* <code>Cake</code>, <code>CakeTopping</code>, <code>CakeLayer</code>) directly since these reside * <code>CakeLayer</code>) directly since these reside on data access layer but instead translates these into business
* on data access layer but instead translates these into business layer DTOs (<code>CakeInfo</code>, <code>CakeToppingInfo</code>, <code>CakeLayerInfo</code>) and returns them instead. This way * layer DTOs (<code>CakeInfo</code>, <code>CakeToppingInfo</code>, <code>CakeLayerInfo</code>) and returns them
* the presentation layer does not have any knowledge of other layers than the business layer and * instead. This way the presentation layer does not have any knowledge of other layers than the business layer and thus
* thus is not affected by changes to them. * is not affected by changes to them.
* *
* @see Cake * @see Cake
* @see CakeTopping * @see CakeTopping
@ -63,8 +63,6 @@ public class App {
/** /**
* Initializes the example data * Initializes the example data
*
* @param cakeBakingService
*/ */
private static void initializeData(CakeBakingService cakeBakingService) { private static void initializeData(CakeBakingService cakeBakingService) {
cakeBakingService.saveNewLayer(new CakeLayerInfo("chocolate", 1200)); cakeBakingService.saveNewLayer(new CakeLayerInfo("chocolate", 1200));

View File

@ -11,44 +11,31 @@ public interface CakeBakingService {
/** /**
* Bakes new cake according to parameters * Bakes new cake according to parameters
*
* @param cakeInfo
* @throws CakeBakingException
*/ */
void bakeNewCake(CakeInfo cakeInfo) throws CakeBakingException; void bakeNewCake(CakeInfo cakeInfo) throws CakeBakingException;
/** /**
* Get all cakes * Get all cakes
*
* @return
*/ */
List<CakeInfo> getAllCakes(); List<CakeInfo> getAllCakes();
/** /**
* Store new cake topping * Store new cake topping
*
* @param toppingInfo
*/ */
void saveNewTopping(CakeToppingInfo toppingInfo); void saveNewTopping(CakeToppingInfo toppingInfo);
/** /**
* Get available cake toppings * Get available cake toppings
*
* @return
*/ */
List<CakeToppingInfo> getAvailableToppings(); List<CakeToppingInfo> getAvailableToppings();
/** /**
* Add new cake layer * Add new cake layer
*
* @param layerInfo
*/ */
void saveNewLayer(CakeLayerInfo layerInfo); void saveNewLayer(CakeLayerInfo layerInfo);
/** /**
* Get available cake layers * Get available cake layers
*
* @return
*/ */
List<CakeLayerInfo> getAvailableLayers(); List<CakeLayerInfo> getAvailableLayers();
} }

View File

@ -14,18 +14,27 @@ public class CakeInfo {
public final CakeToppingInfo cakeToppingInfo; public final CakeToppingInfo cakeToppingInfo;
public final List<CakeLayerInfo> cakeLayerInfos; public final List<CakeLayerInfo> cakeLayerInfos;
/**
* Constructor
*/
public CakeInfo(Long id, CakeToppingInfo cakeToppingInfo, List<CakeLayerInfo> cakeLayerInfos) { public CakeInfo(Long id, CakeToppingInfo cakeToppingInfo, List<CakeLayerInfo> cakeLayerInfos) {
this.id = Optional.of(id); this.id = Optional.of(id);
this.cakeToppingInfo = cakeToppingInfo; this.cakeToppingInfo = cakeToppingInfo;
this.cakeLayerInfos = cakeLayerInfos; this.cakeLayerInfos = cakeLayerInfos;
} }
/**
* Constructor
*/
public CakeInfo(CakeToppingInfo cakeToppingInfo, List<CakeLayerInfo> cakeLayerInfos) { public CakeInfo(CakeToppingInfo cakeToppingInfo, List<CakeLayerInfo> cakeLayerInfos) {
this.id = Optional.empty(); this.id = Optional.empty();
this.cakeToppingInfo = cakeToppingInfo; this.cakeToppingInfo = cakeToppingInfo;
this.cakeLayerInfos = cakeLayerInfos; this.cakeLayerInfos = cakeLayerInfos;
} }
/**
* Calculate calories
*/
public int calculateTotalCalories() { public int calculateTotalCalories() {
int total = cakeToppingInfo != null ? cakeToppingInfo.calories : 0; int total = cakeToppingInfo != null ? cakeToppingInfo.calories : 0;
total += cakeLayerInfos.stream().mapToInt(c -> c.calories).sum(); total += cakeLayerInfos.stream().mapToInt(c -> c.calories).sum();

View File

@ -13,12 +13,18 @@ public class CakeLayerInfo {
public final String name; public final String name;
public final int calories; public final int calories;
/**
* Constructor
*/
public CakeLayerInfo(Long id, String name, int calories) { public CakeLayerInfo(Long id, String name, int calories) {
this.id = Optional.of(id); this.id = Optional.of(id);
this.name = name; this.name = name;
this.calories = calories; this.calories = calories;
} }
/**
* Constructor
*/
public CakeLayerInfo(String name, int calories) { public CakeLayerInfo(String name, int calories) {
this.id = Optional.empty(); this.id = Optional.empty();
this.name = name; this.name = name;

View File

@ -13,12 +13,18 @@ public class CakeToppingInfo {
public final String name; public final String name;
public final int calories; public final int calories;
/**
* Constructor
*/
public CakeToppingInfo(Long id, String name, int calories) { public CakeToppingInfo(Long id, String name, int calories) {
this.id = Optional.of(id); this.id = Optional.of(id);
this.name = name; this.name = name;
this.calories = calories; this.calories = calories;
} }
/**
* Constructor
*/
public CakeToppingInfo(String name, int calories) { public CakeToppingInfo(String name, int calories) {
this.id = Optional.empty(); this.id = Optional.empty();
this.name = name; this.name = name;

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" <persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"> xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="jpaData" /> <persistence-unit name="jpaData" />
</persistence> </persistence>

View File

@ -1,42 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" <beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:context="http://www.springframework.org/schema/context"
xmlns:security="http://www.springframework.org/schema/security" xmlns:security="http://www.springframework.org/schema/security" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<jpa:repositories base-package="com.iluwatar" /> <jpa:repositories base-package="com.iluwatar" />
<tx:annotation-driven transaction-manager="transactionManager" /> <tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" /> <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean> </bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"> destroy-method="close">
<property name="driverClassName" value="org.h2.Driver" /> <property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:~/databases/cake" /> <property name="url" value="jdbc:h2:~/databases/cake" />
<property name="username" value="sa" /> <property name="username" value="sa" />
<property name="password" value="sa" /> <property name="password" value="sa" />
</bean> </bean>
<bean id="entityManagerFactory" <bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" /> <property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.iluwatar" /> <property name="packagesToScan" value="com.iluwatar" />
<property name="persistenceProvider"> <property name="persistenceProvider">
<bean class="org.hibernate.ejb.HibernatePersistence" /> <bean class="org.hibernate.ejb.HibernatePersistence" />
</property> </property>
<property name="jpaProperties"> <property name="jpaProperties">
<map> <map>
<entry key="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" /> <entry key="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
<entry key="hibernate.hbm2ddl.auto" value="create-drop" /> <entry key="hibernate.hbm2ddl.auto" value="create-drop" />
<entry key="hibernate.show_sql" value="false" /> <entry key="hibernate.show_sql" value="false" />
</map> </map>
</property> </property>
</bean> </bean>
</beans> </beans>

View File

@ -7,6 +7,9 @@ package com.iluwatar.lazy.loading;
*/ */
public class Heavy { public class Heavy {
/**
* Constructor
*/
public Heavy() { public Heavy() {
System.out.println("Creating Heavy ..."); System.out.println("Creating Heavy ...");
try { try {

View File

@ -9,10 +9,16 @@ public class HolderNaive {
private Heavy heavy; private Heavy heavy;
/**
* Constructor
*/
public HolderNaive() { public HolderNaive() {
System.out.println("HolderNaive created"); System.out.println("HolderNaive created");
} }
/**
* Get heavy object
*/
public Heavy getHeavy() { public Heavy getHeavy() {
if (heavy == null) { if (heavy == null) {
heavy = new Heavy(); heavy = new Heavy();

View File

@ -10,10 +10,16 @@ public class HolderThreadSafe {
private Heavy heavy; private Heavy heavy;
/**
* Constructor
*/
public HolderThreadSafe() { public HolderThreadSafe() {
System.out.println("HolderThreadSafe created"); System.out.println("HolderThreadSafe created");
} }
/**
* Get heavy object
*/
public synchronized Heavy getHeavy() { public synchronized Heavy getHeavy() {
if (heavy == null) { if (heavy == null) {
heavy = new Heavy(); heavy = new Heavy();

View File

@ -5,7 +5,7 @@ import java.util.function.Supplier;
/** /**
* *
* This lazy loader is thread safe and more efficient than {@link HolderThreadSafe}. It utilizes * This lazy loader is thread safe and more efficient than {@link HolderThreadSafe}. It utilizes
* Java 8 functional interface {@link Supplier<T>} as {@link Heavy} factory. * Java 8 functional interface {@link Supplier} as {@link Heavy} factory.
* *
*/ */
public class Java8Holder { public class Java8Holder {

View File

@ -23,6 +23,9 @@ import java.util.Stack;
*/ */
public class App { public class App {
/**
* Program entry point
*/
public static void main(String[] args) { public static void main(String[] args) {
Stack<StarMemento> states = new Stack<>(); Stack<StarMemento> states = new Stack<>();

View File

@ -11,12 +11,18 @@ public class Star {
private int ageYears; private int ageYears;
private int massTons; private int massTons;
/**
* Constructor
*/
public Star(StarType startType, int startAge, int startMass) { public Star(StarType startType, int startAge, int startMass) {
this.type = startType; this.type = startType;
this.ageYears = startAge; this.ageYears = startAge;
this.massTons = startMass; this.massTons = startMass;
} }
/**
* Makes time pass for the star
*/
public void timePasses() { public void timePasses() {
ageYears *= 2; ageYears *= 2;
massTons *= 8; massTons *= 8;

View File

@ -30,9 +30,6 @@ public class App {
/** /**
* Program entry point * Program entry point
*
* @param args command line args
* @throws Exception
*/ */
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
CamelContext context = new DefaultCamelContext(); CamelContext context = new DefaultCamelContext();

View File

@ -39,9 +39,7 @@ public class FileLoader {
br.close(); br.close();
return sb.toString(); return sb.toString();
} } catch (Exception e) {
catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@ -26,7 +26,7 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
/** /**
* The "OK" button for loading the file. * The "OK" button for loading the file.
*/ */
private JButton OK; private JButton ok;
/** /**
* The cancel button. * The cancel button.
@ -121,10 +121,10 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
/* /*
* Add the OK button. * Add the OK button.
*/ */
this.OK = new JButton("OK"); this.ok = new JButton("OK");
this.panel.add(OK); this.panel.add(ok);
this.OK.setBounds(250, 50, 100, 25); this.ok.setBounds(250, 50, 100, 25);
this.OK.addActionListener(this); this.ok.addActionListener(this);
/* /*
* Add the cancel button. * Add the cancel button.
@ -140,13 +140,11 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (e.getSource() == this.OK) { if (e.getSource() == this.ok) {
this.fileName = this.input.getText(); this.fileName = this.input.getText();
presenter.fileNameChanged(); presenter.fileNameChanged();
presenter.confirmed(); presenter.confirmed();
} } else if (e.getSource() == this.cancel) {
else if (e.getSource() == this.cancel) {
presenter.cancelled(); presenter.cancelled();
} }
} }

View File

@ -51,6 +51,9 @@ public class FileSelectorPresenter {
loader.setFileName(view.getFileName()); loader.setFileName(view.getFileName());
} }
/**
* Ok button handler
*/
public void confirmed() { public void confirmed() {
if (loader.getFileName() == null || loader.getFileName().equals("")) { if (loader.getFileName() == null || loader.getFileName().equals("")) {
view.showMessage("Please give the name of the file first!"); view.showMessage("Please give the name of the file first!");
@ -60,9 +63,7 @@ public class FileSelectorPresenter {
if (loader.fileExists()) { if (loader.fileExists()) {
String data = loader.loadData(); String data = loader.loadData();
view.displayData(data); view.displayData(data);
} } else {
else {
view.showMessage("The file specified does not exist."); view.showMessage("The file specified does not exist.");
} }
} }

View File

@ -1,14 +1,13 @@
package com.iluwatar.model.view.presenter; package com.iluwatar.model.view.presenter;
import static org.junit.Assert.*; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import com.iluwatar.model.view.presenter.FileLoader;
import com.iluwatar.model.view.presenter.FileSelectorPresenter;
import com.iluwatar.model.view.presenter.FileSelectorStub;
/** /**
* This test case is responsible for testing our application by taking advantage of the * This test case is responsible for testing our application by taking advantage of the
* Model-View-Controller architectural pattern. * Model-View-Controller architectural pattern.
@ -57,13 +56,13 @@ public class FileSelectorPresenterTest {
*/ */
@Test @Test
public void updateFileNameToLoader() { public void updateFileNameToLoader() {
String EXPECTED_FILE = "Stamatis"; String expectedFile = "Stamatis";
stub.setFileName(EXPECTED_FILE); stub.setFileName(expectedFile);
presenter.start(); presenter.start();
presenter.fileNameChanged(); presenter.fileNameChanged();
assertEquals(EXPECTED_FILE, loader.getFileName()); assertEquals(expectedFile, loader.getFileName());
} }
/** /**

View File

@ -24,6 +24,9 @@ public class LoadBalancer {
servers.add(new Server("localhost", 8084, ++id)); servers.add(new Server("localhost", 8084, ++id));
} }
/**
* Add new server
*/
public final void addServer(Server server) { public final void addServer(Server server) {
synchronized (servers) { synchronized (servers) {
servers.add(server); servers.add(server);
@ -39,6 +42,9 @@ public class LoadBalancer {
return lastServedId; return lastServedId;
} }
/**
* Handle request
*/
public void serverequest(Request request) { public void serverequest(Request request) {
if (lastServedId >= servers.size()) { if (lastServedId >= servers.size()) {
lastServedId = 0; lastServedId = 0;

View File

@ -11,6 +11,9 @@ public class Server {
public final int port; public final int port;
public final int id; public final int id;
/**
* Constructor
*/
public Server(String host, int port, int id) { public Server(String host, int port, int id) {
this.host = host; this.host = host;
this.port = port; this.port = port;

View File

@ -21,9 +21,7 @@ import org.apache.isis.applib.annotation.HomePage;
import org.apache.isis.applib.annotation.NatureOfService; import org.apache.isis.applib.annotation.NatureOfService;
import org.apache.isis.applib.annotation.SemanticsOf; import org.apache.isis.applib.annotation.SemanticsOf;
@DomainService(nature = NatureOfService.VIEW_CONTRIBUTIONS_ONLY // trick to suppress the actions @DomainService(nature = NatureOfService.VIEW_CONTRIBUTIONS_ONLY)
// from the top-level menu
)
public class HomePageService { public class HomePageService {
// region > homePage (action) // region > homePage (action)

View File

@ -69,9 +69,12 @@ public class SimpleObjects {
} }
} }
/**
* Create simple object
*/
@Action(domainEvent = CreateDomainEvent.class) @Action(domainEvent = CreateDomainEvent.class)
@MemberOrder(sequence = "3") @MemberOrder(sequence = "3")
public SimpleObject create(final @ParameterLayout(named = "Name") String name) { public SimpleObject create(@ParameterLayout(named = "Name") final String name) {
final SimpleObject obj = container.newTransientInstance(SimpleObject.class); final SimpleObject obj = container.newTransientInstance(SimpleObject.class);
obj.setName(name); obj.setName(name);
container.persistIfNotAlready(obj); container.persistIfNotAlready(obj);

View File

@ -45,8 +45,6 @@ public class SimpleObjectCreate extends FixtureScript {
/** /**
* The created simple object (output). * The created simple object (output).
*
* @return
*/ */
public SimpleObject getSimpleObject() { public SimpleObject getSimpleObject() {
return simpleObject; return simpleObject;

View File

@ -29,7 +29,7 @@ import domainapp.fixture.modules.simple.SimpleObjectsTearDown;
public class RecreateSimpleObjects extends FixtureScript { public class RecreateSimpleObjects extends FixtureScript {
public final List<String> NAMES = Collections.unmodifiableList(Arrays.asList("Foo", "Bar", "Baz", public final List<String> names = Collections.unmodifiableList(Arrays.asList("Foo", "Bar", "Baz",
"Frodo", "Froyo", "Fizz", "Bip", "Bop", "Bang", "Boo")); "Frodo", "Froyo", "Fizz", "Bip", "Bop", "Bang", "Boo"));
public RecreateSimpleObjects() { public RecreateSimpleObjects() {
@ -72,9 +72,9 @@ public class RecreateSimpleObjects extends FixtureScript {
final int number = defaultParam("number", ec, 3); final int number = defaultParam("number", ec, 3);
// validate // validate
if (number < 0 || number > NAMES.size()) { if (number < 0 || number > names.size()) {
throw new IllegalArgumentException(String.format("number must be in range [0,%d)", throw new IllegalArgumentException(String.format("number must be in range [0,%d)",
NAMES.size())); names.size()));
} }
// //
@ -83,7 +83,7 @@ public class RecreateSimpleObjects extends FixtureScript {
ec.executeChild(this, new SimpleObjectsTearDown()); ec.executeChild(this, new SimpleObjectsTearDown());
for (int i = 0; i < number; i++) { for (int i = 0; i < number; i++) {
final SimpleObjectCreate fs = new SimpleObjectCreate().setName(NAMES.get(i)); final SimpleObjectCreate fs = new SimpleObjectCreate().setName(names.get(i));
ec.executeChild(this, fs.getName(), fs); ec.executeChild(this, fs.getName(), fs);
simpleObjects.add(fs.getSimpleObject()); simpleObjects.add(fs.getSimpleObject());
} }

View File

@ -21,6 +21,9 @@ import org.apache.isis.objectstore.jdo.datanucleus.IsisConfigurationForJdoIntegT
public class SimpleAppSystemInitializer { public class SimpleAppSystemInitializer {
/**
* Init test system
*/
public static void initIsft() { public static void initIsft() {
IsisSystemForTest isft = IsisSystemForTest.getElseNull(); IsisSystemForTest isft = IsisSystemForTest.getElseNull();
if (isft == null) { if (isft == null) {

View File

@ -29,7 +29,7 @@ import static org.junit.Assert.assertThat;
public class SimpleObjectGlue extends CukeGlueAbstract { public class SimpleObjectGlue extends CukeGlueAbstract {
@Given("^there are.* (\\d+) simple objects$") @Given("^there are.* (\\d+) simple objects$")
public void there_are_N_simple_objects(int n) throws Throwable { public void thereAreNumSimpleObjects(int n) throws Throwable {
try { try {
final List<SimpleObject> findAll = service(SimpleObjects.class).listAll(); final List<SimpleObject> findAll = service(SimpleObjects.class).listAll();
assertThat(findAll.size(), is(n)); assertThat(findAll.size(), is(n));
@ -41,7 +41,7 @@ public class SimpleObjectGlue extends CukeGlueAbstract {
} }
@When("^I create a new simple object$") @When("^I create a new simple object$")
public void I_create_a_new_simple_object() throws Throwable { public void createNewSimpleObject() throws Throwable {
service(SimpleObjects.class).create(UUID.randomUUID().toString()); service(SimpleObjects.class).create(UUID.randomUUID().toString());
} }

View File

@ -27,13 +27,13 @@ import domainapp.integtests.bootstrap.SimpleAppSystemInitializer;
public abstract class SimpleAppIntegTest extends IntegrationTestAbstract { public abstract class SimpleAppIntegTest extends IntegrationTestAbstract {
@BeforeClass @BeforeClass
public static void initClass() { public static void initClass() {
org.apache.log4j.PropertyConfigurator.configure("logging.properties"); org.apache.log4j.PropertyConfigurator.configure("logging.properties");
SimpleAppSystemInitializer.initIsft(); SimpleAppSystemInitializer.initIsft();
// instantiating will install onto ThreadLocal // instantiating will install onto ThreadLocal
new ScenarioExecutionForIntegration(); new ScenarioExecutionForIntegration();
} }
} }

View File

@ -35,87 +35,86 @@ import static org.assertj.core.api.Assertions.assertThat;
public class SimpleObjectIntegTest extends SimpleAppIntegTest { public class SimpleObjectIntegTest extends SimpleAppIntegTest {
@Inject
FixtureScripts fixtureScripts;
RecreateSimpleObjects fs;
SimpleObject simpleObjectPojo;
SimpleObject simpleObjectWrapped;
@Before
public void setUp() throws Exception {
// given
fs = new RecreateSimpleObjects().setNumber(1);
fixtureScripts.runFixtureScript(fs, null);
simpleObjectPojo = fs.getSimpleObjects().get(0);
assertThat(simpleObjectPojo).isNotNull();
simpleObjectWrapped = wrap(simpleObjectPojo);
}
public static class Name extends SimpleObjectIntegTest {
@Test
public void accessible() throws Exception {
// when
final String name = simpleObjectWrapped.getName();
// then
assertThat(name).isEqualTo(fs.names.get(0));
}
@Test
public void cannotBeUpdatedDirectly() throws Exception {
// expect
expectedExceptions.expect(DisabledException.class);
// when
simpleObjectWrapped.setName("new name");
}
}
public static class UpdateName extends SimpleObjectIntegTest {
@Test
public void happyCase() throws Exception {
// when
simpleObjectWrapped.updateName("new name");
// then
assertThat(simpleObjectWrapped.getName()).isEqualTo("new name");
}
@Test
public void failsValidation() throws Exception {
// expect
expectedExceptions.expect(InvalidException.class);
expectedExceptions.expectMessage("Exclamation mark is not allowed");
// when
simpleObjectWrapped.updateName("new name!");
}
}
public static class Title extends SimpleObjectIntegTest {
@Inject @Inject
FixtureScripts fixtureScripts; DomainObjectContainer container;
RecreateSimpleObjects fs; @Test
SimpleObject simpleObjectPojo; public void interpolatesName() throws Exception {
SimpleObject simpleObjectWrapped;
@Before // given
public void setUp() throws Exception { final String name = simpleObjectWrapped.getName();
// given
fs = new RecreateSimpleObjects().setNumber(1);
fixtureScripts.runFixtureScript(fs, null);
simpleObjectPojo = fs.getSimpleObjects().get(0); // when
final String title = container.titleOf(simpleObjectWrapped);
assertThat(simpleObjectPojo).isNotNull(); // then
simpleObjectWrapped = wrap(simpleObjectPojo); assertThat(title).isEqualTo("Object: " + name);
}
public static class Name extends SimpleObjectIntegTest {
@Test
public void accessible() throws Exception {
// when
final String name = simpleObjectWrapped.getName();
// then
assertThat(name).isEqualTo(fs.NAMES.get(0));
}
@Test
public void cannotBeUpdatedDirectly() throws Exception {
// expect
expectedExceptions.expect(DisabledException.class);
// when
simpleObjectWrapped.setName("new name");
}
}
public static class UpdateName extends SimpleObjectIntegTest {
@Test
public void happyCase() throws Exception {
// when
simpleObjectWrapped.updateName("new name");
// then
assertThat(simpleObjectWrapped.getName()).isEqualTo("new name");
}
@Test
public void failsValidation() throws Exception {
// expect
expectedExceptions.expect(InvalidException.class);
expectedExceptions.expectMessage("Exclamation mark is not allowed");
// when
simpleObjectWrapped.updateName("new name!");
}
}
public static class Title extends SimpleObjectIntegTest {
@Inject
DomainObjectContainer container;
@Test
public void interpolatesName() throws Exception {
// given
final String name = simpleObjectWrapped.getName();
// when
final String title = container.titleOf(simpleObjectWrapped);
// then
assertThat(title).isEqualTo("Object: " + name);
}
} }
}
} }

Some files were not shown because too many files have changed in this diff Show More