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:
parent
4dae1fae57
commit
9c8ad4485b
@ -23,10 +23,6 @@
|
||||
|
||||
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.ChannelHandler;
|
||||
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.NioServerSocketChannel;
|
||||
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
|
||||
* Service where it listens on multiple TCP or UDP sockets for incoming log requests.
|
||||
*
|
||||
* <p>
|
||||
* <i>INTENT</i> <br>
|
||||
* <p><i>INTENT</i> <br>
|
||||
* 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
|
||||
* which are called by reactor on specific events.
|
||||
*
|
||||
* <p>
|
||||
* <i>PROBLEM</i> <br>
|
||||
* <p><i>PROBLEM</i> <br>
|
||||
* Server applications in a distributed system must handle multiple clients that send them service
|
||||
* requests. Following forces need to be resolved:
|
||||
* <ul>
|
||||
@ -56,8 +53,7 @@ import com.iluwatar.reactor.framework.ThreadPoolDispatcher;
|
||||
* <li>Adaptability</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* <i>PARTICIPANTS</i> <br>
|
||||
* <p><i>PARTICIPANTS</i> <br>
|
||||
* <ul>
|
||||
* <li>Synchronous Event De-multiplexer
|
||||
* <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
|
||||
* increase).
|
||||
* The example uses Java NIO framework to implement the Reactor.
|
||||
*
|
||||
*/
|
||||
public class App {
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
* be submitted to {@link NioReactor}.
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>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 {
|
||||
|
||||
@ -70,6 +69,8 @@ public abstract class AbstractNioChannel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get channel.
|
||||
*
|
||||
* @return the wrapped NIO channel.
|
||||
*/
|
||||
public SelectableChannel getJavaChannel() {
|
||||
@ -77,8 +78,8 @@ 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
|
||||
@ -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() {
|
||||
@ -141,15 +144,14 @@ 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.
|
||||
*
|
||||
* <p>
|
||||
* This method is used by the {@link ChannelHandler} to send reply back to the client. <br>
|
||||
* <p>This method is used by the {@link ChannelHandler} to send reply back to the client. <br>
|
||||
* Example:
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* {@literal @}Override
|
||||
* public void handleChannelRead(AbstractNioChannel channel, Object readObject, SelectionKey key) {
|
||||
* byte[] data = ((ByteBuffer)readObject).array();
|
||||
* public void handleChannelRead(AbstractNioChannel channel, Object readObj, SelectionKey key) {
|
||||
* byte[] data = ((ByteBuffer)readObj).array();
|
||||
* ByteBuffer buffer = ByteBuffer.wrap("Server reply".getBytes());
|
||||
* channel.write(buffer, key);
|
||||
* }
|
||||
|
@ -29,9 +29,9 @@ import java.nio.channels.SelectionKey;
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>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 {
|
||||
|
||||
|
@ -29,12 +29,10 @@ 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. <br>
|
||||
* Dispatcher should call the {@link ChannelHandler} associated with the channel on which event
|
||||
* occurred.
|
||||
* I/O processing from application specific processing. <br> Dispatcher should call the {@link
|
||||
* ChannelHandler} associated with the channel on which event occurred.
|
||||
*
|
||||
* <p>
|
||||
* The application can customize the way in which event is dispatched such as using the reactor
|
||||
* <p>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
|
||||
@ -46,8 +44,7 @@ public interface Dispatcher {
|
||||
* provided in <code>readObject</code>. The implementation should dispatch this read event to the
|
||||
* associated {@link ChannelHandler} of <code>channel</code>.
|
||||
*
|
||||
* <p>
|
||||
* The type of <code>readObject</code> depends on the channel on which data was received.
|
||||
* <p>The type of <code>readObject</code> depends on the channel on which data was received.
|
||||
*
|
||||
* @param channel on which read event occurred
|
||||
* @param readObject object read by channel
|
||||
|
@ -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,8 +45,8 @@ public class NioDatagramChannel extends AbstractNioChannel {
|
||||
/**
|
||||
* Creates a {@link DatagramChannel} which will bind at provided port and use <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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
@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 <code>data</code> using
|
||||
* {@link DatagramPacket#setReceiver(SocketAddress)}.
|
||||
* datagram packet must be set in the <code>data</code> using {@link
|
||||
* DatagramPacket#setReceiver(SocketAddress)}.
|
||||
*/
|
||||
@Override
|
||||
public void write(Object data, SelectionKey key) {
|
||||
@ -146,6 +147,8 @@ public class NioDatagramChannel extends AbstractNioChannel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sender address.
|
||||
*
|
||||
* @return the sender address.
|
||||
*/
|
||||
public SocketAddress getSender() {
|
||||
@ -162,6 +165,8 @@ public class NioDatagramChannel extends AbstractNioChannel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get receiver address.
|
||||
*
|
||||
* @return the receiver address.
|
||||
*/
|
||||
public SocketAddress getReceiver() {
|
||||
@ -178,6 +183,8 @@ public class NioDatagramChannel extends AbstractNioChannel {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data.
|
||||
*
|
||||
* @return the underlying message that will be written on channel.
|
||||
*/
|
||||
public ByteBuffer getData() {
|
||||
|
@ -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}.
|
||||
* 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}.
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>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.
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>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<Runnable> 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.
|
||||
* 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.
|
||||
* @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;
|
||||
@ -100,10 +97,8 @@ 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.
|
||||
* 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.
|
||||
* @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.
|
||||
* <p>
|
||||
* This is a non-blocking method and does not guarantee that the operations have changed when this method returns.
|
||||
* Queues the change of operations request of a channel, which will change the interested
|
||||
* operations of the channel sometime in future.
|
||||
*
|
||||
* @param key
|
||||
* the key for which operations have to be changed.
|
||||
* @param interestedOps
|
||||
* the new interest operations.
|
||||
* <p>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));
|
||||
|
@ -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,8 +46,8 @@ public class NioServerSocketChannel extends AbstractNioChannel {
|
||||
/**
|
||||
* Creates a {@link ServerSocketChannel} which will bind at provided port and use
|
||||
* <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.
|
||||
*
|
||||
* @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}.
|
||||
*/
|
||||
@Override
|
||||
|
@ -30,17 +30,15 @@ import java.nio.channels.SelectionKey;
|
||||
* small applications where there are limited clients. Using this implementation limits the
|
||||
* scalability because the I/O thread performs the application specific processing.
|
||||
*
|
||||
* <p>
|
||||
* For better performance use {@link ThreadPoolDispatcher}.
|
||||
* <p>For better performance use {@link ThreadPoolDispatcher}.
|
||||
*
|
||||
* @see ThreadPoolDispatcher
|
||||
*/
|
||||
public class SameThreadDispatcher implements Dispatcher {
|
||||
|
||||
/**
|
||||
* Dispatches the read event in the context of caller thread. <br>
|
||||
* 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. <br> 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) {
|
||||
|
@ -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. <br>
|
||||
* 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. <br> 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) {
|
||||
|
@ -28,25 +28,22 @@ 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.
|
||||
* <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>
|
||||
* This example use two mutex to demonstrate the concurrent access of multiple readers and writers.
|
||||
* <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>This example use two mutex to demonstrate the concurrent access of multiple readers and
|
||||
* writers.
|
||||
*
|
||||
* @author hongshuwei@gmail.com
|
||||
*/
|
||||
@ -55,7 +52,7 @@ public class App {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
|
||||
/**
|
||||
* Program entry point
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args command line args
|
||||
*/
|
||||
@ -90,7 +87,6 @@ public class App {
|
||||
LOGGER.info("More readers added...");
|
||||
|
||||
|
||||
|
||||
// In the system console, it can see that the read operations are executed concurrently while
|
||||
// write operations are exclusive.
|
||||
executeService.shutdown();
|
||||
|
@ -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 {
|
||||
|
||||
@ -42,7 +41,7 @@ public class Reader implements Runnable {
|
||||
private long readingTime;
|
||||
|
||||
/**
|
||||
* Create new Reader
|
||||
* Create new Reader.
|
||||
*
|
||||
* @param name - Name of the thread owning the 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 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 {
|
||||
LOGGER.info("{} begin", name);
|
||||
|
@ -29,15 +29,14 @@ 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.
|
||||
* <p>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 {
|
||||
|
||||
@ -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.
|
||||
* <p>
|
||||
* 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. <br>
|
||||
* 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.
|
||||
* <p>
|
||||
* This is the most important field in this class to control the access for reader/writer.
|
||||
*
|
||||
* <p>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. <br> 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.
|
||||
*
|
||||
* <p>This is the most important field in this class to control the access for reader/writer.
|
||||
*/
|
||||
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() {
|
||||
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 {
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
@ -42,7 +41,7 @@ public class Writer implements Runnable {
|
||||
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 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 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 {
|
||||
LOGGER.info("{} begin", name);
|
||||
|
@ -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.
|
||||
* <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
|
||||
* 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
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args
|
||||
* command line args
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
|
@ -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,7 +49,7 @@ 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
|
||||
*/
|
||||
@ -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
|
||||
* Program entry point.
|
||||
*
|
||||
* @param args
|
||||
* command line args
|
||||
* @param args command line args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
|
||||
|
@ -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;
|
||||
|
@ -28,9 +28,7 @@ import org.springframework.data.repository.CrudRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
*
|
||||
* Person repository
|
||||
*
|
||||
* Person repository.
|
||||
*/
|
||||
@Repository
|
||||
public interface PersonRepository
|
||||
|
@ -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<Person> {
|
||||
|
||||
@ -59,8 +58,7 @@ public class PersonSpecifications {
|
||||
}
|
||||
|
||||
/**
|
||||
* Name specification
|
||||
*
|
||||
* Name specification.
|
||||
*/
|
||||
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) {
|
||||
|
||||
|
@ -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.
|
||||
* <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}
|
||||
* 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
|
||||
* <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.
|
||||
*
|
||||
* <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 {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||
|
||||
/**
|
||||
* Program entry point
|
||||
* Program entry point.
|
||||
*/
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
|
@ -27,9 +27,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
* SlidingDoor resource
|
||||
*
|
||||
* SlidingDoor resource.
|
||||
*/
|
||||
public class SlidingDoor implements AutoCloseable {
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -31,30 +31,31 @@ import org.slf4j.LoggerFactory;
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* {@link FindCustomer} is a business operation that looks up a customer's record and returns
|
||||
*
|
||||
* <p>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.
|
||||
*
|
||||
* <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
|
||||
* 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.
|
||||
* <p>
|
||||
* Imagine that, lately, this operation has experienced intermittent failures due to some weird
|
||||
* 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.
|
||||
*
|
||||
* <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
|
||||
* 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.
|
||||
* <p>
|
||||
* 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}.
|
||||
* 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.
|
||||
*
|
||||
* <p>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 <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 {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(App.class);
|
||||
|
@ -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,7 +35,7 @@ public class BusinessException extends Exception {
|
||||
private static final long serialVersionUID = 6235833142062144336L;
|
||||
|
||||
/**
|
||||
* Ctor
|
||||
* Ctor.
|
||||
*
|
||||
* @param message the error message
|
||||
*/
|
||||
|
@ -26,8 +26,8 @@ package com.iluwatar.retry;
|
||||
/**
|
||||
* Performs some business operation.
|
||||
*
|
||||
* @author George Aristy (george.aristy@gmail.com)
|
||||
* @param <T> the return type
|
||||
* @author George Aristy (george.aristy@gmail.com)
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface BusinessOperation<T> {
|
||||
|
@ -25,9 +25,10 @@ package com.iluwatar.retry;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* by an input from some end user, or were the search parameters pulled from your database?
|
||||
*
|
||||
* <p>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)
|
||||
*/
|
||||
|
@ -29,8 +29,8 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* purposes of this example it fails in a programmed way depending on the constructor parameters.
|
||||
*
|
||||
|
@ -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 <T> the remote op's return type
|
||||
* @author George Aristy (george.aristy@gmail.com)
|
||||
*/
|
||||
public final class Retry<T> implements BusinessOperation<T> {
|
||||
private final BusinessOperation<T> op;
|
||||
@ -104,7 +104,6 @@ public final class Retry<T> implements BusinessOperation<T> {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
} while (true);
|
||||
}
|
||||
}
|
||||
|
@ -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 <T> the remote op's return type
|
||||
* @author George Aristy (george.aristy@gmail.com)
|
||||
*/
|
||||
public final class RetryExponentialBackoff<T> implements BusinessOperation<T> {
|
||||
private static final Random RANDOM = new Random();
|
||||
@ -107,8 +107,7 @@ public final class RetryExponentialBackoff<T> implements BusinessOperation<T> {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
while (true);
|
||||
} while (true);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user