Resolves checkstyle errors for patterns starting with letter r (#1072)

* Reduces checkstyle errors in reactor

* Reduces checkstyle errors in reader-writer-lock

* Reduces checkstyle errors in repository

* Reduces checkstyle errors in resource-acquisition-is-initialization

* Reduces checkstyle errors in retry
This commit is contained in:
Anurag Agarwal 2019-11-10 23:12:26 +05:30 committed by Ilkka Seppälä
parent 4dae1fae57
commit 9c8ad4485b
31 changed files with 345 additions and 377 deletions

View File

@ -23,10 +23,6 @@
package com.iluwatar.reactor.app; package com.iluwatar.reactor.app;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.iluwatar.reactor.framework.AbstractNioChannel; import com.iluwatar.reactor.framework.AbstractNioChannel;
import com.iluwatar.reactor.framework.ChannelHandler; import com.iluwatar.reactor.framework.ChannelHandler;
import com.iluwatar.reactor.framework.Dispatcher; import com.iluwatar.reactor.framework.Dispatcher;
@ -34,19 +30,20 @@ import com.iluwatar.reactor.framework.NioDatagramChannel;
import com.iluwatar.reactor.framework.NioReactor; import com.iluwatar.reactor.framework.NioReactor;
import com.iluwatar.reactor.framework.NioServerSocketChannel; import com.iluwatar.reactor.framework.NioServerSocketChannel;
import com.iluwatar.reactor.framework.ThreadPoolDispatcher; import com.iluwatar.reactor.framework.ThreadPoolDispatcher;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/** /**
* This application demonstrates Reactor pattern. The example demonstrated is a Distributed Logging * This application demonstrates Reactor pattern. The example demonstrated is a Distributed Logging
* Service where it listens on multiple TCP or UDP sockets for incoming log requests. * Service where it listens on multiple TCP or UDP sockets for incoming log requests.
* *
* <p> * <p><i>INTENT</i> <br>
* <i>INTENT</i> <br>
* The Reactor design pattern handles service requests that are delivered concurrently to an * The Reactor design pattern handles service requests that are delivered concurrently to an
* application by one or more clients. The application can register specific handlers for processing * application by one or more clients. The application can register specific handlers for processing
* which are called by reactor on specific events. * which are called by reactor on specific events.
* *
* <p> * <p><i>PROBLEM</i> <br>
* <i>PROBLEM</i> <br>
* Server applications in a distributed system must handle multiple clients that send them service * Server applications in a distributed system must handle multiple clients that send them service
* requests. Following forces need to be resolved: * requests. Following forces need to be resolved:
* <ul> * <ul>
@ -56,8 +53,7 @@ import com.iluwatar.reactor.framework.ThreadPoolDispatcher;
* <li>Adaptability</li> * <li>Adaptability</li>
* </ul> * </ul>
* *
* <p> * <p><i>PARTICIPANTS</i> <br>
* <i>PARTICIPANTS</i> <br>
* <ul> * <ul>
* <li>Synchronous Event De-multiplexer * <li>Synchronous Event De-multiplexer
* <p> * <p>
@ -89,7 +85,6 @@ import com.iluwatar.reactor.framework.ThreadPoolDispatcher;
* separate thread for each client, which provides better scalability under load (number of clients * separate thread for each client, which provides better scalability under load (number of clients
* increase). * increase).
* The example uses Java NIO framework to implement the Reactor. * The example uses Java NIO framework to implement the Reactor.
*
*/ */
public class App { public class App {

View File

@ -23,9 +23,6 @@
package com.iluwatar.reactor.app; package com.iluwatar.reactor.app;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -39,6 +36,8 @@ import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; 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 * Represents the clients of Reactor pattern. Multiple clients are run concurrently and send logging

View File

@ -23,12 +23,11 @@
package com.iluwatar.reactor.app; 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.AbstractNioChannel;
import com.iluwatar.reactor.framework.ChannelHandler; import com.iluwatar.reactor.framework.ChannelHandler;
import com.iluwatar.reactor.framework.NioDatagramChannel.DatagramPacket; import com.iluwatar.reactor.framework.NioDatagramChannel.DatagramPacket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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 * Create a reply acknowledgement datagram packet setting the receiver to the sender of incoming
* message. * message.

View File

@ -36,12 +36,11 @@ import java.util.concurrent.ConcurrentLinkedQueue;
* This represents the <i>Handle</i> of Reactor pattern. These are resources managed by OS which can * This represents the <i>Handle</i> of Reactor pattern. These are resources managed by OS which can
* be submitted to {@link NioReactor}. * be submitted to {@link NioReactor}.
* *
* <p> * <p>This class serves has the responsibility of reading the data when a read event occurs and
* This class serves has the responsibility of reading the data when a read event occurs and writing * writing the data back when the channel is writable. It leaves the reading and writing of data on
* the data back when the channel is writable. It leaves the reading and writing of data on the * the concrete implementation. It provides a block writing mechanism wherein when any {@link
* concrete implementation. It provides a block writing mechanism wherein when any * ChannelHandler} wants to write data back, it queues the data in pending write queue and clears it
* {@link ChannelHandler} wants to write data back, it queues the data in pending write queue and * in block manner. This provides better throughput.
* clears it in block manner. This provides better throughput.
*/ */
public abstract class AbstractNioChannel { public abstract class AbstractNioChannel {
@ -70,6 +69,8 @@ public abstract class AbstractNioChannel {
} }
/** /**
* Get channel.
*
* @return the wrapped NIO channel. * @return the wrapped NIO channel.
*/ */
public SelectableChannel getJavaChannel() { public SelectableChannel getJavaChannel() {
@ -77,8 +78,8 @@ public abstract class AbstractNioChannel {
} }
/** /**
* The operation in which the channel is interested, this operation is provided to * The operation in which the channel is interested, this operation is provided to {@link
* {@link Selector}. * Selector}.
* *
* @return interested operation. * @return interested operation.
* @see SelectionKey * @see SelectionKey
@ -103,6 +104,8 @@ public abstract class AbstractNioChannel {
public abstract Object read(SelectionKey key) throws IOException; public abstract Object read(SelectionKey key) throws IOException;
/** /**
* Get handler.
*
* @return the handler associated with this channel. * @return the handler associated with this channel.
*/ */
public ChannelHandler getHandler() { public ChannelHandler getHandler() {
@ -141,15 +144,14 @@ public abstract class AbstractNioChannel {
* Queues the data for writing. The data is not guaranteed to be written on underlying channel * 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. * when this method returns. It will be written when the channel is flushed.
* *
* <p> * <p>This method is used by the {@link ChannelHandler} to send reply back to the client. <br>
* This method is used by the {@link ChannelHandler} to send reply back to the client. <br>
* Example: * Example:
* *
* <pre> * <pre>
* <code> * <code>
* {@literal @}Override * {@literal @}Override
* public void handleChannelRead(AbstractNioChannel channel, Object readObject, SelectionKey key) { * public void handleChannelRead(AbstractNioChannel channel, Object readObj, SelectionKey key) {
* byte[] data = ((ByteBuffer)readObject).array(); * byte[] data = ((ByteBuffer)readObj).array();
* ByteBuffer buffer = ByteBuffer.wrap("Server reply".getBytes()); * ByteBuffer buffer = ByteBuffer.wrap("Server reply".getBytes());
* channel.write(buffer, key); * channel.write(buffer, key);
* } * }

View File

@ -29,9 +29,9 @@ import java.nio.channels.SelectionKey;
* Represents the <i>EventHandler</i> of Reactor pattern. It handles the incoming events dispatched * Represents the <i>EventHandler</i> of Reactor pattern. It handles the incoming events dispatched
* to it by the {@link Dispatcher}. This is where the application logic resides. * to it by the {@link Dispatcher}. This is where the application logic resides.
* *
* <p> * <p>A {@link ChannelHandler} can be associated with one or many {@link AbstractNioChannel}s, and
* 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
* whenever an event occurs on any of the associated channels, the handler is notified of the event. * event.
*/ */
public interface ChannelHandler { public interface ChannelHandler {

View File

@ -29,12 +29,10 @@ import java.nio.channels.SelectionKey;
* Represents the event dispatching strategy. When {@link NioReactor} senses any event on the * 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 * 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 * connect, and then calls the {@link Dispatcher} to dispatch the read events. This decouples the
* I/O processing from application specific processing. <br> * I/O processing from application specific processing. <br> Dispatcher should call the {@link
* Dispatcher should call the {@link ChannelHandler} associated with the channel on which event * ChannelHandler} associated with the channel on which event occurred.
* occurred.
* *
* <p> * <p>The application can customize the way in which event is dispatched such as using the reactor
* 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. * thread to dispatch event to channels or use a worker pool to do the non I/O processing.
* *
* @see SameThreadDispatcher * @see SameThreadDispatcher
@ -46,8 +44,7 @@ public interface Dispatcher {
* provided in <code>readObject</code>. The implementation should dispatch this read event to the * provided in <code>readObject</code>. The implementation should dispatch this read event to the
* associated {@link ChannelHandler} of <code>channel</code>. * associated {@link ChannelHandler} of <code>channel</code>.
* *
* <p> * <p>The type of <code>readObject</code> depends on the channel on which data was received.
* The type of <code>readObject</code> depends on the channel on which data was received.
* *
* @param channel on which read event occurred * @param channel on which read event occurred
* @param readObject object read by channel * @param readObject object read by channel

View File

@ -23,9 +23,6 @@
package com.iluwatar.reactor.framework; package com.iluwatar.reactor.framework;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@ -33,6 +30,8 @@ import java.net.SocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel; import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey; 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. * A wrapper over {@link DatagramChannel} which can read and write data on a DatagramChannel.
@ -46,8 +45,8 @@ public class NioDatagramChannel extends AbstractNioChannel {
/** /**
* Creates a {@link DatagramChannel} which will bind at provided port and use <code>handler</code> * Creates a {@link DatagramChannel} which will bind at provided port and use <code>handler</code>
* to handle incoming events on this channel. * to handle incoming events on this channel.
* <p> *
* Note the constructor does not bind the socket, {@link #bind()} method should be called for * <p>Note the constructor does not bind the socket, {@link #bind()} method should be called for
* binding the socket. * 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.
@ -89,6 +88,8 @@ public class NioDatagramChannel extends AbstractNioChannel {
} }
/** /**
* Get datagram channel.
*
* @return the underlying datagram channel. * @return the underlying datagram channel.
*/ */
@Override @Override
@ -120,8 +121,8 @@ public class NioDatagramChannel extends AbstractNioChannel {
/** /**
* Writes the outgoing {@link DatagramPacket} to the channel. The intended receiver of the * Writes the outgoing {@link DatagramPacket} to the channel. The intended receiver of the
* datagram packet must be set in the <code>data</code> using * datagram packet must be set in the <code>data</code> using {@link
* {@link DatagramPacket#setReceiver(SocketAddress)}. * DatagramPacket#setReceiver(SocketAddress)}.
*/ */
@Override @Override
public void write(Object data, SelectionKey key) { public void write(Object data, SelectionKey key) {
@ -146,6 +147,8 @@ public class NioDatagramChannel extends AbstractNioChannel {
} }
/** /**
* Get sender address.
*
* @return the sender address. * @return the sender address.
*/ */
public SocketAddress getSender() { public SocketAddress getSender() {
@ -162,6 +165,8 @@ public class NioDatagramChannel extends AbstractNioChannel {
} }
/** /**
* Get receiver address.
*
* @return the receiver address. * @return the receiver address.
*/ */
public SocketAddress getReceiver() { public SocketAddress getReceiver() {
@ -178,6 +183,8 @@ public class NioDatagramChannel extends AbstractNioChannel {
} }
/** /**
* Get data.
*
* @return the underlying message that will be written on channel. * @return the underlying message that will be written on channel.
*/ */
public ByteBuffer getData() { public ByteBuffer getData() {

View File

@ -23,9 +23,6 @@
package com.iluwatar.reactor.framework; package com.iluwatar.reactor.framework;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.nio.channels.SelectionKey; import java.nio.channels.SelectionKey;
import java.nio.channels.Selector; import java.nio.channels.Selector;
@ -38,22 +35,23 @@ 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;
import java.util.concurrent.TimeUnit; 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 * This class acts as Synchronous Event De-multiplexer and Initiation Dispatcher of Reactor pattern.
* i.e. {@link AbstractNioChannel}s can be registered to the reactor and it blocks for events from all these handles. * Multiple handles i.e. {@link AbstractNioChannel}s can be registered to the reactor and it blocks
* Whenever an event occurs on any of the registered handles, it synchronously de-multiplexes the event which can be any * for events from all these handles. Whenever an event occurs on any of the registered handles, it
* of read, write or accept, and dispatches the event to the appropriate {@link ChannelHandler} using the * synchronously de-multiplexes the event which can be any of read, write or accept, and dispatches
* {@link Dispatcher}. * the event to the appropriate {@link ChannelHandler} using the {@link Dispatcher}.
* *
* <p> * <p>Implementation: A NIO reactor runs in its own thread when it is started using {@link
* Implementation: A NIO reactor runs in its own thread when it is started using {@link #start()} method. * #start()} method. {@link NioReactor} uses {@link Selector} for realizing Synchronous Event
* {@link NioReactor} uses {@link Selector} for realizing Synchronous Event De-multiplexing. * De-multiplexing.
* *
* <p> * <p>NOTE: This is one of the ways to implement NIO reactor and it does not take care of all
* NOTE: This is one of the ways to implement NIO reactor and it does not take care of all possible edge cases which are * possible edge cases which are required in a real application. This implementation is meant to
* required in a real application. This implementation is meant to demonstrate the fundamental concepts that lie behind * demonstrate the fundamental concepts that lie behind Reactor pattern.
* Reactor pattern.
*/ */
public class NioReactor { public class NioReactor {
@ -62,21 +60,20 @@ public class NioReactor {
private final Selector selector; private final Selector selector;
private final Dispatcher dispatcher; private final Dispatcher dispatcher;
/** /**
* All the work of altering the SelectionKey operations and Selector operations are performed in the context of main * All the work of altering the SelectionKey operations and Selector operations are performed in
* event loop of reactor. So when any channel needs to change its readability or writability, a new command is added * the context of main event loop of reactor. So when any channel needs to change its readability
* in the command queue and then the event loop picks up the command and executes it in next iteration. * 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<Runnable> pendingCommands = new ConcurrentLinkedQueue<>(); private final Queue<Runnable> pendingCommands = new ConcurrentLinkedQueue<>();
private final ExecutorService reactorMain = Executors.newSingleThreadExecutor(); private final ExecutorService reactorMain = Executors.newSingleThreadExecutor();
/** /**
* Creates a reactor which will use provided {@code dispatcher} to dispatch events. The application can provide * Creates a reactor which will use provided {@code dispatcher} to dispatch events. The
* various implementations of dispatcher which suits its needs. * application can provide various implementations of dispatcher which suits its needs.
* *
* @param dispatcher * @param dispatcher a non-null dispatcher used to dispatch events on registered channels.
* a non-null dispatcher used to dispatch events on registered channels. * @throws IOException if any I/O error occurs.
* @throws IOException
* if any I/O error occurs.
*/ */
public NioReactor(Dispatcher dispatcher) throws IOException { public NioReactor(Dispatcher dispatcher) throws IOException {
this.dispatcher = dispatcher; this.dispatcher = dispatcher;
@ -100,10 +97,8 @@ public class NioReactor {
/** /**
* Stops the reactor and related resources such as dispatcher. * Stops the reactor and related resources such as dispatcher.
* *
* @throws InterruptedException * @throws InterruptedException if interrupted while stopping the reactor.
* 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 { public void stop() throws InterruptedException, IOException {
reactorMain.shutdownNow(); 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 * Registers a new channel (handle) with this reactor. Reactor will start waiting for events on
* notify of any events. While registering the channel the reactor uses {@link AbstractNioChannel#getInterestedOps()} * this channel and notify of any events. While registering the channel the reactor uses {@link
* to know about the interested operation of this channel. * AbstractNioChannel#getInterestedOps()} to know about the interested operation of this channel.
* *
* @param channel * @param channel a new channel on which reactor will wait for events. The channel must be bound
* a new channel on which reactor will wait for events. The channel must be bound prior to being registered. * prior to being registered.
* @return this * @return this
* @throws IOException * @throws IOException if any I/O error occurs.
* 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()); SelectionKey key = channel.getJavaChannel().register(selector, channel.getInterestedOps());
@ -143,8 +137,8 @@ public class NioReactor {
processPendingCommands(); processPendingCommands();
/* /*
* Synchronous event de-multiplexing happens here, this is blocking call which returns when it is possible to * Synchronous event de-multiplexing happens here, this is blocking call which returns when it
* initiate non-blocking operation on any of the registered channels. * is possible to initiate non-blocking operation on any of the registered channels.
*/ */
selector.select(); 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 * Initiation dispatcher logic, it checks the type of event and notifier application specific
* the event. * event handler to handle the event.
*/ */
private void processKey(SelectionKey key) throws IOException { private void processKey(SelectionKey key) throws IOException {
if (key.isAcceptable()) { 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 * Queues the change of operations request of a channel, which will change the interested
* sometime in future. * operations of the channel sometime in future.
* <p>
* This is a non-blocking method and does not guarantee that the operations have changed when this method returns.
* *
* @param key * <p>This is a non-blocking method and does not guarantee that the operations have changed when
* the key for which operations have to be changed. * this method returns.
* @param interestedOps *
* the new interest operations. * @param key the key for which operations have to be changed.
* @param interestedOps the new interest operations.
*/ */
public void changeOps(SelectionKey key, int interestedOps) { public void changeOps(SelectionKey key, int interestedOps) {
pendingCommands.add(new ChangeKeyOpsCommand(key, interestedOps)); pendingCommands.add(new ChangeKeyOpsCommand(key, interestedOps));

View File

@ -23,9 +23,6 @@
package com.iluwatar.reactor.framework; package com.iluwatar.reactor.framework;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@ -33,10 +30,12 @@ import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey; import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel; import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel; 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 * A wrapper over {@link NioServerSocketChannel} which can read and write data on a {@link
* {@link SocketChannel}. * SocketChannel}.
*/ */
public class NioServerSocketChannel extends AbstractNioChannel { public class NioServerSocketChannel extends AbstractNioChannel {
@ -47,8 +46,8 @@ public class NioServerSocketChannel extends AbstractNioChannel {
/** /**
* Creates a {@link ServerSocketChannel} which will bind at provided port and use * Creates a {@link ServerSocketChannel} which will bind at provided port and use
* <code>handler</code> to handle incoming events on this channel. * <code>handler</code> to handle incoming events on this channel.
* <p> *
* Note the constructor does not bind the socket, {@link #bind()} method should be called for * <p>Note the constructor does not bind the socket, {@link #bind()} method should be called for
* binding the socket. * 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.
@ -68,6 +67,8 @@ public class NioServerSocketChannel extends AbstractNioChannel {
} }
/** /**
* Get server socket channel.
*
* @return the underlying {@link ServerSocketChannel}. * @return the underlying {@link ServerSocketChannel}.
*/ */
@Override @Override

View File

@ -30,17 +30,15 @@ import java.nio.channels.SelectionKey;
* small applications where there are limited clients. Using this implementation limits the * small applications where there are limited clients. Using this implementation limits the
* scalability because the I/O thread performs the application specific processing. * scalability because the I/O thread performs the application specific processing.
* *
* <p> * <p>For better performance use {@link ThreadPoolDispatcher}.
* For better performance use {@link ThreadPoolDispatcher}.
* *
* @see ThreadPoolDispatcher * @see ThreadPoolDispatcher
*/ */
public class SameThreadDispatcher implements Dispatcher { public class SameThreadDispatcher implements Dispatcher {
/** /**
* Dispatches the read event in the context of caller thread. <br> * Dispatches the read event in the context of caller thread. <br> Note this is a blocking call.
* Note this is a blocking call. It returns only after the associated handler has handled the read * It returns only after the associated handler has handled the read event.
* event.
*/ */
@Override @Override
public void onChannelReadEvent(AbstractNioChannel channel, Object readObject, SelectionKey key) { public void onChannelReadEvent(AbstractNioChannel channel, Object readObject, SelectionKey key) {

View File

@ -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 * Submits the work of dispatching the read event to worker pool, where it gets picked up by
* worker threads. <br> * worker threads. <br> Note that this is a non-blocking call and returns immediately. It is not
* Note that this is a non-blocking call and returns immediately. It is not guaranteed that the * guaranteed that the event has been handled by associated handler.
* event has been handled by associated handler.
*/ */
@Override @Override
public void onChannelReadEvent(AbstractNioChannel channel, Object readObject, SelectionKey key) { public void onChannelReadEvent(AbstractNioChannel channel, Object readObject, SelectionKey key) {

View File

@ -28,25 +28,22 @@ 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 java.util.stream.IntStream;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
*
* In a multiple thread applications, the threads may try to synchronize the shared resources * 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 * 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. * write less" system as indeed the read operations are thread-safe to another read operation.
* <p>
* 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.
* *
* <p> * <p>Reader writer lock is a synchronization primitive that try to resolve this problem. This
* This example use two mutex to demonstrate the concurrent access of multiple readers and writers. * 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.
* *
* <p>This example use two mutex to demonstrate the concurrent access of multiple readers and
* writers.
* *
* @author hongshuwei@gmail.com * @author hongshuwei@gmail.com
*/ */
@ -55,7 +52,7 @@ public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class); private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/** /**
* Program entry point * Program entry point.
* *
* @param args command line args * @param args command line args
*/ */
@ -90,7 +87,6 @@ public class App {
LOGGER.info("More readers added..."); LOGGER.info("More readers added...");
// In the system console, it can see that the read operations are executed concurrently while // In the system console, it can see that the read operations are executed concurrently while
// write operations are exclusive. // write operations are exclusive.
executeService.shutdown(); executeService.shutdown();

View File

@ -24,12 +24,11 @@
package com.iluwatar.reader.writer.lock; package com.iluwatar.reader.writer.lock;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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 { public class Reader implements Runnable {
@ -42,7 +41,7 @@ public class Reader implements Runnable {
private long readingTime; private long readingTime;
/** /**
* Create new Reader * Create new Reader.
* *
* @param name - Name of the thread owning the reader * @param name - Name of the thread owning the reader
* @param readLock - Lock for this reader * @param readLock - Lock for this reader
@ -55,7 +54,7 @@ public class Reader implements Runnable {
} }
/** /**
* Create new Reader who reads for 250ms * Create new Reader who reads for 250ms.
* *
* @param name - Name of the thread owning the reader * @param name - Name of the thread owning the reader
* @param readLock - Lock for this reader * @param readLock - Lock for this reader
@ -78,8 +77,7 @@ public class Reader implements Runnable {
} }
/** /**
* Simulate the read operation * Simulate the read operation.
*
*/ */
public void read() throws InterruptedException { public void read() throws InterruptedException {
LOGGER.info("{} begin", name); LOGGER.info("{} begin", name);

View File

@ -29,15 +29,14 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* Class responsible for control the access for reader or writer * 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 * <p>Allows multiple readers to hold the lock at same time, but if any writer holds the lock then
* holds the lock then writer waits. This lock is not fair. * readers wait. If reader holds the lock then writer waits. This lock is not fair.
*/ */
public class ReaderWriterLock implements ReadWriteLock { public class ReaderWriterLock implements ReadWriteLock {
@ -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. * Global mutex is used to indicate that whether reader or writer gets the lock in the moment.
* <p> *
* 1. When it contains the reference of {@link #readerLock}, it means that the lock is acquired by the reader, another * <p>1. When it contains the reference of {@link #readerLock}, it means that the lock is
* reader can also do the read operation concurrently. <br> * acquired by the reader, another reader can also do the read operation concurrently. <br> 2.
* 2. When it contains the reference of reference of {@link #writerLock}, it means that the lock is acquired by the * When it contains the reference of reference of {@link #writerLock}, it means that the lock is
* writer exclusively, no more reader or writer can get the lock. * acquired by the writer exclusively, no more reader or writer can get the lock.
* <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 Set<Object> 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() { private boolean doesWriterOwnThisLock() {
return globalMutex.contains(writerLock); return globalMutex.contains(writerLock);
} }
/** /**
* Nobody get the lock when globalMutex contains nothing * Nobody get the lock when globalMutex contains nothing.
*
*/ */
private boolean isLockFree() { private boolean isLockFree() {
return globalMutex.isEmpty(); 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 { 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 * Acquire the globalMutex lock on behalf of current and future concurrent readers. Make sure no
* owns the lock. * writers currently owns the lock.
*/ */
private void acquireForReaders() { private void acquireForReaders() {
// Try to get the globalMutex lock for the first reader // Try to get the globalMutex lock for the first reader
@ -116,7 +114,8 @@ public class ReaderWriterLock implements ReadWriteLock {
try { try {
globalMutex.wait(); globalMutex.wait();
} catch (InterruptedException e) { } 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(); 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 { private class WriteLock implements Lock {

View File

@ -24,12 +24,11 @@
package com.iluwatar.reader.writer.lock; package com.iluwatar.reader.writer.lock;
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.Lock;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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 { public class Writer implements Runnable {
@ -42,7 +41,7 @@ public class Writer implements Runnable {
private long writingTime; private long writingTime;
/** /**
* Create new Writer who writes for 250ms * Create new Writer who writes for 250ms.
* *
* @param name - Name of the thread owning the writer * @param name - Name of the thread owning the writer
* @param writeLock - Lock for this writer * @param writeLock - Lock for this writer
@ -52,7 +51,7 @@ public class Writer implements Runnable {
} }
/** /**
* Create new Writer * Create new Writer.
* *
* @param name - Name of the thread owning the writer * @param name - Name of the thread owning the writer
* @param writeLock - Lock for this writer * @param writeLock - Lock for this writer
@ -79,7 +78,7 @@ public class Writer implements Runnable {
} }
/** /**
* Simulate the write operation * Simulate the write operation.
*/ */
public void write() throws InterruptedException { public void write() throws InterruptedException {
LOGGER.info("{} begin", name); LOGGER.info("{} begin", name);

View File

@ -25,7 +25,6 @@ package com.iluwatar.repository;
import java.util.List; import java.util.List;
import java.util.Optional; 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;
@ -38,8 +37,8 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
* query construction code is concentrated. This becomes more important when there are a large * 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 * number of domain classes or heavy querying. In these cases particularly, adding this layer helps
* minimize duplicate query logic. * minimize duplicate query logic.
* <p> *
* In this example we utilize Spring Data to automatically generate a repository for us from the * <p>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 * {@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 * 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 * 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); private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/** /**
* Program entry point * Program entry point.
* *
* @param args * @param args command line args
* command line args
*/ */
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -27,9 +27,7 @@ import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.Optional; 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;
import org.hibernate.jpa.HibernatePersistenceProvider; import org.hibernate.jpa.HibernatePersistenceProvider;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -42,9 +40,7 @@ import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
/** /**
* This is the same example as in {@link App} but with annotations based * This is the same example as in {@link App} but with annotations based configuration for Spring.
* configuration for Spring.
*
*/ */
@EnableJpaRepositories @EnableJpaRepositories
@SpringBootConfiguration @SpringBootConfiguration
@ -53,7 +49,7 @@ public class AppConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(AppConfig.class); private static final Logger LOGGER = LoggerFactory.getLogger(AppConfig.class);
/** /**
* Creation of H2 db * Creation of H2 db.
* *
* @return A new Instance of DataSource * @return A new Instance of DataSource
*/ */
@ -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 @Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() { public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean(); LocalContainerEntityManagerFactoryBean entityManager =
new LocalContainerEntityManagerFactoryBean();
entityManager.setDataSource(dataSource()); entityManager.setDataSource(dataSource());
entityManager.setPackagesToScan("com.iluwatar"); entityManager.setPackagesToScan("com.iluwatar");
entityManager.setPersistenceProvider(new HibernatePersistenceProvider()); entityManager.setPersistenceProvider(new HibernatePersistenceProvider());
@ -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(); Properties properties = new Properties();
@ -92,7 +89,7 @@ public class AppConfig {
} }
/** /**
* Get transaction manager * Get transaction manager.
*/ */
@Bean @Bean
public JpaTransactionManager transactionManager() throws SQLException { public JpaTransactionManager transactionManager() throws SQLException {
@ -102,10 +99,9 @@ public class AppConfig {
} }
/** /**
* Program entry point * Program entry point.
* *
* @param args * @param args command line args
* command line args
*/ */
public static void main(String[] args) { public static void main(String[] args) {

View File

@ -28,9 +28,7 @@ import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
/** /**
* * Person entity.
* Person entity
*
*/ */
@Entity @Entity
public class Person { public class Person {
@ -47,7 +45,7 @@ public class Person {
} }
/** /**
* Constructor * Constructor.
*/ */
public Person(String name, String surname, int age) { public Person(String name, String surname, int age) {
this.name = name; this.name = name;

View File

@ -28,9 +28,7 @@ import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
/** /**
* * Person repository.
* Person repository
*
*/ */
@Repository @Repository
public interface PersonRepository public interface PersonRepository

View File

@ -27,16 +27,15 @@ import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root; import javax.persistence.criteria.Root;
import org.springframework.data.jpa.domain.Specification; 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 { 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<Person> { public static class AgeBetweenSpec implements Specification<Person> {
@ -59,8 +58,7 @@ public class PersonSpecifications {
} }
/** /**
* Name specification * Name specification.
*
*/ */
public static class NameEqualSpec implements Specification<Person> { public static class NameEqualSpec implements Specification<Person> {
@ -71,7 +69,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) {

View File

@ -27,31 +27,30 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
*
* Resource Acquisition Is Initialization pattern was developed for exception safe resource * Resource Acquisition Is Initialization pattern was developed for exception safe resource
* management by C++ creator Bjarne Stroustrup. * management by C++ creator Bjarne Stroustrup.
* <p>
* In RAII resource is tied to object lifetime: resource allocation is done during object creation
* while resource deallocation is done during object destruction.
* <p>
* 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} * <p>In RAII resource is tied to object lifetime: resource allocation is done during object
* implements {@link java.io.Closeable}. Running the example, we can observe that both resources are * creation while resource deallocation is done during object destruction.
* automatically closed.
* <p>
* http://docs.oracle.com/javase/7/docs/technotes/guides/language/try-with-resources.html
* *
* <p>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.
*
* <p>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.
*
* <p>http://docs.oracle.com/javase/7/docs/technotes/guides/language/try-with-resources.html
*/ */
public class App { public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class); private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
/** /**
* Program entry point * Program entry point.
*/ */
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {

View File

@ -27,9 +27,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
/** /**
* * SlidingDoor resource.
* SlidingDoor resource
*
*/ */
public class SlidingDoor implements AutoCloseable { public class SlidingDoor implements AutoCloseable {

View File

@ -23,16 +23,13 @@
package com.iluwatar.resource.acquisition.is.initialization; package com.iluwatar.resource.acquisition.is.initialization;
import java.io.Closeable;
import java.io.IOException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.Closeable;
import java.io.IOException;
/** /**
* * TreasureChest resource.
* TreasureChest resource
*
*/ */
public class TreasureChest implements Closeable { public class TreasureChest implements Closeable {

View File

@ -31,30 +31,31 @@ import org.slf4j.LoggerFactory;
* the environment if the business requirements and nature of the failures allow it. By retrying * 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 * failed operations on external dependencies, the application may maintain stability and minimize
* negative impact on the user experience. * negative impact on the user experience.
* <p> *
* In our example, we have the {@link BusinessOperation} interface as an abstraction over * <p>In our example, we have the {@link BusinessOperation} interface as an abstraction over all
* all operations that our application performs involving remote systems. The calling code should * operations that our application performs involving remote systems. The calling code should remain
* remain decoupled from implementations. * decoupled from implementations.
* <p> *
* {@link FindCustomer} is a business operation that looks up a customer's record and returns * <p>{@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 * 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 * returning its ID. We can pass {@link CustomerNotFoundException} as one of its {@link
* {@link FindCustomer#FindCustomer(java.lang.String, com.iluwatar.retry.BusinessException...) * FindCustomer#FindCustomer(java.lang.String, com.iluwatar.retry.BusinessException...) constructor
* constructor parameters} in order to simulate not finding the customer. * parameters} in order to simulate not finding the customer.
* <p> *
* Imagine that, lately, this operation has experienced intermittent failures due to some weird * <p>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 * 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 * 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 * found to the problem, our engineers advise us to retry the operation a set number of times with a
* of times with a set delay between retries, although not too many retries otherwise the end user * set delay between retries, although not too many retries otherwise the end user will be left
* will be left waiting for a long time, while delays that are too short will not allow the database * waiting for a long time, while delays that are too short will not allow the database to recover
* to recover from the load. * from the load.
* <p> *
* To keep the calling code as decoupled as possible from this workaround, we have implemented the * <p>To keep the calling code as decoupled as possible from this workaround, we have implemented
* retry mechanism as a {@link BusinessOperation} named {@link Retry}. * the retry mechanism as a {@link BusinessOperation} named {@link Retry}.
* *
* @author George Aristy (george.aristy@gmail.com) * @author George Aristy (george.aristy@gmail.com)
* @see <a href="https://docs.microsoft.com/en-us/azure/architecture/patterns/retry">Retry pattern (Microsoft Azure Docs)</a> * @see <a href="https://docs.microsoft.com/en-us/azure/architecture/patterns/retry">Retry pattern
* (Microsoft Azure Docs)</a>
*/ */
public final class App { public final class App {
private static final Logger LOG = LoggerFactory.getLogger(App.class); private static final Logger LOG = LoggerFactory.getLogger(App.class);

View File

@ -24,10 +24,10 @@
package com.iluwatar.retry; package com.iluwatar.retry;
/** /**
* The top-most type in our exception hierarchy that signifies that an unexpected error * The top-most type in our exception hierarchy that signifies that an unexpected error condition
* condition occurred. Its use is reserved as a "catch-all" for cases where no other subtype * occurred. Its use is reserved as a "catch-all" for cases where no other subtype captures the
* captures the specificity of the error condition in question. Calling code is not expected to * specificity of the error condition in question. Calling code is not expected to be able to handle
* be able to handle this error and should be reported to the maintainers immediately. * this error and should be reported to the maintainers immediately.
* *
* @author George Aristy (george.aristy@gmail.com) * @author George Aristy (george.aristy@gmail.com)
*/ */
@ -35,7 +35,7 @@ public class BusinessException extends Exception {
private static final long serialVersionUID = 6235833142062144336L; private static final long serialVersionUID = 6235833142062144336L;
/** /**
* Ctor * Ctor.
* *
* @param message the error message * @param message the error message
*/ */

View File

@ -26,8 +26,8 @@ package com.iluwatar.retry;
/** /**
* Performs some business operation. * Performs some business operation.
* *
* @author George Aristy (george.aristy@gmail.com)
* @param <T> the return type * @param <T> the return type
* @author George Aristy (george.aristy@gmail.com)
*/ */
@FunctionalInterface @FunctionalInterface
public interface BusinessOperation<T> { public interface BusinessOperation<T> {

View File

@ -25,9 +25,10 @@ package com.iluwatar.retry;
/** /**
* Indicates that the customer was not found. * Indicates that the customer was not found.
* <p> *
* The severity of this error is bounded by its context: was the search for the customer triggered * <p>The severity of this error is bounded by its context: was the search for the customer
* by an input from some end user, or were the search parameters pulled from your database? * triggered by an input from some end user, or were the search parameters pulled from your
* database?
* *
* @author George Aristy (george.aristy@gmail.com) * @author George Aristy (george.aristy@gmail.com)
*/ */

View File

@ -29,8 +29,8 @@ import java.util.List;
/** /**
* Finds a customer, returning its ID from our records. * Finds a customer, returning its ID from our records.
* <p> *
* This is an imaginary operation that, for some imagined input, returns the ID for a customer. * <p>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 * 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. * purposes of this example it fails in a programmed way depending on the constructor parameters.
* *

View File

@ -33,8 +33,8 @@ import java.util.function.Predicate;
/** /**
* Decorates {@link BusinessOperation business operation} with "retry" capabilities. * Decorates {@link BusinessOperation business operation} with "retry" capabilities.
* *
* @author George Aristy (george.aristy@gmail.com)
* @param <T> the remote op's return type * @param <T> the remote op's return type
* @author George Aristy (george.aristy@gmail.com)
*/ */
public final class Retry<T> implements BusinessOperation<T> { public final class Retry<T> implements BusinessOperation<T> {
private final BusinessOperation<T> op; private final BusinessOperation<T> op;
@ -104,7 +104,6 @@ public final class Retry<T> implements BusinessOperation<T> {
//ignore //ignore
} }
} }
} } while (true);
while (true);
} }
} }

View File

@ -34,8 +34,8 @@ import java.util.function.Predicate;
/** /**
* Decorates {@link BusinessOperation business operation} with "retry" capabilities. * Decorates {@link BusinessOperation business operation} with "retry" capabilities.
* *
* @author George Aristy (george.aristy@gmail.com)
* @param <T> the remote op's return type * @param <T> the remote op's return type
* @author George Aristy (george.aristy@gmail.com)
*/ */
public final class RetryExponentialBackoff<T> implements BusinessOperation<T> { public final class RetryExponentialBackoff<T> implements BusinessOperation<T> {
private static final Random RANDOM = new Random(); private static final Random RANDOM = new Random();
@ -107,8 +107,7 @@ public final class RetryExponentialBackoff<T> implements BusinessOperation<T> {
//ignore //ignore
} }
} }
} } while (true);
while (true);
} }
} }