Java 11 migrate remaining q-r (#1121)
* Moves queue-load-leveling to Java 11 * Moves reactor to Java 11 * Moves reader-writer-lock to Java 11 * Moves repository to Java 11 * Moves resource-acquisition-is-initialization to Java 11 * Moves retry to Java 11 * Moves role-object to Java 11
This commit is contained in:
parent
cd2a2e7711
commit
20ea465b7f
@ -78,17 +78,17 @@ public class App {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Create a MessageQueue object.
|
// Create a MessageQueue object.
|
||||||
MessageQueue msgQueue = new MessageQueue();
|
var msgQueue = new MessageQueue();
|
||||||
|
|
||||||
LOGGER.info("Submitting TaskGenerators and ServiceExecutor threads.");
|
LOGGER.info("Submitting TaskGenerators and ServiceExecutor threads.");
|
||||||
|
|
||||||
// Create three TaskGenerator threads. Each of them will submit different number of jobs.
|
// Create three TaskGenerator threads. Each of them will submit different number of jobs.
|
||||||
final Runnable taskRunnable1 = new TaskGenerator(msgQueue, 5);
|
final var taskRunnable1 = new TaskGenerator(msgQueue, 5);
|
||||||
final Runnable taskRunnable2 = new TaskGenerator(msgQueue, 1);
|
final var taskRunnable2 = new TaskGenerator(msgQueue, 1);
|
||||||
final Runnable taskRunnable3 = new TaskGenerator(msgQueue, 2);
|
final var taskRunnable3 = new TaskGenerator(msgQueue, 2);
|
||||||
|
|
||||||
// Create e service which should process the submitted jobs.
|
// Create e service which should process the submitted jobs.
|
||||||
final Runnable srvRunnable = new ServiceExecutor(msgQueue);
|
final var srvRunnable = new ServiceExecutor(msgQueue);
|
||||||
|
|
||||||
// Create a ThreadPool of 2 threads and
|
// Create a ThreadPool of 2 threads and
|
||||||
// submit all Runnable task for execution to executor..
|
// submit all Runnable task for execution to executor..
|
||||||
|
@ -40,7 +40,7 @@ public class MessageQueue {
|
|||||||
|
|
||||||
// Default constructor when called creates Blocking Queue object.
|
// Default constructor when called creates Blocking Queue object.
|
||||||
public MessageQueue() {
|
public MessageQueue() {
|
||||||
this.blkQueue = new ArrayBlockingQueue<Message>(1024);
|
this.blkQueue = new ArrayBlockingQueue<>(1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -62,13 +62,11 @@ public class MessageQueue {
|
|||||||
* them. Retrieves and removes the head of this queue, or returns null if this queue is empty.
|
* them. Retrieves and removes the head of this queue, or returns null if this queue is empty.
|
||||||
*/
|
*/
|
||||||
public Message retrieveMsg() {
|
public Message retrieveMsg() {
|
||||||
Message retrievedMsg = null;
|
|
||||||
try {
|
try {
|
||||||
retrievedMsg = blkQueue.poll();
|
return blkQueue.poll();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.error(e.getMessage());
|
LOGGER.error(e.getMessage());
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
return retrievedMsg;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ public class ServiceExecutor implements Runnable {
|
|||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
while (!Thread.currentThread().isInterrupted()) {
|
while (!Thread.currentThread().isInterrupted()) {
|
||||||
Message msg = msgQueue.retrieveMsg();
|
var msg = msgQueue.retrieveMsg();
|
||||||
|
|
||||||
if (null != msg) {
|
if (null != msg) {
|
||||||
LOGGER.info(msg.toString() + " is served.");
|
LOGGER.info(msg.toString() + " is served.");
|
||||||
|
@ -63,12 +63,11 @@ public class TaskGenerator implements Task, Runnable {
|
|||||||
* submission TaskGenerator thread will sleep for 1 second.
|
* submission TaskGenerator thread will sleep for 1 second.
|
||||||
*/
|
*/
|
||||||
public void run() {
|
public void run() {
|
||||||
|
var count = this.msgCount;
|
||||||
int count = this.msgCount;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
while (count > 0) {
|
while (count > 0) {
|
||||||
String statusMsg = "Message-" + count + " submitted by " + Thread.currentThread().getName();
|
var statusMsg = "Message-" + count + " submitted by " + Thread.currentThread().getName();
|
||||||
this.submit(new Message(statusMsg));
|
this.submit(new Message(statusMsg));
|
||||||
|
|
||||||
LOGGER.info(statusMsg);
|
LOGGER.info(statusMsg);
|
||||||
|
@ -25,15 +25,12 @@ package com.iluwatar.queue.load.leveling;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application Test
|
* Application Test
|
||||||
*/
|
*/
|
||||||
public class AppTest {
|
public class AppTest {
|
||||||
@Test
|
@Test
|
||||||
public void test() throws IOException {
|
public void test() {
|
||||||
String[] args = {};
|
App.main(new String[]{});
|
||||||
App.main(args);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -23,25 +23,23 @@
|
|||||||
|
|
||||||
package com.iluwatar.queue.load.leveling;
|
package com.iluwatar.queue.load.leveling;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Test case for submitting and retrieving messages from Blocking Queue.
|
* Test case for submitting and retrieving messages from Blocking Queue.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class MessageQueueTest {
|
public class MessageQueueTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void messageQueueTest() {
|
public void messageQueueTest() {
|
||||||
|
|
||||||
MessageQueue msgQueue = new MessageQueue();
|
var msgQueue = new MessageQueue();
|
||||||
|
|
||||||
// submit message
|
// submit message
|
||||||
msgQueue.submitMsg(new Message("MessageQueue Test"));
|
msgQueue.submitMsg(new Message("MessageQueue Test"));
|
||||||
|
|
||||||
// retrieve message
|
// retrieve message
|
||||||
assertEquals("MessageQueue Test", msgQueue.retrieveMsg().getMsg());
|
assertEquals("MessageQueue Test", msgQueue.retrieveMsg().getMsg());
|
||||||
}
|
}
|
||||||
|
@ -23,23 +23,21 @@
|
|||||||
|
|
||||||
package com.iluwatar.queue.load.leveling;
|
package com.iluwatar.queue.load.leveling;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Test case for creating and checking the Message.
|
* Test case for creating and checking the Message.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class MessageTest {
|
public class MessageTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void messageTest() {
|
public void messageTest() {
|
||||||
|
|
||||||
// Parameterized constructor test.
|
// Parameterized constructor test.
|
||||||
String testMsg = "Message Test";
|
var testMsg = "Message Test";
|
||||||
Message msg = new Message(testMsg);
|
var msg = new Message(testMsg);
|
||||||
assertEquals(testMsg, msg.getMsg());
|
assertEquals(testMsg, msg.getMsg());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,25 +26,23 @@ package com.iluwatar.queue.load.leveling;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Test case for submitting Message to Blocking Queue by TaskGenerator and retrieve the message by
|
||||||
* Test case for submitting Message to Blocking Queue by TaskGenerator
|
* ServiceExecutor.
|
||||||
* and retrieve the message by ServiceExecutor.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class TaskGenSrvExeTest {
|
public class TaskGenSrvExeTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void taskGeneratorTest() {
|
public void taskGeneratorTest() {
|
||||||
MessageQueue msgQueue = new MessageQueue();
|
var msgQueue = new MessageQueue();
|
||||||
|
|
||||||
// Create a task generator thread with 1 job to submit.
|
// Create a task generator thread with 1 job to submit.
|
||||||
Runnable taskRunnable = new TaskGenerator(msgQueue, 1);
|
var taskRunnable = new TaskGenerator(msgQueue, 1);
|
||||||
Thread taskGenThr = new Thread(taskRunnable);
|
var taskGenThr = new Thread(taskRunnable);
|
||||||
taskGenThr.start();
|
taskGenThr.start();
|
||||||
|
|
||||||
// Create a service executor thread.
|
// Create a service executor thread.
|
||||||
Runnable srvRunnable = new ServiceExecutor(msgQueue);
|
var srvRunnable = new ServiceExecutor(msgQueue);
|
||||||
Thread srvExeThr = new Thread(srvRunnable);
|
var srvExeThr = new Thread(srvRunnable);
|
||||||
srvExeThr.start();
|
srvExeThr.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,15 +124,17 @@ public class App {
|
|||||||
* This represents application specific business logic that dispatcher will call on appropriate
|
* This represents application specific business logic that dispatcher will call on appropriate
|
||||||
* events. These events are read events in our example.
|
* events. These events are read events in our example.
|
||||||
*/
|
*/
|
||||||
LoggingHandler loggingHandler = new LoggingHandler();
|
var loggingHandler = new LoggingHandler();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Our application binds to multiple channels and uses same logging handler to handle incoming
|
* Our application binds to multiple channels and uses same logging handler to handle incoming
|
||||||
* log requests.
|
* log requests.
|
||||||
*/
|
*/
|
||||||
reactor.registerChannel(tcpChannel(6666, loggingHandler))
|
reactor
|
||||||
|
.registerChannel(tcpChannel(6666, loggingHandler))
|
||||||
.registerChannel(tcpChannel(6667, loggingHandler))
|
.registerChannel(tcpChannel(6667, loggingHandler))
|
||||||
.registerChannel(udpChannel(6668, loggingHandler)).start();
|
.registerChannel(udpChannel(6668, loggingHandler))
|
||||||
|
.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,20 +146,20 @@ public class App {
|
|||||||
public void stop() throws InterruptedException, IOException {
|
public void stop() throws InterruptedException, IOException {
|
||||||
reactor.stop();
|
reactor.stop();
|
||||||
dispatcher.stop();
|
dispatcher.stop();
|
||||||
for (AbstractNioChannel channel : channels) {
|
for (var channel : channels) {
|
||||||
channel.getJavaChannel().close();
|
channel.getJavaChannel().close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AbstractNioChannel tcpChannel(int port, ChannelHandler handler) throws IOException {
|
private AbstractNioChannel tcpChannel(int port, ChannelHandler handler) throws IOException {
|
||||||
NioServerSocketChannel channel = new NioServerSocketChannel(port, handler);
|
var channel = new NioServerSocketChannel(port, handler);
|
||||||
channel.bind();
|
channel.bind();
|
||||||
channels.add(channel);
|
channels.add(channel);
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AbstractNioChannel udpChannel(int port, ChannelHandler handler) throws IOException {
|
private AbstractNioChannel udpChannel(int port, ChannelHandler handler) throws IOException {
|
||||||
NioDatagramChannel channel = new NioDatagramChannel(port, handler);
|
var channel = new NioDatagramChannel(port, handler);
|
||||||
channel.bind();
|
channel.bind();
|
||||||
channels.add(channel);
|
channels.add(channel);
|
||||||
return channel;
|
return channel;
|
||||||
|
@ -25,7 +25,6 @@ package com.iluwatar.reactor.app;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.net.DatagramPacket;
|
import java.net.DatagramPacket;
|
||||||
import java.net.DatagramSocket;
|
import java.net.DatagramSocket;
|
||||||
@ -55,7 +54,7 @@ public class AppClient {
|
|||||||
* @throws IOException if any I/O error occurs.
|
* @throws IOException if any I/O error occurs.
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) throws IOException {
|
public static void main(String[] args) throws IOException {
|
||||||
AppClient appClient = new AppClient();
|
var appClient = new AppClient();
|
||||||
appClient.start();
|
appClient.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,8 +117,8 @@ public class AppClient {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try (Socket socket = new Socket(InetAddress.getLocalHost(), serverPort)) {
|
try (Socket socket = new Socket(InetAddress.getLocalHost(), serverPort)) {
|
||||||
OutputStream outputStream = socket.getOutputStream();
|
var outputStream = socket.getOutputStream();
|
||||||
PrintWriter writer = new PrintWriter(outputStream);
|
var writer = new PrintWriter(outputStream);
|
||||||
sendLogRequests(writer, socket.getInputStream());
|
sendLogRequests(writer, socket.getInputStream());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
LOGGER.error("error sending requests", e);
|
LOGGER.error("error sending requests", e);
|
||||||
@ -128,12 +127,12 @@ public class AppClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void sendLogRequests(PrintWriter writer, InputStream inputStream) throws IOException {
|
private void sendLogRequests(PrintWriter writer, InputStream inputStream) throws IOException {
|
||||||
for (int i = 0; i < 4; i++) {
|
for (var i = 0; i < 4; i++) {
|
||||||
writer.println(clientName + " - Log request: " + i);
|
writer.println(clientName + " - Log request: " + i);
|
||||||
writer.flush();
|
writer.flush();
|
||||||
|
|
||||||
byte[] data = new byte[1024];
|
var data = new byte[1024];
|
||||||
int read = inputStream.read(data, 0, data.length);
|
var read = inputStream.read(data, 0, data.length);
|
||||||
if (read == 0) {
|
if (read == 0) {
|
||||||
LOGGER.info("Read zero bytes");
|
LOGGER.info("Read zero bytes");
|
||||||
} else {
|
} else {
|
||||||
@ -167,17 +166,17 @@ public class AppClient {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try (DatagramSocket socket = new DatagramSocket()) {
|
try (var socket = new DatagramSocket()) {
|
||||||
for (int i = 0; i < 4; i++) {
|
for (var i = 0; i < 4; i++) {
|
||||||
|
|
||||||
String message = clientName + " - Log request: " + i;
|
var message = clientName + " - Log request: " + i;
|
||||||
DatagramPacket request =
|
var bytes = message.getBytes();
|
||||||
new DatagramPacket(message.getBytes(), message.getBytes().length, remoteAddress);
|
var request = new DatagramPacket(bytes, bytes.length, remoteAddress);
|
||||||
|
|
||||||
socket.send(request);
|
socket.send(request);
|
||||||
|
|
||||||
byte[] data = new byte[1024];
|
var data = new byte[1024];
|
||||||
DatagramPacket reply = new DatagramPacket(data, data.length);
|
var reply = new DatagramPacket(data, data.length);
|
||||||
socket.receive(reply);
|
socket.receive(reply);
|
||||||
if (reply.getLength() == 0) {
|
if (reply.getLength() == 0) {
|
||||||
LOGGER.info("Read zero bytes");
|
LOGGER.info("Read zero bytes");
|
||||||
|
@ -54,7 +54,7 @@ public class LoggingHandler implements ChannelHandler {
|
|||||||
doLogging((ByteBuffer) readObject);
|
doLogging((ByteBuffer) readObject);
|
||||||
sendReply(channel, key);
|
sendReply(channel, key);
|
||||||
} else if (readObject instanceof DatagramPacket) {
|
} else if (readObject instanceof DatagramPacket) {
|
||||||
DatagramPacket datagram = (DatagramPacket) readObject;
|
var datagram = (DatagramPacket) readObject;
|
||||||
doLogging(datagram.getData());
|
doLogging(datagram.getData());
|
||||||
sendReply(channel, datagram, key);
|
sendReply(channel, datagram, key);
|
||||||
} else {
|
} else {
|
||||||
@ -71,14 +71,14 @@ public class LoggingHandler implements ChannelHandler {
|
|||||||
* Create a reply acknowledgement datagram packet setting the receiver to the sender of incoming
|
* Create a reply acknowledgement datagram packet setting the receiver to the sender of incoming
|
||||||
* message.
|
* message.
|
||||||
*/
|
*/
|
||||||
DatagramPacket replyPacket = new DatagramPacket(ByteBuffer.wrap(ACK));
|
var replyPacket = new DatagramPacket(ByteBuffer.wrap(ACK));
|
||||||
replyPacket.setReceiver(incomingPacket.getSender());
|
replyPacket.setReceiver(incomingPacket.getSender());
|
||||||
|
|
||||||
channel.write(replyPacket, key);
|
channel.write(replyPacket, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void sendReply(AbstractNioChannel channel, SelectionKey key) {
|
private static void sendReply(AbstractNioChannel channel, SelectionKey key) {
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(ACK);
|
var buffer = ByteBuffer.wrap(ACK);
|
||||||
channel.write(buffer, key);
|
channel.write(buffer, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,8 +46,7 @@ public abstract class AbstractNioChannel {
|
|||||||
|
|
||||||
private final SelectableChannel channel;
|
private final SelectableChannel channel;
|
||||||
private final ChannelHandler handler;
|
private final ChannelHandler handler;
|
||||||
private final Map<SelectableChannel, Queue<Object>> channelToPendingWrites =
|
private final Map<SelectableChannel, Queue<Object>> channelToPendingWrites;
|
||||||
new ConcurrentHashMap<>();
|
|
||||||
private NioReactor reactor;
|
private NioReactor reactor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,6 +58,7 @@ public abstract class AbstractNioChannel {
|
|||||||
public AbstractNioChannel(ChannelHandler handler, SelectableChannel channel) {
|
public AbstractNioChannel(ChannelHandler handler, SelectableChannel channel) {
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
this.channel = channel;
|
this.channel = channel;
|
||||||
|
this.channelToPendingWrites = new ConcurrentHashMap<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -117,18 +117,14 @@ public abstract class AbstractNioChannel {
|
|||||||
* whole pending block of data at once.
|
* whole pending block of data at once.
|
||||||
*/
|
*/
|
||||||
void flush(SelectionKey key) throws IOException {
|
void flush(SelectionKey key) throws IOException {
|
||||||
Queue<Object> pendingWrites = channelToPendingWrites.get(key.channel());
|
var pendingWrites = channelToPendingWrites.get(key.channel());
|
||||||
while (true) {
|
Object pendingWrite;
|
||||||
Object pendingWrite = pendingWrites.poll();
|
while ((pendingWrite = pendingWrites.poll()) != null) {
|
||||||
if (pendingWrite == null) {
|
|
||||||
// We don't have anything more to write so channel is interested in reading more data
|
|
||||||
reactor.changeOps(key, SelectionKey.OP_READ);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ask the concrete channel to make sense of data and write it to java channel
|
// ask the concrete channel to make sense of data and write it to java channel
|
||||||
doWrite(pendingWrite, key);
|
doWrite(pendingWrite, key);
|
||||||
}
|
}
|
||||||
|
// We don't have anything more to write so channel is interested in reading more data
|
||||||
|
reactor.changeOps(key, SelectionKey.OP_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -162,7 +158,7 @@ public abstract class AbstractNioChannel {
|
|||||||
* @param key the key which is writable.
|
* @param key the key which is writable.
|
||||||
*/
|
*/
|
||||||
public void write(Object data, SelectionKey key) {
|
public void write(Object data, SelectionKey key) {
|
||||||
Queue<Object> pendingWrites = this.channelToPendingWrites.get(key.channel());
|
var pendingWrites = this.channelToPendingWrites.get(key.channel());
|
||||||
if (pendingWrites == null) {
|
if (pendingWrites == null) {
|
||||||
synchronized (this.channelToPendingWrites) {
|
synchronized (this.channelToPendingWrites) {
|
||||||
pendingWrites = this.channelToPendingWrites.get(key.channel());
|
pendingWrites = this.channelToPendingWrites.get(key.channel());
|
||||||
|
@ -73,15 +73,15 @@ public class NioDatagramChannel extends AbstractNioChannel {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DatagramPacket read(SelectionKey key) throws IOException {
|
public DatagramPacket read(SelectionKey key) throws IOException {
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(1024);
|
var buffer = ByteBuffer.allocate(1024);
|
||||||
SocketAddress sender = ((DatagramChannel) key.channel()).receive(buffer);
|
var sender = ((DatagramChannel) key.channel()).receive(buffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It is required to create a DatagramPacket because we need to preserve which socket address
|
* It is required to create a DatagramPacket because we need to preserve which socket address
|
||||||
* acts as destination for sending reply packets.
|
* acts as destination for sending reply packets.
|
||||||
*/
|
*/
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
DatagramPacket packet = new DatagramPacket(buffer);
|
var packet = new DatagramPacket(buffer);
|
||||||
packet.setSender(sender);
|
packet.setSender(sender);
|
||||||
|
|
||||||
return packet;
|
return packet;
|
||||||
@ -115,7 +115,7 @@ public class NioDatagramChannel extends AbstractNioChannel {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void doWrite(Object pendingWrite, SelectionKey key) throws IOException {
|
protected void doWrite(Object pendingWrite, SelectionKey key) throws IOException {
|
||||||
DatagramPacket pendingPacket = (DatagramPacket) pendingWrite;
|
var pendingPacket = (DatagramPacket) pendingWrite;
|
||||||
getJavaChannel().send(pendingPacket.getData(), pendingPacket.getReceiver());
|
getJavaChannel().send(pendingPacket.getData(), pendingPacket.getReceiver());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,10 +27,7 @@ import java.io.IOException;
|
|||||||
import java.nio.channels.SelectionKey;
|
import java.nio.channels.SelectionKey;
|
||||||
import java.nio.channels.Selector;
|
import java.nio.channels.Selector;
|
||||||
import java.nio.channels.ServerSocketChannel;
|
import java.nio.channels.ServerSocketChannel;
|
||||||
import java.nio.channels.SocketChannel;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@ -119,20 +116,15 @@ public class NioReactor {
|
|||||||
* @throws IOException if any I/O error occurs.
|
* @throws IOException if any I/O error occurs.
|
||||||
*/
|
*/
|
||||||
public NioReactor registerChannel(AbstractNioChannel channel) throws IOException {
|
public NioReactor registerChannel(AbstractNioChannel channel) throws IOException {
|
||||||
SelectionKey key = channel.getJavaChannel().register(selector, channel.getInterestedOps());
|
var key = channel.getJavaChannel().register(selector, channel.getInterestedOps());
|
||||||
key.attach(channel);
|
key.attach(channel);
|
||||||
channel.setReactor(this);
|
channel.setReactor(this);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void eventLoop() throws IOException {
|
private void eventLoop() throws IOException {
|
||||||
while (true) {
|
// honor interrupt request
|
||||||
|
while (!Thread.interrupted()) {
|
||||||
// honor interrupt request
|
|
||||||
if (Thread.interrupted()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// honor any pending commands first
|
// honor any pending commands first
|
||||||
processPendingCommands();
|
processPendingCommands();
|
||||||
|
|
||||||
@ -145,12 +137,11 @@ public class NioReactor {
|
|||||||
/*
|
/*
|
||||||
* Represents the events that have occurred on registered handles.
|
* Represents the events that have occurred on registered handles.
|
||||||
*/
|
*/
|
||||||
Set<SelectionKey> keys = selector.selectedKeys();
|
var keys = selector.selectedKeys();
|
||||||
|
var iterator = keys.iterator();
|
||||||
Iterator<SelectionKey> iterator = keys.iterator();
|
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
SelectionKey key = iterator.next();
|
var key = iterator.next();
|
||||||
if (!key.isValid()) {
|
if (!key.isValid()) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
continue;
|
continue;
|
||||||
@ -162,9 +153,9 @@ public class NioReactor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processPendingCommands() {
|
private void processPendingCommands() {
|
||||||
Iterator<Runnable> iterator = pendingCommands.iterator();
|
var iterator = pendingCommands.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
Runnable command = iterator.next();
|
var command = iterator.next();
|
||||||
command.run();
|
command.run();
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
}
|
}
|
||||||
@ -185,15 +176,14 @@ public class NioReactor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void onChannelWritable(SelectionKey key) throws IOException {
|
private static void onChannelWritable(SelectionKey key) throws IOException {
|
||||||
AbstractNioChannel channel = (AbstractNioChannel) key.attachment();
|
var channel = (AbstractNioChannel) key.attachment();
|
||||||
channel.flush(key);
|
channel.flush(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onChannelReadable(SelectionKey key) {
|
private void onChannelReadable(SelectionKey key) {
|
||||||
try {
|
try {
|
||||||
// reads the incoming data in context of reactor main loop. Can this be improved?
|
// reads the incoming data in context of reactor main loop. Can this be improved?
|
||||||
Object readObject = ((AbstractNioChannel) key.attachment()).read(key);
|
var readObject = ((AbstractNioChannel) key.attachment()).read(key);
|
||||||
|
|
||||||
dispatchReadEvent(key, readObject);
|
dispatchReadEvent(key, readObject);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
try {
|
try {
|
||||||
@ -212,10 +202,10 @@ public class NioReactor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void onChannelAcceptable(SelectionKey key) throws IOException {
|
private void onChannelAcceptable(SelectionKey key) throws IOException {
|
||||||
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
|
var serverSocketChannel = (ServerSocketChannel) key.channel();
|
||||||
SocketChannel socketChannel = serverSocketChannel.accept();
|
var socketChannel = serverSocketChannel.accept();
|
||||||
socketChannel.configureBlocking(false);
|
socketChannel.configureBlocking(false);
|
||||||
SelectionKey readKey = socketChannel.register(selector, SelectionKey.OP_READ);
|
var readKey = socketChannel.register(selector, SelectionKey.OP_READ);
|
||||||
readKey.attach(key.attachment());
|
readKey.attach(key.attachment());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,9 +83,9 @@ public class NioServerSocketChannel extends AbstractNioChannel {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer read(SelectionKey key) throws IOException {
|
public ByteBuffer read(SelectionKey key) throws IOException {
|
||||||
SocketChannel socketChannel = (SocketChannel) key.channel();
|
var socketChannel = (SocketChannel) key.channel();
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(1024);
|
var buffer = ByteBuffer.allocate(1024);
|
||||||
int read = socketChannel.read(buffer);
|
var read = socketChannel.read(buffer);
|
||||||
buffer.flip();
|
buffer.flip();
|
||||||
if (read == -1) {
|
if (read == -1) {
|
||||||
throw new IOException("Socket closed");
|
throw new IOException("Socket closed");
|
||||||
@ -100,9 +100,9 @@ public class NioServerSocketChannel extends AbstractNioChannel {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void bind() throws IOException {
|
public void bind() throws IOException {
|
||||||
getJavaChannel().socket().bind(
|
var javaChannel = getJavaChannel();
|
||||||
new InetSocketAddress(InetAddress.getLocalHost(), port));
|
javaChannel.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), port));
|
||||||
getJavaChannel().configureBlocking(false);
|
javaChannel.configureBlocking(false);
|
||||||
LOGGER.info("Bound TCP socket at port: {}", port);
|
LOGGER.info("Bound TCP socket at port: {}", port);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +112,7 @@ public class NioServerSocketChannel extends AbstractNioChannel {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void doWrite(Object pendingWrite, SelectionKey key) throws IOException {
|
protected void doWrite(Object pendingWrite, SelectionKey key) throws IOException {
|
||||||
ByteBuffer pendingBuffer = (ByteBuffer) pendingWrite;
|
var pendingBuffer = (ByteBuffer) pendingWrite;
|
||||||
((SocketChannel) key.channel()).write(pendingBuffer);
|
((SocketChannel) key.channel()).write(pendingBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,14 +25,12 @@ package com.iluwatar.reactor.app;
|
|||||||
|
|
||||||
import com.iluwatar.reactor.framework.SameThreadDispatcher;
|
import com.iluwatar.reactor.framework.SameThreadDispatcher;
|
||||||
import com.iluwatar.reactor.framework.ThreadPoolDispatcher;
|
import com.iluwatar.reactor.framework.ThreadPoolDispatcher;
|
||||||
|
import java.io.IOException;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* This class tests the Distributed Logging service by starting a Reactor and then sending it
|
* This class tests the Distributed Logging service by starting a Reactor and then sending it
|
||||||
* concurrent logging requests using multiple clients.
|
* concurrent logging requests using multiple clients.
|
||||||
*/
|
*/
|
||||||
@ -42,17 +40,17 @@ public class ReactorTest {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the application using pooled thread dispatcher.
|
* Test the application using pooled thread dispatcher.
|
||||||
*
|
*
|
||||||
* @throws IOException if any I/O error occurs.
|
* @throws IOException if any I/O error occurs.
|
||||||
* @throws InterruptedException if interrupted while stopping the application.
|
* @throws InterruptedException if interrupted while stopping the application.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testAppUsingThreadPoolDispatcher() throws IOException, InterruptedException {
|
public void testAppUsingThreadPoolDispatcher() throws IOException, InterruptedException {
|
||||||
LOGGER.info("testAppUsingThreadPoolDispatcher start");
|
LOGGER.info("testAppUsingThreadPoolDispatcher start");
|
||||||
App app = new App(new ThreadPoolDispatcher(2));
|
var app = new App(new ThreadPoolDispatcher(2));
|
||||||
app.start();
|
app.start();
|
||||||
|
|
||||||
AppClient client = new AppClient();
|
var client = new AppClient();
|
||||||
client.start();
|
client.start();
|
||||||
|
|
||||||
// allow clients to send requests. Artificial delay.
|
// allow clients to send requests. Artificial delay.
|
||||||
@ -70,17 +68,17 @@ public class ReactorTest {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Test the application using same thread dispatcher.
|
* Test the application using same thread dispatcher.
|
||||||
*
|
*
|
||||||
* @throws IOException if any I/O error occurs.
|
* @throws IOException if any I/O error occurs.
|
||||||
* @throws InterruptedException if interrupted while stopping the application.
|
* @throws InterruptedException if interrupted while stopping the application.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testAppUsingSameThreadDispatcher() throws IOException, InterruptedException {
|
public void testAppUsingSameThreadDispatcher() throws IOException, InterruptedException {
|
||||||
LOGGER.info("testAppUsingSameThreadDispatcher start");
|
LOGGER.info("testAppUsingSameThreadDispatcher start");
|
||||||
App app = new App(new SameThreadDispatcher());
|
var app = new App(new SameThreadDispatcher());
|
||||||
app.start();
|
app.start();
|
||||||
|
|
||||||
AppClient client = new AppClient();
|
var client = new AppClient();
|
||||||
client.start();
|
client.start();
|
||||||
|
|
||||||
// allow clients to send requests. Artificial delay.
|
// allow clients to send requests. Artificial delay.
|
||||||
|
@ -23,11 +23,9 @@
|
|||||||
|
|
||||||
package com.iluwatar.reader.writer.lock;
|
package com.iluwatar.reader.writer.lock;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.IntStream;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -58,19 +56,21 @@ public class App {
|
|||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
||||||
ExecutorService executeService = Executors.newFixedThreadPool(10);
|
var executeService = Executors.newFixedThreadPool(10);
|
||||||
ReaderWriterLock lock = new ReaderWriterLock();
|
var lock = new ReaderWriterLock();
|
||||||
|
|
||||||
// Start writers
|
// Start writers
|
||||||
IntStream.range(0, 5)
|
for (var i = 0; i < 5; i++) {
|
||||||
.forEach(i -> executeService.submit(new Writer("Writer " + i, lock.writeLock(),
|
var writingTime = ThreadLocalRandom.current().nextLong(5000);
|
||||||
ThreadLocalRandom.current().nextLong(5000))));
|
executeService.submit(new Writer("Writer " + i, lock.writeLock(), writingTime));
|
||||||
|
}
|
||||||
LOGGER.info("Writers added...");
|
LOGGER.info("Writers added...");
|
||||||
|
|
||||||
// Start readers
|
// Start readers
|
||||||
IntStream.range(0, 5)
|
for (var i = 0; i < 5; i++) {
|
||||||
.forEach(i -> executeService.submit(new Reader("Reader " + i, lock.readLock(),
|
var readingTime = ThreadLocalRandom.current().nextLong(10);
|
||||||
ThreadLocalRandom.current().nextLong(10))));
|
executeService.submit(new Reader("Reader " + i, lock.readLock(), readingTime));
|
||||||
|
}
|
||||||
LOGGER.info("Readers added...");
|
LOGGER.info("Readers added...");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -81,9 +81,10 @@ public class App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start readers
|
// Start readers
|
||||||
IntStream.range(6, 10)
|
for (var i = 6; i < 10; i++) {
|
||||||
.forEach(i -> executeService.submit(new Reader("Reader " + i, lock.readLock(),
|
var readingTime = ThreadLocalRandom.current().nextLong(10);
|
||||||
ThreadLocalRandom.current().nextLong(10))));
|
executeService.submit(new Reader("Reader " + i, lock.readLock(), readingTime));
|
||||||
|
}
|
||||||
LOGGER.info("More readers added...");
|
LOGGER.info("More readers added...");
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ public class ReaderWriterLock implements ReadWriteLock {
|
|||||||
private static final Logger LOGGER = LoggerFactory.getLogger(ReaderWriterLock.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(ReaderWriterLock.class);
|
||||||
|
|
||||||
|
|
||||||
private Object readerMutex = new Object();
|
private final Object readerMutex = new Object();
|
||||||
|
|
||||||
private int currentReaderCount;
|
private int currentReaderCount;
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ public class ReaderWriterLock implements ReadWriteLock {
|
|||||||
*
|
*
|
||||||
* <p>This is the most important field in this class to control the access for reader/writer.
|
* <p>This is the most important field in this class to control the access for reader/writer.
|
||||||
*/
|
*/
|
||||||
private Set<Object> globalMutex = new HashSet<>();
|
private final Set<Object> globalMutex = new HashSet<>();
|
||||||
|
|
||||||
private ReadLock readerLock = new ReadLock();
|
private ReadLock readerLock = new ReadLock();
|
||||||
private WriteLock writerLock = new WriteLock();
|
private WriteLock writerLock = new WriteLock();
|
||||||
@ -114,8 +114,8 @@ public class ReaderWriterLock implements ReadWriteLock {
|
|||||||
try {
|
try {
|
||||||
globalMutex.wait();
|
globalMutex.wait();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOGGER
|
var message = "InterruptedException while waiting for globalMutex in acquireForReaders";
|
||||||
.info("InterruptedException while waiting for globalMutex in acquireForReaders", e);
|
LOGGER.info(message, e);
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,7 +125,6 @@ public class ReaderWriterLock implements ReadWriteLock {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unlock() {
|
public void unlock() {
|
||||||
|
|
||||||
synchronized (readerMutex) {
|
synchronized (readerMutex) {
|
||||||
currentReaderCount--;
|
currentReaderCount--;
|
||||||
// Release the lock only when it is the last reader, it is ensure that the lock is released
|
// Release the lock only when it is the last reader, it is ensure that the lock is released
|
||||||
@ -142,7 +141,7 @@ public class ReaderWriterLock implements ReadWriteLock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void lockInterruptibly() throws InterruptedException {
|
public void lockInterruptibly() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +151,7 @@ public class ReaderWriterLock implements ReadWriteLock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
|
public boolean tryLock(long time, TimeUnit unit) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +169,6 @@ public class ReaderWriterLock implements ReadWriteLock {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void lock() {
|
public void lock() {
|
||||||
|
|
||||||
synchronized (globalMutex) {
|
synchronized (globalMutex) {
|
||||||
|
|
||||||
// Wait until the lock is free.
|
// Wait until the lock is free.
|
||||||
@ -189,7 +187,6 @@ public class ReaderWriterLock implements ReadWriteLock {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unlock() {
|
public void unlock() {
|
||||||
|
|
||||||
synchronized (globalMutex) {
|
synchronized (globalMutex) {
|
||||||
globalMutex.remove(this);
|
globalMutex.remove(this);
|
||||||
// Notify the waiter, other writer or reader
|
// Notify the waiter, other writer or reader
|
||||||
@ -198,7 +195,7 @@ public class ReaderWriterLock implements ReadWriteLock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void lockInterruptibly() throws InterruptedException {
|
public void lockInterruptibly() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,7 +205,7 @@ public class ReaderWriterLock implements ReadWriteLock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
|
public boolean tryLock(long time, TimeUnit unit) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,9 +31,8 @@ import org.junit.jupiter.api.Test;
|
|||||||
public class AppTest {
|
public class AppTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() throws Exception {
|
public void test() {
|
||||||
String[] args = {};
|
App.main(new String[]{});
|
||||||
App.main(args);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,19 +23,17 @@
|
|||||||
|
|
||||||
package com.iluwatar.reader.writer.lock;
|
package com.iluwatar.reader.writer.lock;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import com.iluwatar.reader.writer.lock.utils.InMemoryAppender;
|
import com.iluwatar.reader.writer.lock.utils.InMemoryAppender;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author hongshuwei@gmail.com
|
* @author hongshuwei@gmail.com
|
||||||
*/
|
*/
|
||||||
@ -61,12 +59,12 @@ public class ReaderAndWriterTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadAndWrite() throws Exception {
|
public void testReadAndWrite() throws Exception {
|
||||||
|
|
||||||
ReaderWriterLock lock = new ReaderWriterLock();
|
var lock = new ReaderWriterLock();
|
||||||
|
|
||||||
Reader reader1 = new Reader("Reader 1", lock.readLock());
|
var reader1 = new Reader("Reader 1", lock.readLock());
|
||||||
Writer writer1 = new Writer("Writer 1", lock.writeLock());
|
var writer1 = new Writer("Writer 1", lock.writeLock());
|
||||||
|
|
||||||
ExecutorService executeService = Executors.newFixedThreadPool(2);
|
var executeService = Executors.newFixedThreadPool(2);
|
||||||
executeService.submit(reader1);
|
executeService.submit(reader1);
|
||||||
// Let reader1 execute first
|
// Let reader1 execute first
|
||||||
Thread.sleep(150);
|
Thread.sleep(150);
|
||||||
@ -91,11 +89,11 @@ public class ReaderAndWriterTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testWriteAndRead() throws Exception {
|
public void testWriteAndRead() throws Exception {
|
||||||
|
|
||||||
ExecutorService executeService = Executors.newFixedThreadPool(2);
|
var executeService = Executors.newFixedThreadPool(2);
|
||||||
ReaderWriterLock lock = new ReaderWriterLock();
|
var lock = new ReaderWriterLock();
|
||||||
|
|
||||||
Reader reader1 = new Reader("Reader 1", lock.readLock());
|
var reader1 = new Reader("Reader 1", lock.readLock());
|
||||||
Writer writer1 = new Writer("Writer 1", lock.writeLock());
|
var writer1 = new Writer("Writer 1", lock.writeLock());
|
||||||
|
|
||||||
executeService.submit(writer1);
|
executeService.submit(writer1);
|
||||||
// Let writer1 execute first
|
// Let writer1 execute first
|
||||||
|
@ -23,20 +23,18 @@
|
|||||||
|
|
||||||
package com.iluwatar.reader.writer.lock;
|
package com.iluwatar.reader.writer.lock;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
|
||||||
import com.iluwatar.reader.writer.lock.utils.InMemoryAppender;
|
import com.iluwatar.reader.writer.lock.utils.InMemoryAppender;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.mockito.Mockito.spy;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author hongshuwei@gmail.com
|
* @author hongshuwei@gmail.com
|
||||||
*/
|
*/
|
||||||
@ -62,11 +60,11 @@ public class ReaderTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testRead() throws Exception {
|
public void testRead() throws Exception {
|
||||||
|
|
||||||
ExecutorService executeService = Executors.newFixedThreadPool(2);
|
var executeService = Executors.newFixedThreadPool(2);
|
||||||
ReaderWriterLock lock = new ReaderWriterLock();
|
var lock = new ReaderWriterLock();
|
||||||
|
|
||||||
Reader reader1 = spy(new Reader("Reader 1", lock.readLock()));
|
var reader1 = spy(new Reader("Reader 1", lock.readLock()));
|
||||||
Reader reader2 = spy(new Reader("Reader 2", lock.readLock()));
|
var reader2 = spy(new Reader("Reader 2", lock.readLock()));
|
||||||
|
|
||||||
executeService.submit(reader1);
|
executeService.submit(reader1);
|
||||||
Thread.sleep(150);
|
Thread.sleep(150);
|
||||||
|
@ -23,20 +23,18 @@
|
|||||||
|
|
||||||
package com.iluwatar.reader.writer.lock;
|
package com.iluwatar.reader.writer.lock;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
|
||||||
import com.iluwatar.reader.writer.lock.utils.InMemoryAppender;
|
import com.iluwatar.reader.writer.lock.utils.InMemoryAppender;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.mockito.Mockito.spy;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author hongshuwei@gmail.com
|
* @author hongshuwei@gmail.com
|
||||||
*/
|
*/
|
||||||
@ -62,11 +60,11 @@ public class WriterTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testWrite() throws Exception {
|
public void testWrite() throws Exception {
|
||||||
|
|
||||||
ExecutorService executeService = Executors.newFixedThreadPool(2);
|
var executeService = Executors.newFixedThreadPool(2);
|
||||||
ReaderWriterLock lock = new ReaderWriterLock();
|
var lock = new ReaderWriterLock();
|
||||||
|
|
||||||
Writer writer1 = spy(new Writer("Writer 1", lock.writeLock()));
|
var writer1 = spy(new Writer("Writer 1", lock.writeLock()));
|
||||||
Writer writer2 = spy(new Writer("Writer 2", lock.writeLock()));
|
var writer2 = spy(new Writer("Writer 2", lock.writeLock()));
|
||||||
|
|
||||||
executeService.submit(writer1);
|
executeService.submit(writer1);
|
||||||
// Let write1 execute first
|
// Let write1 execute first
|
||||||
|
@ -26,10 +26,9 @@ package com.iluwatar.reader.writer.lock.utils;
|
|||||||
import ch.qos.logback.classic.Logger;
|
import ch.qos.logback.classic.Logger;
|
||||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
import ch.qos.logback.core.AppenderBase;
|
import ch.qos.logback.core.AppenderBase;
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* InMemory Log Appender Util.
|
* InMemory Log Appender Util.
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
package com.iluwatar.repository;
|
package com.iluwatar.repository;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||||
@ -55,14 +54,13 @@ public class App {
|
|||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
|
||||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
|
var context = new ClassPathXmlApplicationContext("applicationContext.xml");
|
||||||
"applicationContext.xml");
|
var repository = context.getBean(PersonRepository.class);
|
||||||
PersonRepository repository = context.getBean(PersonRepository.class);
|
|
||||||
|
|
||||||
Person peter = new Person("Peter", "Sagan", 17);
|
var peter = new Person("Peter", "Sagan", 17);
|
||||||
Person nasta = new Person("Nasta", "Kuzminova", 25);
|
var nasta = new Person("Nasta", "Kuzminova", 25);
|
||||||
Person john = new Person("John", "lawrence", 35);
|
var john = new Person("John", "lawrence", 35);
|
||||||
Person terry = new Person("Terry", "Law", 36);
|
var terry = new Person("Terry", "Law", 36);
|
||||||
|
|
||||||
// Add new Person records
|
// Add new Person records
|
||||||
repository.save(peter);
|
repository.save(peter);
|
||||||
@ -74,17 +72,15 @@ public class App {
|
|||||||
LOGGER.info("Count Person records: {}", repository.count());
|
LOGGER.info("Count Person records: {}", repository.count());
|
||||||
|
|
||||||
// Print all records
|
// Print all records
|
||||||
List<Person> persons = (List<Person>) repository.findAll();
|
var persons = (List<Person>) repository.findAll();
|
||||||
for (Person person : persons) {
|
persons.stream().map(Person::toString).forEach(LOGGER::info);
|
||||||
LOGGER.info(person.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update Person
|
// Update Person
|
||||||
nasta.setName("Barbora");
|
nasta.setName("Barbora");
|
||||||
nasta.setSurname("Spotakova");
|
nasta.setSurname("Spotakova");
|
||||||
repository.save(nasta);
|
repository.save(nasta);
|
||||||
|
|
||||||
LOGGER.info("Find by id 2: {}", repository.findById(2L).get());
|
repository.findById(2L).ifPresent(p -> LOGGER.info("Find by id 2: {}", p));
|
||||||
|
|
||||||
// Remove record from Person
|
// Remove record from Person
|
||||||
repository.deleteById(2L);
|
repository.deleteById(2L);
|
||||||
@ -93,16 +89,15 @@ public class App {
|
|||||||
LOGGER.info("Count Person records: {}", repository.count());
|
LOGGER.info("Count Person records: {}", repository.count());
|
||||||
|
|
||||||
// find by name
|
// find by name
|
||||||
Optional<Person> p = repository.findOne(new PersonSpecifications.NameEqualSpec("John"));
|
repository
|
||||||
LOGGER.info("Find by John is {}", p.get());
|
.findOne(new PersonSpecifications.NameEqualSpec("John"))
|
||||||
|
.ifPresent(p -> LOGGER.info("Find by John is {}", p));
|
||||||
|
|
||||||
// find by age
|
// find by age
|
||||||
persons = repository.findAll(new PersonSpecifications.AgeBetweenSpec(20, 40));
|
persons = repository.findAll(new PersonSpecifications.AgeBetweenSpec(20, 40));
|
||||||
|
|
||||||
LOGGER.info("Find Person with age between 20,40: ");
|
LOGGER.info("Find Person with age between 20,40: ");
|
||||||
for (Person person : persons) {
|
persons.stream().map(Person::toString).forEach(LOGGER::info);
|
||||||
LOGGER.info(person.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
repository.deleteAll();
|
repository.deleteAll();
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@ package com.iluwatar.repository;
|
|||||||
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
import org.apache.commons.dbcp.BasicDataSource;
|
import org.apache.commons.dbcp.BasicDataSource;
|
||||||
@ -55,7 +54,7 @@ public class AppConfig {
|
|||||||
*/
|
*/
|
||||||
@Bean(destroyMethod = "close")
|
@Bean(destroyMethod = "close")
|
||||||
public DataSource dataSource() {
|
public DataSource dataSource() {
|
||||||
BasicDataSource basicDataSource = new BasicDataSource();
|
var basicDataSource = new BasicDataSource();
|
||||||
basicDataSource.setDriverClassName("org.h2.Driver");
|
basicDataSource.setDriverClassName("org.h2.Driver");
|
||||||
basicDataSource.setUrl("jdbc:h2:~/databases/person");
|
basicDataSource.setUrl("jdbc:h2:~/databases/person");
|
||||||
basicDataSource.setUsername("sa");
|
basicDataSource.setUsername("sa");
|
||||||
@ -68,13 +67,11 @@ public class AppConfig {
|
|||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||||
LocalContainerEntityManagerFactoryBean entityManager =
|
var entityManager = new LocalContainerEntityManagerFactoryBean();
|
||||||
new LocalContainerEntityManagerFactoryBean();
|
|
||||||
entityManager.setDataSource(dataSource());
|
entityManager.setDataSource(dataSource());
|
||||||
entityManager.setPackagesToScan("com.iluwatar");
|
entityManager.setPackagesToScan("com.iluwatar");
|
||||||
entityManager.setPersistenceProvider(new HibernatePersistenceProvider());
|
entityManager.setPersistenceProvider(new HibernatePersistenceProvider());
|
||||||
entityManager.setJpaProperties(jpaProperties());
|
entityManager.setJpaProperties(jpaProperties());
|
||||||
|
|
||||||
return entityManager;
|
return entityManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +79,7 @@ public class AppConfig {
|
|||||||
* Properties for Jpa.
|
* Properties for Jpa.
|
||||||
*/
|
*/
|
||||||
private static Properties jpaProperties() {
|
private static Properties jpaProperties() {
|
||||||
Properties properties = new Properties();
|
var properties = new Properties();
|
||||||
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
|
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
|
||||||
properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
|
properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
|
||||||
return properties;
|
return properties;
|
||||||
@ -93,7 +90,7 @@ public class AppConfig {
|
|||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public JpaTransactionManager transactionManager() throws SQLException {
|
public JpaTransactionManager transactionManager() throws SQLException {
|
||||||
JpaTransactionManager transactionManager = new JpaTransactionManager();
|
var transactionManager = new JpaTransactionManager();
|
||||||
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
|
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
|
||||||
return transactionManager;
|
return transactionManager;
|
||||||
}
|
}
|
||||||
@ -104,15 +101,13 @@ public class AppConfig {
|
|||||||
* @param args command line args
|
* @param args command line args
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
var context = new AnnotationConfigApplicationContext(AppConfig.class);
|
||||||
|
var repository = context.getBean(PersonRepository.class);
|
||||||
|
|
||||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
var peter = new Person("Peter", "Sagan", 17);
|
||||||
AppConfig.class);
|
var nasta = new Person("Nasta", "Kuzminova", 25);
|
||||||
PersonRepository repository = context.getBean(PersonRepository.class);
|
var john = new Person("John", "lawrence", 35);
|
||||||
|
var terry = new Person("Terry", "Law", 36);
|
||||||
Person peter = new Person("Peter", "Sagan", 17);
|
|
||||||
Person nasta = new Person("Nasta", "Kuzminova", 25);
|
|
||||||
Person john = new Person("John", "lawrence", 35);
|
|
||||||
Person terry = new Person("Terry", "Law", 36);
|
|
||||||
|
|
||||||
// Add new Person records
|
// Add new Person records
|
||||||
repository.save(peter);
|
repository.save(peter);
|
||||||
@ -124,17 +119,15 @@ public class AppConfig {
|
|||||||
LOGGER.info("Count Person records: {}", repository.count());
|
LOGGER.info("Count Person records: {}", repository.count());
|
||||||
|
|
||||||
// Print all records
|
// Print all records
|
||||||
List<Person> persons = (List<Person>) repository.findAll();
|
var persons = (List<Person>) repository.findAll();
|
||||||
for (Person person : persons) {
|
persons.stream().map(Person::toString).forEach(LOGGER::info);
|
||||||
LOGGER.info(person.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update Person
|
// Update Person
|
||||||
nasta.setName("Barbora");
|
nasta.setName("Barbora");
|
||||||
nasta.setSurname("Spotakova");
|
nasta.setSurname("Spotakova");
|
||||||
repository.save(nasta);
|
repository.save(nasta);
|
||||||
|
|
||||||
LOGGER.info("Find by id 2: {}", repository.findById(2L).get());
|
repository.findById(2L).ifPresent(p -> LOGGER.info("Find by id 2: {}", p));
|
||||||
|
|
||||||
// Remove record from Person
|
// Remove record from Person
|
||||||
repository.deleteById(2L);
|
repository.deleteById(2L);
|
||||||
@ -143,16 +136,15 @@ public class AppConfig {
|
|||||||
LOGGER.info("Count Person records: {}", repository.count());
|
LOGGER.info("Count Person records: {}", repository.count());
|
||||||
|
|
||||||
// find by name
|
// find by name
|
||||||
Optional<Person> p = repository.findOne(new PersonSpecifications.NameEqualSpec("John"));
|
repository
|
||||||
LOGGER.info("Find by John is {}", p.get());
|
.findOne(new PersonSpecifications.NameEqualSpec("John"))
|
||||||
|
.ifPresent(p -> LOGGER.info("Find by John is {}", p));
|
||||||
|
|
||||||
// find by age
|
// find by age
|
||||||
persons = repository.findAll(new PersonSpecifications.AgeBetweenSpec(20, 40));
|
persons = repository.findAll(new PersonSpecifications.AgeBetweenSpec(20, 40));
|
||||||
|
|
||||||
LOGGER.info("Find Person with age between 20,40: ");
|
LOGGER.info("Find Person with age between 20,40: ");
|
||||||
for (Person person : persons) {
|
persons.stream().map(Person::toString).forEach(LOGGER::info);
|
||||||
LOGGER.info(person.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
context.close();
|
context.close();
|
||||||
|
|
||||||
|
@ -92,9 +92,8 @@ public class Person {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
|
final var prime = 31;
|
||||||
final int prime = 31;
|
var result = 1;
|
||||||
int result = 1;
|
|
||||||
result = prime * result + age;
|
result = prime * result + age;
|
||||||
result = prime * result + (id == null ? 0 : id.hashCode());
|
result = prime * result + (id == null ? 0 : id.hashCode());
|
||||||
result = prime * result + (name == null ? 0 : name.hashCode());
|
result = prime * result + (name == null ? 0 : name.hashCode());
|
||||||
@ -113,7 +112,7 @@ public class Person {
|
|||||||
if (getClass() != obj.getClass()) {
|
if (getClass() != obj.getClass()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Person other = (Person) obj;
|
var other = (Person) obj;
|
||||||
if (age != other.age) {
|
if (age != other.age) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -132,13 +131,9 @@ public class Person {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (surname == null) {
|
if (surname == null) {
|
||||||
if (other.surname != null) {
|
return other.surname == null;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else if (!surname.equals(other.surname)) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return true;
|
return surname.equals(other.surname);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -50,9 +50,7 @@ public class PersonSpecifications {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
|
public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
|
||||||
|
|
||||||
return cb.between(root.get("age"), from, to);
|
return cb.between(root.get("age"), from, to);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -72,9 +70,7 @@ public class PersonSpecifications {
|
|||||||
* Get predicate.
|
* Get predicate.
|
||||||
*/
|
*/
|
||||||
public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
|
public Predicate toPredicate(Root<Person> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
|
||||||
|
|
||||||
return cb.equal(root.get("name"), this.name);
|
return cb.equal(root.get("name"), this.name);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,13 @@
|
|||||||
|
|
||||||
package com.iluwatar.repository;
|
package com.iluwatar.repository;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.annotation.Resource;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -31,51 +37,41 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test case to test the functions of {@link PersonRepository}, beside the CRUD functions, the query
|
* Test case to test the functions of {@link PersonRepository}, beside the CRUD functions, the query
|
||||||
* by {@link org.springframework.data.jpa.domain.Specification} are also test.
|
* by {@link org.springframework.data.jpa.domain.Specification} are also test.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@ExtendWith(SpringExtension.class)
|
@ExtendWith(SpringExtension.class)
|
||||||
@SpringBootTest(classes = { AppConfig.class })
|
@SpringBootTest(classes = {AppConfig.class})
|
||||||
public class AnnotationBasedRepositoryTest {
|
public class AnnotationBasedRepositoryTest {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PersonRepository repository;
|
private PersonRepository repository;
|
||||||
|
|
||||||
Person peter = new Person("Peter", "Sagan", 17);
|
private Person peter = new Person("Peter", "Sagan", 17);
|
||||||
Person nasta = new Person("Nasta", "Kuzminova", 25);
|
private Person nasta = new Person("Nasta", "Kuzminova", 25);
|
||||||
Person john = new Person("John", "lawrence", 35);
|
private Person john = new Person("John", "lawrence", 35);
|
||||||
Person terry = new Person("Terry", "Law", 36);
|
private Person terry = new Person("Terry", "Law", 36);
|
||||||
|
|
||||||
List<Person> persons = List.of(peter, nasta, john, terry);
|
private List<Person> persons = List.of(peter, nasta, john, terry);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare data for test
|
* Prepare data for test
|
||||||
*/
|
*/
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
|
|
||||||
repository.saveAll(persons);
|
repository.saveAll(persons);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindAll() {
|
public void testFindAll() {
|
||||||
|
var actuals = Lists.newArrayList(repository.findAll());
|
||||||
List<Person> actuals = Lists.newArrayList(repository.findAll());
|
|
||||||
assertTrue(actuals.containsAll(persons) && persons.containsAll(actuals));
|
assertTrue(actuals.containsAll(persons) && persons.containsAll(actuals));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSave() {
|
public void testSave() {
|
||||||
|
var terry = repository.findByName("Terry");
|
||||||
Person terry = repository.findByName("Terry");
|
|
||||||
terry.setSurname("Lee");
|
terry.setSurname("Lee");
|
||||||
terry.setAge(47);
|
terry.setAge(47);
|
||||||
repository.save(terry);
|
repository.save(terry);
|
||||||
@ -87,8 +83,7 @@ public class AnnotationBasedRepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDelete() {
|
public void testDelete() {
|
||||||
|
var terry = repository.findByName("Terry");
|
||||||
Person terry = repository.findByName("Terry");
|
|
||||||
repository.delete(terry);
|
repository.delete(terry);
|
||||||
|
|
||||||
assertEquals(3, repository.count());
|
assertEquals(3, repository.count());
|
||||||
@ -97,31 +92,26 @@ public class AnnotationBasedRepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCount() {
|
public void testCount() {
|
||||||
|
|
||||||
assertEquals(4, repository.count());
|
assertEquals(4, repository.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindAllByAgeBetweenSpec() {
|
public void testFindAllByAgeBetweenSpec() {
|
||||||
|
var persons = repository.findAll(new PersonSpecifications.AgeBetweenSpec(20, 40));
|
||||||
List<Person> persons = repository.findAll(new PersonSpecifications.AgeBetweenSpec(20, 40));
|
|
||||||
|
|
||||||
assertEquals(3, persons.size());
|
assertEquals(3, persons.size());
|
||||||
assertTrue(persons.stream().allMatch((item) -> {
|
assertTrue(persons.stream().allMatch((item) -> item.getAge() > 20 && item.getAge() < 40));
|
||||||
return item.getAge() > 20 && item.getAge() < 40;
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindOneByNameEqualSpec() {
|
public void testFindOneByNameEqualSpec() {
|
||||||
|
var actual = repository.findOne(new PersonSpecifications.NameEqualSpec("Terry"));
|
||||||
Optional<Person> actual = repository.findOne(new PersonSpecifications.NameEqualSpec("Terry"));
|
assertTrue(actual.isPresent());
|
||||||
assertEquals(terry, actual.get());
|
assertEquals(terry, actual.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
|
|
||||||
repository.deleteAll();
|
repository.deleteAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,12 @@
|
|||||||
|
|
||||||
package com.iluwatar.repository;
|
package com.iluwatar.repository;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import javax.sql.DataSource;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -30,19 +36,11 @@ import org.springframework.boot.test.context.SpringBootTest;
|
|||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This case is Just for test the Annotation Based configuration
|
* This case is Just for test the Annotation Based configuration
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
@ExtendWith(SpringExtension.class)
|
@ExtendWith(SpringExtension.class)
|
||||||
@SpringBootTest(classes = { AppConfig.class })
|
@SpringBootTest(classes = {AppConfig.class})
|
||||||
public class AppConfigTest {
|
public class AppConfigTest {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@ -62,12 +60,11 @@ public class AppConfigTest {
|
|||||||
@Test
|
@Test
|
||||||
@Transactional
|
@Transactional
|
||||||
public void testQuery() throws SQLException {
|
public void testQuery() throws SQLException {
|
||||||
ResultSet resultSet = dataSource.getConnection().createStatement().executeQuery("SELECT 1");
|
var resultSet = dataSource.getConnection().createStatement().executeQuery("SELECT 1");
|
||||||
|
var expected = "1";
|
||||||
String result = null;
|
String result = null;
|
||||||
String expected = "1";
|
|
||||||
while (resultSet.next()) {
|
while (resultSet.next()) {
|
||||||
result = resultSet.getString(1);
|
result = resultSet.getString(1);
|
||||||
|
|
||||||
}
|
}
|
||||||
assertEquals(expected, result);
|
assertEquals(expected, result);
|
||||||
}
|
}
|
||||||
|
@ -25,15 +25,12 @@ package com.iluwatar.repository;
|
|||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that Repository example runs without errors.
|
* Tests that Repository example runs without errors.
|
||||||
*/
|
*/
|
||||||
public class AppTest {
|
public class AppTest {
|
||||||
@Test
|
@Test
|
||||||
public void test() {
|
public void test() {
|
||||||
String[] args = {};
|
App.main(new String[]{});
|
||||||
App.main(args);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,13 @@
|
|||||||
|
|
||||||
package com.iluwatar.repository;
|
package com.iluwatar.repository;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.annotation.Resource;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -31,50 +37,41 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test case to test the functions of {@link PersonRepository}, beside the CRUD functions, the query
|
* Test case to test the functions of {@link PersonRepository}, beside the CRUD functions, the query
|
||||||
* by {@link org.springframework.data.jpa.domain.Specification} are also test.
|
* by {@link org.springframework.data.jpa.domain.Specification} are also test.
|
||||||
*/
|
*/
|
||||||
@ExtendWith(SpringExtension.class)
|
@ExtendWith(SpringExtension.class)
|
||||||
@SpringBootTest(properties = { "locations=classpath:applicationContext.xml" })
|
@SpringBootTest(properties = {"locations=classpath:applicationContext.xml"})
|
||||||
public class RepositoryTest {
|
public class RepositoryTest {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PersonRepository repository;
|
private PersonRepository repository;
|
||||||
|
|
||||||
Person peter = new Person("Peter", "Sagan", 17);
|
private Person peter = new Person("Peter", "Sagan", 17);
|
||||||
Person nasta = new Person("Nasta", "Kuzminova", 25);
|
private Person nasta = new Person("Nasta", "Kuzminova", 25);
|
||||||
Person john = new Person("John", "lawrence", 35);
|
private Person john = new Person("John", "lawrence", 35);
|
||||||
Person terry = new Person("Terry", "Law", 36);
|
private Person terry = new Person("Terry", "Law", 36);
|
||||||
|
|
||||||
List<Person> persons = List.of(peter, nasta, john, terry);
|
private List<Person> persons = List.of(peter, nasta, john, terry);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prepare data for test
|
* Prepare data for test
|
||||||
*/
|
*/
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
|
|
||||||
repository.saveAll(persons);
|
repository.saveAll(persons);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindAll() {
|
public void testFindAll() {
|
||||||
|
var actuals = Lists.newArrayList(repository.findAll());
|
||||||
List<Person> actuals = Lists.newArrayList(repository.findAll());
|
|
||||||
assertTrue(actuals.containsAll(persons) && persons.containsAll(actuals));
|
assertTrue(actuals.containsAll(persons) && persons.containsAll(actuals));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSave() {
|
public void testSave() {
|
||||||
|
var terry = repository.findByName("Terry");
|
||||||
Person terry = repository.findByName("Terry");
|
|
||||||
terry.setSurname("Lee");
|
terry.setSurname("Lee");
|
||||||
terry.setAge(47);
|
terry.setAge(47);
|
||||||
repository.save(terry);
|
repository.save(terry);
|
||||||
@ -86,8 +83,7 @@ public class RepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDelete() {
|
public void testDelete() {
|
||||||
|
var terry = repository.findByName("Terry");
|
||||||
Person terry = repository.findByName("Terry");
|
|
||||||
repository.delete(terry);
|
repository.delete(terry);
|
||||||
|
|
||||||
assertEquals(3, repository.count());
|
assertEquals(3, repository.count());
|
||||||
@ -96,14 +92,12 @@ public class RepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCount() {
|
public void testCount() {
|
||||||
|
|
||||||
assertEquals(4, repository.count());
|
assertEquals(4, repository.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindAllByAgeBetweenSpec() {
|
public void testFindAllByAgeBetweenSpec() {
|
||||||
|
var persons = repository.findAll(new PersonSpecifications.AgeBetweenSpec(20, 40));
|
||||||
List<Person> persons = repository.findAll(new PersonSpecifications.AgeBetweenSpec(20, 40));
|
|
||||||
|
|
||||||
assertEquals(3, persons.size());
|
assertEquals(3, persons.size());
|
||||||
assertTrue(persons.stream().allMatch(item -> item.getAge() > 20 && item.getAge() < 40));
|
assertTrue(persons.stream().allMatch(item -> item.getAge() > 20 && item.getAge() < 40));
|
||||||
@ -111,14 +105,13 @@ public class RepositoryTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindOneByNameEqualSpec() {
|
public void testFindOneByNameEqualSpec() {
|
||||||
|
var actual = repository.findOne(new PersonSpecifications.NameEqualSpec("Terry"));
|
||||||
Optional<Person> actual = repository.findOne(new PersonSpecifications.NameEqualSpec("Terry"));
|
assertTrue(actual.isPresent());
|
||||||
assertEquals(terry, actual.get());
|
assertEquals(terry, actual.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
|
|
||||||
repository.deleteAll();
|
repository.deleteAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,11 +54,11 @@ public class App {
|
|||||||
*/
|
*/
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
try (SlidingDoor slidingDoor = new SlidingDoor()) {
|
try (var ignored = new SlidingDoor()) {
|
||||||
LOGGER.info("Walking in.");
|
LOGGER.info("Walking in.");
|
||||||
}
|
}
|
||||||
|
|
||||||
try (TreasureChest treasureChest = new TreasureChest()) {
|
try (var ignored = new TreasureChest()) {
|
||||||
LOGGER.info("Looting contents.");
|
LOGGER.info("Looting contents.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ public class SlidingDoor implements AutoCloseable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws Exception {
|
public void close() {
|
||||||
LOGGER.info("Sliding door closes.");
|
LOGGER.info("Sliding door closes.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
package com.iluwatar.resource.acquisition.is.initialization;
|
package com.iluwatar.resource.acquisition.is.initialization;
|
||||||
|
|
||||||
import java.io.Closeable;
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -40,7 +39,7 @@ public class TreasureChest implements Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() {
|
||||||
LOGGER.info("Treasure chest closes.");
|
LOGGER.info("Treasure chest closes.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,15 +26,12 @@ package com.iluwatar.resource.acquisition.is.initialization;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Application test
|
* Application test
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class AppTest {
|
public class AppTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() throws Exception {
|
public void test() throws Exception {
|
||||||
String[] args = {};
|
App.main(new String[]{});
|
||||||
App.main(args);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,19 +23,18 @@
|
|||||||
|
|
||||||
package com.iluwatar.resource.acquisition.is.initialization;
|
package com.iluwatar.resource.acquisition.is.initialization;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import ch.qos.logback.classic.Logger;
|
import ch.qos.logback.classic.Logger;
|
||||||
import ch.qos.logback.classic.spi.ILoggingEvent;
|
import ch.qos.logback.classic.spi.ILoggingEvent;
|
||||||
import ch.qos.logback.core.AppenderBase;
|
import ch.qos.logback.core.AppenderBase;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Date: 12/28/15 - 9:31 PM
|
* Date: 12/28/15 - 9:31 PM
|
||||||
*
|
*
|
||||||
@ -56,8 +55,8 @@ public class ClosableTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOpenClose() throws Exception {
|
public void testOpenClose() {
|
||||||
try (final SlidingDoor door = new SlidingDoor(); final TreasureChest chest = new TreasureChest()) {
|
try (final var ignored = new SlidingDoor(); final var ignored1 = new TreasureChest()) {
|
||||||
assertTrue(appender.logContains("Sliding door opens."));
|
assertTrue(appender.logContains("Sliding door opens."));
|
||||||
assertTrue(appender.logContains("Treasure chest opens."));
|
assertTrue(appender.logContains("Treasure chest opens."));
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ to recover from this error.
|
|||||||
We can model a 'recoverable' scenario by instantiating `FindCustomer` like this:
|
We can model a 'recoverable' scenario by instantiating `FindCustomer` like this:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
final BusinessOperation<String> op = new FindCustomer(
|
final var op = new FindCustomer(
|
||||||
"12345",
|
"12345",
|
||||||
new CustomerNotFoundException("not found"),
|
new CustomerNotFoundException("not found"),
|
||||||
new CustomerNotFoundException("still not found"),
|
new CustomerNotFoundException("still not found"),
|
||||||
@ -97,7 +97,7 @@ worker thread in the database subsystem typically needs 50ms to
|
|||||||
this:
|
this:
|
||||||
|
|
||||||
```java
|
```java
|
||||||
final BusinessOperation<String> op = new Retry<>(
|
final var op = new Retry<>(
|
||||||
new FindCustomer(
|
new FindCustomer(
|
||||||
"1235",
|
"1235",
|
||||||
new CustomerNotFoundException("not found"),
|
new CustomerNotFoundException("not found"),
|
||||||
|
@ -90,14 +90,14 @@ public final class App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void errorWithRetry() throws Exception {
|
private static void errorWithRetry() throws Exception {
|
||||||
final Retry<String> retry = new Retry<>(
|
final var retry = new Retry<>(
|
||||||
new FindCustomer("123", new CustomerNotFoundException("not found")),
|
new FindCustomer("123", new CustomerNotFoundException("not found")),
|
||||||
3, //3 attempts
|
3, //3 attempts
|
||||||
100, //100 ms delay between attempts
|
100, //100 ms delay between attempts
|
||||||
e -> CustomerNotFoundException.class.isAssignableFrom(e.getClass())
|
e -> CustomerNotFoundException.class.isAssignableFrom(e.getClass())
|
||||||
);
|
);
|
||||||
op = retry;
|
op = retry;
|
||||||
final String customerId = op.perform();
|
final var customerId = op.perform();
|
||||||
LOG.info(String.format(
|
LOG.info(String.format(
|
||||||
"However, retrying the operation while ignoring a recoverable error will eventually yield "
|
"However, retrying the operation while ignoring a recoverable error will eventually yield "
|
||||||
+ "the result %s after a number of attempts %s", customerId, retry.attempts()
|
+ "the result %s after a number of attempts %s", customerId, retry.attempts()
|
||||||
@ -105,14 +105,14 @@ public final class App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void errorWithRetryExponentialBackoff() throws Exception {
|
private static void errorWithRetryExponentialBackoff() throws Exception {
|
||||||
final RetryExponentialBackoff<String> retry = new RetryExponentialBackoff<>(
|
final var retry = new RetryExponentialBackoff<>(
|
||||||
new FindCustomer("123", new CustomerNotFoundException("not found")),
|
new FindCustomer("123", new CustomerNotFoundException("not found")),
|
||||||
6, //6 attempts
|
6, //6 attempts
|
||||||
30000, //30 s max delay between attempts
|
30000, //30 s max delay between attempts
|
||||||
e -> CustomerNotFoundException.class.isAssignableFrom(e.getClass())
|
e -> CustomerNotFoundException.class.isAssignableFrom(e.getClass())
|
||||||
);
|
);
|
||||||
op = retry;
|
op = retry;
|
||||||
final String customerId = op.perform();
|
final var customerId = op.perform();
|
||||||
LOG.info(String.format(
|
LOG.info(String.format(
|
||||||
"However, retrying the operation while ignoring a recoverable error will eventually yield "
|
"However, retrying the operation while ignoring a recoverable error will eventually yield "
|
||||||
+ "the result %s after a number of attempts %s", customerId, retry.attempts()
|
+ "the result %s after a number of attempts %s", customerId, retry.attempts()
|
||||||
|
@ -100,8 +100,8 @@ public final class RetryExponentialBackoff<T> implements BusinessOperation<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
long testDelay = (long) Math.pow(2, this.attempts()) * 1000 + RANDOM.nextInt(1000);
|
var testDelay = (long) Math.pow(2, this.attempts()) * 1000 + RANDOM.nextInt(1000);
|
||||||
long delay = testDelay < this.maxDelay ? testDelay : maxDelay;
|
var delay = Math.min(testDelay, this.maxDelay);
|
||||||
Thread.sleep(delay);
|
Thread.sleep(delay);
|
||||||
} catch (InterruptedException f) {
|
} catch (InterruptedException f) {
|
||||||
//ignore
|
//ignore
|
||||||
|
@ -23,12 +23,12 @@
|
|||||||
|
|
||||||
package com.iluwatar.retry;
|
package com.iluwatar.retry;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link FindCustomer}.
|
* Unit tests for {@link FindCustomer}.
|
||||||
*
|
*
|
||||||
@ -40,33 +40,29 @@ public class FindCustomerTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void noExceptions() throws Exception {
|
public void noExceptions() throws Exception {
|
||||||
assertThat(
|
assertThat(new FindCustomer("123").perform(), is("123"));
|
||||||
new FindCustomer("123").perform(),
|
|
||||||
is("123")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Throws the given exception.
|
* Throws the given exception.
|
||||||
*
|
*
|
||||||
* @throws Exception the expected exception
|
* @throws Exception the expected exception
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void oneException() {
|
public void oneException() {
|
||||||
assertThrows(BusinessException.class, () -> {
|
var findCustomer = new FindCustomer("123", new BusinessException("test"));
|
||||||
new FindCustomer("123", new BusinessException("test")).perform();
|
assertThrows(BusinessException.class, findCustomer::perform);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should first throw the given exceptions, then return the given result.
|
* Should first throw the given exceptions, then return the given result.
|
||||||
*
|
*
|
||||||
* @throws Exception not an expected exception
|
* @throws Exception not an expected exception
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void resultAfterExceptions() throws Exception {
|
public void resultAfterExceptions() throws Exception {
|
||||||
final BusinessOperation<String> op = new FindCustomer(
|
final var op = new FindCustomer(
|
||||||
"123",
|
"123",
|
||||||
new CustomerNotFoundException("not found"),
|
new CustomerNotFoundException("not found"),
|
||||||
new DatabaseNotAvailableException("not available")
|
new DatabaseNotAvailableException("not available")
|
||||||
);
|
);
|
||||||
@ -81,9 +77,6 @@ public class FindCustomerTest {
|
|||||||
//ignore
|
//ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(
|
assertThat(op.perform(), is("123"));
|
||||||
op.perform(),
|
|
||||||
is("123")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,26 +23,27 @@
|
|||||||
|
|
||||||
package com.iluwatar.retry;
|
package com.iluwatar.retry;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
import static org.hamcrest.CoreMatchers.hasItem;
|
import static org.hamcrest.CoreMatchers.hasItem;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link Retry}.
|
* Unit tests for {@link Retry}.
|
||||||
*
|
*
|
||||||
* @author George Aristy (george.aristy@gmail.com)
|
* @author George Aristy (george.aristy@gmail.com)
|
||||||
*/
|
*/
|
||||||
public class RetryExponentialBackoffTest {
|
public class RetryExponentialBackoffTest {
|
||||||
/**
|
/**
|
||||||
* Should contain all errors thrown.
|
* Should contain all errors thrown.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void errors() throws Exception {
|
public void errors() {
|
||||||
final BusinessException e = new BusinessException("unhandled");
|
final var e = new BusinessException("unhandled");
|
||||||
final RetryExponentialBackoff<String> retry = new RetryExponentialBackoff<>(
|
final var retry = new RetryExponentialBackoff<String>(
|
||||||
() -> {
|
() -> {
|
||||||
throw e;
|
throw e;
|
||||||
},
|
},
|
||||||
2,
|
2,
|
||||||
0
|
0
|
||||||
@ -53,22 +54,19 @@ public class RetryExponentialBackoffTest {
|
|||||||
//ignore
|
//ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(
|
assertThat(retry.errors(), hasItem(e));
|
||||||
retry.errors(),
|
|
||||||
hasItem(e)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* No exceptions will be ignored, hence final number of attempts should be 1 even if we're asking
|
* No exceptions will be ignored, hence final number of attempts should be 1 even if we're asking
|
||||||
* it to attempt twice.
|
* it to attempt twice.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void attempts() {
|
public void attempts() {
|
||||||
final BusinessException e = new BusinessException("unhandled");
|
final var e = new BusinessException("unhandled");
|
||||||
final RetryExponentialBackoff<String> retry = new RetryExponentialBackoff<>(
|
final var retry = new RetryExponentialBackoff<String>(
|
||||||
() -> {
|
() -> {
|
||||||
throw e;
|
throw e;
|
||||||
},
|
},
|
||||||
2,
|
2,
|
||||||
0
|
0
|
||||||
@ -79,22 +77,19 @@ public class RetryExponentialBackoffTest {
|
|||||||
//ignore
|
//ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(
|
assertThat(retry.attempts(), is(1));
|
||||||
retry.attempts(),
|
|
||||||
is(1)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Final number of attempts should be equal to the number of attempts asked because we are
|
* Final number of attempts should be equal to the number of attempts asked because we are asking
|
||||||
* asking it to ignore the exception that will be thrown.
|
* it to ignore the exception that will be thrown.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void ignore() throws Exception {
|
public void ignore() {
|
||||||
final BusinessException e = new CustomerNotFoundException("customer not found");
|
final var e = new CustomerNotFoundException("customer not found");
|
||||||
final RetryExponentialBackoff<String> retry = new RetryExponentialBackoff<>(
|
final var retry = new RetryExponentialBackoff<String>(
|
||||||
() -> {
|
() -> {
|
||||||
throw e;
|
throw e;
|
||||||
},
|
},
|
||||||
2,
|
2,
|
||||||
0,
|
0,
|
||||||
@ -106,9 +101,6 @@ public class RetryExponentialBackoffTest {
|
|||||||
//ignore
|
//ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(
|
assertThat(retry.attempts(), is(2));
|
||||||
retry.attempts(),
|
|
||||||
is(2)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,12 +23,12 @@
|
|||||||
|
|
||||||
package com.iluwatar.retry;
|
package com.iluwatar.retry;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.hasItem;
|
import static org.hamcrest.CoreMatchers.hasItem;
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link Retry}.
|
* Unit tests for {@link Retry}.
|
||||||
*
|
*
|
||||||
@ -40,10 +40,11 @@ public class RetryTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void errors() {
|
public void errors() {
|
||||||
final BusinessException e = new BusinessException("unhandled");
|
final var e = new BusinessException("unhandled");
|
||||||
final Retry<String> retry = new Retry<>(
|
final var retry = new Retry<String>(
|
||||||
() -> {
|
() -> {
|
||||||
throw e; },
|
throw e;
|
||||||
|
},
|
||||||
2,
|
2,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
@ -53,10 +54,7 @@ public class RetryTest {
|
|||||||
//ignore
|
//ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(
|
assertThat(retry.errors(), hasItem(e));
|
||||||
retry.errors(),
|
|
||||||
hasItem(e)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,10 +63,11 @@ public class RetryTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void attempts() {
|
public void attempts() {
|
||||||
final BusinessException e = new BusinessException("unhandled");
|
final var e = new BusinessException("unhandled");
|
||||||
final Retry<String> retry = new Retry<>(
|
final var retry = new Retry<String>(
|
||||||
() -> {
|
() -> {
|
||||||
throw e; },
|
throw e;
|
||||||
|
},
|
||||||
2,
|
2,
|
||||||
0
|
0
|
||||||
);
|
);
|
||||||
@ -78,22 +77,20 @@ public class RetryTest {
|
|||||||
//ignore
|
//ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(
|
assertThat(retry.attempts(), is(1));
|
||||||
retry.attempts(),
|
|
||||||
is(1)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Final number of attempts should be equal to the number of attempts asked because we are
|
* Final number of attempts should be equal to the number of attempts asked because we are asking
|
||||||
* asking it to ignore the exception that will be thrown.
|
* it to ignore the exception that will be thrown.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void ignore() throws Exception {
|
public void ignore() {
|
||||||
final BusinessException e = new CustomerNotFoundException("customer not found");
|
final var e = new CustomerNotFoundException("customer not found");
|
||||||
final Retry<String> retry = new Retry<>(
|
final var retry = new Retry<String>(
|
||||||
() -> {
|
() -> {
|
||||||
throw e; },
|
throw e;
|
||||||
|
},
|
||||||
2,
|
2,
|
||||||
0,
|
0,
|
||||||
ex -> CustomerNotFoundException.class.isAssignableFrom(ex.getClass())
|
ex -> CustomerNotFoundException.class.isAssignableFrom(ex.getClass())
|
||||||
@ -104,10 +101,7 @@ public class RetryTest {
|
|||||||
//ignore
|
//ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
assertThat(
|
assertThat(retry.attempts(), is(2));
|
||||||
retry.attempts(),
|
|
||||||
is(2)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -30,37 +30,31 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Role Object pattern suggests to model context-specific views
|
* The Role Object pattern suggests to model context-specific views of an object as separate role
|
||||||
* of an object as separate role objects which are
|
* objects which are dynamically attached to and removed from the core object. We call the resulting
|
||||||
* dynamically attached to and removed from the core object.
|
* composite object structure, consisting of the core and its role objects, a subject. A subject
|
||||||
* We call the resulting composite object structure,
|
* often plays several roles and the same role is likely to be played by different subjects. As an
|
||||||
* consisting of the core and its role objects, a subject.
|
* example consider two different customers playing the role of borrower and investor, respectively.
|
||||||
* A subject often plays several roles and the same role is likely to
|
* Both roles could as well be played by a single {@link Customer} object. The common superclass for
|
||||||
* be played by different subjects.
|
* customer-specific roles is provided by {@link CustomerRole}, which also supports the {@link
|
||||||
* As an example consider two different customers playing the role of borrower and
|
* Customer} interface.
|
||||||
* investor, respectively. Both roles could as well be played by a single {@link Customer} object.
|
|
||||||
* The common superclass for customer-specific roles is provided by {@link CustomerRole},
|
|
||||||
* which also supports the {@link Customer} interface.
|
|
||||||
*
|
*
|
||||||
* <p>The {@link CustomerRole} class is abstract and not meant to be instantiated.
|
* <p>The {@link CustomerRole} class is abstract and not meant to be instantiated.
|
||||||
* Concrete subclasses of {@link CustomerRole}, for example {@link BorrowerRole}
|
* Concrete subclasses of {@link CustomerRole}, for example {@link BorrowerRole} or {@link
|
||||||
* or {@link InvestorRole}, define and implement the interface for specific roles. It is only
|
* InvestorRole}, define and implement the interface for specific roles. It is only these subclasses
|
||||||
* these subclasses which are instantiated at runtime.
|
* which are instantiated at runtime. The {@link BorrowerRole} class defines the context-specific
|
||||||
* The {@link BorrowerRole} class defines the context-specific view of {@link Customer}
|
* view of {@link Customer} objects as needed by the loan department. It defines additional
|
||||||
* objects as needed by the loan department.
|
* operations to manage the customer’s credits and securities. Similarly, the {@link InvestorRole}
|
||||||
* It defines additional operations to manage the customer’s
|
* class adds operations specific to the investment department’s view of customers. A client like
|
||||||
* credits and securities. Similarly, the {@link InvestorRole} class adds operations specific
|
* the loan application may either work with objects of the {@link CustomerRole} class, using the
|
||||||
* to the investment department’s view of customers.
|
* interface class {@link Customer}, or with objects of concrete {@link CustomerRole} subclasses.
|
||||||
* A client like the loan application may either work with objects of the {@link CustomerRole}
|
* Suppose the loan application knows a particular {@link Customer} instance through its {@link
|
||||||
* class, using the interface class {@link Customer}, or with objects of concrete
|
* Customer} interface. The loan application may want to check whether the {@link Customer} object
|
||||||
* {@link CustomerRole} subclasses. Suppose the loan application knows a particular
|
* plays the role of Borrower. To this end it calls {@link Customer#hasRole(Role)} with a suitable
|
||||||
* {@link Customer} instance through its {@link Customer} interface. The loan application
|
* role specification. For the purpose of our example, let’s assume we can name roles with enum. If
|
||||||
* may want to check whether the {@link Customer} object plays the role of Borrower.
|
* the {@link Customer} object can play the role named “Borrower,” the loan application will ask it
|
||||||
* To this end it calls {@link Customer#hasRole(Role)} with a suitable role specification. For
|
* to return a reference to the corresponding object. The loan application may now use this
|
||||||
* the purpose of our example, let’s assume we can name roles with enum.
|
* reference to call Borrower-specific operations.
|
||||||
* If the {@link Customer} object can play the role named “Borrower,” the loan application will
|
|
||||||
* ask it to return a reference to the corresponding object.
|
|
||||||
* The loan application may now use this reference to call Borrower-specific operations.
|
|
||||||
*/
|
*/
|
||||||
public class ApplicationRoleObject {
|
public class ApplicationRoleObject {
|
||||||
|
|
||||||
@ -72,13 +66,13 @@ public class ApplicationRoleObject {
|
|||||||
* @param args program arguments
|
* @param args program arguments
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
Customer customer = Customer.newCustomer(Borrower, Investor);
|
var customer = Customer.newCustomer(Borrower, Investor);
|
||||||
|
|
||||||
logger.info(" the new customer created : {}", customer);
|
logger.info(" the new customer created : {}", customer);
|
||||||
|
|
||||||
boolean hasBorrowerRole = customer.hasRole(Borrower);
|
var hasBorrowerRole = customer.hasRole(Borrower);
|
||||||
logger.info(" customer has a borrowed role - {}", hasBorrowerRole);
|
logger.info(" customer has a borrowed role - {}", hasBorrowerRole);
|
||||||
boolean hasInvestorRole = customer.hasRole(Investor);
|
var hasInvestorRole = customer.hasRole(Investor);
|
||||||
logger.info(" customer has an investor role - {}", hasInvestorRole);
|
logger.info(" customer has an investor role - {}", hasInvestorRole);
|
||||||
|
|
||||||
customer.getRole(Investor, InvestorRole.class)
|
customer.getRole(Investor, InvestorRole.class)
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
package com.iluwatar.roleobject;
|
package com.iluwatar.roleobject;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,6 +33,7 @@ public abstract class Customer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Add specific role @see {@link Role}.
|
* Add specific role @see {@link Role}.
|
||||||
|
*
|
||||||
* @param role to add
|
* @param role to add
|
||||||
* @return true if the operation has been successful otherwise false
|
* @return true if the operation has been successful otherwise false
|
||||||
*/
|
*/
|
||||||
@ -39,6 +41,7 @@ public abstract class Customer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check specific role @see {@link Role}.
|
* Check specific role @see {@link Role}.
|
||||||
|
*
|
||||||
* @param role to check
|
* @param role to check
|
||||||
* @return true if the role exists otherwise false
|
* @return true if the role exists otherwise false
|
||||||
*/
|
*/
|
||||||
@ -47,6 +50,7 @@ public abstract class Customer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove specific role @see {@link Role}.
|
* Remove specific role @see {@link Role}.
|
||||||
|
*
|
||||||
* @param role to remove
|
* @param role to remove
|
||||||
* @return true if the operation has been successful otherwise false
|
* @return true if the operation has been successful otherwise false
|
||||||
*/
|
*/
|
||||||
@ -54,6 +58,7 @@ public abstract class Customer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get specific instance associated with this role @see {@link Role}.
|
* Get specific instance associated with this role @see {@link Role}.
|
||||||
|
*
|
||||||
* @param role to get
|
* @param role to get
|
||||||
* @param expectedRole instance class expected to get
|
* @param expectedRole instance class expected to get
|
||||||
* @return optional with value if the instance exists and corresponds expected class
|
* @return optional with value if the instance exists and corresponds expected class
|
||||||
@ -67,14 +72,13 @@ public abstract class Customer {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create {@link Customer} with given roles.
|
* Create {@link Customer} with given roles.
|
||||||
|
*
|
||||||
* @param role roles
|
* @param role roles
|
||||||
* @return Customer
|
* @return Customer
|
||||||
*/
|
*/
|
||||||
public static Customer newCustomer(Role... role) {
|
public static Customer newCustomer(Role... role) {
|
||||||
Customer customer = newCustomer();
|
var customer = newCustomer();
|
||||||
for (Role r : role) {
|
Arrays.stream(role).forEach(customer::addRole);
|
||||||
customer.addRole(r);
|
|
||||||
}
|
|
||||||
return customer;
|
return customer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ public class CustomerCore extends Customer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
String roles = Arrays.toString(this.roles.keySet().toArray());
|
var roles = Arrays.toString(this.roles.keySet().toArray());
|
||||||
return "Customer{roles=" + roles + "}";
|
return "Customer{roles=" + roles + "}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,5 +26,5 @@ package com.iluwatar.roleobject;
|
|||||||
/**
|
/**
|
||||||
* Key abstraction for segregated roles.
|
* Key abstraction for segregated roles.
|
||||||
*/
|
*/
|
||||||
public abstract class CustomerRole extends CustomerCore{
|
public abstract class CustomerRole extends CustomerCore {
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
package com.iluwatar.roleobject;
|
package com.iluwatar.roleobject;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -48,7 +47,7 @@ public enum Role {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T extends CustomerRole> Optional<T> instance() {
|
public <T extends CustomerRole> Optional<T> instance() {
|
||||||
Class<? extends CustomerRole> typeCst = this.typeCst;
|
var typeCst = this.typeCst;
|
||||||
try {
|
try {
|
||||||
return (Optional<T>) Optional.of(typeCst.newInstance());
|
return (Optional<T>) Optional.of(typeCst.newInstance());
|
||||||
} catch (InstantiationException | IllegalAccessException e) {
|
} catch (InstantiationException | IllegalAccessException e) {
|
||||||
|
@ -26,8 +26,8 @@ import org.junit.Test;
|
|||||||
|
|
||||||
public class ApplicationRoleObjectTest {
|
public class ApplicationRoleObjectTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void mainTest() {
|
public void mainTest() {
|
||||||
ApplicationRoleObject.main(new String[]{});
|
ApplicationRoleObject.main(new String[]{});
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -25,16 +25,12 @@ package com.iluwatar.roleobject;
|
|||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
public class BorrowerRoleTest {
|
public class BorrowerRoleTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void borrowTest() {
|
public void borrowTest() {
|
||||||
BorrowerRole borrowerRole = new BorrowerRole();
|
var borrowerRole = new BorrowerRole();
|
||||||
borrowerRole.setName("test");
|
borrowerRole.setName("test");
|
||||||
String res = "Borrower test wants to get some money.";
|
Assert.assertEquals(borrowerRole.borrow(), "Borrower test wants to get some money.");
|
||||||
|
}
|
||||||
Assert.assertEquals(borrowerRole.borrow(),res);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -22,82 +22,72 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.roleobject;
|
package com.iluwatar.roleobject;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
public class CustomerCoreTest {
|
public class CustomerCoreTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void addRole() {
|
public void addRole() {
|
||||||
CustomerCore core = new CustomerCore();
|
var core = new CustomerCore();
|
||||||
boolean add = core.addRole(Role.Borrower);
|
assertTrue(core.addRole(Role.Borrower));
|
||||||
assertTrue(add);
|
}
|
||||||
|
|
||||||
}
|
@Test
|
||||||
|
public void hasRole() {
|
||||||
|
var core = new CustomerCore();
|
||||||
|
core.addRole(Role.Borrower);
|
||||||
|
assertTrue(core.hasRole(Role.Borrower));
|
||||||
|
assertFalse(core.hasRole(Role.Investor));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void hasRole() {
|
public void remRole() {
|
||||||
CustomerCore core = new CustomerCore();
|
var core = new CustomerCore();
|
||||||
core.addRole(Role.Borrower);
|
core.addRole(Role.Borrower);
|
||||||
|
|
||||||
boolean has = core.hasRole(Role.Borrower);
|
var bRole = core.getRole(Role.Borrower, BorrowerRole.class);
|
||||||
assertTrue(has);
|
assertTrue(bRole.isPresent());
|
||||||
|
|
||||||
boolean notHas = core.hasRole(Role.Investor);
|
assertTrue(core.remRole(Role.Borrower));
|
||||||
assertFalse(notHas);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
var empt = core.getRole(Role.Borrower, BorrowerRole.class);
|
||||||
public void remRole() {
|
assertFalse(empt.isPresent());
|
||||||
CustomerCore core = new CustomerCore();
|
}
|
||||||
core.addRole(Role.Borrower);
|
|
||||||
|
|
||||||
Optional<BorrowerRole> bRole = core.getRole(Role.Borrower, BorrowerRole.class);
|
@Test
|
||||||
assertTrue(bRole.isPresent());
|
public void getRole() {
|
||||||
|
var core = new CustomerCore();
|
||||||
|
core.addRole(Role.Borrower);
|
||||||
|
|
||||||
boolean res = core.remRole(Role.Borrower);
|
var bRole = core.getRole(Role.Borrower, BorrowerRole.class);
|
||||||
assertTrue(res);
|
assertTrue(bRole.isPresent());
|
||||||
|
|
||||||
Optional<BorrowerRole> empt = core.getRole(Role.Borrower, BorrowerRole.class);
|
var nonRole = core.getRole(Role.Borrower, InvestorRole.class);
|
||||||
assertFalse(empt.isPresent());
|
assertFalse(nonRole.isPresent());
|
||||||
|
|
||||||
}
|
var invRole = core.getRole(Role.Investor, InvestorRole.class);
|
||||||
|
assertFalse(invRole.isPresent());
|
||||||
@Test
|
}
|
||||||
public void getRole() {
|
|
||||||
CustomerCore core = new CustomerCore();
|
|
||||||
core.addRole(Role.Borrower);
|
|
||||||
|
|
||||||
Optional<BorrowerRole> bRole = core.getRole(Role.Borrower, BorrowerRole.class);
|
|
||||||
assertTrue(bRole.isPresent());
|
|
||||||
|
|
||||||
Optional<InvestorRole> nonRole = core.getRole(Role.Borrower, InvestorRole.class);
|
|
||||||
assertFalse(nonRole.isPresent());
|
|
||||||
|
|
||||||
Optional<InvestorRole> invRole = core.getRole(Role.Investor, InvestorRole.class);
|
|
||||||
assertFalse(invRole.isPresent());
|
|
||||||
|
|
||||||
|
|
||||||
}
|
@Test
|
||||||
|
public void toStringTest() {
|
||||||
|
var core = new CustomerCore();
|
||||||
|
core.addRole(Role.Borrower);
|
||||||
|
assertEquals(core.toString(), "Customer{roles=[Borrower]}");
|
||||||
|
|
||||||
|
core = new CustomerCore();
|
||||||
|
core.addRole(Role.Investor);
|
||||||
|
assertEquals(core.toString(), "Customer{roles=[Investor]}");
|
||||||
|
|
||||||
|
core = new CustomerCore();
|
||||||
|
assertEquals(core.toString(), "Customer{roles=[]}");
|
||||||
|
|
||||||
|
|
||||||
@Test
|
}
|
||||||
public void toStringTest() {
|
|
||||||
CustomerCore core = new CustomerCore();
|
|
||||||
core.addRole(Role.Borrower);
|
|
||||||
assertEquals(core.toString(), "Customer{roles=[Borrower]}");
|
|
||||||
|
|
||||||
core = new CustomerCore();
|
|
||||||
core.addRole(Role.Investor);
|
|
||||||
assertEquals(core.toString(), "Customer{roles=[Investor]}");
|
|
||||||
|
|
||||||
core = new CustomerCore();
|
|
||||||
assertEquals(core.toString(), "Customer{roles=[]}");
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -27,12 +27,11 @@ import org.junit.Test;
|
|||||||
|
|
||||||
public class InvestorRoleTest {
|
public class InvestorRoleTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void investTest() {
|
public void investTest() {
|
||||||
InvestorRole investorRole = new InvestorRole();
|
var investorRole = new InvestorRole();
|
||||||
investorRole.setName("test");
|
investorRole.setName("test");
|
||||||
investorRole.setAmountToInvest(10);
|
investorRole.setAmountToInvest(10);
|
||||||
String res = "Investor test has invested 10 dollars";
|
Assert.assertEquals(investorRole.invest(), "Investor test has invested 10 dollars");
|
||||||
Assert.assertEquals(investorRole.invest(), res);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@ -25,16 +25,12 @@ package com.iluwatar.roleobject;
|
|||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
public class RoleTest {
|
public class RoleTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void instanceTest() {
|
public void instanceTest() {
|
||||||
Optional<CustomerRole> instance = Role.Borrower.instance();
|
var instance = Role.Borrower.instance();
|
||||||
Assert.assertTrue(instance.isPresent());
|
Assert.assertTrue(instance.isPresent());
|
||||||
Assert.assertEquals(instance.get().getClass(),BorrowerRole.class);
|
Assert.assertEquals(instance.get().getClass(), BorrowerRole.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user