Adjust checkstyle rules. Make checkstyle fail the build when violations are found. Correct all current checkstyle violations.
This commit is contained in:
parent
9fbb085985
commit
cec9a99410
@ -1,20 +1,18 @@
|
||||
package com.iluwatar.abstractfactory;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* The Abstract Factory pattern provides a way to encapsulate a group of individual factories that
|
||||
* have a common theme without specifying their concrete classes. In normal usage, the client
|
||||
* software creates a concrete implementation of the abstract factory and then uses the generic
|
||||
* interface of the factory to create the concrete objects that are part of the theme. The client
|
||||
* does not know (or care) which concrete objects it gets from each of these internal factories,
|
||||
* since it uses only the generic interfaces of their products. This pattern separates the details
|
||||
* of implementation of a set of objects from their general usage and relies on object composition,
|
||||
* as object creation is implemented in methods exposed in the factory interface.
|
||||
* The Abstract Factory pattern provides a way to encapsulate a group of individual factories that have a common theme
|
||||
* without specifying their concrete classes. In normal usage, the client software creates a concrete implementation of
|
||||
* the abstract factory and then uses the generic interface of the factory to create the concrete objects that are part
|
||||
* of the theme. The client does not know (or care) which concrete objects it gets from each of these internal
|
||||
* factories, since it uses only the generic interfaces of their products. This pattern separates the details of
|
||||
* implementation of a set of objects from their general usage and relies on object composition, as object creation is
|
||||
* implemented in methods exposed in the factory interface.
|
||||
* <p>
|
||||
* The essence of the Abstract Factory pattern is a factory interface ({@link KingdomFactory}) and
|
||||
* its implementations ({@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses both
|
||||
* concrete implementations to create a king, a castle and an army.
|
||||
* The essence of the Abstract Factory pattern is a factory interface ({@link KingdomFactory}) and its implementations (
|
||||
* {@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses both concrete implementations to create a
|
||||
* king, a castle and an army.
|
||||
*
|
||||
*/
|
||||
public class App {
|
||||
@ -23,11 +21,8 @@ public class App {
|
||||
private Castle castle;
|
||||
private Army army;
|
||||
|
||||
|
||||
/**
|
||||
* Creates kingdom
|
||||
*
|
||||
* @param factory
|
||||
*/
|
||||
public void createKingdom(final KingdomFactory factory) {
|
||||
setKing(factory.createKing());
|
||||
@ -47,14 +42,6 @@ public class App {
|
||||
return factory.createKing();
|
||||
}
|
||||
|
||||
Castle getCastle(final KingdomFactory factory) {
|
||||
return factory.createCastle();
|
||||
}
|
||||
|
||||
Army getArmy(final KingdomFactory factory) {
|
||||
return factory.createArmy();
|
||||
}
|
||||
|
||||
public King getKing() {
|
||||
return king;
|
||||
}
|
||||
@ -62,6 +49,10 @@ public class App {
|
||||
private void setKing(final King king) {
|
||||
this.king = king;
|
||||
}
|
||||
|
||||
Castle getCastle(final KingdomFactory factory) {
|
||||
return factory.createCastle();
|
||||
}
|
||||
|
||||
public Castle getCastle() {
|
||||
return castle;
|
||||
@ -70,6 +61,10 @@ public class App {
|
||||
private void setCastle(final Castle castle) {
|
||||
this.castle = castle;
|
||||
}
|
||||
|
||||
Army getArmy(final KingdomFactory factory) {
|
||||
return factory.createArmy();
|
||||
}
|
||||
|
||||
public Army getArmy() {
|
||||
return army;
|
||||
@ -79,32 +74,32 @@ public class App {
|
||||
this.army = army;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Program entry point
|
||||
*
|
||||
* @param args command line args
|
||||
* @param args
|
||||
* command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
App app = new App();
|
||||
|
||||
System.out.println("Elf Kingdom");
|
||||
KingdomFactory elfKingdomFactory;
|
||||
elfKingdomFactory = app.getElfKingdomFactory();
|
||||
app.createKingdom(elfKingdomFactory);
|
||||
System.out.println(app.getArmy().getDescription());
|
||||
System.out.println(app.getCastle().getDescription());
|
||||
System.out.println(app.getKing().getDescription());
|
||||
|
||||
System.out.println("\nOrc Kingdom");
|
||||
KingdomFactory orcKingdomFactory;
|
||||
orcKingdomFactory = app.getOrcKingdomFactory();
|
||||
app.createKingdom(orcKingdomFactory);
|
||||
System.out.println(app.getArmy().getDescription());
|
||||
System.out.println(app.getCastle().getDescription());
|
||||
System.out.println(app.getKing().getDescription());
|
||||
|
||||
|
||||
App app = new App();
|
||||
|
||||
System.out.println("Elf Kingdom");
|
||||
KingdomFactory elfKingdomFactory;
|
||||
elfKingdomFactory = app.getElfKingdomFactory();
|
||||
app.createKingdom(elfKingdomFactory);
|
||||
System.out.println(app.getArmy().getDescription());
|
||||
System.out.println(app.getCastle().getDescription());
|
||||
System.out.println(app.getKing().getDescription());
|
||||
|
||||
System.out.println("\nOrc Kingdom");
|
||||
KingdomFactory orcKingdomFactory;
|
||||
orcKingdomFactory = app.getOrcKingdomFactory();
|
||||
app.createKingdom(orcKingdomFactory);
|
||||
System.out.println(app.getArmy().getDescription());
|
||||
System.out.println(app.getCastle().getDescription());
|
||||
System.out.println(app.getKing().getDescription());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -4,24 +4,23 @@ import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* value, <code>AsyncCallback</code> which can be provided to be executed on task completion and
|
||||
* <code>AsyncExecutor</code> that manages the execution of the async tasks.
|
||||
* <code>AsyncResult</code> which is an intermediate container for an asynchronously evaluated value,
|
||||
* <code>AsyncCallback</code> which can be provided to be executed on task completion and <code>AsyncExecutor</code>
|
||||
* that manages the execution of the async tasks.
|
||||
* <p>
|
||||
* The main method shows example flow of async invocations. The main thread starts multiple tasks
|
||||
* with variable durations and then continues its own work. When the main thread has done it's job
|
||||
* it collects the results of the async tasks. Two of the tasks are handled with callbacks, meaning
|
||||
* the callbacks are executed immediately when the tasks complete.
|
||||
* The main method shows example flow of async invocations. The main thread starts multiple tasks with variable
|
||||
* durations and then continues its own work. When the main thread has done it's job it collects the results of the
|
||||
* async tasks. Two of the tasks are handled with callbacks, meaning the callbacks are executed immediately when the
|
||||
* tasks complete.
|
||||
* <p>
|
||||
* Noteworthy difference of thread usage between the async results and callbacks is that the async
|
||||
* results are collected in the main thread but the callbacks are executed within the worker
|
||||
* threads. This should be noted when working with thread pools.
|
||||
* Noteworthy difference of thread usage between the async results and callbacks is that the async results are collected
|
||||
* in the main thread but the callbacks are executed within the worker threads. This should be noted when working with
|
||||
* thread pools.
|
||||
* <p>
|
||||
* Java provides its own implementations of async method invocation pattern. FutureTask,
|
||||
* CompletableFuture and ExecutorService are the real world implementations of this pattern. But due
|
||||
* to the nature of parallel programming, the implementations are not trivial. This example does not
|
||||
* take all possible scenarios into account but rather provides a simple version that helps to
|
||||
* understand the pattern.
|
||||
* Java provides its own implementations of async method invocation pattern. FutureTask, CompletableFuture and
|
||||
* ExecutorService are the real world implementations of this pattern. But due to the nature of parallel programming,
|
||||
* the implementations are not trivial. This example does not take all possible scenarios into account but rather
|
||||
* provides a simple version that helps to understand the pattern.
|
||||
*
|
||||
* @see AsyncResult
|
||||
* @see AsyncCallback
|
||||
@ -33,6 +32,9 @@ import java.util.concurrent.Callable;
|
||||
*/
|
||||
public class App {
|
||||
|
||||
/**
|
||||
* Program entry point
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
// construct a new executor that will run async tasks
|
||||
AsyncExecutor executor = new ThreadAsyncExecutor();
|
||||
@ -41,10 +43,8 @@ public class App {
|
||||
AsyncResult<Integer> asyncResult1 = executor.startProcess(lazyval(10, 500));
|
||||
AsyncResult<String> asyncResult2 = executor.startProcess(lazyval("test", 300));
|
||||
AsyncResult<Long> asyncResult3 = executor.startProcess(lazyval(50L, 700));
|
||||
AsyncResult<Integer> asyncResult4 =
|
||||
executor.startProcess(lazyval(20, 400), callback("Callback result 4"));
|
||||
AsyncResult<String> asyncResult5 =
|
||||
executor.startProcess(lazyval("callback", 600), callback("Callback result 5"));
|
||||
AsyncResult<Integer> asyncResult4 = executor.startProcess(lazyval(20, 400), callback("Callback result 4"));
|
||||
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
|
||||
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.
|
||||
*
|
||||
* @param value value to evaluate
|
||||
* @param delayMillis artificial delay in milliseconds
|
||||
* @param value
|
||||
* value to evaluate
|
||||
* @param delayMillis
|
||||
* artificial delay in milliseconds
|
||||
* @return new callable for lazy evaluation
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param name callback name
|
||||
* @param name
|
||||
* callback name
|
||||
* @return new async callback
|
||||
*/
|
||||
private static <T> AsyncCallback<T> callback(String name) {
|
||||
|
@ -5,8 +5,6 @@ import java.util.concurrent.ExecutionException;
|
||||
/**
|
||||
*
|
||||
* AsyncResult interface
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public interface AsyncResult<T> {
|
||||
|
||||
|
@ -29,13 +29,12 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
|
||||
} catch (Exception ex) {
|
||||
result.setException(ex);
|
||||
}
|
||||
}, "executor-" + idx.incrementAndGet()).start();
|
||||
} , "executor-" + idx.incrementAndGet()).start();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException,
|
||||
InterruptedException {
|
||||
public <T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException, InterruptedException {
|
||||
if (asyncResult.isCompleted()) {
|
||||
return asyncResult.getValue();
|
||||
} else {
|
||||
@ -45,9 +44,8 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple implementation of async result that allows completing it successfully with a value or
|
||||
* exceptionally with an exception. A really simplified version from its real life cousins
|
||||
* FutureTask and CompletableFuture.
|
||||
* Simple implementation of async result that allows completing it successfully with a value or exceptionally with an
|
||||
* exception. A really simplified version from its real life cousins FutureTask and CompletableFuture.
|
||||
*
|
||||
* @see java.util.concurrent.FutureTask
|
||||
* @see java.util.concurrent.CompletableFuture
|
||||
@ -71,10 +69,11 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value from successful execution and executes callback if available. Notifies any
|
||||
* thread waiting for completion.
|
||||
* Sets the value from successful execution and executes callback if available. Notifies any thread waiting for
|
||||
* completion.
|
||||
*
|
||||
* @param value value of the evaluated task
|
||||
* @param value
|
||||
* value of the evaluated task
|
||||
*/
|
||||
void setValue(T 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
|
||||
* thread waiting for completion.
|
||||
* Sets the exception from failed execution and executes callback if available. Notifies any thread waiting for
|
||||
* completion.
|
||||
*
|
||||
* @param exception exception of the failed task
|
||||
* @param exception
|
||||
* exception of the failed task
|
||||
*/
|
||||
void setException(Exception exception) {
|
||||
this.exception = exception;
|
||||
|
@ -55,8 +55,7 @@ public class ThreadAsyncExecutorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test used to verify the happy path of
|
||||
* {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)}
|
||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)}
|
||||
*/
|
||||
@Test(timeout = 3000)
|
||||
public void testSuccessfulTaskWithCallback() throws Exception {
|
||||
@ -77,8 +76,7 @@ public class ThreadAsyncExecutorTest {
|
||||
verify(task, times(1)).call();
|
||||
|
||||
// ... same for the callback, we expect our object
|
||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor
|
||||
.forClass((Class) Optional.class);
|
||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
|
||||
verify(callback, times(1)).onComplete(eq(result), optionalCaptor.capture());
|
||||
|
||||
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
|
||||
* task takes a while to execute
|
||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a task takes a while
|
||||
* to execute
|
||||
*/
|
||||
@Test(timeout = 5000)
|
||||
public void testLongRunningTaskWithoutCallback() throws Exception {
|
||||
@ -101,9 +99,9 @@ public class ThreadAsyncExecutorTest {
|
||||
final Object result = new Object();
|
||||
final Callable<Object> task = mock(Callable.class);
|
||||
when(task.call()).thenAnswer(i -> {
|
||||
Thread.sleep(1500);
|
||||
return result;
|
||||
});
|
||||
Thread.sleep(1500);
|
||||
return result;
|
||||
});
|
||||
|
||||
final AsyncResult<Object> asyncResult = executor.startProcess(task);
|
||||
assertNotNull(asyncResult);
|
||||
@ -111,8 +109,7 @@ public class ThreadAsyncExecutorTest {
|
||||
|
||||
try {
|
||||
asyncResult.getValue();
|
||||
fail(
|
||||
"Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
|
||||
fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
|
||||
} catch (IllegalStateException e) {
|
||||
assertNotNull(e.getMessage());
|
||||
}
|
||||
@ -130,9 +127,8 @@ public class ThreadAsyncExecutorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test used to verify the happy path of
|
||||
* {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when a task takes a while to
|
||||
* execute
|
||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when a task
|
||||
* takes a while to execute
|
||||
*/
|
||||
@Test(timeout = 5000)
|
||||
public void testLongRunningTaskWithCallback() throws Exception {
|
||||
@ -142,9 +138,9 @@ public class ThreadAsyncExecutorTest {
|
||||
final Object result = new Object();
|
||||
final Callable<Object> task = mock(Callable.class);
|
||||
when(task.call()).thenAnswer(i -> {
|
||||
Thread.sleep(1500);
|
||||
return result;
|
||||
});
|
||||
Thread.sleep(1500);
|
||||
return result;
|
||||
});
|
||||
|
||||
final AsyncCallback<Object> callback = mock(AsyncCallback.class);
|
||||
final AsyncResult<Object> asyncResult = executor.startProcess(task, callback);
|
||||
@ -155,8 +151,7 @@ public class ThreadAsyncExecutorTest {
|
||||
|
||||
try {
|
||||
asyncResult.getValue();
|
||||
fail(
|
||||
"Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
|
||||
fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
|
||||
} catch (IllegalStateException e) {
|
||||
assertNotNull(e.getMessage());
|
||||
}
|
||||
@ -164,8 +159,7 @@ public class ThreadAsyncExecutorTest {
|
||||
// Our task should only execute once, but it can take a while ...
|
||||
verify(task, timeout(3000).times(1)).call();
|
||||
|
||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor
|
||||
.forClass((Class) Optional.class);
|
||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
|
||||
verify(callback, timeout(3000).times(1)).onComplete(eq(result), optionalCaptor.capture());
|
||||
|
||||
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
|
||||
* task takes a while to execute, while waiting on the result using
|
||||
* {@link ThreadAsyncExecutor#endProcess(AsyncResult)}
|
||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a task takes a while
|
||||
* to execute, while waiting on the result using {@link ThreadAsyncExecutor#endProcess(AsyncResult)}
|
||||
*/
|
||||
@Test(timeout = 5000)
|
||||
public void testEndProcess() throws Exception {
|
||||
@ -194,9 +187,9 @@ public class ThreadAsyncExecutorTest {
|
||||
final Object result = new Object();
|
||||
final Callable<Object> task = mock(Callable.class);
|
||||
when(task.call()).thenAnswer(i -> {
|
||||
Thread.sleep(1500);
|
||||
return result;
|
||||
});
|
||||
Thread.sleep(1500);
|
||||
return result;
|
||||
});
|
||||
|
||||
final AsyncResult<Object> asyncResult = executor.startProcess(task);
|
||||
assertNotNull(asyncResult);
|
||||
@ -204,8 +197,7 @@ public class ThreadAsyncExecutorTest {
|
||||
|
||||
try {
|
||||
asyncResult.getValue();
|
||||
fail(
|
||||
"Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
|
||||
fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
|
||||
} catch (IllegalStateException e) {
|
||||
assertNotNull(e.getMessage());
|
||||
}
|
||||
@ -220,8 +212,7 @@ public class ThreadAsyncExecutorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable)} when
|
||||
* the callable is 'null'
|
||||
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable)} when the callable is 'null'
|
||||
*/
|
||||
@Test(timeout = 3000)
|
||||
public void testNullTask() throws Exception {
|
||||
@ -229,8 +220,7 @@ public class ThreadAsyncExecutorTest {
|
||||
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
||||
final AsyncResult<Object> asyncResult = executor.startProcess(null);
|
||||
|
||||
assertNotNull("The AsyncResult should not be 'null', even though the task was 'null'.",
|
||||
asyncResult);
|
||||
assertNotNull("The AsyncResult should not be 'null', even though the task was 'null'.", asyncResult);
|
||||
asyncResult.await(); // Prevent timing issues, and wait until the result is available
|
||||
assertTrue(asyncResult.isCompleted());
|
||||
|
||||
@ -246,9 +236,8 @@ public class ThreadAsyncExecutorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test used to verify the behaviour of
|
||||
* {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when the callable is 'null',
|
||||
* but the asynchronous callback is provided
|
||||
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when the
|
||||
* callable is 'null', but the asynchronous callback is provided
|
||||
*/
|
||||
@Test(timeout = 3000)
|
||||
public void testNullTaskWithCallback() throws Exception {
|
||||
@ -257,13 +246,11 @@ public class ThreadAsyncExecutorTest {
|
||||
final AsyncCallback<Object> callback = mock(AsyncCallback.class);
|
||||
final AsyncResult<Object> asyncResult = executor.startProcess(null, callback);
|
||||
|
||||
assertNotNull("The AsyncResult should not be 'null', even though the task was 'null'.",
|
||||
asyncResult);
|
||||
assertNotNull("The AsyncResult should not be 'null', even though the task was 'null'.", asyncResult);
|
||||
asyncResult.await(); // Prevent timing issues, and wait until the result is available
|
||||
assertTrue(asyncResult.isCompleted());
|
||||
|
||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor
|
||||
.forClass((Class) Optional.class);
|
||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
|
||||
verify(callback, times(1)).onComplete(Matchers.isNull(), optionalCaptor.capture());
|
||||
|
||||
final Optional<Exception> optionalException = optionalCaptor.getValue();
|
||||
@ -286,9 +273,8 @@ public class ThreadAsyncExecutorTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Test used to verify the behaviour of
|
||||
* {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when both the callable and
|
||||
* the asynchronous callback are 'null'
|
||||
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when both
|
||||
* the callable and the asynchronous callback are 'null'
|
||||
*/
|
||||
@Test(timeout = 3000)
|
||||
public void testNullTaskWithNullCallback() throws Exception {
|
||||
@ -296,9 +282,7 @@ public class ThreadAsyncExecutorTest {
|
||||
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
||||
final AsyncResult<Object> asyncResult = executor.startProcess(null, null);
|
||||
|
||||
assertNotNull(
|
||||
"The AsyncResult should not be 'null', even though the task and callback were 'null'.",
|
||||
asyncResult);
|
||||
assertNotNull("The AsyncResult should not be 'null', even though the task and callback were 'null'.", asyncResult);
|
||||
asyncResult.await(); // Prevent timing issues, and wait until the result is available
|
||||
assertTrue(asyncResult.isCompleted());
|
||||
|
||||
|
@ -93,6 +93,9 @@ public class Hero {
|
||||
private Armor armor;
|
||||
private Weapon weapon;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public HeroBuilder(Profession profession, String name) {
|
||||
if (profession == null || name == null) {
|
||||
throw new IllegalArgumentException("profession and name can not be null");
|
||||
|
@ -5,20 +5,20 @@ package com.iluwatar.business.delegate;
|
||||
*/
|
||||
public class BusinessDelegate {
|
||||
|
||||
private BusinessLookup lookupService;
|
||||
private BusinessService businessService;
|
||||
private ServiceType serviceType;
|
||||
private BusinessLookup lookupService;
|
||||
private BusinessService businessService;
|
||||
private ServiceType serviceType;
|
||||
|
||||
public void setLookupService(BusinessLookup businessLookup) {
|
||||
this.lookupService = businessLookup;
|
||||
}
|
||||
public void setLookupService(BusinessLookup businessLookup) {
|
||||
this.lookupService = businessLookup;
|
||||
}
|
||||
|
||||
public void setServiceType(ServiceType serviceType) {
|
||||
this.serviceType = serviceType;
|
||||
}
|
||||
public void setServiceType(ServiceType serviceType) {
|
||||
this.serviceType = serviceType;
|
||||
}
|
||||
|
||||
public void doTask() {
|
||||
businessService = lookupService.getBusinessService(serviceType);
|
||||
businessService.doProcessing();
|
||||
}
|
||||
public void doTask() {
|
||||
businessService = lookupService.getBusinessService(serviceType);
|
||||
businessService.doProcessing();
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ package com.iluwatar.caching;
|
||||
* application data. The cache itself is implemented as an internal (Java) data structure. It adopts
|
||||
* a Least-Recently-Used (LRU) strategy for evicting data from itself when its full. The three
|
||||
* strategies are individually tested. The testing of the cache is restricted towards saving and
|
||||
* querying of user accounts from the underlying data store ( {@link DBManager}). The main class (
|
||||
* querying of user accounts from the underlying data store ( {@link DbManager}). The main class (
|
||||
* {@link App} is not aware of the underlying mechanics of the application (i.e. save and query) and
|
||||
* whether the data is coming from the cache or the DB (i.e. separation of concern). The AppManager
|
||||
* ({@link AppManager}) handles the transaction of data to-and-from the underlying data store
|
||||
@ -43,7 +43,7 @@ public class App {
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
AppManager.initDB(false); // VirtualDB (instead of MongoDB) was used in running the JUnit tests
|
||||
AppManager.initDb(false); // VirtualDB (instead of MongoDB) was used in running the JUnit tests
|
||||
// and the App class to avoid Maven compilation errors. Set flag to
|
||||
// true to run the tests with MongoDB (provided that MongoDB is
|
||||
// installed and socket connection is open).
|
||||
|
@ -21,18 +21,21 @@ public class AppManager {
|
||||
* data storage or a simple Java data structure to (temporarily) store the data/objects during
|
||||
* runtime.
|
||||
*/
|
||||
public static void initDB(boolean useMongoDB) {
|
||||
if (useMongoDB) {
|
||||
public static void initDb(boolean useMongoDb) {
|
||||
if (useMongoDb) {
|
||||
try {
|
||||
DBManager.connect();
|
||||
DbManager.connect();
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
DBManager.createVirtualDB();
|
||||
DbManager.createVirtualDb();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize caching policy
|
||||
*/
|
||||
public static void initCachingPolicy(CachingPolicy policy) {
|
||||
cachingPolicy = policy;
|
||||
if (cachingPolicy == CachingPolicy.BEHIND) {
|
||||
@ -50,15 +53,21 @@ public class AppManager {
|
||||
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) {
|
||||
return CacheStore.readThrough(userID);
|
||||
return CacheStore.readThrough(userId);
|
||||
} else if (cachingPolicy == CachingPolicy.BEHIND) {
|
||||
return CacheStore.readThroughWithWriteBackPolicy(userID);
|
||||
return CacheStore.readThroughWithWriteBackPolicy(userId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save user account
|
||||
*/
|
||||
public static void save(UserAccount userAccount) {
|
||||
if (cachingPolicy == CachingPolicy.THROUGH) {
|
||||
CacheStore.writeThrough(userAccount);
|
||||
|
@ -9,73 +9,96 @@ import java.util.ArrayList;
|
||||
*/
|
||||
public class CacheStore {
|
||||
|
||||
static LRUCache cache = null;
|
||||
static LruCache cache = null;
|
||||
|
||||
/**
|
||||
* Init cache capacity
|
||||
*/
|
||||
public static void initCapacity(int capacity) {
|
||||
if (null == cache)
|
||||
cache = new LRUCache(capacity);
|
||||
else
|
||||
if (null == cache) {
|
||||
cache = new LruCache(capacity);
|
||||
} else {
|
||||
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!");
|
||||
return cache.get(userID);
|
||||
return cache.get(userId);
|
||||
}
|
||||
System.out.println("# Cache Miss!");
|
||||
UserAccount userAccount = DBManager.readFromDB(userID);
|
||||
cache.set(userID, userAccount);
|
||||
UserAccount userAccount = DbManager.readFromDb(userId);
|
||||
cache.set(userId, userAccount);
|
||||
return userAccount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get user account using write-through cache
|
||||
*/
|
||||
public static void writeThrough(UserAccount userAccount) {
|
||||
if (cache.contains(userAccount.getUserID())) {
|
||||
DBManager.updateDB(userAccount);
|
||||
if (cache.contains(userAccount.getUserId())) {
|
||||
DbManager.updateDb(userAccount);
|
||||
} 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) {
|
||||
if (cache.contains(userAccount.getUserID())) {
|
||||
DBManager.updateDB(userAccount);
|
||||
cache.invalidate(userAccount.getUserID()); // Cache data has been updated -- remove older
|
||||
if (cache.contains(userAccount.getUserId())) {
|
||||
DbManager.updateDb(userAccount);
|
||||
cache.invalidate(userAccount.getUserId()); // Cache data has been updated -- remove older
|
||||
// version from cache.
|
||||
} else {
|
||||
DBManager.writeToDB(userAccount);
|
||||
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!");
|
||||
return cache.get(userID);
|
||||
return cache.get(userId);
|
||||
}
|
||||
System.out.println("# Cache Miss!");
|
||||
UserAccount userAccount = DBManager.readFromDB(userID);
|
||||
UserAccount userAccount = DbManager.readFromDb(userId);
|
||||
if (cache.isFull()) {
|
||||
System.out.println("# Cache is FULL! Writing LRU data to DB...");
|
||||
UserAccount toBeWrittenToDB = cache.getLRUData();
|
||||
DBManager.upsertDB(toBeWrittenToDB);
|
||||
UserAccount toBeWrittenToDb = cache.getLruData();
|
||||
DbManager.upsertDb(toBeWrittenToDb);
|
||||
}
|
||||
cache.set(userID, userAccount);
|
||||
cache.set(userId, userAccount);
|
||||
return userAccount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user account
|
||||
*/
|
||||
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...");
|
||||
UserAccount toBeWrittenToDB = cache.getLRUData();
|
||||
DBManager.upsertDB(toBeWrittenToDB);
|
||||
UserAccount toBeWrittenToDb = cache.getLruData();
|
||||
DbManager.upsertDb(toBeWrittenToDb);
|
||||
}
|
||||
cache.set(userAccount.getUserID(), userAccount);
|
||||
cache.set(userAccount.getUserId(), userAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears cache
|
||||
*/
|
||||
public static void clearCache() {
|
||||
if (null != cache)
|
||||
if (null != cache) {
|
||||
cache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,14 +106,18 @@ public class CacheStore {
|
||||
*/
|
||||
public static void flushCache() {
|
||||
System.out.println("# flushCache...");
|
||||
if (null == cache)
|
||||
if (null == cache) {
|
||||
return;
|
||||
}
|
||||
ArrayList<UserAccount> listOfUserAccounts = cache.getCacheDataInListForm();
|
||||
for (UserAccount userAccount : listOfUserAccounts) {
|
||||
DBManager.upsertDB(userAccount);
|
||||
DbManager.upsertDb(userAccount);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print user accounts
|
||||
*/
|
||||
public static String print() {
|
||||
ArrayList<UserAccount> listOfUserAccounts = cache.getCacheDataInListForm();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
@ -21,7 +21,7 @@ import com.mongodb.client.model.UpdateOptions;
|
||||
* during runtime (createVirtualDB()).</p>
|
||||
*
|
||||
*/
|
||||
public class DBManager {
|
||||
public class DbManager {
|
||||
|
||||
private static MongoClient mongoClient;
|
||||
private static MongoDatabase db;
|
||||
@ -29,21 +29,31 @@ public class DBManager {
|
||||
|
||||
private static HashMap<String, UserAccount> virtualDB;
|
||||
|
||||
public static void createVirtualDB() {
|
||||
/**
|
||||
* Create DB
|
||||
*/
|
||||
public static void createVirtualDb() {
|
||||
useMongoDB = false;
|
||||
virtualDB = new HashMap<String, UserAccount>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to DB
|
||||
*/
|
||||
public static void connect() throws ParseException {
|
||||
useMongoDB = true;
|
||||
mongoClient = new MongoClient();
|
||||
db = mongoClient.getDatabase("test");
|
||||
}
|
||||
|
||||
public static UserAccount readFromDB(String userID) {
|
||||
/**
|
||||
* Read user account from DB
|
||||
*/
|
||||
public static UserAccount readFromDb(String userId) {
|
||||
if (!useMongoDB) {
|
||||
if (virtualDB.containsKey(userID))
|
||||
return virtualDB.get(userID);
|
||||
if (virtualDB.containsKey(userId)) {
|
||||
return virtualDB.get(userId);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (null == db) {
|
||||
@ -54,18 +64,22 @@ public class DBManager {
|
||||
}
|
||||
}
|
||||
FindIterable<Document> iterable =
|
||||
db.getCollection("user_accounts").find(new Document("userID", userID));
|
||||
if (iterable == null)
|
||||
db.getCollection("user_accounts").find(new Document("userID", userId));
|
||||
if (iterable == null) {
|
||||
return null;
|
||||
}
|
||||
Document doc = iterable.first();
|
||||
UserAccount userAccount =
|
||||
new UserAccount(userID, doc.getString("userName"), doc.getString("additionalInfo"));
|
||||
new UserAccount(userId, doc.getString("userName"), doc.getString("additionalInfo"));
|
||||
return userAccount;
|
||||
}
|
||||
|
||||
public static void writeToDB(UserAccount userAccount) {
|
||||
/**
|
||||
* Write user account to DB
|
||||
*/
|
||||
public static void writeToDb(UserAccount userAccount) {
|
||||
if (!useMongoDB) {
|
||||
virtualDB.put(userAccount.getUserID(), userAccount);
|
||||
virtualDB.put(userAccount.getUserId(), userAccount);
|
||||
return;
|
||||
}
|
||||
if (null == db) {
|
||||
@ -76,13 +90,16 @@ public class DBManager {
|
||||
}
|
||||
}
|
||||
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()));
|
||||
}
|
||||
|
||||
public static void updateDB(UserAccount userAccount) {
|
||||
/**
|
||||
* Update DB
|
||||
*/
|
||||
public static void updateDb(UserAccount userAccount) {
|
||||
if (!useMongoDB) {
|
||||
virtualDB.put(userAccount.getUserID(), userAccount);
|
||||
virtualDB.put(userAccount.getUserId(), userAccount);
|
||||
return;
|
||||
}
|
||||
if (null == db) {
|
||||
@ -93,7 +110,7 @@ public class DBManager {
|
||||
}
|
||||
}
|
||||
db.getCollection("user_accounts").updateOne(
|
||||
new Document("userID", userAccount.getUserID()),
|
||||
new Document("userID", userAccount.getUserId()),
|
||||
new Document("$set", new Document("userName", userAccount.getUserName()).append(
|
||||
"additionalInfo", userAccount.getAdditionalInfo())));
|
||||
}
|
||||
@ -102,9 +119,9 @@ public class DBManager {
|
||||
*
|
||||
* 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) {
|
||||
virtualDB.put(userAccount.getUserID(), userAccount);
|
||||
virtualDB.put(userAccount.getUserId(), userAccount);
|
||||
return;
|
||||
}
|
||||
if (null == db) {
|
||||
@ -115,8 +132,8 @@ public class DBManager {
|
||||
}
|
||||
}
|
||||
db.getCollection("user_accounts").updateOne(
|
||||
new Document("userID", userAccount.getUserID()),
|
||||
new Document("$set", new Document("userID", userAccount.getUserID()).append("userName",
|
||||
new Document("userID", userAccount.getUserId()),
|
||||
new Document("$set", new Document("userID", userAccount.getUserId()).append("userName",
|
||||
userAccount.getUserName()).append("additionalInfo", userAccount.getAdditionalInfo())),
|
||||
new UpdateOptions().upsert(true));
|
||||
}
|
@ -12,16 +12,16 @@ import java.util.HashMap;
|
||||
* LRU data is always at the end of the list.
|
||||
*
|
||||
*/
|
||||
public class LRUCache {
|
||||
public class LruCache {
|
||||
|
||||
class Node {
|
||||
String userID;
|
||||
String userId;
|
||||
UserAccount userAccount;
|
||||
Node previous;
|
||||
Node next;
|
||||
|
||||
public Node(String userID, UserAccount userAccount) {
|
||||
this.userID = userID;
|
||||
public Node(String userId, UserAccount userAccount) {
|
||||
this.userId = userId;
|
||||
this.userAccount = userAccount;
|
||||
}
|
||||
}
|
||||
@ -31,13 +31,16 @@ public class LRUCache {
|
||||
Node head = null;
|
||||
Node end = null;
|
||||
|
||||
public LRUCache(int capacity) {
|
||||
public LruCache(int capacity) {
|
||||
this.capacity = capacity;
|
||||
}
|
||||
|
||||
public UserAccount get(String userID) {
|
||||
if (cache.containsKey(userID)) {
|
||||
Node node = cache.get(userID);
|
||||
/**
|
||||
* Get user account
|
||||
*/
|
||||
public UserAccount get(String userId) {
|
||||
if (cache.containsKey(userId)) {
|
||||
Node node = cache.get(userId);
|
||||
remove(node);
|
||||
setHead(node);
|
||||
return node.userAccount;
|
||||
@ -69,52 +72,63 @@ public class LRUCache {
|
||||
public void setHead(Node node) {
|
||||
node.next = head;
|
||||
node.previous = null;
|
||||
if (head != null)
|
||||
if (head != null) {
|
||||
head.previous = node;
|
||||
}
|
||||
head = node;
|
||||
if (end == null)
|
||||
if (end == null) {
|
||||
end = head;
|
||||
}
|
||||
}
|
||||
|
||||
public void set(String userID, UserAccount userAccount) {
|
||||
if (cache.containsKey(userID)) {
|
||||
Node old = cache.get(userID);
|
||||
/**
|
||||
* Set user account
|
||||
*/
|
||||
public void set(String userId, UserAccount userAccount) {
|
||||
if (cache.containsKey(userId)) {
|
||||
Node old = cache.get(userId);
|
||||
old.userAccount = userAccount;
|
||||
remove(old);
|
||||
setHead(old);
|
||||
} else {
|
||||
Node newNode = new Node(userID, userAccount);
|
||||
Node newNode = new Node(userId, userAccount);
|
||||
if (cache.size() >= capacity) {
|
||||
System.out.println("# Cache is FULL! Removing " + end.userID + " from cache...");
|
||||
cache.remove(end.userID); // remove LRU data from cache.
|
||||
System.out.println("# Cache is FULL! Removing " + end.userId + " from cache...");
|
||||
cache.remove(end.userId); // remove LRU data from cache.
|
||||
remove(end);
|
||||
setHead(newNode);
|
||||
} else {
|
||||
setHead(newNode);
|
||||
}
|
||||
cache.put(userID, newNode);
|
||||
cache.put(userId, newNode);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(String userID) {
|
||||
return cache.containsKey(userID);
|
||||
public boolean contains(String userId) {
|
||||
return cache.containsKey(userId);
|
||||
}
|
||||
|
||||
public void invalidate(String userID) {
|
||||
System.out.println("# " + userID + " has been updated! Removing older version from cache...");
|
||||
Node toBeRemoved = cache.get(userID);
|
||||
/**
|
||||
* Invalidate cache for user
|
||||
*/
|
||||
public void invalidate(String userId) {
|
||||
System.out.println("# " + userId + " has been updated! Removing older version from cache...");
|
||||
Node toBeRemoved = cache.get(userId);
|
||||
remove(toBeRemoved);
|
||||
cache.remove(userID);
|
||||
cache.remove(userId);
|
||||
}
|
||||
|
||||
public boolean isFull() {
|
||||
return cache.size() >= capacity;
|
||||
}
|
||||
|
||||
public UserAccount getLRUData() {
|
||||
public UserAccount getLruData() {
|
||||
return end.userAccount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear cache
|
||||
*/
|
||||
public void clear() {
|
||||
head = null;
|
||||
end = null;
|
||||
@ -135,6 +149,9 @@ public class LRUCache {
|
||||
return listOfCacheData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set cache capacity
|
||||
*/
|
||||
public void setCapacity(int newCapacity) {
|
||||
if (capacity > newCapacity) {
|
||||
clear(); // Behavior can be modified to accommodate for decrease in cache size. For now, we'll
|
@ -6,22 +6,25 @@ package com.iluwatar.caching;
|
||||
*
|
||||
*/
|
||||
public class UserAccount {
|
||||
private String userID;
|
||||
private String userId;
|
||||
private String userName;
|
||||
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.additionalInfo = additionalInfo;
|
||||
}
|
||||
|
||||
public String getUserID() {
|
||||
return userID;
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserID(String userID) {
|
||||
this.userID = userID;
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
@ -42,6 +45,6 @@ public class UserAccount {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return userID + ", " + userName + ", " + additionalInfo;
|
||||
return userId + ", " + userName + ", " + additionalInfo;
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ public class AppTest {
|
||||
*/
|
||||
@Before
|
||||
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
|
||||
// tests with MongoDB (provided that MongoDB is installed and socket
|
||||
// connection is open).
|
||||
|
@ -9,6 +9,9 @@ package com.iluwatar.callback;
|
||||
*/
|
||||
public class App {
|
||||
|
||||
/**
|
||||
* Program entry point
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
Task task = new SimpleTask();
|
||||
Callback callback = new Callback() {
|
||||
|
@ -7,6 +7,9 @@ package com.iluwatar.callback;
|
||||
*/
|
||||
public abstract class Task {
|
||||
|
||||
/**
|
||||
* Execute with callback
|
||||
*/
|
||||
public final void executeWith(Callback callback) {
|
||||
execute();
|
||||
if (callback != null) {
|
||||
|
@ -13,6 +13,9 @@ public abstract class RequestHandler {
|
||||
this.next = next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request handler
|
||||
*/
|
||||
public void handleRequest(Request req) {
|
||||
if (next != null) {
|
||||
next.handleRequest(req);
|
||||
|
@ -25,8 +25,10 @@
|
||||
|
||||
<module name="Checker">
|
||||
<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 -->
|
||||
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
|
||||
@ -48,7 +50,7 @@
|
||||
<property name="allowNonPrintableEscapes" value="true"/>
|
||||
</module>
|
||||
<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://"/>
|
||||
</module>
|
||||
<module name="AvoidStarImport"/>
|
||||
@ -61,7 +63,7 @@
|
||||
</module>
|
||||
<module name="NeedBraces"/>
|
||||
<module name="LeftCurly">
|
||||
<property name="maxLineLength" value="100"/>
|
||||
<property name="maxLineLength" value="120"/>
|
||||
</module>
|
||||
<module name="RightCurly"/>
|
||||
<module name="RightCurly">
|
||||
@ -86,9 +88,6 @@
|
||||
<module name="FallThrough"/>
|
||||
<module name="UpperEll"/>
|
||||
<module name="ModifierOrder"/>
|
||||
<module name="EmptyLineSeparator">
|
||||
<property name="allowNoEmptyLineBetweenFields" value="true"/>
|
||||
</module>
|
||||
<module name="SeparatorWrap">
|
||||
<property name="tokens" value="DOT"/>
|
||||
<property name="option" value="nl"/>
|
||||
@ -97,42 +96,19 @@
|
||||
<property name="tokens" value="COMMA"/>
|
||||
<property name="option" value="EOL"/>
|
||||
</module>
|
||||
<module name="PackageName">
|
||||
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
|
||||
<message key="name.invalidPattern"
|
||||
value="Package name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="TypeName">
|
||||
<message key="name.invalidPattern"
|
||||
value="Type name ''{0}'' must match pattern ''{1}''."/>
|
||||
</module>
|
||||
<module name="MemberName">
|
||||
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
|
||||
<message key="name.invalidPattern"
|
||||
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>
|
||||
|
||||
<!-- Checks for Naming Conventions. -->
|
||||
<!-- See http://checkstyle.sf.net/config_naming.html -->
|
||||
<module name="ConstantName"/>
|
||||
<module name="LocalFinalVariableName"/>
|
||||
<module name="LocalVariableName"/>
|
||||
<module name="MemberName"/>
|
||||
<module name="MethodName"/>
|
||||
<module name="PackageName"/>
|
||||
<module name="ParameterName"/>
|
||||
<module name="StaticVariableName"/>
|
||||
<module name="TypeName"/>
|
||||
|
||||
<module name="NoFinalizer"/>
|
||||
<module name="GenericWhitespace">
|
||||
<message key="ws.followed"
|
||||
@ -157,14 +133,6 @@
|
||||
<property name="allowedAbbreviationLength" value="1"/>
|
||||
</module>
|
||||
<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="OperatorWrap">
|
||||
<property name="option" value="NL"/>
|
||||
@ -180,11 +148,6 @@
|
||||
</module>
|
||||
<module name="NonEmptyAtclauseDescription"/>
|
||||
<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">
|
||||
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
|
||||
<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="allowMissingReturnTag" value="true"/>
|
||||
<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"/>
|
||||
</module>
|
||||
<module name="MethodName">
|
||||
|
@ -30,6 +30,9 @@ public abstract class Target {
|
||||
@Override
|
||||
public abstract String toString();
|
||||
|
||||
/**
|
||||
* Print status
|
||||
*/
|
||||
public void printStatus() {
|
||||
System.out.println(String.format("%s, [size=%s] [visibility=%s]", this, getSize(),
|
||||
getVisibility()));
|
||||
|
@ -15,12 +15,18 @@ public class Wizard {
|
||||
|
||||
public Wizard() {}
|
||||
|
||||
/**
|
||||
* Cast spell
|
||||
*/
|
||||
public void castSpell(Command command, Target target) {
|
||||
System.out.println(this + " casts " + command + " at " + target);
|
||||
command.execute(target);
|
||||
undoStack.offerLast(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undo last spell
|
||||
*/
|
||||
public void undoLastSpell() {
|
||||
if (!undoStack.isEmpty()) {
|
||||
Command previousSpell = undoStack.pollLast();
|
||||
@ -30,6 +36,9 @@ public class Wizard {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redo last spell
|
||||
*/
|
||||
public void redoLastSpell() {
|
||||
if (!redoStack.isEmpty()) {
|
||||
Command previousSpell = redoStack.pollLast();
|
||||
|
@ -24,6 +24,9 @@ public abstract class LetterComposite {
|
||||
|
||||
protected abstract void printThisAfter();
|
||||
|
||||
/**
|
||||
* Print
|
||||
*/
|
||||
public void print() {
|
||||
printThisBefore();
|
||||
for (LetterComposite letter : children) {
|
||||
|
@ -9,6 +9,9 @@ import java.util.List;
|
||||
*/
|
||||
public class Sentence extends LetterComposite {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Sentence(List<Word> words) {
|
||||
for (Word w : words) {
|
||||
this.add(w);
|
||||
|
@ -9,6 +9,9 @@ import java.util.List;
|
||||
*/
|
||||
public class Word extends LetterComposite {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Word(List<Letter> letters) {
|
||||
for (Letter l : letters) {
|
||||
this.add(l);
|
||||
|
@ -21,7 +21,7 @@ import org.apache.log4j.Logger;
|
||||
*/
|
||||
public class App {
|
||||
|
||||
private static Logger LOGGER = Logger.getLogger(App.class);
|
||||
private static Logger log = Logger.getLogger(App.class);
|
||||
|
||||
/**
|
||||
* Program entry point.
|
||||
@ -30,17 +30,17 @@ public class App {
|
||||
*/
|
||||
public static void main(final String[] args) {
|
||||
final CustomerDaoImpl customerDao = new CustomerDaoImpl(generateSampleCustomers());
|
||||
LOGGER.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
|
||||
LOGGER.info("customerDao.getCusterById(2): " + customerDao.getCustomerById(2));
|
||||
log.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
|
||||
log.info("customerDao.getCusterById(2): " + customerDao.getCustomerById(2));
|
||||
final Customer customer = new Customer(4, "Dan", "Danson");
|
||||
customerDao.addCustomer(customer);
|
||||
LOGGER.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
|
||||
log.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
|
||||
customer.setFirstName("Daniel");
|
||||
customer.setLastName("Danielson");
|
||||
customerDao.updateCustomer(customer);
|
||||
LOGGER.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
|
||||
log.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
|
||||
customerDao.deleteCustomer(customer);
|
||||
LOGGER.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
|
||||
log.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -11,6 +11,9 @@ public class Customer {
|
||||
private String firstName;
|
||||
private String lastName;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Customer(final int id, final String firstName, final String lastName) {
|
||||
this.id = id;
|
||||
this.firstName = firstName;
|
||||
@ -54,8 +57,9 @@ public class Customer {
|
||||
isEqual = true;
|
||||
} else if (o != null && (getClass() == o.getClass())) {
|
||||
final Customer customer = (Customer) o;
|
||||
if (getId() == customer.getId())
|
||||
if (getId() == customer.getId()) {
|
||||
isEqual = true;
|
||||
}
|
||||
}
|
||||
return isEqual;
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
|
||||
<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">
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
|
||||
</layout>
|
||||
</appender>
|
||||
<appender name="console" class="org.apache.log4j.ConsoleAppender">
|
||||
<layout class="org.apache.log4j.PatternLayout">
|
||||
<param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<root>
|
||||
<level value="INFO" />
|
||||
<appender-ref ref="console" />
|
||||
</root>
|
||||
<root>
|
||||
<level value="INFO" />
|
||||
<appender-ref ref="console" />
|
||||
</root>
|
||||
|
||||
</log4j:configuration>
|
@ -28,7 +28,7 @@ public class App {
|
||||
ExecutorService executorService = Executors.newFixedThreadPool(3);
|
||||
for (int i = 0; i < 3; i++) {
|
||||
executorService.execute(() -> {
|
||||
while (inventory.addItem(new Item()));
|
||||
while (inventory.addItem(new Item())) {};
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -17,12 +17,18 @@ public class Inventory {
|
||||
private final List<Item> items;
|
||||
private final Lock lock;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Inventory(int inventorySize) {
|
||||
this.inventorySize = inventorySize;
|
||||
this.items = new ArrayList<>(inventorySize);
|
||||
this.lock = new ReentrantLock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add item
|
||||
*/
|
||||
public boolean addItem(Item item) {
|
||||
if (items.size() < inventorySize) {
|
||||
lock.lock();
|
||||
|
@ -77,8 +77,8 @@ public class InventoryTest {
|
||||
final ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);
|
||||
for (int i = 0; i < THREAD_COUNT; i++) {
|
||||
executorService.execute(() -> {
|
||||
while (inventory.addItem(new Item())) ;
|
||||
});
|
||||
while (inventory.addItem(new Item())) {};
|
||||
});
|
||||
}
|
||||
|
||||
// Wait until all threads have finished
|
||||
|
@ -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
|
||||
* implementation of that method in the receiver. Sometimes the behaviour must also be determined by
|
||||
* the type of the parameter.
|
||||
* When a message with a parameter is sent to an object, the resultant behaviour is defined by the implementation of
|
||||
* that method in the receiver. Sometimes the behaviour must also be determined by the type of the parameter.
|
||||
* <p>
|
||||
* One way to implement this would be to create multiple instanceof-checks for the methods
|
||||
* parameter. However, this creates a maintenance issue. When new types are added we would also need
|
||||
* to change the method's implementation and add a new instanceof-check. This violates the single
|
||||
* responsibility principle - a class should have only one reason to change.
|
||||
* One way to implement this would be to create multiple instanceof-checks for the methods parameter. However, this
|
||||
* creates a maintenance issue. When new types are added we would also need to change the method's implementation and
|
||||
* add a new instanceof-check. This violates the single responsibility principle - a class should have only one reason
|
||||
* to change.
|
||||
* <p>
|
||||
* Instead of the instanceof-checks a better way is to make another virtual call on the parameter
|
||||
* object. This way new functionality can be easily added without the need to modify existing
|
||||
* implementation (open-closed principle).
|
||||
* Instead of the instanceof-checks a better way is to make another virtual call on the parameter object. This way new
|
||||
* functionality can be easily added without the need to modify existing implementation (open-closed principle).
|
||||
* <p>
|
||||
* In this example we have hierarchy of objects ({@link GameObject}) that can collide to each other.
|
||||
* Each object has its own coordinates which are checked against the other objects' coordinates. If
|
||||
* there is an overlap, then the objects collide utilizing the Double Dispatch pattern.
|
||||
* In this example we have hierarchy of objects ({@link GameObject}) that can collide to each other. Each object has its
|
||||
* own coordinates which are checked against the other objects' coordinates. If there is an overlap, then the objects
|
||||
* collide utilizing the Double Dispatch pattern.
|
||||
*
|
||||
*/
|
||||
public class App {
|
||||
@ -28,7 +26,8 @@ public class App {
|
||||
/**
|
||||
* Program entry point
|
||||
*
|
||||
* @param args command line args
|
||||
* @param args
|
||||
* command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// initialize game objects and print their status
|
||||
@ -42,8 +41,9 @@ public class App {
|
||||
|
||||
// collision check
|
||||
objects.stream().forEach(o1 -> objects.stream().forEach(o2 -> {
|
||||
if (o1 != o2 && o1.intersectsWith(o2))
|
||||
if (o1 != o2 && o1.intersectsWith(o2)) {
|
||||
o1.collision(o2);
|
||||
}
|
||||
}));
|
||||
System.out.println("");
|
||||
|
||||
|
@ -12,6 +12,9 @@ public class Rectangle {
|
||||
private int right;
|
||||
private int bottom;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Rectangle(int left, int top, int right, int bottom) {
|
||||
this.left = left;
|
||||
this.top = top;
|
||||
|
@ -107,9 +107,9 @@ public abstract class CollisionTest<O extends GameObject> {
|
||||
final String targetName = target.getClass().getSimpleName();
|
||||
final String otherName = other.getClass().getSimpleName();
|
||||
|
||||
final String errorMessage = expectTargetOnFire ?
|
||||
"Expected [" + targetName + "] to be on fire after colliding with [" + otherName + "] but it was not!" :
|
||||
"Expected [" + targetName + "] not to be on fire after colliding with [" + otherName + "] but it was!";
|
||||
final String errorMessage = expectTargetOnFire
|
||||
? "Expected [" + targetName + "] to be on fire after colliding with [" + otherName + "] but it was not!"
|
||||
: "Expected [" + targetName + "] not to be on fire after colliding with [" + otherName + "] but it was!";
|
||||
|
||||
assertEquals(errorMessage, expectTargetOnFire, target.isOnFire());
|
||||
}
|
||||
@ -126,9 +126,9 @@ public abstract class CollisionTest<O extends GameObject> {
|
||||
final String targetName = target.getClass().getSimpleName();
|
||||
final String otherName = other.getClass().getSimpleName();
|
||||
|
||||
final String errorMessage = expectedDamage ?
|
||||
"Expected [" + targetName + "] to be damaged after colliding with [" + otherName + "] but it was not!" :
|
||||
"Expected [" + targetName + "] not to be damaged after colliding with [" + otherName + "] but it was!";
|
||||
final String errorMessage = expectedDamage
|
||||
? "Expected [" + targetName + "] to be damaged after colliding with [" + otherName + "] but it was not!"
|
||||
: "Expected [" + targetName + "] not to be damaged after colliding with [" + otherName + "] but it was!";
|
||||
|
||||
assertEquals(errorMessage, expectedDamage, target.isDamaged());
|
||||
}
|
||||
|
@ -63,6 +63,37 @@ public abstract class EventEmitterTest<E extends EventEmitter> {
|
||||
testAllDaysWithDefaultObserver(specialDay, event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass each week of the day, day by day to the event emitter and verify of the given observers
|
||||
* received the correct event on the special day.
|
||||
*
|
||||
* @param specialDay The special day on which an event is emitted
|
||||
* @param event The expected event emitted by the test object
|
||||
* @param emitter The event emitter
|
||||
* @param observers The registered observer mocks
|
||||
*/
|
||||
private void testAllDays(final Weekday specialDay, final Event event, final E emitter,
|
||||
final EventObserver... observers) {
|
||||
|
||||
for (final Weekday weekday : Weekday.values()) {
|
||||
// Pass each week of the day, day by day to the event emitter
|
||||
emitter.timePasses(weekday);
|
||||
|
||||
if (weekday == specialDay) {
|
||||
// On a special day, every observer should have received the event
|
||||
for (final EventObserver observer : observers) {
|
||||
verify(observer, times(1)).onEvent(eq(event));
|
||||
}
|
||||
} else {
|
||||
// On any other normal day, the observers should have received nothing at all
|
||||
verifyZeroInteractions(observers);
|
||||
}
|
||||
}
|
||||
|
||||
// The observers should not have received any additional events after the week
|
||||
verifyNoMoreInteractions(observers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Go over every day of the month, and check if the event is emitted on the given day. Use an
|
||||
* event emitter without a default observer
|
||||
@ -99,35 +130,4 @@ public abstract class EventEmitterTest<E extends EventEmitter> {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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
|
||||
* mocked observer.
|
||||
*/
|
||||
|
@ -17,9 +17,6 @@ public class App {
|
||||
|
||||
/**
|
||||
* Program entry point
|
||||
*
|
||||
* @param args command line args
|
||||
* @throws IOException
|
||||
*/
|
||||
public static void main(String[] args) throws IOException {
|
||||
|
||||
|
@ -11,6 +11,9 @@ import java.io.IOException;
|
||||
*/
|
||||
public class SimpleFileWriter {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public SimpleFileWriter(String filename, FileWriterAction action) throws IOException {
|
||||
FileWriter writer = new FileWriter(filename);
|
||||
try {
|
||||
|
@ -65,11 +65,11 @@ public class SimpleFileWriterTest {
|
||||
* Verify if an {@link IOException} during the write ripples through
|
||||
*/
|
||||
@Test(expected = IOException.class)
|
||||
public void testIOException() throws Exception {
|
||||
public void testIoException() throws Exception {
|
||||
final File temporaryFile = this.testFolder.newFile();
|
||||
new SimpleFileWriter(temporaryFile.getPath(), writer -> {
|
||||
throw new IOException("");
|
||||
});
|
||||
throw new IOException("");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,9 @@ public class DwarvenGoldmineFacade {
|
||||
|
||||
private final List<DwarvenMineWorker> workers;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public DwarvenGoldmineFacade() {
|
||||
workers = new ArrayList<>();
|
||||
workers.add(new DwarvenGoldDigger());
|
||||
|
@ -46,6 +46,9 @@ public abstract class DwarvenMineWorker {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform actions
|
||||
*/
|
||||
public void action(Action... actions) {
|
||||
for (Action action : actions) {
|
||||
action(action);
|
||||
|
@ -1,15 +1,19 @@
|
||||
package com.iluwatar.fluentinterface.app;
|
||||
|
||||
import static java.lang.String.valueOf;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.iluwatar.fluentinterface.fluentiterable.FluentIterable;
|
||||
import com.iluwatar.fluentinterface.fluentiterable.lazy.LazyFluentIterable;
|
||||
import com.iluwatar.fluentinterface.fluentiterable.simple.SimpleFluentIterable;
|
||||
|
||||
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.
|
||||
* 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 {
|
||||
|
||||
/**
|
||||
* Program entry point
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
List<Integer> integerList = new ArrayList<>();
|
||||
|
@ -5,8 +5,6 @@ import java.util.Iterator;
|
||||
/**
|
||||
* This class is used to realize LazyFluentIterables. It decorates a given iterator. Does not
|
||||
* support consecutive hasNext() calls.
|
||||
*
|
||||
* @param <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.
|
||||
*
|
||||
* @param fromIterator
|
||||
*/
|
||||
public DecoratingIterator(Iterator<TYPE> fromIterator) {
|
||||
this.fromIterator = fromIterator;
|
||||
|
@ -1,12 +1,16 @@
|
||||
package com.iluwatar.fluentinterface.fluentiterable.simple;
|
||||
|
||||
import com.iluwatar.fluentinterface.fluentiterable.FluentIterable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Spliterator;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.iluwatar.fluentinterface.fluentiterable.FluentIterable;
|
||||
|
||||
/**
|
||||
* This is a simple implementation of the FluentIterable interface. It evaluates all chained
|
||||
* operations eagerly. This implementation would be costly to be utilized in real applications.
|
||||
|
@ -26,7 +26,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
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
|
||||
* @return The new iterable, use for testing
|
||||
|
@ -31,6 +31,9 @@ public class Dispatcher {
|
||||
stores.add(store);
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu item selected handler
|
||||
*/
|
||||
public void menuItemSelected(MenuItem menuItem) {
|
||||
dispatchAction(new MenuAction(menuItem));
|
||||
switch (menuItem) {
|
||||
|
@ -14,6 +14,9 @@ public class AlchemistShop {
|
||||
private List<Potion> topShelf;
|
||||
private List<Potion> bottomShelf;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public AlchemistShop() {
|
||||
topShelf = new ArrayList<>();
|
||||
bottomShelf = new ArrayList<>();
|
||||
@ -58,6 +61,9 @@ public class AlchemistShop {
|
||||
return Collections.unmodifiableList(this.bottomShelf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerate potions
|
||||
*/
|
||||
public void enumerate() {
|
||||
|
||||
System.out.println("Enumerating top shelf potions\n");
|
||||
|
@ -2,32 +2,34 @@ package com.iluwatar.front.controller;
|
||||
|
||||
/**
|
||||
*
|
||||
* The Front Controller is a presentation tier pattern. Essentially it defines a
|
||||
* controller that handles all requests for a web site.
|
||||
* The Front Controller is a presentation tier pattern. Essentially it defines a controller that
|
||||
* handles all requests for a web site.
|
||||
* <p>
|
||||
* The Front Controller pattern consolidates request handling through a single handler
|
||||
* object ({@link FrontController}). This object can carry out the common the behavior such as
|
||||
* The Front Controller pattern consolidates request handling through a single handler object (
|
||||
* {@link FrontController}). This object can carry out the common the behavior such as
|
||||
* authorization, request logging and routing requests to corresponding views.
|
||||
* <p>
|
||||
* Typically the requests are mapped to command objects ({@link Command}) which then display
|
||||
* the correct view ({@link View}).
|
||||
* Typically the requests are mapped to command objects ({@link Command}) which then display the
|
||||
* correct view ({@link View}).
|
||||
* <p>
|
||||
* 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,
|
||||
* the {@link ArcherView} gets displayed when {@link FrontController} receives request "Archer". When
|
||||
* are displayed by sending correct request to the {@link FrontController} object. For example, the
|
||||
* {@link ArcherView} gets displayed when {@link FrontController} receives request "Archer". When
|
||||
* the request is unknown, we display the error view ({@link ErrorView}).
|
||||
*
|
||||
*/
|
||||
public class App {
|
||||
|
||||
/**
|
||||
* Program entry point
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
FrontController controller = new FrontController();
|
||||
controller.handleRequest("Archer");
|
||||
controller.handleRequest("Catapult");
|
||||
controller.handleRequest("foobar");
|
||||
}
|
||||
|
||||
/**
|
||||
* Program entry point
|
||||
*
|
||||
* @param args
|
||||
* command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
FrontController controller = new FrontController();
|
||||
controller.handleRequest("Archer");
|
||||
controller.handleRequest("Catapult");
|
||||
controller.handleRequest("foobar");
|
||||
}
|
||||
}
|
||||
|
@ -7,9 +7,9 @@ package com.iluwatar.front.controller;
|
||||
*/
|
||||
public class ApplicationException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ApplicationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
public ApplicationException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
|
||||
*/
|
||||
public class ArcherCommand implements Command {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
new ArcherView().display();
|
||||
}
|
||||
@Override
|
||||
public void process() {
|
||||
new ArcherView().display();
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
|
||||
*/
|
||||
public class ArcherView implements View {
|
||||
|
||||
@Override
|
||||
public void display() {
|
||||
System.out.println("Displaying archers");
|
||||
}
|
||||
@Override
|
||||
public void display() {
|
||||
System.out.println("Displaying archers");
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
|
||||
*/
|
||||
public class CatapultCommand implements Command {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
new CatapultView().display();
|
||||
}
|
||||
@Override
|
||||
public void process() {
|
||||
new CatapultView().display();
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
|
||||
*/
|
||||
public class CatapultView implements View {
|
||||
|
||||
@Override
|
||||
public void display() {
|
||||
System.out.println("Displaying catapults");
|
||||
}
|
||||
@Override
|
||||
public void display() {
|
||||
System.out.println("Displaying catapults");
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,6 @@ package com.iluwatar.front.controller;
|
||||
*
|
||||
*/
|
||||
public interface Command {
|
||||
|
||||
void process();
|
||||
|
||||
void process();
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
|
||||
*/
|
||||
public class ErrorView implements View {
|
||||
|
||||
@Override
|
||||
public void display() {
|
||||
System.out.println("Error 500");
|
||||
}
|
||||
@Override
|
||||
public void display() {
|
||||
System.out.println("Error 500");
|
||||
}
|
||||
}
|
||||
|
@ -2,33 +2,33 @@ package com.iluwatar.front.controller;
|
||||
|
||||
/**
|
||||
*
|
||||
* FrontController is the handler class that takes in all the requests and
|
||||
* renders the correct response.
|
||||
* FrontController is the handler class that takes in all the requests and renders the correct
|
||||
* response.
|
||||
*
|
||||
*/
|
||||
public class FrontController {
|
||||
|
||||
public void handleRequest(String request) {
|
||||
Command command = getCommand(request);
|
||||
command.process();
|
||||
}
|
||||
|
||||
private Command getCommand(String request) {
|
||||
Class commandClass = getCommandClass(request);
|
||||
try {
|
||||
return (Command) commandClass.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new ApplicationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Class getCommandClass(String request) {
|
||||
Class result;
|
||||
try {
|
||||
result = Class.forName("com.iluwatar.front.controller." + request + "Command");
|
||||
} catch (ClassNotFoundException e) {
|
||||
result = UnknownCommand.class;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void handleRequest(String request) {
|
||||
Command command = getCommand(request);
|
||||
command.process();
|
||||
}
|
||||
|
||||
private Command getCommand(String request) {
|
||||
Class commandClass = getCommandClass(request);
|
||||
try {
|
||||
return (Command) commandClass.newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new ApplicationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Class getCommandClass(String request) {
|
||||
Class result;
|
||||
try {
|
||||
result = Class.forName("com.iluwatar.front.controller." + request + "Command");
|
||||
} catch (ClassNotFoundException e) {
|
||||
result = UnknownCommand.class;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
|
||||
*/
|
||||
public class UnknownCommand implements Command {
|
||||
|
||||
@Override
|
||||
public void process() {
|
||||
new ErrorView().display();
|
||||
}
|
||||
@Override
|
||||
public void process() {
|
||||
new ErrorView().display();
|
||||
}
|
||||
}
|
||||
|
@ -7,5 +7,5 @@ package com.iluwatar.front.controller;
|
||||
*/
|
||||
public interface View {
|
||||
|
||||
void display();
|
||||
void display();
|
||||
}
|
||||
|
@ -10,10 +10,10 @@ import com.iluwatar.front.controller.App;
|
||||
*
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
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
|
||||
|
@ -21,17 +21,15 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||
*
|
||||
* <p>
|
||||
* <i>APPLICABILITY</i> <br/>
|
||||
* <ul>
|
||||
* <li>UNIX network subsystems - In operating systems network operations are carried out
|
||||
* asynchronously with help of hardware level interrupts.</li>
|
||||
* <li>CORBA - At the asynchronous layer one thread is associated with each socket that is connected
|
||||
* UNIX network subsystems - In operating systems network operations are carried out
|
||||
* asynchronously with help of hardware level interrupts.<br/>
|
||||
* 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
|
||||
* 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>
|
||||
* <li>Android AsyncTask framework - Framework provides a way to execute long running blocking
|
||||
* request and sends response back to the client.<br/>
|
||||
* 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
|
||||
* respond to user inputs.</i>
|
||||
* </ul>
|
||||
* respond to user inputs.<br/>
|
||||
*
|
||||
* <p>
|
||||
* <i>IMPLEMENTATION</i> <br/>
|
||||
@ -121,6 +119,7 @@ public class App {
|
||||
try {
|
||||
Thread.sleep(i);
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
return (i) * (i + 1) / 2;
|
||||
}
|
||||
|
@ -14,7 +14,8 @@ public class AddressFilter extends AbstractFilter {
|
||||
String result = super.execute(order);
|
||||
if (order.getAddress() == null || order.getAddress().isEmpty()) {
|
||||
return result + "Invalid address! ";
|
||||
} else
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,12 @@ public class Client extends JFrame {
|
||||
private JLabel jl;
|
||||
private JTextField[] jtFields;
|
||||
private JTextArea[] jtAreas;
|
||||
private JButton clearButton, processButton;
|
||||
private JButton clearButton;
|
||||
private JButton processButton;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Client() {
|
||||
super("Client System");
|
||||
setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
|
@ -11,30 +11,21 @@ public interface Filter {
|
||||
|
||||
/**
|
||||
* Execute order processing filter.
|
||||
*
|
||||
* @param order
|
||||
* @return empty string on success, otherwise error message.
|
||||
*/
|
||||
String execute(Order order);
|
||||
|
||||
/**
|
||||
* Set next filter in chain after this.
|
||||
*
|
||||
* @param filter
|
||||
*/
|
||||
void setNext(Filter filter);
|
||||
|
||||
/**
|
||||
* Get next filter in chain after this.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Filter getNext();
|
||||
|
||||
/**
|
||||
* Get last filter in the chain.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Filter getLast();
|
||||
}
|
||||
|
@ -12,10 +12,16 @@ public class FilterChain {
|
||||
|
||||
private final Target target;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public FilterChain(Target target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds filter
|
||||
*/
|
||||
public void addFilter(Filter filter) {
|
||||
if (chain == null) {
|
||||
chain = filter;
|
||||
@ -24,6 +30,9 @@ public class FilterChain {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute filter chain
|
||||
*/
|
||||
public String execute(Order order) {
|
||||
if (chain != null) {
|
||||
return chain.execute(order);
|
||||
|
@ -14,6 +14,9 @@ public class Order {
|
||||
|
||||
public Order() {}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Order(String name, String contactNumber, String address, String depositNumber, String order) {
|
||||
this.name = name;
|
||||
this.contactNumber = contactNumber;
|
||||
|
@ -29,6 +29,9 @@ public class Target extends JFrame {
|
||||
private DefaultTableModel dtm;
|
||||
private JButton del;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Target() {
|
||||
super("Order System");
|
||||
setDefaultCloseOperation(EXIT_ON_CLOSE);
|
||||
@ -67,8 +70,9 @@ public class Target extends JFrame {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int temp = jt.getSelectedRow();
|
||||
if (temp == -1)
|
||||
if (temp == -1) {
|
||||
return;
|
||||
}
|
||||
int temp2 = jt.getSelectedRowCount();
|
||||
for (int i = 0; i < temp2; i++) {
|
||||
dtm.removeRow(temp);
|
||||
|
@ -73,6 +73,9 @@ public class FilterTest {
|
||||
private final Order order;
|
||||
private final String result;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public FilterTest(Filter filter, Order order, String result) {
|
||||
this.filter = filter;
|
||||
this.order = order;
|
||||
|
@ -55,6 +55,9 @@ public class App {
|
||||
return s.equals("+") || s.equals("-") || s.equals("*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get expression for string
|
||||
*/
|
||||
public static Expression getOperatorInstance(String s, Expression left, Expression right) {
|
||||
switch (s) {
|
||||
case "+":
|
||||
@ -63,7 +66,8 @@ public class App {
|
||||
return new MinusExpression(left, right);
|
||||
case "*":
|
||||
return new MultiplyExpression(left, right);
|
||||
default:
|
||||
return new MultiplyExpression(left, right);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -27,9 +27,9 @@ public abstract class ExpressionTest<E extends Expression> {
|
||||
for (int i = -10; i < 10; i++) {
|
||||
for (int j = -10; j < 10; j++) {
|
||||
testData.add(new Object[]{
|
||||
new NumberExpression(i),
|
||||
new NumberExpression(j),
|
||||
resultCalc.apply(i, j)
|
||||
new NumberExpression(i),
|
||||
new NumberExpression(j),
|
||||
resultCalc.apply(i, j)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -20,28 +20,28 @@ public class App {
|
||||
public static void main(String[] args) {
|
||||
TreasureChest chest = new TreasureChest();
|
||||
|
||||
ItemIterator ringIterator = chest.Iterator(ItemType.RING);
|
||||
ItemIterator ringIterator = chest.iterator(ItemType.RING);
|
||||
while (ringIterator.hasNext()) {
|
||||
System.out.println(ringIterator.next());
|
||||
}
|
||||
|
||||
System.out.println("----------");
|
||||
|
||||
ItemIterator potionIterator = chest.Iterator(ItemType.POTION);
|
||||
ItemIterator potionIterator = chest.iterator(ItemType.POTION);
|
||||
while (potionIterator.hasNext()) {
|
||||
System.out.println(potionIterator.next());
|
||||
}
|
||||
|
||||
System.out.println("----------");
|
||||
|
||||
ItemIterator weaponIterator = chest.Iterator(ItemType.WEAPON);
|
||||
ItemIterator weaponIterator = chest.iterator(ItemType.WEAPON);
|
||||
while (weaponIterator.hasNext()) {
|
||||
System.out.println(weaponIterator.next());
|
||||
}
|
||||
|
||||
System.out.println("----------");
|
||||
|
||||
ItemIterator it = chest.Iterator(ItemType.ANY);
|
||||
ItemIterator it = chest.iterator(ItemType.ANY);
|
||||
while (it.hasNext()) {
|
||||
System.out.println(it.next());
|
||||
}
|
||||
|
@ -12,6 +12,9 @@ public class TreasureChest {
|
||||
|
||||
private List<Item> items;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public TreasureChest() {
|
||||
items = new ArrayList<>();
|
||||
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"));
|
||||
}
|
||||
|
||||
ItemIterator Iterator(ItemType type) {
|
||||
return new TreasureChestItemIterator(this, type);
|
||||
ItemIterator iterator(ItemType itemType) {
|
||||
return new TreasureChestItemIterator(this, itemType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all items
|
||||
*/
|
||||
public List<Item> getItems() {
|
||||
ArrayList<Item> list = new ArrayList<>();
|
||||
list.addAll(items);
|
||||
|
@ -13,6 +13,9 @@ public class TreasureChestItemIterator implements ItemIterator {
|
||||
private int idx;
|
||||
private ItemType type;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public TreasureChestItemIterator(TreasureChest chest, ItemType type) {
|
||||
this.chest = chest;
|
||||
this.type = type;
|
||||
|
@ -60,7 +60,7 @@ public class TreasureChestTest {
|
||||
@Test
|
||||
public void testIterator() {
|
||||
final TreasureChest chest = new TreasureChest();
|
||||
final ItemIterator iterator = chest.Iterator(expectedItem.getType());
|
||||
final ItemIterator iterator = chest.iterator(expectedItem.getType());
|
||||
assertNotNull(iterator);
|
||||
|
||||
while (iterator.hasNext()) {
|
||||
|
@ -4,31 +4,31 @@ import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*
|
||||
* Layers is an architectural style where software responsibilities are divided among the different
|
||||
* layers of the application.
|
||||
* Layers is an architectural style where software responsibilities are divided among the different layers of the
|
||||
* application.
|
||||
* <p>
|
||||
* This example demonstrates a traditional 3-layer architecture consisting of data access layer,
|
||||
* business layer and presentation layer.
|
||||
* This example demonstrates a traditional 3-layer architecture consisting of data access layer, business layer and
|
||||
* presentation layer.
|
||||
* <p>
|
||||
* The data access layer is formed of Spring Data repositories <code>CakeDao</code>,
|
||||
* <code>CakeToppingDao</code> and <code>CakeLayerDao</code>. The repositories can be used for CRUD
|
||||
* operations on cakes, cake toppings and cake layers respectively.
|
||||
* The data access layer is formed of Spring Data repositories <code>CakeDao</code>, <code>CakeToppingDao</code> and
|
||||
* <code>CakeLayerDao</code>. The repositories can be used for CRUD operations on cakes, cake toppings and cake layers
|
||||
* respectively.
|
||||
* <p>
|
||||
* The business layer is built on top of the data access layer. <code>CakeBakingService</code>
|
||||
* offers methods to retrieve available cake toppings and cake layers and baked cakes. Also the
|
||||
* service is used to create new cakes out of cake toppings and cake layers.
|
||||
* The business layer is built on top of the data access layer. <code>CakeBakingService</code> offers methods to
|
||||
* retrieve available cake toppings and cake layers and baked cakes. Also the service is used to create new cakes out of
|
||||
* cake toppings and cake layers.
|
||||
* <p>
|
||||
* The presentation layer is built on the business layer and in this example it simply lists the
|
||||
* cakes that have been baked.
|
||||
* The presentation layer is built on the business layer and in this example it simply lists the cakes that have been
|
||||
* baked.
|
||||
* <p>
|
||||
* We have applied so called strict layering which means that the layers can only access the classes
|
||||
* directly beneath them. This leads the solution to create an additional set of DTOs (
|
||||
* <code>CakeInfo</code>, <code>CakeToppingInfo</code>, <code>CakeLayerInfo</code>) to translate
|
||||
* data between layers. In other words, <code>CakeBakingService</code> cannot return entities (
|
||||
* <code>Cake</code>, <code>CakeTopping</code>, <code>CakeLayer</code>) directly since these reside
|
||||
* 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
|
||||
* the presentation layer does not have any knowledge of other layers than the business layer and
|
||||
* thus is not affected by changes to them.
|
||||
* We have applied so called strict layering which means that the layers can only access the classes directly beneath
|
||||
* them. This leads the solution to create an additional set of DTOs ( <code>CakeInfo</code>,
|
||||
* <code>CakeToppingInfo</code>, <code>CakeLayerInfo</code>) to translate data between layers. In other words,
|
||||
* <code>CakeBakingService</code> cannot return entities ( <code>Cake</code>, <code>CakeTopping</code>,
|
||||
* <code>CakeLayer</code>) directly since these reside 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 the presentation layer does not have any knowledge of other layers than the business layer and thus
|
||||
* is not affected by changes to them.
|
||||
*
|
||||
* @see Cake
|
||||
* @see CakeTopping
|
||||
@ -63,8 +63,6 @@ public class App {
|
||||
|
||||
/**
|
||||
* Initializes the example data
|
||||
*
|
||||
* @param cakeBakingService
|
||||
*/
|
||||
private static void initializeData(CakeBakingService cakeBakingService) {
|
||||
cakeBakingService.saveNewLayer(new CakeLayerInfo("chocolate", 1200));
|
||||
|
@ -11,44 +11,31 @@ public interface CakeBakingService {
|
||||
|
||||
/**
|
||||
* Bakes new cake according to parameters
|
||||
*
|
||||
* @param cakeInfo
|
||||
* @throws CakeBakingException
|
||||
*/
|
||||
void bakeNewCake(CakeInfo cakeInfo) throws CakeBakingException;
|
||||
|
||||
/**
|
||||
* Get all cakes
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<CakeInfo> getAllCakes();
|
||||
|
||||
/**
|
||||
* Store new cake topping
|
||||
*
|
||||
* @param toppingInfo
|
||||
*/
|
||||
void saveNewTopping(CakeToppingInfo toppingInfo);
|
||||
|
||||
/**
|
||||
* Get available cake toppings
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<CakeToppingInfo> getAvailableToppings();
|
||||
|
||||
/**
|
||||
* Add new cake layer
|
||||
*
|
||||
* @param layerInfo
|
||||
*/
|
||||
void saveNewLayer(CakeLayerInfo layerInfo);
|
||||
|
||||
/**
|
||||
* Get available cake layers
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<CakeLayerInfo> getAvailableLayers();
|
||||
}
|
||||
|
@ -14,18 +14,27 @@ public class CakeInfo {
|
||||
public final CakeToppingInfo cakeToppingInfo;
|
||||
public final List<CakeLayerInfo> cakeLayerInfos;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public CakeInfo(Long id, CakeToppingInfo cakeToppingInfo, List<CakeLayerInfo> cakeLayerInfos) {
|
||||
this.id = Optional.of(id);
|
||||
this.cakeToppingInfo = cakeToppingInfo;
|
||||
this.cakeLayerInfos = cakeLayerInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public CakeInfo(CakeToppingInfo cakeToppingInfo, List<CakeLayerInfo> cakeLayerInfos) {
|
||||
this.id = Optional.empty();
|
||||
this.cakeToppingInfo = cakeToppingInfo;
|
||||
this.cakeLayerInfos = cakeLayerInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate calories
|
||||
*/
|
||||
public int calculateTotalCalories() {
|
||||
int total = cakeToppingInfo != null ? cakeToppingInfo.calories : 0;
|
||||
total += cakeLayerInfos.stream().mapToInt(c -> c.calories).sum();
|
||||
|
@ -13,12 +13,18 @@ public class CakeLayerInfo {
|
||||
public final String name;
|
||||
public final int calories;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public CakeLayerInfo(Long id, String name, int calories) {
|
||||
this.id = Optional.of(id);
|
||||
this.name = name;
|
||||
this.calories = calories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public CakeLayerInfo(String name, int calories) {
|
||||
this.id = Optional.empty();
|
||||
this.name = name;
|
||||
|
@ -13,12 +13,18 @@ public class CakeToppingInfo {
|
||||
public final String name;
|
||||
public final int calories;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public CakeToppingInfo(Long id, String name, int calories) {
|
||||
this.id = Optional.of(id);
|
||||
this.name = name;
|
||||
this.calories = calories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public CakeToppingInfo(String name, int calories) {
|
||||
this.id = Optional.empty();
|
||||
this.name = name;
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<persistence version="1.0"
|
||||
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">
|
||||
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">
|
||||
|
||||
<persistence-unit name="jpaData" />
|
||||
<persistence-unit name="jpaData" />
|
||||
|
||||
</persistence>
|
@ -1,42 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:security="http://www.springframework.org/schema/security"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
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">
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:security="http://www.springframework.org/schema/security" xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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">
|
||||
|
||||
<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">
|
||||
<property name="entityManagerFactory" ref="entityManagerFactory" />
|
||||
</bean>
|
||||
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
|
||||
<property name="entityManagerFactory" ref="entityManagerFactory" />
|
||||
</bean>
|
||||
|
||||
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
|
||||
destroy-method="close">
|
||||
<property name="driverClassName" value="org.h2.Driver" />
|
||||
<property name="url" value="jdbc:h2:~/databases/cake" />
|
||||
<property name="username" value="sa" />
|
||||
<property name="password" value="sa" />
|
||||
</bean>
|
||||
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
|
||||
destroy-method="close">
|
||||
<property name="driverClassName" value="org.h2.Driver" />
|
||||
<property name="url" value="jdbc:h2:~/databases/cake" />
|
||||
<property name="username" value="sa" />
|
||||
<property name="password" value="sa" />
|
||||
</bean>
|
||||
|
||||
<bean id="entityManagerFactory"
|
||||
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
|
||||
<property name="dataSource" ref="dataSource" />
|
||||
<property name="packagesToScan" value="com.iluwatar" />
|
||||
<property name="persistenceProvider">
|
||||
<bean class="org.hibernate.ejb.HibernatePersistence" />
|
||||
</property>
|
||||
<property name="jpaProperties">
|
||||
<map>
|
||||
<entry key="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
|
||||
<entry key="hibernate.hbm2ddl.auto" value="create-drop" />
|
||||
<entry key="hibernate.show_sql" value="false" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
<bean id="entityManagerFactory"
|
||||
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
|
||||
<property name="dataSource" ref="dataSource" />
|
||||
<property name="packagesToScan" value="com.iluwatar" />
|
||||
<property name="persistenceProvider">
|
||||
<bean class="org.hibernate.ejb.HibernatePersistence" />
|
||||
</property>
|
||||
<property name="jpaProperties">
|
||||
<map>
|
||||
<entry key="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
|
||||
<entry key="hibernate.hbm2ddl.auto" value="create-drop" />
|
||||
<entry key="hibernate.show_sql" value="false" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
</beans>
|
||||
|
@ -7,6 +7,9 @@ package com.iluwatar.lazy.loading;
|
||||
*/
|
||||
public class Heavy {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Heavy() {
|
||||
System.out.println("Creating Heavy ...");
|
||||
try {
|
||||
|
@ -9,10 +9,16 @@ public class HolderNaive {
|
||||
|
||||
private Heavy heavy;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public HolderNaive() {
|
||||
System.out.println("HolderNaive created");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get heavy object
|
||||
*/
|
||||
public Heavy getHeavy() {
|
||||
if (heavy == null) {
|
||||
heavy = new Heavy();
|
||||
|
@ -10,10 +10,16 @@ public class HolderThreadSafe {
|
||||
|
||||
private Heavy heavy;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public HolderThreadSafe() {
|
||||
System.out.println("HolderThreadSafe created");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get heavy object
|
||||
*/
|
||||
public synchronized Heavy getHeavy() {
|
||||
if (heavy == null) {
|
||||
heavy = new Heavy();
|
||||
|
@ -5,7 +5,7 @@ import java.util.function.Supplier;
|
||||
/**
|
||||
*
|
||||
* 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 {
|
||||
|
@ -23,6 +23,9 @@ import java.util.Stack;
|
||||
*/
|
||||
public class App {
|
||||
|
||||
/**
|
||||
* Program entry point
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
Stack<StarMemento> states = new Stack<>();
|
||||
|
||||
|
@ -11,12 +11,18 @@ public class Star {
|
||||
private int ageYears;
|
||||
private int massTons;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Star(StarType startType, int startAge, int startMass) {
|
||||
this.type = startType;
|
||||
this.ageYears = startAge;
|
||||
this.massTons = startMass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes time pass for the star
|
||||
*/
|
||||
public void timePasses() {
|
||||
ageYears *= 2;
|
||||
massTons *= 8;
|
||||
|
@ -30,9 +30,6 @@ public class App {
|
||||
|
||||
/**
|
||||
* Program entry point
|
||||
*
|
||||
* @param args command line args
|
||||
* @throws Exception
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
CamelContext context = new DefaultCamelContext();
|
||||
|
@ -39,9 +39,7 @@ public class FileLoader {
|
||||
br.close();
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
|
||||
/**
|
||||
* The "OK" button for loading the file.
|
||||
*/
|
||||
private JButton OK;
|
||||
private JButton ok;
|
||||
|
||||
/**
|
||||
* The cancel button.
|
||||
@ -121,10 +121,10 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
|
||||
/*
|
||||
* Add the OK button.
|
||||
*/
|
||||
this.OK = new JButton("OK");
|
||||
this.panel.add(OK);
|
||||
this.OK.setBounds(250, 50, 100, 25);
|
||||
this.OK.addActionListener(this);
|
||||
this.ok = new JButton("OK");
|
||||
this.panel.add(ok);
|
||||
this.ok.setBounds(250, 50, 100, 25);
|
||||
this.ok.addActionListener(this);
|
||||
|
||||
/*
|
||||
* Add the cancel button.
|
||||
@ -140,13 +140,11 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (e.getSource() == this.OK) {
|
||||
if (e.getSource() == this.ok) {
|
||||
this.fileName = this.input.getText();
|
||||
presenter.fileNameChanged();
|
||||
presenter.confirmed();
|
||||
}
|
||||
|
||||
else if (e.getSource() == this.cancel) {
|
||||
} else if (e.getSource() == this.cancel) {
|
||||
presenter.cancelled();
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,9 @@ public class FileSelectorPresenter {
|
||||
loader.setFileName(view.getFileName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Ok button handler
|
||||
*/
|
||||
public void confirmed() {
|
||||
if (loader.getFileName() == null || loader.getFileName().equals("")) {
|
||||
view.showMessage("Please give the name of the file first!");
|
||||
@ -60,9 +63,7 @@ public class FileSelectorPresenter {
|
||||
if (loader.fileExists()) {
|
||||
String data = loader.loadData();
|
||||
view.displayData(data);
|
||||
}
|
||||
|
||||
else {
|
||||
} else {
|
||||
view.showMessage("The file specified does not exist.");
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,13 @@
|
||||
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.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
|
||||
* Model-View-Controller architectural pattern.
|
||||
@ -57,13 +56,13 @@ public class FileSelectorPresenterTest {
|
||||
*/
|
||||
@Test
|
||||
public void updateFileNameToLoader() {
|
||||
String EXPECTED_FILE = "Stamatis";
|
||||
stub.setFileName(EXPECTED_FILE);
|
||||
String expectedFile = "Stamatis";
|
||||
stub.setFileName(expectedFile);
|
||||
|
||||
presenter.start();
|
||||
presenter.fileNameChanged();
|
||||
|
||||
assertEquals(EXPECTED_FILE, loader.getFileName());
|
||||
assertEquals(expectedFile, loader.getFileName());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,6 +24,9 @@ public class LoadBalancer {
|
||||
servers.add(new Server("localhost", 8084, ++id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new server
|
||||
*/
|
||||
public final void addServer(Server server) {
|
||||
synchronized (servers) {
|
||||
servers.add(server);
|
||||
@ -39,6 +42,9 @@ public class LoadBalancer {
|
||||
return lastServedId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle request
|
||||
*/
|
||||
public void serverequest(Request request) {
|
||||
if (lastServedId >= servers.size()) {
|
||||
lastServedId = 0;
|
||||
|
@ -11,6 +11,9 @@ public class Server {
|
||||
public final int port;
|
||||
public final int id;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public Server(String host, int port, int id) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
|
@ -21,9 +21,7 @@ import org.apache.isis.applib.annotation.HomePage;
|
||||
import org.apache.isis.applib.annotation.NatureOfService;
|
||||
import org.apache.isis.applib.annotation.SemanticsOf;
|
||||
|
||||
@DomainService(nature = NatureOfService.VIEW_CONTRIBUTIONS_ONLY // trick to suppress the actions
|
||||
// from the top-level menu
|
||||
)
|
||||
@DomainService(nature = NatureOfService.VIEW_CONTRIBUTIONS_ONLY)
|
||||
public class HomePageService {
|
||||
|
||||
// region > homePage (action)
|
||||
|
@ -69,9 +69,12 @@ public class SimpleObjects {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create simple object
|
||||
*/
|
||||
@Action(domainEvent = CreateDomainEvent.class)
|
||||
@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);
|
||||
obj.setName(name);
|
||||
container.persistIfNotAlready(obj);
|
||||
|
@ -45,8 +45,6 @@ public class SimpleObjectCreate extends FixtureScript {
|
||||
|
||||
/**
|
||||
* The created simple object (output).
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public SimpleObject getSimpleObject() {
|
||||
return simpleObject;
|
||||
|
@ -29,7 +29,7 @@ import domainapp.fixture.modules.simple.SimpleObjectsTearDown;
|
||||
|
||||
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"));
|
||||
|
||||
public RecreateSimpleObjects() {
|
||||
@ -72,9 +72,9 @@ public class RecreateSimpleObjects extends FixtureScript {
|
||||
final int number = defaultParam("number", ec, 3);
|
||||
|
||||
// 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)",
|
||||
NAMES.size()));
|
||||
names.size()));
|
||||
}
|
||||
|
||||
//
|
||||
@ -83,7 +83,7 @@ public class RecreateSimpleObjects extends FixtureScript {
|
||||
ec.executeChild(this, new SimpleObjectsTearDown());
|
||||
|
||||
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);
|
||||
simpleObjects.add(fs.getSimpleObject());
|
||||
}
|
||||
|
@ -21,6 +21,9 @@ import org.apache.isis.objectstore.jdo.datanucleus.IsisConfigurationForJdoIntegT
|
||||
|
||||
public class SimpleAppSystemInitializer {
|
||||
|
||||
/**
|
||||
* Init test system
|
||||
*/
|
||||
public static void initIsft() {
|
||||
IsisSystemForTest isft = IsisSystemForTest.getElseNull();
|
||||
if (isft == null) {
|
||||
|
@ -29,7 +29,7 @@ import static org.junit.Assert.assertThat;
|
||||
public class SimpleObjectGlue extends CukeGlueAbstract {
|
||||
|
||||
@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 {
|
||||
final List<SimpleObject> findAll = service(SimpleObjects.class).listAll();
|
||||
assertThat(findAll.size(), is(n));
|
||||
@ -41,7 +41,7 @@ public class SimpleObjectGlue extends CukeGlueAbstract {
|
||||
}
|
||||
|
||||
@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());
|
||||
}
|
||||
|
||||
|
@ -27,13 +27,13 @@ import domainapp.integtests.bootstrap.SimpleAppSystemInitializer;
|
||||
|
||||
public abstract class SimpleAppIntegTest extends IntegrationTestAbstract {
|
||||
|
||||
@BeforeClass
|
||||
public static void initClass() {
|
||||
org.apache.log4j.PropertyConfigurator.configure("logging.properties");
|
||||
SimpleAppSystemInitializer.initIsft();
|
||||
@BeforeClass
|
||||
public static void initClass() {
|
||||
org.apache.log4j.PropertyConfigurator.configure("logging.properties");
|
||||
SimpleAppSystemInitializer.initIsft();
|
||||
|
||||
// instantiating will install onto ThreadLocal
|
||||
new ScenarioExecutionForIntegration();
|
||||
}
|
||||
// instantiating will install onto ThreadLocal
|
||||
new ScenarioExecutionForIntegration();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -35,87 +35,86 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
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
|
||||
FixtureScripts fixtureScripts;
|
||||
DomainObjectContainer container;
|
||||
|
||||
RecreateSimpleObjects fs;
|
||||
SimpleObject simpleObjectPojo;
|
||||
SimpleObject simpleObjectWrapped;
|
||||
@Test
|
||||
public void interpolatesName() throws Exception {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
// given
|
||||
fs = new RecreateSimpleObjects().setNumber(1);
|
||||
fixtureScripts.runFixtureScript(fs, null);
|
||||
// given
|
||||
final String name = simpleObjectWrapped.getName();
|
||||
|
||||
simpleObjectPojo = fs.getSimpleObjects().get(0);
|
||||
// when
|
||||
final String title = container.titleOf(simpleObjectWrapped);
|
||||
|
||||
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
|
||||
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);
|
||||
}
|
||||
// then
|
||||
assertThat(title).isEqualTo("Object: " + name);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user