@@ -89,7 +85,6 @@ import com.iluwatar.reactor.framework.ThreadPoolDispatcher;
* separate thread for each client, which provides better scalability under load (number of clients
* increase).
* The example uses Java NIO framework to implement the Reactor.
- *
*/
public class App {
@@ -100,7 +95,7 @@ public class App {
/**
* Creates an instance of App which will use provided dispatcher for dispatching events on
* reactor.
- *
+ *
* @param dispatcher the dispatcher that will be used to dispatch events.
*/
public App(Dispatcher dispatcher) {
@@ -142,9 +137,9 @@ public class App {
/**
* Stops the NIO reactor. This is a blocking call.
- *
+ *
* @throws InterruptedException if interrupted while stopping the reactor.
- * @throws IOException if any I/O error occurs
+ * @throws IOException if any I/O error occurs
*/
public void stop() throws InterruptedException, IOException {
reactor.stop();
diff --git a/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java b/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java
index 75db3079b..a15437396 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java
@@ -23,9 +23,6 @@
package com.iluwatar.reactor.app;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -39,6 +36,8 @@ import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Represents the clients of Reactor pattern. Multiple clients are run concurrently and send logging
@@ -158,7 +157,7 @@ public class AppClient {
* Creates a new UDP logging client.
*
* @param clientName the name of the client to be sent in logging requests.
- * @param port the port on which client will send logging requests.
+ * @param port the port on which client will send logging requests.
* @throws UnknownHostException if localhost is unknown
*/
public UdpLoggingClient(String clientName, int port) throws UnknownHostException {
diff --git a/reactor/src/main/java/com/iluwatar/reactor/app/LoggingHandler.java b/reactor/src/main/java/com/iluwatar/reactor/app/LoggingHandler.java
index f0de033be..edf7e26fd 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/app/LoggingHandler.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/app/LoggingHandler.java
@@ -23,12 +23,11 @@
package com.iluwatar.reactor.app;
-import java.nio.ByteBuffer;
-import java.nio.channels.SelectionKey;
-
import com.iluwatar.reactor.framework.AbstractNioChannel;
import com.iluwatar.reactor.framework.ChannelHandler;
import com.iluwatar.reactor.framework.NioDatagramChannel.DatagramPacket;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -63,7 +62,11 @@ public class LoggingHandler implements ChannelHandler {
}
}
- private static void sendReply(AbstractNioChannel channel, DatagramPacket incomingPacket, SelectionKey key) {
+ private static void sendReply(
+ AbstractNioChannel channel,
+ DatagramPacket incomingPacket,
+ SelectionKey key
+ ) {
/*
* Create a reply acknowledgement datagram packet setting the receiver to the sender of incoming
* message.
diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/AbstractNioChannel.java b/reactor/src/main/java/com/iluwatar/reactor/framework/AbstractNioChannel.java
index dd0572aef..6b356d021 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/framework/AbstractNioChannel.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/framework/AbstractNioChannel.java
@@ -35,13 +35,12 @@ import java.util.concurrent.ConcurrentLinkedQueue;
/**
* This represents the Handle of Reactor pattern. These are resources managed by OS which can
* be submitted to {@link NioReactor}.
- *
- *
- * This class serves has the responsibility of reading the data when a read event occurs and writing
- * the data back when the channel is writable. It leaves the reading and writing of data on the
- * concrete implementation. It provides a block writing mechanism wherein when any
- * {@link ChannelHandler} wants to write data back, it queues the data in pending write queue and
- * clears it in block manner. This provides better throughput.
+ *
+ *
This class serves has the responsibility of reading the data when a read event occurs and
+ * writing the data back when the channel is writable. It leaves the reading and writing of data on
+ * the concrete implementation. It provides a block writing mechanism wherein when any {@link
+ * ChannelHandler} wants to write data back, it queues the data in pending write queue and clears it
+ * in block manner. This provides better throughput.
*/
public abstract class AbstractNioChannel {
@@ -53,7 +52,7 @@ public abstract class AbstractNioChannel {
/**
* Creates a new channel.
- *
+ *
* @param handler which will handle events occurring on this channel.
* @param channel a NIO channel to be wrapped.
*/
@@ -70,6 +69,8 @@ public abstract class AbstractNioChannel {
}
/**
+ * Get channel.
+ *
* @return the wrapped NIO channel.
*/
public SelectableChannel getJavaChannel() {
@@ -77,9 +78,9 @@ public abstract class AbstractNioChannel {
}
/**
- * The operation in which the channel is interested, this operation is provided to
- * {@link Selector}.
- *
+ * The operation in which the channel is interested, this operation is provided to {@link
+ * Selector}.
+ *
* @return interested operation.
* @see SelectionKey
*/
@@ -87,7 +88,7 @@ public abstract class AbstractNioChannel {
/**
* Binds the channel on provided port.
- *
+ *
* @throws IOException if any I/O error occurs.
*/
public abstract void bind() throws IOException;
@@ -95,7 +96,7 @@ public abstract class AbstractNioChannel {
/**
* Reads the data using the key and returns the read data. The underlying channel should be
* fetched using {@link SelectionKey#channel()}.
- *
+ *
* @param key the key on which read event occurred.
* @return data read.
* @throws IOException if any I/O error occurs.
@@ -103,6 +104,8 @@ public abstract class AbstractNioChannel {
public abstract Object read(SelectionKey key) throws IOException;
/**
+ * Get handler.
+ *
* @return the handler associated with this channel.
*/
public ChannelHandler getHandler() {
@@ -130,9 +133,9 @@ public abstract class AbstractNioChannel {
/**
* Writes the data to the channel.
- *
+ *
* @param pendingWrite the data to be written on channel.
- * @param key the key which is writable.
+ * @param key the key which is writable.
* @throws IOException if any I/O error occurs.
*/
protected abstract void doWrite(Object pendingWrite, SelectionKey key) throws IOException;
@@ -140,24 +143,23 @@ public abstract class AbstractNioChannel {
/**
* Queues the data for writing. The data is not guaranteed to be written on underlying channel
* when this method returns. It will be written when the channel is flushed.
- *
- *
- * This method is used by the {@link ChannelHandler} to send reply back to the client.
+ *
+ *
This method is used by the {@link ChannelHandler} to send reply back to the client.
* Example:
- *
+ *
*
pendingWrites = this.channelToPendingWrites.get(key.channel());
diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/ChannelHandler.java b/reactor/src/main/java/com/iluwatar/reactor/framework/ChannelHandler.java
index e7204a550..5bd145a38 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/framework/ChannelHandler.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/framework/ChannelHandler.java
@@ -28,19 +28,19 @@ import java.nio.channels.SelectionKey;
/**
* Represents the EventHandler of Reactor pattern. It handles the incoming events dispatched
* to it by the {@link Dispatcher}. This is where the application logic resides.
- *
- *
- * A {@link ChannelHandler} can be associated with one or many {@link AbstractNioChannel}s, and
- * whenever an event occurs on any of the associated channels, the handler is notified of the event.
+ *
+ *
A {@link ChannelHandler} can be associated with one or many {@link AbstractNioChannel}s, and
+ * whenever an event occurs on any of the associated channels, the handler is notified of the
+ * event.
*/
public interface ChannelHandler {
/**
* Called when the {@code channel} receives some data from remote peer.
- *
- * @param channel the channel from which the data was received.
+ *
+ * @param channel the channel from which the data was received.
* @param readObject the data read.
- * @param key the key on which read event occurred.
+ * @param key the key on which read event occurred.
*/
void handleChannelRead(AbstractNioChannel channel, Object readObject, SelectionKey key);
}
diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/Dispatcher.java b/reactor/src/main/java/com/iluwatar/reactor/framework/Dispatcher.java
index 17ccb2ef8..0a2db2ca8 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/framework/Dispatcher.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/framework/Dispatcher.java
@@ -29,14 +29,12 @@ import java.nio.channels.SelectionKey;
* Represents the event dispatching strategy. When {@link NioReactor} senses any event on the
* registered {@link AbstractNioChannel}s then it de-multiplexes the event type, read or write or
* connect, and then calls the {@link Dispatcher} to dispatch the read events. This decouples the
- * I/O processing from application specific processing.
- * Dispatcher should call the {@link ChannelHandler} associated with the channel on which event
- * occurred.
- *
- *
- * The application can customize the way in which event is dispatched such as using the reactor
+ * I/O processing from application specific processing. Dispatcher should call the {@link
+ * ChannelHandler} associated with the channel on which event occurred.
+ *
+ *
The application can customize the way in which event is dispatched such as using the reactor
* thread to dispatch event to channels or use a worker pool to do the non I/O processing.
- *
+ *
* @see SameThreadDispatcher
* @see ThreadPoolDispatcher
*/
@@ -45,19 +43,18 @@ public interface Dispatcher {
* This hook method is called when read event occurs on particular channel. The data read is
* provided in readObject
. The implementation should dispatch this read event to the
* associated {@link ChannelHandler} of channel
.
- *
- *
- * The type of readObject
depends on the channel on which data was received.
- *
- * @param channel on which read event occurred
+ *
+ *
The type of readObject
depends on the channel on which data was received.
+ *
+ * @param channel on which read event occurred
* @param readObject object read by channel
- * @param key on which event occurred
+ * @param key on which event occurred
*/
void onChannelReadEvent(AbstractNioChannel channel, Object readObject, SelectionKey key);
/**
* Stops dispatching events and cleans up any acquired resources such as threads.
- *
+ *
* @throws InterruptedException if interrupted while stopping dispatcher.
*/
void stop() throws InterruptedException;
diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/NioDatagramChannel.java b/reactor/src/main/java/com/iluwatar/reactor/framework/NioDatagramChannel.java
index f62e46e72..ba4b68231 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/framework/NioDatagramChannel.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/framework/NioDatagramChannel.java
@@ -23,9 +23,6 @@
package com.iluwatar.reactor.framework;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -33,6 +30,8 @@ import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* A wrapper over {@link DatagramChannel} which can read and write data on a DatagramChannel.
@@ -46,11 +45,11 @@ public class NioDatagramChannel extends AbstractNioChannel {
/**
* Creates a {@link DatagramChannel} which will bind at provided port and use handler
* to handle incoming events on this channel.
- *
- * Note the constructor does not bind the socket, {@link #bind()} method should be called for
+ *
+ *
Note the constructor does not bind the socket, {@link #bind()} method should be called for
* binding the socket.
- *
- * @param port the port to be bound to listen for incoming datagram requests.
+ *
+ * @param port the port to be bound to listen for incoming datagram requests.
* @param handler the handler to be used for handling incoming requests on this channel.
* @throws IOException if any I/O error occurs.
*/
@@ -69,7 +68,7 @@ public class NioDatagramChannel extends AbstractNioChannel {
/**
* Reads and returns a {@link DatagramPacket} from the underlying channel.
- *
+ *
* @return the datagram packet read having the sender address.
*/
@Override
@@ -89,6 +88,8 @@ public class NioDatagramChannel extends AbstractNioChannel {
}
/**
+ * Get datagram channel.
+ *
* @return the underlying datagram channel.
*/
@Override
@@ -98,7 +99,7 @@ public class NioDatagramChannel extends AbstractNioChannel {
/**
* Binds UDP socket on the provided port
.
- *
+ *
* @throws IOException if any I/O error occurs.
*/
@Override
@@ -120,8 +121,8 @@ public class NioDatagramChannel extends AbstractNioChannel {
/**
* Writes the outgoing {@link DatagramPacket} to the channel. The intended receiver of the
- * datagram packet must be set in the data
using
- * {@link DatagramPacket#setReceiver(SocketAddress)}.
+ * datagram packet must be set in the data
using {@link
+ * DatagramPacket#setReceiver(SocketAddress)}.
*/
@Override
public void write(Object data, SelectionKey key) {
@@ -138,7 +139,7 @@ public class NioDatagramChannel extends AbstractNioChannel {
/**
* Creates a container with underlying data.
- *
+ *
* @param data the underlying message to be written on channel.
*/
public DatagramPacket(ByteBuffer data) {
@@ -146,6 +147,8 @@ public class NioDatagramChannel extends AbstractNioChannel {
}
/**
+ * Get sender address.
+ *
* @return the sender address.
*/
public SocketAddress getSender() {
@@ -154,7 +157,7 @@ public class NioDatagramChannel extends AbstractNioChannel {
/**
* Sets the sender address of this packet.
- *
+ *
* @param sender the sender address.
*/
public void setSender(SocketAddress sender) {
@@ -162,6 +165,8 @@ public class NioDatagramChannel extends AbstractNioChannel {
}
/**
+ * Get receiver address.
+ *
* @return the receiver address.
*/
public SocketAddress getReceiver() {
@@ -170,7 +175,7 @@ public class NioDatagramChannel extends AbstractNioChannel {
/**
* Sets the intended receiver address. This must be set when writing to the channel.
- *
+ *
* @param receiver the receiver address.
*/
public void setReceiver(SocketAddress receiver) {
@@ -178,6 +183,8 @@ public class NioDatagramChannel extends AbstractNioChannel {
}
/**
+ * Get data.
+ *
* @return the underlying message that will be written on channel.
*/
public ByteBuffer getData() {
diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java b/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java
index 9c71ed80e..becf1fd2d 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java
@@ -23,9 +23,6 @@
package com.iluwatar.reactor.framework;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
@@ -38,22 +35,23 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
- * This class acts as Synchronous Event De-multiplexer and Initiation Dispatcher of Reactor pattern. Multiple handles
- * i.e. {@link AbstractNioChannel}s can be registered to the reactor and it blocks for events from all these handles.
- * Whenever an event occurs on any of the registered handles, it synchronously de-multiplexes the event which can be any
- * of read, write or accept, and dispatches the event to the appropriate {@link ChannelHandler} using the
- * {@link Dispatcher}.
- *
- *
- * Implementation: A NIO reactor runs in its own thread when it is started using {@link #start()} method.
- * {@link NioReactor} uses {@link Selector} for realizing Synchronous Event De-multiplexing.
- *
- *
- * NOTE: This is one of the ways to implement NIO reactor and it does not take care of all possible edge cases which are
- * required in a real application. This implementation is meant to demonstrate the fundamental concepts that lie behind
- * Reactor pattern.
+ * This class acts as Synchronous Event De-multiplexer and Initiation Dispatcher of Reactor pattern.
+ * Multiple handles i.e. {@link AbstractNioChannel}s can be registered to the reactor and it blocks
+ * for events from all these handles. Whenever an event occurs on any of the registered handles, it
+ * synchronously de-multiplexes the event which can be any of read, write or accept, and dispatches
+ * the event to the appropriate {@link ChannelHandler} using the {@link Dispatcher}.
+ *
+ *
Implementation: A NIO reactor runs in its own thread when it is started using {@link
+ * #start()} method. {@link NioReactor} uses {@link Selector} for realizing Synchronous Event
+ * De-multiplexing.
+ *
+ *
NOTE: This is one of the ways to implement NIO reactor and it does not take care of all
+ * possible edge cases which are required in a real application. This implementation is meant to
+ * demonstrate the fundamental concepts that lie behind Reactor pattern.
*/
public class NioReactor {
@@ -62,21 +60,20 @@ public class NioReactor {
private final Selector selector;
private final Dispatcher dispatcher;
/**
- * All the work of altering the SelectionKey operations and Selector operations are performed in the context of main
- * event loop of reactor. So when any channel needs to change its readability or writability, a new command is added
- * in the command queue and then the event loop picks up the command and executes it in next iteration.
+ * All the work of altering the SelectionKey operations and Selector operations are performed in
+ * the context of main event loop of reactor. So when any channel needs to change its readability
+ * or writability, a new command is added in the command queue and then the event loop picks up
+ * the command and executes it in next iteration.
*/
private final Queue pendingCommands = new ConcurrentLinkedQueue<>();
private final ExecutorService reactorMain = Executors.newSingleThreadExecutor();
/**
- * Creates a reactor which will use provided {@code dispatcher} to dispatch events. The application can provide
- * various implementations of dispatcher which suits its needs.
- *
- * @param dispatcher
- * a non-null dispatcher used to dispatch events on registered channels.
- * @throws IOException
- * if any I/O error occurs.
+ * Creates a reactor which will use provided {@code dispatcher} to dispatch events. The
+ * application can provide various implementations of dispatcher which suits its needs.
+ *
+ * @param dispatcher a non-null dispatcher used to dispatch events on registered channels.
+ * @throws IOException if any I/O error occurs.
*/
public NioReactor(Dispatcher dispatcher) throws IOException {
this.dispatcher = dispatcher;
@@ -99,11 +96,9 @@ public class NioReactor {
/**
* Stops the reactor and related resources such as dispatcher.
- *
- * @throws InterruptedException
- * if interrupted while stopping the reactor.
- * @throws IOException
- * if any I/O error occurs.
+ *
+ * @throws InterruptedException if interrupted while stopping the reactor.
+ * @throws IOException if any I/O error occurs.
*/
public void stop() throws InterruptedException, IOException {
reactorMain.shutdownNow();
@@ -114,15 +109,14 @@ public class NioReactor {
}
/**
- * Registers a new channel (handle) with this reactor. Reactor will start waiting for events on this channel and
- * notify of any events. While registering the channel the reactor uses {@link AbstractNioChannel#getInterestedOps()}
- * to know about the interested operation of this channel.
- *
- * @param channel
- * a new channel on which reactor will wait for events. The channel must be bound prior to being registered.
+ * Registers a new channel (handle) with this reactor. Reactor will start waiting for events on
+ * this channel and notify of any events. While registering the channel the reactor uses {@link
+ * AbstractNioChannel#getInterestedOps()} to know about the interested operation of this channel.
+ *
+ * @param channel a new channel on which reactor will wait for events. The channel must be bound
+ * prior to being registered.
* @return this
- * @throws IOException
- * if any I/O error occurs.
+ * @throws IOException if any I/O error occurs.
*/
public NioReactor registerChannel(AbstractNioChannel channel) throws IOException {
SelectionKey key = channel.getJavaChannel().register(selector, channel.getInterestedOps());
@@ -143,8 +137,8 @@ public class NioReactor {
processPendingCommands();
/*
- * Synchronous event de-multiplexing happens here, this is blocking call which returns when it is possible to
- * initiate non-blocking operation on any of the registered channels.
+ * Synchronous event de-multiplexing happens here, this is blocking call which returns when it
+ * is possible to initiate non-blocking operation on any of the registered channels.
*/
selector.select();
@@ -177,8 +171,8 @@ public class NioReactor {
}
/*
- * Initiation dispatcher logic, it checks the type of event and notifier application specific event handler to handle
- * the event.
+ * Initiation dispatcher logic, it checks the type of event and notifier application specific
+ * event handler to handle the event.
*/
private void processKey(SelectionKey key) throws IOException {
if (key.isAcceptable()) {
@@ -226,15 +220,14 @@ public class NioReactor {
}
/**
- * Queues the change of operations request of a channel, which will change the interested operations of the channel
- * sometime in future.
- *
- * This is a non-blocking method and does not guarantee that the operations have changed when this method returns.
- *
- * @param key
- * the key for which operations have to be changed.
- * @param interestedOps
- * the new interest operations.
+ * Queues the change of operations request of a channel, which will change the interested
+ * operations of the channel sometime in future.
+ *
+ *
This is a non-blocking method and does not guarantee that the operations have changed when
+ * this method returns.
+ *
+ * @param key the key for which operations have to be changed.
+ * @param interestedOps the new interest operations.
*/
public void changeOps(SelectionKey key, int interestedOps) {
pendingCommands.add(new ChangeKeyOpsCommand(key, interestedOps));
diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/NioServerSocketChannel.java b/reactor/src/main/java/com/iluwatar/reactor/framework/NioServerSocketChannel.java
index a56b5dfe9..7c52a95c3 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/framework/NioServerSocketChannel.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/framework/NioServerSocketChannel.java
@@ -23,9 +23,6 @@
package com.iluwatar.reactor.framework;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -33,10 +30,12 @@ import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
- * A wrapper over {@link NioServerSocketChannel} which can read and write data on a
- * {@link SocketChannel}.
+ * A wrapper over {@link NioServerSocketChannel} which can read and write data on a {@link
+ * SocketChannel}.
*/
public class NioServerSocketChannel extends AbstractNioChannel {
@@ -47,11 +46,11 @@ public class NioServerSocketChannel extends AbstractNioChannel {
/**
* Creates a {@link ServerSocketChannel} which will bind at provided port and use
* handler
to handle incoming events on this channel.
- *
- * Note the constructor does not bind the socket, {@link #bind()} method should be called for
+ *
+ *
Note the constructor does not bind the socket, {@link #bind()} method should be called for
* binding the socket.
- *
- * @param port the port on which channel will be bound to accept incoming connection requests.
+ *
+ * @param port the port on which channel will be bound to accept incoming connection requests.
* @param handler the handler that will handle incoming requests on this channel.
* @throws IOException if any I/O error occurs.
*/
@@ -68,6 +67,8 @@ public class NioServerSocketChannel extends AbstractNioChannel {
}
/**
+ * Get server socket channel.
+ *
* @return the underlying {@link ServerSocketChannel}.
*/
@Override
@@ -94,7 +95,7 @@ public class NioServerSocketChannel extends AbstractNioChannel {
/**
* Binds TCP socket on the provided port
.
- *
+ *
* @throws IOException if any I/O error occurs.
*/
@Override
diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/SameThreadDispatcher.java b/reactor/src/main/java/com/iluwatar/reactor/framework/SameThreadDispatcher.java
index a64acc069..0faff6793 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/framework/SameThreadDispatcher.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/framework/SameThreadDispatcher.java
@@ -29,18 +29,16 @@ import java.nio.channels.SelectionKey;
* Dispatches the events in the context of caller thread. This implementation is a good fit for
* small applications where there are limited clients. Using this implementation limits the
* scalability because the I/O thread performs the application specific processing.
- *
- *
- * For better performance use {@link ThreadPoolDispatcher}.
- *
+ *
+ *
For better performance use {@link ThreadPoolDispatcher}.
+ *
* @see ThreadPoolDispatcher
*/
public class SameThreadDispatcher implements Dispatcher {
/**
- * Dispatches the read event in the context of caller thread.
- * Note this is a blocking call. It returns only after the associated handler has handled the read
- * event.
+ * Dispatches the read event in the context of caller thread. Note this is a blocking call.
+ * It returns only after the associated handler has handled the read event.
*/
@Override
public void onChannelReadEvent(AbstractNioChannel channel, Object readObject, SelectionKey key) {
diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/ThreadPoolDispatcher.java b/reactor/src/main/java/com/iluwatar/reactor/framework/ThreadPoolDispatcher.java
index e4bd20cfd..b75f0f64d 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/framework/ThreadPoolDispatcher.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/framework/ThreadPoolDispatcher.java
@@ -39,7 +39,7 @@ public class ThreadPoolDispatcher implements Dispatcher {
/**
* Creates a pooled dispatcher with tunable pool size.
- *
+ *
* @param poolSize number of pooled threads
*/
public ThreadPoolDispatcher(int poolSize) {
@@ -48,9 +48,8 @@ public class ThreadPoolDispatcher implements Dispatcher {
/**
* Submits the work of dispatching the read event to worker pool, where it gets picked up by
- * worker threads.
- * Note that this is a non-blocking call and returns immediately. It is not guaranteed that the
- * event has been handled by associated handler.
+ * worker threads. Note that this is a non-blocking call and returns immediately. It is not
+ * guaranteed that the event has been handled by associated handler.
*/
@Override
public void onChannelReadEvent(AbstractNioChannel channel, Object readObject, SelectionKey key) {
@@ -59,7 +58,7 @@ public class ThreadPoolDispatcher implements Dispatcher {
/**
* Stops the pool of workers.
- *
+ *
* @throws InterruptedException if interrupted while stopping pool of workers.
*/
@Override
diff --git a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/App.java b/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/App.java
index 1232a73f7..f59ba10cc 100644
--- a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/App.java
+++ b/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/App.java
@@ -28,26 +28,23 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- *
* In a multiple thread applications, the threads may try to synchronize the shared resources
* regardless of read or write operation. It leads to a low performance especially in a "read more
* write less" system as indeed the read operations are thread-safe to another read operation.
- *
- * Reader writer lock is a synchronization primitive that try to resolve this problem. This pattern
- * allows concurrent access for read-only operations, while write operations require exclusive
- * access. This means that multiple threads can read the data in parallel but an exclusive lock is
- * needed for writing or modifying data. When a writer is writing the data, all other writers or
- * readers will be blocked until the writer is finished writing.
- *
- *
- * This example use two mutex to demonstrate the concurrent access of multiple readers and writers.
- *
- *
+ *
+ *
Reader writer lock is a synchronization primitive that try to resolve this problem. This
+ * pattern allows concurrent access for read-only operations, while write operations require
+ * exclusive access. This means that multiple threads can read the data in parallel but an exclusive
+ * lock is needed for writing or modifying data. When a writer is writing the data, all other
+ * writers or readers will be blocked until the writer is finished writing.
+ *
+ *
This example use two mutex to demonstrate the concurrent access of multiple readers and
+ * writers.
+ *
* @author hongshuwei@gmail.com
*/
public class App {
@@ -55,27 +52,27 @@ public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/**
- * Program entry point
- *
+ * Program entry point.
+ *
* @param args command line args
*/
public static void main(String[] args) {
ExecutorService executeService = Executors.newFixedThreadPool(10);
ReaderWriterLock lock = new ReaderWriterLock();
-
+
// Start writers
IntStream.range(0, 5)
- .forEach(i -> executeService.submit(new Writer("Writer " + i, lock.writeLock(),
+ .forEach(i -> executeService.submit(new Writer("Writer " + i, lock.writeLock(),
ThreadLocalRandom.current().nextLong(5000))));
LOGGER.info("Writers added...");
// Start readers
IntStream.range(0, 5)
- .forEach(i -> executeService.submit(new Reader("Reader " + i, lock.readLock(),
+ .forEach(i -> executeService.submit(new Reader("Reader " + i, lock.readLock(),
ThreadLocalRandom.current().nextLong(10))));
LOGGER.info("Readers added...");
-
+
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
@@ -85,11 +82,10 @@ public class App {
// Start readers
IntStream.range(6, 10)
- .forEach(i -> executeService.submit(new Reader("Reader " + i, lock.readLock(),
+ .forEach(i -> executeService.submit(new Reader("Reader " + i, lock.readLock(),
ThreadLocalRandom.current().nextLong(10))));
LOGGER.info("More readers added...");
-
-
+
// In the system console, it can see that the read operations are executed concurrently while
// write operations are exclusive.
diff --git a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Reader.java b/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Reader.java
index a4c7d0744..6d705de2f 100644
--- a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Reader.java
+++ b/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Reader.java
@@ -24,12 +24,11 @@
package com.iluwatar.reader.writer.lock;
import java.util.concurrent.locks.Lock;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * Reader class, read when it acquired the read lock
+ * Reader class, read when it acquired the read lock.
*/
public class Reader implements Runnable {
@@ -38,14 +37,14 @@ public class Reader implements Runnable {
private Lock readLock;
private String name;
-
+
private long readingTime;
/**
- * Create new Reader
- *
- * @param name - Name of the thread owning the reader
- * @param readLock - Lock for this reader
+ * Create new Reader.
+ *
+ * @param name - Name of the thread owning the reader
+ * @param readLock - Lock for this reader
* @param readingTime - amount of time (in milliseconds) for this reader to engage reading
*/
public Reader(String name, Lock readLock, long readingTime) {
@@ -53,11 +52,11 @@ public class Reader implements Runnable {
this.readLock = readLock;
this.readingTime = readingTime;
}
-
+
/**
- * Create new Reader who reads for 250ms
- *
- * @param name - Name of the thread owning the reader
+ * Create new Reader who reads for 250ms.
+ *
+ * @param name - Name of the thread owning the reader
* @param readLock - Lock for this reader
*/
public Reader(String name, Lock readLock) {
@@ -78,8 +77,7 @@ public class Reader implements Runnable {
}
/**
- * Simulate the read operation
- *
+ * Simulate the read operation.
*/
public void read() throws InterruptedException {
LOGGER.info("{} begin", name);
diff --git a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/ReaderWriterLock.java b/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/ReaderWriterLock.java
index 282503ea6..d578b0f21 100644
--- a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/ReaderWriterLock.java
+++ b/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/ReaderWriterLock.java
@@ -29,18 +29,17 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class responsible for control the access for reader or writer
- *
- * Allows multiple readers to hold the lock at same time, but if any writer holds the lock then readers wait. If reader
- * holds the lock then writer waits. This lock is not fair.
+ *
+ *
Allows multiple readers to hold the lock at same time, but if any writer holds the lock then
+ * readers wait. If reader holds the lock then writer waits. This lock is not fair.
*/
public class ReaderWriterLock implements ReadWriteLock {
-
+
private static final Logger LOGGER = LoggerFactory.getLogger(ReaderWriterLock.class);
@@ -50,13 +49,13 @@ public class ReaderWriterLock implements ReadWriteLock {
/**
* Global mutex is used to indicate that whether reader or writer gets the lock in the moment.
- *
- * 1. When it contains the reference of {@link #readerLock}, it means that the lock is acquired by the reader, another
- * reader can also do the read operation concurrently.
- * 2. When it contains the reference of reference of {@link #writerLock}, it means that the lock is acquired by the
- * writer exclusively, no more reader or writer can get the lock.
- *
- * This is the most important field in this class to control the access for reader/writer.
+ *
+ *
1. When it contains the reference of {@link #readerLock}, it means that the lock is
+ * acquired by the reader, another reader can also do the read operation concurrently. 2.
+ * When it contains the reference of reference of {@link #writerLock}, it means that the lock is
+ * acquired by the writer exclusively, no more reader or writer can get the lock.
+ *
+ *
This is the most important field in this class to control the access for reader/writer.
*/
private Set globalMutex = new HashSet<>();
@@ -74,22 +73,21 @@ public class ReaderWriterLock implements ReadWriteLock {
}
/**
- * return true when globalMutex hold the reference of writerLock
+ * return true when globalMutex hold the reference of writerLock.
*/
private boolean doesWriterOwnThisLock() {
return globalMutex.contains(writerLock);
}
/**
- * Nobody get the lock when globalMutex contains nothing
- *
+ * Nobody get the lock when globalMutex contains nothing.
*/
private boolean isLockFree() {
return globalMutex.isEmpty();
}
/**
- * Reader Lock, can be access for more than one reader concurrently if no writer get the lock
+ * Reader Lock, can be access for more than one reader concurrently if no writer get the lock.
*/
private class ReadLock implements Lock {
@@ -104,8 +102,8 @@ public class ReaderWriterLock implements ReadWriteLock {
}
/**
- * Acquire the globalMutex lock on behalf of current and future concurrent readers. Make sure no writers currently
- * owns the lock.
+ * Acquire the globalMutex lock on behalf of current and future concurrent readers. Make sure no
+ * writers currently owns the lock.
*/
private void acquireForReaders() {
// Try to get the globalMutex lock for the first reader
@@ -116,7 +114,8 @@ public class ReaderWriterLock implements ReadWriteLock {
try {
globalMutex.wait();
} catch (InterruptedException e) {
- LOGGER.info("InterruptedException while waiting for globalMutex in acquireForReaders", e);
+ LOGGER
+ .info("InterruptedException while waiting for globalMutex in acquireForReaders", e);
Thread.currentThread().interrupt();
}
}
@@ -165,7 +164,7 @@ public class ReaderWriterLock implements ReadWriteLock {
}
/**
- * Writer Lock, can only be accessed by one writer concurrently
+ * Writer Lock, can only be accessed by one writer concurrently.
*/
private class WriteLock implements Lock {
diff --git a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Writer.java b/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Writer.java
index afe93efd7..7a971b28b 100644
--- a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Writer.java
+++ b/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Writer.java
@@ -24,12 +24,11 @@
package com.iluwatar.reader.writer.lock;
import java.util.concurrent.locks.Lock;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * Writer class, write when it acquired the write lock
+ * Writer class, write when it acquired the write lock.
*/
public class Writer implements Runnable {
@@ -38,24 +37,24 @@ public class Writer implements Runnable {
private Lock writeLock;
private String name;
-
+
private long writingTime;
/**
- * Create new Writer who writes for 250ms
- *
- * @param name - Name of the thread owning the writer
+ * Create new Writer who writes for 250ms.
+ *
+ * @param name - Name of the thread owning the writer
* @param writeLock - Lock for this writer
*/
public Writer(String name, Lock writeLock) {
this(name, writeLock, 250L);
}
-
+
/**
- * Create new Writer
- *
- * @param name - Name of the thread owning the writer
- * @param writeLock - Lock for this writer
+ * Create new Writer.
+ *
+ * @param name - Name of the thread owning the writer
+ * @param writeLock - Lock for this writer
* @param writingTime - amount of time (in milliseconds) for this reader to engage writing
*/
public Writer(String name, Lock writeLock, long writingTime) {
@@ -77,9 +76,9 @@ public class Writer implements Runnable {
writeLock.unlock();
}
}
-
+
/**
- * Simulate the write operation
+ * Simulate the write operation.
*/
public void write() throws InterruptedException {
LOGGER.info("{} begin", name);
diff --git a/repository/src/main/java/com/iluwatar/repository/App.java b/repository/src/main/java/com/iluwatar/repository/App.java
index 0ecafd030..ac932b815 100644
--- a/repository/src/main/java/com/iluwatar/repository/App.java
+++ b/repository/src/main/java/com/iluwatar/repository/App.java
@@ -25,7 +25,6 @@ package com.iluwatar.repository;
import java.util.List;
import java.util.Optional;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@@ -38,8 +37,8 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
* query construction code is concentrated. This becomes more important when there are a large
* number of domain classes or heavy querying. In these cases particularly, adding this layer helps
* minimize duplicate query logic.
- *
- * In this example we utilize Spring Data to automatically generate a repository for us from the
+ *
+ *
In this example we utilize Spring Data to automatically generate a repository for us from the
* {@link Person} domain object. Using the {@link PersonRepository} we perform CRUD operations on
* the entity, moreover, the query by {@link org.springframework.data.jpa.domain.Specification} are
* also performed. Underneath we have configured in-memory H2 database for which schema is created
@@ -50,10 +49,9 @@ public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/**
- * Program entry point
- *
- * @param args
- * command line args
+ * Program entry point.
+ *
+ * @param args command line args
*/
public static void main(String[] args) {
@@ -107,7 +105,7 @@ public class App {
}
repository.deleteAll();
-
+
context.close();
}
diff --git a/repository/src/main/java/com/iluwatar/repository/AppConfig.java b/repository/src/main/java/com/iluwatar/repository/AppConfig.java
index f4f46be88..197205773 100644
--- a/repository/src/main/java/com/iluwatar/repository/AppConfig.java
+++ b/repository/src/main/java/com/iluwatar/repository/AppConfig.java
@@ -27,9 +27,7 @@ import java.sql.SQLException;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
-
import javax.sql.DataSource;
-
import org.apache.commons.dbcp.BasicDataSource;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.slf4j.Logger;
@@ -42,9 +40,7 @@ import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
/**
- * This is the same example as in {@link App} but with annotations based
- * configuration for Spring.
- *
+ * This is the same example as in {@link App} but with annotations based configuration for Spring.
*/
@EnableJpaRepositories
@SpringBootConfiguration
@@ -53,8 +49,8 @@ public class AppConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(AppConfig.class);
/**
- * Creation of H2 db
- *
+ * Creation of H2 db.
+ *
* @return A new Instance of DataSource
*/
@Bean(destroyMethod = "close")
@@ -68,11 +64,12 @@ public class AppConfig {
}
/**
- * Factory to create a especific instance of Entity Manager
+ * Factory to create a especific instance of Entity Manager.
*/
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
- LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
+ LocalContainerEntityManagerFactoryBean entityManager =
+ new LocalContainerEntityManagerFactoryBean();
entityManager.setDataSource(dataSource());
entityManager.setPackagesToScan("com.iluwatar");
entityManager.setPersistenceProvider(new HibernatePersistenceProvider());
@@ -82,7 +79,7 @@ public class AppConfig {
}
/**
- * Properties for Jpa
+ * Properties for Jpa.
*/
private static Properties jpaProperties() {
Properties properties = new Properties();
@@ -92,7 +89,7 @@ public class AppConfig {
}
/**
- * Get transaction manager
+ * Get transaction manager.
*/
@Bean
public JpaTransactionManager transactionManager() throws SQLException {
@@ -102,10 +99,9 @@ public class AppConfig {
}
/**
- * Program entry point
- *
- * @param args
- * command line args
+ * Program entry point.
+ *
+ * @param args command line args
*/
public static void main(String[] args) {
diff --git a/repository/src/main/java/com/iluwatar/repository/Person.java b/repository/src/main/java/com/iluwatar/repository/Person.java
index ded5b8cfa..e83f0ce46 100644
--- a/repository/src/main/java/com/iluwatar/repository/Person.java
+++ b/repository/src/main/java/com/iluwatar/repository/Person.java
@@ -28,9 +28,7 @@ import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
- *
- * Person entity
- *
+ * Person entity.
*/
@Entity
public class Person {
@@ -47,7 +45,7 @@ public class Person {
}
/**
- * Constructor
+ * Constructor.
*/
public Person(String name, String surname, int age) {
this.name = name;
diff --git a/repository/src/main/java/com/iluwatar/repository/PersonRepository.java b/repository/src/main/java/com/iluwatar/repository/PersonRepository.java
index e181d19b5..2bdd0feb7 100644
--- a/repository/src/main/java/com/iluwatar/repository/PersonRepository.java
+++ b/repository/src/main/java/com/iluwatar/repository/PersonRepository.java
@@ -28,9 +28,7 @@ import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
/**
- *
- * Person repository
- *
+ * Person repository.
*/
@Repository
public interface PersonRepository
diff --git a/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java b/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java
index 5a14985c9..149c2488e 100644
--- a/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java
+++ b/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java
@@ -27,16 +27,15 @@ import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
-
import org.springframework.data.jpa.domain.Specification;
/**
- * Helper class, includes vary Specification as the abstraction of sql query criteria
+ * Helper class, includes vary Specification as the abstraction of sql query criteria.
*/
public class PersonSpecifications {
/**
- * Specifications stating the Between (From - To) Age Specification
+ * Specifications stating the Between (From - To) Age Specification.
*/
public static class AgeBetweenSpec implements Specification {
@@ -59,8 +58,7 @@ public class PersonSpecifications {
}
/**
- * Name specification
- *
+ * Name specification.
*/
public static class NameEqualSpec implements Specification {
@@ -71,7 +69,7 @@ public class PersonSpecifications {
}
/**
- * Get predicate
+ * Get predicate.
*/
public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder cb) {
diff --git a/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/App.java b/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/App.java
index fc67465a7..293675e99 100644
--- a/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/App.java
+++ b/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/App.java
@@ -27,31 +27,30 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- *
* Resource Acquisition Is Initialization pattern was developed for exception safe resource
* management by C++ creator Bjarne Stroustrup.
- *
- * In RAII resource is tied to object lifetime: resource allocation is done during object creation
- * while resource deallocation is done during object destruction.
- *
- * In Java RAII is achieved with try-with-resources statement and interfaces {@link java.io.Closeable} and
- * {@link AutoCloseable}. The try-with-resources statement ensures that each resource is closed at
- * the end of the statement. Any object that implements {@link java.lang.AutoCloseable}, which
- * includes all objects which implement {@link java.io.Closeable}, can be used as a resource.
*
- * In this example, {@link SlidingDoor} implements {@link AutoCloseable} and {@link TreasureChest}
- * implements {@link java.io.Closeable}. Running the example, we can observe that both resources are
- * automatically closed.
- *
- * http://docs.oracle.com/javase/7/docs/technotes/guides/language/try-with-resources.html
+ *
In RAII resource is tied to object lifetime: resource allocation is done during object
+ * creation while resource deallocation is done during object destruction.
*
+ *
In Java RAII is achieved with try-with-resources statement and interfaces {@link
+ * java.io.Closeable} and {@link AutoCloseable}. The try-with-resources statement ensures that each
+ * resource is closed at the end of the statement. Any object that implements {@link
+ * java.lang.AutoCloseable}, which includes all objects which implement {@link java.io.Closeable},
+ * can be used as a resource.
+ *
+ *
In this example, {@link SlidingDoor} implements {@link AutoCloseable} and {@link
+ * TreasureChest} implements {@link java.io.Closeable}. Running the example, we can observe that
+ * both resources are automatically closed.
+ *
+ *
http://docs.oracle.com/javase/7/docs/technotes/guides/language/try-with-resources.html
*/
public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/**
- * Program entry point
+ * Program entry point.
*/
public static void main(String[] args) throws Exception {
diff --git a/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/SlidingDoor.java b/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/SlidingDoor.java
index 47c36a77f..d890eb4c3 100644
--- a/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/SlidingDoor.java
+++ b/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/SlidingDoor.java
@@ -27,9 +27,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- *
- * SlidingDoor resource
- *
+ * SlidingDoor resource.
*/
public class SlidingDoor implements AutoCloseable {
diff --git a/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/TreasureChest.java b/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/TreasureChest.java
index d8adf2ed4..26eab1405 100644
--- a/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/TreasureChest.java
+++ b/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/TreasureChest.java
@@ -23,16 +23,13 @@
package com.iluwatar.resource.acquisition.is.initialization;
+import java.io.Closeable;
+import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.Closeable;
-import java.io.IOException;
-
/**
- *
- * TreasureChest resource
- *
+ * TreasureChest resource.
*/
public class TreasureChest implements Closeable {
diff --git a/retry/src/main/java/com/iluwatar/retry/App.java b/retry/src/main/java/com/iluwatar/retry/App.java
index 5eb78125c..594c48295 100644
--- a/retry/src/main/java/com/iluwatar/retry/App.java
+++ b/retry/src/main/java/com/iluwatar/retry/App.java
@@ -27,34 +27,35 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * The Retry pattern enables applications to handle potentially recoverable failures from
- * the environment if the business requirements and nature of the failures allow it. By retrying
+ * The Retry pattern enables applications to handle potentially recoverable failures from
+ * the environment if the business requirements and nature of the failures allow it. By retrying
* failed operations on external dependencies, the application may maintain stability and minimize
* negative impact on the user experience.
- *
- * In our example, we have the {@link BusinessOperation} interface as an abstraction over
- * all operations that our application performs involving remote systems. The calling code should
- * remain decoupled from implementations.
- *
- * {@link FindCustomer} is a business operation that looks up a customer's record and returns
- * its ID. Imagine its job is performed by looking up the customer in our local database and
- * returning its ID. We can pass {@link CustomerNotFoundException} as one of its
- * {@link FindCustomer#FindCustomer(java.lang.String, com.iluwatar.retry.BusinessException...)
- * constructor parameters} in order to simulate not finding the customer.
- *
- * Imagine that, lately, this operation has experienced intermittent failures due to some weird
- * corruption and/or locking in the data. After retrying a few times the customer is found. The
- * database is still, however, expected to always be available. While a definitive solution is
- * found to the problem, our engineers advise us to retry the operation a set number
- * of times with a set delay between retries, although not too many retries otherwise the end user
- * will be left waiting for a long time, while delays that are too short will not allow the database
- * to recover from the load.
- *
- * To keep the calling code as decoupled as possible from this workaround, we have implemented the
- * retry mechanism as a {@link BusinessOperation} named {@link Retry}.
- *
+ *
+ *
In our example, we have the {@link BusinessOperation} interface as an abstraction over all
+ * operations that our application performs involving remote systems. The calling code should remain
+ * decoupled from implementations.
+ *
+ *
{@link FindCustomer} is a business operation that looks up a customer's record and returns
+ * its ID. Imagine its job is performed by looking up the customer in our local database and
+ * returning its ID. We can pass {@link CustomerNotFoundException} as one of its {@link
+ * FindCustomer#FindCustomer(java.lang.String, com.iluwatar.retry.BusinessException...) constructor
+ * parameters} in order to simulate not finding the customer.
+ *
+ *
Imagine that, lately, this operation has experienced intermittent failures due to some weird
+ * corruption and/or locking in the data. After retrying a few times the customer is found. The
+ * database is still, however, expected to always be available. While a definitive solution is
+ * found to the problem, our engineers advise us to retry the operation a set number of times with a
+ * set delay between retries, although not too many retries otherwise the end user will be left
+ * waiting for a long time, while delays that are too short will not allow the database to recover
+ * from the load.
+ *
+ *
To keep the calling code as decoupled as possible from this workaround, we have implemented
+ * the retry mechanism as a {@link BusinessOperation} named {@link Retry}.
+ *
* @author George Aristy (george.aristy@gmail.com)
- * @see Retry pattern (Microsoft Azure Docs)
+ * @see Retry pattern
+ * (Microsoft Azure Docs)
*/
public final class App {
private static final Logger LOG = LoggerFactory.getLogger(App.class);
@@ -62,7 +63,7 @@ public final class App {
/**
* Entry point.
- *
+ *
* @param args not used
* @throws Exception not expected
*/
@@ -99,22 +100,22 @@ public final class App {
final String customerId = op.perform();
LOG.info(String.format(
"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()
));
}
-
+
private static void errorWithRetryExponentialBackoff() throws Exception {
final RetryExponentialBackoff retry = new RetryExponentialBackoff<>(
new FindCustomer("123", new CustomerNotFoundException("not found")),
6, //6 attempts
30000, //30 s max delay between attempts
e -> CustomerNotFoundException.class.isAssignableFrom(e.getClass())
- );
+ );
op = retry;
final String customerId = op.perform();
LOG.info(String.format(
- "However, retrying the operation while ignoring a recoverable error will eventually yield "
- + "the result %s after a number of attempts %s", customerId, retry.attempts()
- ));
+ "However, retrying the operation while ignoring a recoverable error will eventually yield "
+ + "the result %s after a number of attempts %s", customerId, retry.attempts()
+ ));
}
}
diff --git a/retry/src/main/java/com/iluwatar/retry/BusinessException.java b/retry/src/main/java/com/iluwatar/retry/BusinessException.java
index 2da1cca8a..397a4623b 100644
--- a/retry/src/main/java/com/iluwatar/retry/BusinessException.java
+++ b/retry/src/main/java/com/iluwatar/retry/BusinessException.java
@@ -24,10 +24,10 @@
package com.iluwatar.retry;
/**
- * The top-most type in our exception hierarchy that signifies that an unexpected error
- * condition occurred. Its use is reserved as a "catch-all" for cases where no other subtype
- * captures the specificity of the error condition in question. Calling code is not expected to
- * be able to handle this error and should be reported to the maintainers immediately.
+ * The top-most type in our exception hierarchy that signifies that an unexpected error condition
+ * occurred. Its use is reserved as a "catch-all" for cases where no other subtype captures the
+ * specificity of the error condition in question. Calling code is not expected to be able to handle
+ * this error and should be reported to the maintainers immediately.
*
* @author George Aristy (george.aristy@gmail.com)
*/
@@ -35,8 +35,8 @@ public class BusinessException extends Exception {
private static final long serialVersionUID = 6235833142062144336L;
/**
- * Ctor
- *
+ * Ctor.
+ *
* @param message the error message
*/
public BusinessException(String message) {
diff --git a/retry/src/main/java/com/iluwatar/retry/BusinessOperation.java b/retry/src/main/java/com/iluwatar/retry/BusinessOperation.java
index a829ff541..a67240d3c 100644
--- a/retry/src/main/java/com/iluwatar/retry/BusinessOperation.java
+++ b/retry/src/main/java/com/iluwatar/retry/BusinessOperation.java
@@ -26,18 +26,18 @@ package com.iluwatar.retry;
/**
* Performs some business operation.
*
- * @author George Aristy (george.aristy@gmail.com)
* @param the return type
+ * @author George Aristy (george.aristy@gmail.com)
*/
@FunctionalInterface
public interface BusinessOperation {
/**
* Performs some business operation, returning a value {@code T} if successful, otherwise throwing
* an exception if an error occurs.
- *
+ *
* @return the return value
* @throws BusinessException if the operation fails. Implementations are allowed to throw more
- * specific subtypes depending on the error conditions
+ * specific subtypes depending on the error conditions
*/
T perform() throws BusinessException;
}
diff --git a/retry/src/main/java/com/iluwatar/retry/CustomerNotFoundException.java b/retry/src/main/java/com/iluwatar/retry/CustomerNotFoundException.java
index c0a9ca434..3826fe0e1 100644
--- a/retry/src/main/java/com/iluwatar/retry/CustomerNotFoundException.java
+++ b/retry/src/main/java/com/iluwatar/retry/CustomerNotFoundException.java
@@ -24,10 +24,11 @@
package com.iluwatar.retry;
/**
- * Indicates that the customer was not found.
- *
- * The severity of this error is bounded by its context: was the search for the customer triggered
- * by an input from some end user, or were the search parameters pulled from your database?
+ * Indicates that the customer was not found.
+ *
+ *
The severity of this error is bounded by its context: was the search for the customer
+ * triggered by an input from some end user, or were the search parameters pulled from your
+ * database?
*
* @author George Aristy (george.aristy@gmail.com)
*/
@@ -36,7 +37,7 @@ public final class CustomerNotFoundException extends BusinessException {
/**
* Ctor.
- *
+ *
* @param message the error message
*/
public CustomerNotFoundException(String message) {
diff --git a/retry/src/main/java/com/iluwatar/retry/DatabaseNotAvailableException.java b/retry/src/main/java/com/iluwatar/retry/DatabaseNotAvailableException.java
index 02cbc6521..37fcecf32 100644
--- a/retry/src/main/java/com/iluwatar/retry/DatabaseNotAvailableException.java
+++ b/retry/src/main/java/com/iluwatar/retry/DatabaseNotAvailableException.java
@@ -33,7 +33,7 @@ public final class DatabaseNotAvailableException extends BusinessException {
/**
* Ctor.
- *
+ *
* @param message the error message
*/
public DatabaseNotAvailableException(String message) {
diff --git a/retry/src/main/java/com/iluwatar/retry/FindCustomer.java b/retry/src/main/java/com/iluwatar/retry/FindCustomer.java
index e5013f50e..af3e5469a 100644
--- a/retry/src/main/java/com/iluwatar/retry/FindCustomer.java
+++ b/retry/src/main/java/com/iluwatar/retry/FindCustomer.java
@@ -29,9 +29,9 @@ import java.util.List;
/**
* Finds a customer, returning its ID from our records.
- *
- * This is an imaginary operation that, for some imagined input, returns the ID for a customer.
- * However, this is a "flaky" operation that is supposed to fail intermittently, but for the
+ *
+ *
This is an imaginary operation that, for some imagined input, returns the ID for a customer.
+ * However, this is a "flaky" operation that is supposed to fail intermittently, but for the
* purposes of this example it fails in a programmed way depending on the constructor parameters.
*
* @author George Aristy (george.aristy@gmail.com)
@@ -42,15 +42,15 @@ public final class FindCustomer implements BusinessOperation {
/**
* Ctor.
- *
+ *
* @param customerId the final result of the remote operation
- * @param errors the errors to throw before returning {@code customerId}
+ * @param errors the errors to throw before returning {@code customerId}
*/
public FindCustomer(String customerId, BusinessException... errors) {
this.customerId = customerId;
this.errors = new ArrayDeque<>(List.of(errors));
}
-
+
@Override
public String perform() throws BusinessException {
if (!this.errors.isEmpty()) {
diff --git a/retry/src/main/java/com/iluwatar/retry/Retry.java b/retry/src/main/java/com/iluwatar/retry/Retry.java
index 7f188cb8f..f54c51301 100644
--- a/retry/src/main/java/com/iluwatar/retry/Retry.java
+++ b/retry/src/main/java/com/iluwatar/retry/Retry.java
@@ -33,8 +33,8 @@ import java.util.function.Predicate;
/**
* Decorates {@link BusinessOperation business operation} with "retry" capabilities.
*
- * @author George Aristy (george.aristy@gmail.com)
* @param the remote op's return type
+ * @author George Aristy (george.aristy@gmail.com)
*/
public final class Retry implements BusinessOperation {
private final BusinessOperation op;
@@ -46,18 +46,18 @@ public final class Retry implements BusinessOperation {
/**
* Ctor.
- *
- * @param op the {@link BusinessOperation} to retry
+ *
+ * @param op the {@link BusinessOperation} to retry
* @param maxAttempts number of times to retry
- * @param delay delay (in milliseconds) between attempts
+ * @param delay delay (in milliseconds) between attempts
* @param ignoreTests tests to check whether the remote exception can be ignored. No exceptions
- * will be ignored if no tests are given
+ * will be ignored if no tests are given
*/
@SafeVarargs
public Retry(
- BusinessOperation op,
- int maxAttempts,
- long delay,
+ BusinessOperation op,
+ int maxAttempts,
+ long delay,
Predicate... ignoreTests
) {
this.op = op;
@@ -70,7 +70,7 @@ public final class Retry implements BusinessOperation {
/**
* The errors encountered while retrying, in the encounter order.
- *
+ *
* @return the errors encountered while retrying
*/
public List errors() {
@@ -79,7 +79,7 @@ public final class Retry implements BusinessOperation {
/**
* The number of retries performed.
- *
+ *
* @return the number of retries performed
*/
public int attempts() {
@@ -93,7 +93,7 @@ public final class Retry implements BusinessOperation {
return this.op.perform();
} catch (BusinessException e) {
this.errors.add(e);
-
+
if (this.attempts.incrementAndGet() >= this.maxAttempts || !this.test.test(e)) {
throw e;
}
@@ -104,7 +104,6 @@ public final class Retry implements BusinessOperation {
//ignore
}
}
- }
- while (true);
+ } while (true);
}
}
diff --git a/retry/src/main/java/com/iluwatar/retry/RetryExponentialBackoff.java b/retry/src/main/java/com/iluwatar/retry/RetryExponentialBackoff.java
index 91dc0d6b2..c074f9cd4 100644
--- a/retry/src/main/java/com/iluwatar/retry/RetryExponentialBackoff.java
+++ b/retry/src/main/java/com/iluwatar/retry/RetryExponentialBackoff.java
@@ -34,8 +34,8 @@ import java.util.function.Predicate;
/**
* Decorates {@link BusinessOperation business operation} with "retry" capabilities.
*
- * @author George Aristy (george.aristy@gmail.com)
* @param the remote op's return type
+ * @author George Aristy (george.aristy@gmail.com)
*/
public final class RetryExponentialBackoff implements BusinessOperation {
private static final Random RANDOM = new Random();
@@ -46,20 +46,20 @@ public final class RetryExponentialBackoff implements BusinessOperation {
private final Predicate test;
private final List errors;
- /**
- * Ctor.
- *
- * @param op the {@link BusinessOperation} to retry
- * @param maxAttempts number of times to retry
- * @param ignoreTests tests to check whether the remote exception can be ignored. No exceptions
- * will be ignored if no tests are given
- */
+ /**
+ * Ctor.
+ *
+ * @param op the {@link BusinessOperation} to retry
+ * @param maxAttempts number of times to retry
+ * @param ignoreTests tests to check whether the remote exception can be ignored. No exceptions
+ * will be ignored if no tests are given
+ */
@SafeVarargs
public RetryExponentialBackoff(
- BusinessOperation op,
- int maxAttempts,
- long maxDelay,
- Predicate... ignoreTests
+ BusinessOperation op,
+ int maxAttempts,
+ long maxDelay,
+ Predicate... ignoreTests
) {
this.op = op;
this.maxAttempts = maxAttempts;
@@ -69,20 +69,20 @@ public final class RetryExponentialBackoff implements BusinessOperation {
this.errors = new ArrayList<>();
}
- /**
- * The errors encountered while retrying, in the encounter order.
- *
- * @return the errors encountered while retrying
- */
+ /**
+ * The errors encountered while retrying, in the encounter order.
+ *
+ * @return the errors encountered while retrying
+ */
public List errors() {
return Collections.unmodifiableList(this.errors);
}
- /**
- * The number of retries performed.
- *
- * @return the number of retries performed
- */
+ /**
+ * The number of retries performed.
+ *
+ * @return the number of retries performed
+ */
public int attempts() {
return this.attempts.intValue();
}
@@ -107,8 +107,7 @@ public final class RetryExponentialBackoff implements BusinessOperation {
//ignore
}
}
- }
- while (true);
+ } while (true);
}
}