This is an automated email from the ASF dual-hosted git repository.

rmaucher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/main by this push:
     new a45fa4c73c Minor fixes from code review
a45fa4c73c is described below

commit a45fa4c73c03d7925371e80f8fa1826470a2289a
Author: remm <[email protected]>
AuthorDate: Thu Jul 9 20:42:02 2026 +0200

    Minor fixes from code review
    
    Direct access to entries in AbstractReplicatedMap (it seems the double
    lookup is obvious now and can be removed, but looking at the history
    things were a lot more convoluted before).
    Make ExceptionUtils constructor private, hopefully no regression on this
    one ...
    NioSender.setMessage looked really weird with offset > 0 (which does not
    happen).
    PooledSender called a second time keepalive.
    ReplicatedMap.publishEntryInfo should return an empty array instead of
    null or an exception.
    Update javadoc for AbstractReplicatedMap. The javadoc generated (using
    OpenCode) looks good.
---
 .../tribes/membership/LocalStrings.properties      |   1 +
 .../catalina/tribes/membership/StaticMember.java   |   2 +-
 .../membership/StaticMembershipProvider.java       |   7 +-
 .../tribes/tipis/AbstractReplicatedMap.java        | 114 +++++++++++++--------
 .../catalina/tribes/tipis/ReplicatedMap.java       |   8 +-
 .../catalina/tribes/transport/AbstractSender.java  |   2 +-
 .../catalina/tribes/transport/PooledSender.java    |  14 ++-
 .../catalina/tribes/transport/ReceiverBase.java    |  31 ++----
 .../tribes/transport/ReplicationTransmitter.java   |   2 +-
 .../catalina/tribes/transport/RxTaskPool.java      |   5 +-
 .../tribes/transport/nio/LocalStrings.properties   |   1 +
 .../catalina/tribes/transport/nio/NioReceiver.java |  10 +-
 .../tribes/transport/nio/NioReplicationTask.java   |   8 +-
 .../catalina/tribes/transport/nio/NioSender.java   |   8 +-
 .../tribes/transport/nio/PooledParallelSender.java |   7 +-
 java/org/apache/catalina/tribes/util/Arrays.java   |  16 ++-
 .../catalina/tribes/util/ExceptionUtils.java       |   2 +-
 .../apache/catalina/tribes/util/UUIDGenerator.java |  23 +++--
 18 files changed, 141 insertions(+), 120 deletions(-)

diff --git a/java/org/apache/catalina/tribes/membership/LocalStrings.properties 
b/java/org/apache/catalina/tribes/membership/LocalStrings.properties
index 687814df7c..6ab3bf6ff5 100644
--- a/java/org/apache/catalina/tribes/membership/LocalStrings.properties
+++ b/java/org/apache/catalina/tribes/membership/LocalStrings.properties
@@ -59,6 +59,7 @@ memberImpl.large.payload=Payload is too large for tribes to 
handle.
 memberImpl.notEnough.bytes=Not enough bytes in member package.
 memberImpl.package.small=Member package too small to validate.
 
+staticMember.invalid.host=Invalid host [{0}]
 staticMember.invalid.uuidLength=UUID must be exactly 16 bytes, not:[{0}]
 
 staticMembershipProvider.heartbeat.failed=Unable to send 
StaticMembershipProvider.ping message.
diff --git a/java/org/apache/catalina/tribes/membership/StaticMember.java 
b/java/org/apache/catalina/tribes/membership/StaticMember.java
index 7df9845e02..4baf279aed 100644
--- a/java/org/apache/catalina/tribes/membership/StaticMember.java
+++ b/java/org/apache/catalina/tribes/membership/StaticMember.java
@@ -69,7 +69,7 @@ public class StaticMember extends MemberImpl {
             try {
                 setHostname(host);
             } catch (IOException ioe) {
-                throw new RuntimeException(ioe);
+                throw new 
IllegalArgumentException(sm.getString("staticMember.invalid.host", host), ioe);
             }
         }
 
diff --git 
a/java/org/apache/catalina/tribes/membership/StaticMembershipProvider.java 
b/java/org/apache/catalina/tribes/membership/StaticMembershipProvider.java
index 489c976a65..3e94478057 100644
--- a/java/org/apache/catalina/tribes/membership/StaticMembershipProvider.java
+++ b/java/org/apache/catalina/tribes/membership/StaticMembershipProvider.java
@@ -119,6 +119,7 @@ public class StaticMembershipProvider extends 
MembershipProviderBase
 
     @Override
     public void init(Properties properties) throws Exception {
+        // All the default properties have been set by 
StaticMembershipService.setDefaults, so no need to check
         String expirationTimeStr = properties.getProperty("expirationTime");
         this.expirationTime = Long.parseLong(expirationTimeStr);
         String connectTimeoutStr = properties.getProperty("connectTimeout");
@@ -396,7 +397,7 @@ public class StaticMembershipProvider extends 
MembershipProviderBase
     protected void checkExpired() {
         Member[] expired = membership.expire(expirationTime);
         for (Member member : expired) {
-            membershipListener.memberDisappeared(member);
+            memberDisappeared(member);
         }
     }
 
@@ -506,8 +507,8 @@ public class StaticMembershipProvider extends 
MembershipProviderBase
 
         @Override
         public String toString() {
-            return "MemberMessage[" + "name=" + new String(membershipId) + "; 
type=" + getTypeDesc() + "; member=" +
-                    member + ']';
+            return "MemberMessage[" + "name=" + new String(membershipId, 
StandardCharsets.ISO_8859_1) + "; type=" +
+                    getTypeDesc() + "; member=" + member + ']';
         }
 
         /**
diff --git a/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java 
b/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java
index c2f527d630..ad005129bf 100644
--- a/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java
+++ b/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java
@@ -183,17 +183,28 @@ public abstract class AbstractReplicatedMap<K, V>
     // 
------------------------------------------------------------------------------
 
     /**
-     * Creates a new map.
-     *
-     * @param owner              The map owner
-     * @param channel            The channel to use for communication
-     * @param timeout            long - timeout for RPC messages
-     * @param mapContextName     String - unique name for this map, to allow 
multiple maps per channel
-     * @param initialCapacity    int - the size of this map, see HashMap
-     * @param loadFactor         float - load factor, see HashMap
-     * @param channelSendOptions Send options
-     * @param cls                - a list of classloaders to be used for 
deserialization of objects.
-     * @param terminate          - Flag for whether to terminate this map that 
failed to start.
+     * Creates a new replicated map with the specified configuration.
+     *
+     * Initializes the internal {@link ConcurrentHashMap} with the given 
capacity and load factor,
+     * then delegates to {@link #init(MapOwner, Channel, String, long, int, 
ClassLoader[], boolean)}
+     * to configure the map, register listeners, and perform state transfer 
from existing cluster members.
+     *
+     * @param owner              the object that owns this map and receives 
notifications when entries
+     *                           become primary on this node
+     * @param channel            the channel used for cluster communication; 
must not be {@code null}
+     * @param timeout            the timeout in milliseconds for RPC messages
+     * @param mapContextName     a unique name for this map that distinguishes 
it from other maps
+     *                           sharing the same channel
+     * @param initialCapacity    the initial capacity of the internal map, as 
defined by
+     *                           {@link 
ConcurrentHashMap#ConcurrentHashMap(int, float, int)}
+     * @param loadFactor         the load factor of the internal map, as 
defined by
+     *                           {@link 
ConcurrentHashMap#ConcurrentHashMap(int, float, int)}
+     * @param channelSendOptions the send options to use when transmitting 
messages through the channel
+     * @param cls                an array of class loaders used during 
deserialization of received objects,
+     *                           or {@code null} if no external loaders are 
needed
+     * @param terminate          if {@code true}, the map will terminate 
itself and throw a {@link RuntimeException}
+     *                           when initialization fails; if {@code false}, 
the failure is logged and the map
+     *                           continues in a degraded state
      */
     public AbstractReplicatedMap(MapOwner owner, Channel channel, long 
timeout, String mapContextName,
             int initialCapacity, float loadFactor, int channelSendOptions, 
ClassLoader[] cls, boolean terminate) {
@@ -218,16 +229,36 @@ public abstract class AbstractReplicatedMap<K, V>
     }
 
     /**
-     * Initializes the map by creating the RPC channel, registering itself as 
a channel listener This method is also
-     * responsible for initiating the state transfer
+     * Initializes the replicated map by configuring its internal state, 
registering with the channel,
+     * and performing state transfer from existing cluster members.
      *
-     * @param owner              Object
-     * @param channel            Channel
-     * @param mapContextName     String
-     * @param timeout            long
-     * @param channelSendOptions int
-     * @param cls                ClassLoader[]
-     * @param terminate          - Flag for whether to terminate this map that 
failed to start.
+     * This method performs the following steps:
+     * <ol>
+     *   <li>Stores the provided configuration parameters</li>
+     *   <li>Creates an {@link RpcChannel} for sending RPC messages</li>
+     *   <li>Registers this map as a {@link ChannelListener} and {@link 
MembershipListener} on the channel</li>
+     *   <li>Broadcasts a {@code MSG_INIT} message to announce this map to 
existing cluster members</li>
+     *   <li>Invokes {@link #transferState()} to receive the current map state 
from an existing member</li>
+     *   <li>Broadcasts a {@code MSG_START} message to signal that this map is 
ready for normal operation</li>
+     * </ol>
+     *
+     * If a {@link ChannelException} occurs during the broadcast or state 
transfer steps, the behavior
+     * depends on the {@code terminate} flag: when {@code true}, the map is 
torn down via {@link #breakdown()}
+     * and a {@link RuntimeException} is thrown; when {@code false}, the error 
is logged and the map
+     * continues in a partially initialized state.
+     *
+     * @param owner              the object that owns this map and receives 
notifications when entries
+     *                           become primary on this node
+     * @param channel            the channel used for cluster communication; 
must not be {@code null}
+     * @param mapContextName     a unique name for this map that distinguishes 
it from other maps
+     *                           sharing the same channel
+     * @param timeout            the timeout in milliseconds for RPC messages
+     * @param channelSendOptions the send options to use when transmitting 
messages through the channel
+     * @param cls                an array of class loaders used during 
deserialization of received objects,
+     *                           or {@code null} if no external loaders are 
needed
+     * @param terminate          if {@code true}, the map will terminate 
itself and throw a {@link RuntimeException}
+     *                           when initialization fails; if {@code false}, 
the failure is logged and the map
+     *                           continues in a degraded state
      */
     protected void init(MapOwner owner, Channel channel, String 
mapContextName, long timeout, int channelSendOptions,
             ClassLoader[] cls, boolean terminate) {
@@ -1323,12 +1354,8 @@ public abstract class AbstractReplicatedMap<K, V>
         entry.setCopy(false);
         entry.setPrimary(channel.getLocalMember(false));
 
-        V old = null;
-
-        // make sure that any old values get removed
-        if (containsKey(key)) {
-            old = remove(key);
-        }
+        // Make sure that any old values get removed, even if ours was only a 
proxy
+        V old = remove(key, notify);
         try {
             if (notify) {
                 Member[] backup = publishEntryInfo(key, value);
@@ -1390,7 +1417,7 @@ public abstract class AbstractReplicatedMap<K, V>
     }
 
     /**
-     * Returns the entire contents of the map Map.Entry.getValue() will return 
a LazyReplicatedMap.MapEntry object
+     * Returns the entire contents of the map Map.Entry.getValue() will return 
a AbstractReplicatedMap.MapEntry object
      * containing all the information about the object.
      *
      * @return Set
@@ -1426,7 +1453,7 @@ public abstract class AbstractReplicatedMap<K, V>
     public Set<Map.Entry<K,V>> entrySet() {
         LinkedHashSet<Map.Entry<K,V>> set = new 
LinkedHashSet<>(innerMap.size());
         for (Entry<K,MapEntry<K,V>> e : innerMap.entrySet()) {
-            MapEntry<K,V> entry = innerMap.get(e.getKey());
+            MapEntry<K,V> entry = e.getValue();
             if (entry != null && entry.isActive()) {
                 set.add(entry);
             }
@@ -1446,7 +1473,7 @@ public abstract class AbstractReplicatedMap<K, V>
         LinkedHashSet<K> set = new LinkedHashSet<>(innerMap.size());
         for (Entry<K,MapEntry<K,V>> e : innerMap.entrySet()) {
             K key = e.getKey();
-            MapEntry<K,V> entry = innerMap.get(key);
+            MapEntry<K,V> entry = e.getValue();
             if (entry != null && entry.isActive()) {
                 set.add(key);
             }
@@ -1463,15 +1490,12 @@ public abstract class AbstractReplicatedMap<K, V>
      */
     @Override
     public int size() {
-        // todo, implement a counter variable instead
         // only count active members in this node
         int counter = 0;
-        for (Entry<K,?> e : innerMap.entrySet()) {
-            if (e != null) {
-                MapEntry<K,V> entry = innerMap.get(e.getKey());
-                if (entry != null && entry.isActive() && entry.getValue() != 
null) {
-                    counter++;
-                }
+        for (Entry<K,MapEntry<K,V>> e : innerMap.entrySet()) {
+            MapEntry<K,V> entry = e.getValue();
+            if (entry != null && entry.isActive() && entry.getValue() != null) 
{
+                counter++;
             }
         }
         return counter;
@@ -1496,7 +1520,7 @@ public abstract class AbstractReplicatedMap<K, V>
     public Collection<V> values() {
         List<V> values = new ArrayList<>();
         for (Entry<K,MapEntry<K,V>> e : innerMap.entrySet()) {
-            MapEntry<K,V> entry = innerMap.get(e.getKey());
+            MapEntry<K,V> entry = e.getValue();
             if (entry != null && entry.isActive() && entry.getValue() != null) 
{
                 values.add(entry.getValue());
             }
@@ -1735,12 +1759,20 @@ public abstract class AbstractReplicatedMap<K, V>
 
         @Override
         public int hashCode() {
-            return key.hashCode();
+            return key == null ? 0 : key.hashCode();
         }
 
         @Override
         public boolean equals(Object o) {
-            return key.equals(o);
+            if (!(o instanceof MapEntry)) {
+                return false;
+            }
+            @SuppressWarnings("rawtypes")
+            MapEntry other = (MapEntry) o;
+            if (key == null) {
+                return other.key == null;
+            }
+            return key.equals(other.key);
         }
 
         /**
@@ -1851,8 +1883,8 @@ public abstract class AbstractReplicatedMap<K, V>
          */
         @Override
         public String toString() {
-            return "MapMessage[context=" + new String(mapId) + "; type=" + 
getTypeDesc() + "; key=" + key + "; value=" +
-                    value + ']';
+            return "MapMessage[context=" + new String(mapId, 
StandardCharsets.ISO_8859_1) + "; type=" + getTypeDesc() +
+                    "; key=" + key + "; value=" + value + ']';
         }
 
         /**
diff --git a/java/org/apache/catalina/tribes/tipis/ReplicatedMap.java 
b/java/org/apache/catalina/tribes/tipis/ReplicatedMap.java
index c436c0fb8a..527a8d9ee1 100644
--- a/java/org/apache/catalina/tribes/tipis/ReplicatedMap.java
+++ b/java/org/apache/catalina/tribes/tipis/ReplicatedMap.java
@@ -149,8 +149,8 @@ public class ReplicatedMap<K, V> extends 
AbstractReplicatedMap<K,V> {
         // select a backup node
         Member[] backup = getMapMembers();
 
-        if (backup == null || backup.length == 0) {
-            return null;
+        if (backup.length == 0) {
+            return backup;
         }
 
         try {
@@ -174,7 +174,7 @@ public class ReplicatedMap<K, V> extends 
AbstractReplicatedMap<K,V> {
             if (realFaultyMembers.length != 0) {
                 backup = excludeFromSet(realFaultyMembers, backup);
                 if (backup.length == 0) {
-                    throw e;
+                    return backup;
                 } else {
                     if (getLog().isWarnEnabled()) {
                         
getLog().warn(sm.getString("replicatedMap.unableReplicate.completely", key,
@@ -248,7 +248,7 @@ public class ReplicatedMap<K, V> extends 
AbstractReplicatedMap<K,V> {
                 }
             }
 
-        } // while
+        }
         long complete = System.currentTimeMillis() - start;
         if (log.isInfoEnabled()) {
             log.info(sm.getString("replicatedMap.relocate.complete", 
Long.toString(complete)));
diff --git a/java/org/apache/catalina/tribes/transport/AbstractSender.java 
b/java/org/apache/catalina/tribes/transport/AbstractSender.java
index eb6d5ed677..49ff819ca9 100644
--- a/java/org/apache/catalina/tribes/transport/AbstractSender.java
+++ b/java/org/apache/catalina/tribes/transport/AbstractSender.java
@@ -118,7 +118,7 @@ public abstract class AbstractSender implements DataSender {
     public boolean keepalive() {
         boolean disconnect = false;
         if (isUdpBased()) {
-            disconnect = true; // always disconnect UDP, TODO optimize the 
keepalive handling
+            disconnect = true; // always disconnect UDP
         } else if (keepAliveCount >= 0 && requestCount > keepAliveCount) {
             disconnect = true;
         } else if (keepAliveTime >= 0 && (System.currentTimeMillis() - 
connectTime) > keepAliveTime) {
diff --git a/java/org/apache/catalina/tribes/transport/PooledSender.java 
b/java/org/apache/catalina/tribes/transport/PooledSender.java
index 1f25b99083..35a267c372 100644
--- a/java/org/apache/catalina/tribes/transport/PooledSender.java
+++ b/java/org/apache/catalina/tribes/transport/PooledSender.java
@@ -64,7 +64,6 @@ public abstract class PooledSender extends AbstractSender 
implements MultiPointS
      * @param sender the sender to return
      */
     public void returnSender(DataSender sender) {
-        sender.keepalive();
         queue.returnSender(sender);
     }
 
@@ -221,12 +220,12 @@ public abstract class PooledSender extends AbstractSender 
implements MultiPointS
                 long delta = System.currentTimeMillis() - start;
                 if (delta > timeout && timeout > 0) {
                     return null;
-                } else {
-                    try {
-                        wait(Math.max(timeout - delta, 1));
-                    } catch (InterruptedException x) {
-                        // Ignore
-                    }
+                }
+                long remaining = timeout > 0 ? Math.max(timeout - delta, 1) : 
1;
+                try {
+                    wait(remaining);
+                } catch (InterruptedException x) {
+                    // Ignore
                 }
             }
         }
@@ -236,7 +235,6 @@ public abstract class PooledSender extends AbstractSender 
implements MultiPointS
                 sender.disconnect();
                 return;
             }
-            // to do
             inuse.remove(sender);
             // just in case the limit has changed
             if (notinuse.size() < this.getLimit()) {
diff --git a/java/org/apache/catalina/tribes/transport/ReceiverBase.java 
b/java/org/apache/catalina/tribes/transport/ReceiverBase.java
index 1351386dff..0ca6f9700e 100644
--- a/java/org/apache/catalina/tribes/transport/ReceiverBase.java
+++ b/java/org/apache/catalina/tribes/transport/ReceiverBase.java
@@ -145,21 +145,11 @@ public abstract class ReceiverBase implements 
ChannelReceiver, ListenCallback, R
         channel = null;
     }
 
-    /**
-     * Returns the message listener for this receiver.
-     *
-     * @return the message listener
-     */
     @Override
     public MessageListener getMessageListener() {
         return listener;
     }
 
-    /**
-     * Returns the port on which this receiver is listening.
-     *
-     * @return the port number
-     */
     @Override
     public int getPort() {
         return port;
@@ -183,11 +173,6 @@ public abstract class ReceiverBase implements 
ChannelReceiver, ListenCallback, R
         return txBufSize;
     }
 
-    /**
-     * Sets the message listener for this receiver.
-     *
-     * @param listener the message listener to set
-     */
     @Override
     public void setMessageListener(MessageListener listener) {
         this.listener = listener;
@@ -280,11 +265,12 @@ public abstract class ReceiverBase implements 
ChannelReceiver, ListenCallback, R
      */
     protected int bindUdp(DatagramSocket socket, int portstart, int retries) 
throws IOException {
         InetSocketAddress addr = null;
+        int port = portstart;
         while (retries > 0) {
             try {
-                addr = new InetSocketAddress(getBind(), portstart);
+                addr = new InetSocketAddress(getBind(), port);
                 socket.bind(addr);
-                setUdpPort(portstart);
+                setUdpPort(port);
                 log.info(sm.getString("receiverBase.udp.bind", addr));
                 return 0;
             } catch (IOException ioe) {
@@ -293,13 +279,12 @@ public abstract class ReceiverBase implements 
ChannelReceiver, ListenCallback, R
                     log.info(sm.getString("receiverBase.unable.bind.udp", 
addr));
                     throw ioe;
                 }
-                portstart++;
+                port++;
                 try {
                     Thread.sleep(25);
                 } catch (InterruptedException ti) {
                     Thread.currentThread().interrupt();
                 }
-                retries = bindUdp(socket, portstart, retries);
             }
         }
         return retries;
@@ -373,11 +358,6 @@ public abstract class ReceiverBase implements 
ChannelReceiver, ListenCallback, R
         return this.host;
     }
 
-    /**
-     * Returns the host address for this receiver.
-     *
-     * @return the host address
-     */
     @Override
     public String getHost() {
         return getAddress();
@@ -397,6 +377,7 @@ public abstract class ReceiverBase implements 
ChannelReceiver, ListenCallback, R
      *
      * @return true if the receiver is listening
      */
+    @Deprecated
     public boolean doListen() {
         return listen;
     }
@@ -406,6 +387,7 @@ public abstract class ReceiverBase implements 
ChannelReceiver, ListenCallback, R
      *
      * @return the message listener
      */
+    @Deprecated
     public MessageListener getListener() {
         return listener;
     }
@@ -616,6 +598,7 @@ public abstract class ReceiverBase implements 
ChannelReceiver, ListenCallback, R
      *
      * @param listener the message listener to set
      */
+    @Deprecated
     public void setListener(MessageListener listener) {
         this.listener = listener;
     }
diff --git 
a/java/org/apache/catalina/tribes/transport/ReplicationTransmitter.java 
b/java/org/apache/catalina/tribes/transport/ReplicationTransmitter.java
index 13a3db44b9..dfc9b5a83a 100644
--- a/java/org/apache/catalina/tribes/transport/ReplicationTransmitter.java
+++ b/java/org/apache/catalina/tribes/transport/ReplicationTransmitter.java
@@ -108,7 +108,7 @@ public class ReplicationTransmitter implements 
ChannelSender {
     /**
      * Call transmitter to check for sender socket status
      *
-     * @see org.apache.catalina.ha.tcp.SimpleTcpCluster#backgroundProcess()
+     * @see org.apache.catalina.tribes.ChannelSender#heartbeat()
      */
     @Override
     public void heartbeat() {
diff --git a/java/org/apache/catalina/tribes/transport/RxTaskPool.java 
b/java/org/apache/catalina/tribes/transport/RxTaskPool.java
index 6120bd379e..bf75c9aa05 100644
--- a/java/org/apache/catalina/tribes/transport/RxTaskPool.java
+++ b/java/org/apache/catalina/tribes/transport/RxTaskPool.java
@@ -21,8 +21,7 @@ import java.util.Iterator;
 import java.util.List;
 
 /**
- * A very simple thread pool class. The pool size is set at construction time 
and remains fixed. Threads are cycled
- * through a FIFO idle queue.
+ * A very simple thread pool class. Threads are cycled through a FIFO idle 
queue.
  */
 public class RxTaskPool {
 
@@ -30,7 +29,7 @@ public class RxTaskPool {
     final List<AbstractRxTask> used = new ArrayList<>();
 
     final Object mutex = new Object();
-    boolean running = true;
+    volatile boolean running = true;
 
     private int maxTasks;
     private int minTasks;
diff --git 
a/java/org/apache/catalina/tribes/transport/nio/LocalStrings.properties 
b/java/org/apache/catalina/tribes/transport/nio/LocalStrings.properties
index 441b425d12..7a4ad9a184 100644
--- a/java/org/apache/catalina/tribes/transport/nio/LocalStrings.properties
+++ b/java/org/apache/catalina/tribes/transport/nio/LocalStrings.properties
@@ -56,6 +56,7 @@ parallelNioSender.sender.disconnected.notRetry=Not retrying 
send for:[{0}]; Send
 parallelNioSender.sender.disconnected.sendFailed=Send failed, and sender is 
disconnected. Not retrying.
 parallelNioSender.unable.setup.NioSender=Unable to setup NioSender.
 
+pooledParallelSender.disconnectOnError=Disconnect following error
 pooledParallelSender.sender.disconnected=Sender not connected.
 pooledParallelSender.unable.open=Unable to open NIO selector.
 pooledParallelSender.unable.retrieveSender=Unable to retrieve a sender from 
the sender pool
diff --git a/java/org/apache/catalina/tribes/transport/nio/NioReceiver.java 
b/java/org/apache/catalina/tribes/transport/nio/NioReceiver.java
index 065b7d0ade..8602710505 100644
--- a/java/org/apache/catalina/tribes/transport/nio/NioReceiver.java
+++ b/java/org/apache/catalina/tribes/transport/nio/NioReceiver.java
@@ -170,7 +170,11 @@ public class NioReceiver extends ReceiverBase implements 
Runnable, NioReceiverMB
                 log.trace("Adding event to selector:" + event);
             }
             if (isListening()) {
-                selector.wakeup();
+                try {
+                    selector.wakeup();
+                } catch (ClosedSelectorException ignore) {
+                    // Selector already closed during shutdown
+                }
             }
         }
     }
@@ -298,7 +302,7 @@ public class NioReceiver extends ReceiverBase implements 
Runnable, NioReceiverMB
      * @throws IOException IO error
      */
     protected void listen() throws Exception {
-        if (doListen()) {
+        if (isListening()) {
             log.warn(sm.getString("nioReceiver.alreadyStarted"));
             return;
         }
@@ -313,7 +317,7 @@ public class NioReceiver extends ReceiverBase implements 
Runnable, NioReceiverMB
             registerChannel(selector, datagramChannel, SelectionKey.OP_READ, 
oreader);
         }
 
-        while (doListen() && selector != null) {
+        while (isListening() && selector != null) {
             // this may block for a long time, upon return the
             // selected set contains keys of the ready channels
             try {
diff --git 
a/java/org/apache/catalina/tribes/transport/nio/NioReplicationTask.java 
b/java/org/apache/catalina/tribes/transport/nio/NioReplicationTask.java
index 7e4567ee49..fa283949c7 100644
--- a/java/org/apache/catalina/tribes/transport/nio/NioReplicationTask.java
+++ b/java/org/apache/catalina/tribes/transport/nio/NioReplicationTask.java
@@ -42,11 +42,9 @@ import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 
 /**
- * A worker thread class which can drain channels and echo-back the input. 
Each instance is constructed with a reference
- * to the owning thread pool object. When started, the thread loops forever 
waiting to be awakened to service the
- * channel associated with a SelectionKey object. The worker is tasked by 
calling its serviceChannel() method with a
- * SelectionKey object. The serviceChannel() method stores the key reference 
in the thread object then calls notify() to
- * wake it up. When the channel has been drained, the worker thread returns 
itself to its parent pool.
+ * A worker thread class which drains a channel and processes received 
messages.
+ * Each instance services a single SelectionKey per invocation. After 
completion,
+ * the worker returns itself to its parent pool for reuse.
  */
 public class NioReplicationTask extends AbstractRxTask {
 
diff --git a/java/org/apache/catalina/tribes/transport/nio/NioSender.java 
b/java/org/apache/catalina/tribes/transport/nio/NioSender.java
index 3fdbea3aeb..de0e497cf5 100644
--- a/java/org/apache/catalina/tribes/transport/nio/NioSender.java
+++ b/java/org/apache/catalina/tribes/transport/nio/NioSender.java
@@ -426,7 +426,11 @@ public class NioSender extends AbstractSender {
      */
     public void setMessage(byte[] data, int offset, int length) throws 
IOException {
         if (data != null) {
-            current = data;
+            if (offset == 0 && length == data.length) {
+                current = data;
+            } else {
+                current = Arrays.copyOfRange(data, offset, offset + length);
+            }
             remaining = length;
             ackbuf.clear();
             if (writebuf != null) {
@@ -437,8 +441,6 @@ public class NioSender extends AbstractSender {
             if (writebuf.capacity() < length) {
                 writebuf = getBuffer(length);
             }
-
-            // TODO use ByteBuffer.wrap to avoid copying the data.
             writebuf.put(data, offset, length);
             writebuf.flip();
             if (isConnected()) {
diff --git 
a/java/org/apache/catalina/tribes/transport/nio/PooledParallelSender.java 
b/java/org/apache/catalina/tribes/transport/nio/PooledParallelSender.java
index d41b739bb9..36f26b75f6 100644
--- a/java/org/apache/catalina/tribes/transport/nio/PooledParallelSender.java
+++ b/java/org/apache/catalina/tribes/transport/nio/PooledParallelSender.java
@@ -24,12 +24,14 @@ import org.apache.catalina.tribes.Member;
 import org.apache.catalina.tribes.transport.DataSender;
 import org.apache.catalina.tribes.transport.PooledSender;
 import org.apache.catalina.tribes.util.StringManager;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
 
 /**
  * A pooled sender that uses {@link ParallelNioSender} instances for parallel 
message delivery.
  */
 public class PooledParallelSender extends PooledSender implements 
PooledParallelSenderMBean {
-    /** StringManager for internationalized log messages. */
+    private static final Log log = 
LogFactory.getLog(PooledParallelSender.class);
     protected static final StringManager sm = 
StringManager.getManager(PooledParallelSender.class);
 
     /**
@@ -61,6 +63,9 @@ public class PooledParallelSender extends PooledSender 
implements PooledParallel
                 sender.sendMessage(destination, message);
                 sender.keepalive();
             } catch (ChannelException x) {
+                if (log.isDebugEnabled()) {
+                    
log.debug(sm.getString("pooledParallelSender.disconnectOnError"), x);
+                }
                 sender.disconnect();
                 throw x;
             } finally {
diff --git a/java/org/apache/catalina/tribes/util/Arrays.java 
b/java/org/apache/catalina/tribes/util/Arrays.java
index 8d986d0968..e4c4cdf0a8 100644
--- a/java/org/apache/catalina/tribes/util/Arrays.java
+++ b/java/org/apache/catalina/tribes/util/Arrays.java
@@ -54,7 +54,7 @@ public class Arrays {
         if (keyoffset < 0 || keyoffset >= key.length) {
             throw new 
ArrayIndexOutOfBoundsException(sm.getString("arrays.keyoffset.outOfBounds"));
         }
-        if (length > (key.length - keyoffset)) {
+        if (length < 0 || length > (key.length - keyoffset)) {
             throw new 
ArrayIndexOutOfBoundsException(sm.getString("arrays.length.outOfBounds"));
         }
         // we don't have enough data to validate it
@@ -235,17 +235,12 @@ public class Arrays {
      * @return {@code true} if the arrays are equal
      */
     public static boolean equals(Object[] o1, Object[] o2) {
-        boolean result = o1.length == o2.length;
-        if (result) {
-            for (int i = 0; i < o1.length && result; i++) {
-                result = o1[i].equals(o2[i]);
-            }
-        }
-        return result;
+        return java.util.Arrays.equals(o1, o2);
     }
 
     /**
-     * Checks if two member arrays contain the same members.
+     * Checks if two member arrays contain the same members. Both arrays will
+     * be mutated to be sorted.
      *
      * @param m1 the first member array
      * @param m2 the second member array
@@ -258,7 +253,8 @@ public class Arrays {
     }
 
     /**
-     * Merges two member arrays, removing duplicates.
+     * Merges two member arrays, removing duplicates. Both arrays will
+     * be mutated to be sorted.
      *
      * @param m1 the first member array
      * @param m2 the second member array
diff --git a/java/org/apache/catalina/tribes/util/ExceptionUtils.java 
b/java/org/apache/catalina/tribes/util/ExceptionUtils.java
index a3908b9cba..90346f26ef 100644
--- a/java/org/apache/catalina/tribes/util/ExceptionUtils.java
+++ b/java/org/apache/catalina/tribes/util/ExceptionUtils.java
@@ -24,7 +24,7 @@ public class ExceptionUtils {
     /**
      * Default constructor. This class is not intended to be instantiated.
      */
-    public ExceptionUtils() {
+    private ExceptionUtils() {
         // NO-OP
     }
 
diff --git a/java/org/apache/catalina/tribes/util/UUIDGenerator.java 
b/java/org/apache/catalina/tribes/util/UUIDGenerator.java
index 95e1019fd2..6f78b57117 100644
--- a/java/org/apache/catalina/tribes/util/UUIDGenerator.java
+++ b/java/org/apache/catalina/tribes/util/UUIDGenerator.java
@@ -91,26 +91,27 @@ public class UUIDGenerator {
      * Generates a random UUID and stores it in the provided byte array.
      *
      * @param secure Whether to use a secure random generator
-     * @param into   The byte array to store the UUID
+     * @param dest   The byte array to store the UUID
      * @param offset The offset in the byte array
      *
      * @return The byte array containing the UUID
      *
-     * @throws ArrayIndexOutOfBoundsException If the byte array is too small
+     * @throws ArrayIndexOutOfBoundsException If the byte array is too small 
or null
      */
-    public static byte[] randomUUID(boolean secure, byte[] into, int offset) {
-        if ((offset + UUID_LENGTH) > into.length) {
+    public static byte[] randomUUID(boolean secure, byte[] dest, int offset) {
+        int destLength = (dest == null) ? 0 : dest.length;
+        if ((offset + UUID_LENGTH) > destLength) {
             throw new ArrayIndexOutOfBoundsException(
                     sm.getString("uuidGenerator.unable.fit", 
Integer.toString(UUID_LENGTH),
-                            Integer.toString(into.length), 
Integer.toString(offset + UUID_LENGTH)));
+                            Integer.toString(destLength), 
Integer.toString(offset + UUID_LENGTH)));
         }
         Random r = (secure && (secrand != null)) ? secrand : rand;
-        nextBytes(into, offset, UUID_LENGTH, r);
-        into[6 + offset] &= 0x0F;
-        into[6 + offset] |= (UUID_VERSION << 4);
-        into[8 + offset] &= 0x3F; // 0011 1111
-        into[8 + offset] |= (byte) 0x80; // 1000 0000
-        return into;
+        nextBytes(dest, offset, UUID_LENGTH, r);
+        dest[6 + offset] &= 0x0F;
+        dest[6 + offset] |= (UUID_VERSION << 4);
+        dest[8 + offset] &= 0x3F; // 0011 1111
+        dest[8 + offset] |= (byte) 0x80; // 1000 0000
+        return dest;
     }
 
     /**


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to