You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2019/11/14 12:05:24 UTC

[tomcat] 03/06: SpotBugs fixes back-ports and additional clean-up spotted along the way

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

markt pushed a commit to branch 7.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 459b3f301bde62300a8da3e02fc8ffd2bafc71e3
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Nov 13 22:13:46 2019 +0000

    SpotBugs fixes back-ports and additional clean-up spotted along the way
---
 java/org/apache/catalina/ha/ClusterDeployer.java   |   4 +-
 java/org/apache/catalina/ha/ClusterListener.java   |  16 +--
 .../catalina/loader/WebappClassLoaderBase.java     |  22 ++--
 java/org/apache/catalina/realm/JAASRealm.java      |  11 +-
 java/org/apache/catalina/realm/LockOutRealm.java   |   2 +-
 .../apache/catalina/security/SecurityConfig.java   |  33 ++++--
 java/org/apache/catalina/session/FileStore.java    |  17 ++-
 .../catalina/session/LocalStrings.properties       |   2 +
 .../catalina/session/LocalStrings_es.properties    |   1 +
 .../catalina/session/LocalStrings_fr.properties    |   2 +
 .../catalina/session/LocalStrings_ja.properties    |   2 +
 .../catalina/session/LocalStrings_ko.properties    |   2 +
 .../catalina/session/LocalStrings_zh_CN.properties |   2 +
 .../apache/catalina/session/StandardManager.java   |   8 +-
 java/org/apache/catalina/startup/Bootstrap.java    | 122 +++++++++------------
 .../org/apache/catalina/startup/ContextConfig.java |   6 +-
 .../catalina/startup/LocalStrings.properties       |   2 +
 .../catalina/startup/LocalStrings_fr.properties    |   2 +
 .../catalina/startup/LocalStrings_ja.properties    |   2 +
 .../catalina/startup/LocalStrings_ko.properties    |   2 +
 .../catalina/startup/LocalStrings_zh_CN.properties |   1 +
 java/org/apache/catalina/startup/Tomcat.java       |   4 +-
 .../apache/catalina/tribes/ChannelListener.java    |   1 -
 .../catalina/tribes/group/ChannelCoordinator.java  |   8 +-
 .../apache/catalina/tribes/group/GroupChannel.java |   5 +-
 .../group/interceptors/TcpPingInterceptor.java     |   4 +-
 .../group/interceptors/ThroughputInterceptor.java  |  10 +-
 .../org/apache/catalina/tribes/io/ChannelData.java |  22 ++--
 .../org/apache/catalina/tribes/io/XByteBuffer.java |   7 +-
 .../tribes/membership/McastServiceImpl.java        |   3 +-
 .../catalina/tribes/membership/Membership.java     |  34 ++++--
 .../tribes/tipis/AbstractReplicatedMap.java        |  21 ++--
 .../catalina/tribes/tipis/LazyReplicatedMap.java   |  21 +++-
 .../catalina/tribes/tipis/LocalStrings.properties  |  22 ++++
 .../tribes/tipis/LocalStrings_de.properties        |  17 +++
 .../tribes/tipis/LocalStrings_es.properties        |  19 ++++
 .../tribes/tipis/LocalStrings_fr.properties        |  22 ++++
 .../tribes/tipis/LocalStrings_ja.properties        |  22 ++++
 .../tribes/tipis/LocalStrings_ko.properties        |  22 ++++
 .../tribes/tipis/LocalStrings_zh_CN.properties     |  20 ++++
 .../catalina/tribes/tipis/ReplicatedMap.java       |  61 +++++++----
 .../catalina/tribes/transport/AbstractRxTask.java  |   8 +-
 .../tribes/transport/MultiPointSender.java         |   1 -
 .../catalina/tribes/transport/PooledSender.java    |  20 +---
 .../catalina/tribes/transport/RxTaskPool.java      |  27 ++---
 .../tribes/transport/bio/MultipointBioSender.java  |  26 +++--
 .../tribes/transport/nio/ParallelNioSender.java    |  40 ++++---
 .../catalina/tribes/util/ExecutorFactory.java      |   2 +-
 48 files changed, 444 insertions(+), 286 deletions(-)

diff --git a/java/org/apache/catalina/ha/ClusterDeployer.java b/java/org/apache/catalina/ha/ClusterDeployer.java
index 61798fe..a8dbb92 100644
--- a/java/org/apache/catalina/ha/ClusterDeployer.java
+++ b/java/org/apache/catalina/ha/ClusterDeployer.java
@@ -26,8 +26,6 @@ import org.apache.catalina.tribes.ChannelListener;
 /**
  * A <b>ClusterDeployer</b> interface allows to plug in and out the
  * different deployment implementations
- *
- * @author Filip Hanik
  */
 public interface ClusterDeployer extends ChannelListener {
     /**
@@ -42,7 +40,7 @@ public interface ClusterDeployer extends ChannelListener {
 
     /**
      * Stops the cluster deployer, the owning container will invoke this
-     * @throws LifecycleException
+     * @throws LifecycleException Error stopping cluster deployer
      */
     public void stop() throws LifecycleException;
 
diff --git a/java/org/apache/catalina/ha/ClusterListener.java b/java/org/apache/catalina/ha/ClusterListener.java
index be9509f..348b136 100644
--- a/java/org/apache/catalina/ha/ClusterListener.java
+++ b/java/org/apache/catalina/ha/ClusterListener.java
@@ -21,6 +21,8 @@ import java.io.Serializable;
 
 import org.apache.catalina.tribes.ChannelListener;
 import org.apache.catalina.tribes.Member;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
 
 
 /**
@@ -28,12 +30,10 @@ import org.apache.catalina.tribes.Member;
  * node is failed.
  *
  * @author Peter Rossbach
- * @author Filip Hanik
  */
 public abstract class ClusterListener implements ChannelListener {
 
-    private static final org.apache.juli.logging.Log log =
-        org.apache.juli.logging.LogFactory.getLog(ClusterListener.class);
+    private static final Log log = LogFactory.getLog(ClusterListener.class);
 
     //--Instance Variables--------------------------------------
 
@@ -67,16 +67,6 @@ public abstract class ClusterListener implements ChannelListener {
         this.cluster = cluster;
     }
 
-    @Override
-    public boolean equals(Object listener) {
-        return super.equals(listener);
-    }
-
-    @Override
-    public int hashCode() {
-        return super.hashCode();
-    }
-
     //--Logic---------------------------------------------------
 
     @Override
diff --git a/java/org/apache/catalina/loader/WebappClassLoaderBase.java b/java/org/apache/catalina/loader/WebappClassLoaderBase.java
index b86d38a..ded743d 100644
--- a/java/org/apache/catalina/loader/WebappClassLoaderBase.java
+++ b/java/org/apache/catalina/loader/WebappClassLoaderBase.java
@@ -2567,7 +2567,7 @@ public abstract class WebappClassLoaderBase extends URLClassLoader
                                 contextName, thread.getName()));
                     }
 
-                    // Don't try an stop the threads unless explicitly
+                    // Don't try and stop the threads unless explicitly
                     // configured to do so
                     if (!clearReferencesStopThreads) {
                         continue;
@@ -2583,11 +2583,9 @@ public abstract class WebappClassLoaderBase extends URLClassLoader
                         // "runnable" in IBM JDK
                         // "action" in Apache Harmony
                         Object target = null;
-                        for (String fieldName : new String[] { "target",
-                                "runnable", "action" }) {
+                        for (String fieldName : new String[] { "target", "runnable", "action" }) {
                             try {
-                                Field targetField = thread.getClass()
-                                        .getDeclaredField(fieldName);
+                                Field targetField = thread.getClass().getDeclaredField(fieldName);
                                 targetField.setAccessible(true);
                                 target = targetField.get(thread);
                                 break;
@@ -2598,12 +2596,10 @@ public abstract class WebappClassLoaderBase extends URLClassLoader
 
                         // "java.util.concurrent" code is in public domain,
                         // so all implementations are similar
-                        if (target != null &&
-                                target.getClass().getCanonicalName() != null
-                                && target.getClass().getCanonicalName().equals(
-                                "java.util.concurrent.ThreadPoolExecutor.Worker")) {
-                            Field executorField =
-                                target.getClass().getDeclaredField("this$0");
+                        if (target != null && target.getClass().getCanonicalName() != null &&
+                                target.getClass().getCanonicalName().equals(
+                                        "java.util.concurrent.ThreadPoolExecutor.Worker")) {
+                            Field executorField = target.getClass().getDeclaredField("this$0");
                             executorField.setAccessible(true);
                             Object executor = executorField.get(target);
                             if (executor instanceof ThreadPoolExecutor) {
@@ -2728,7 +2724,9 @@ public abstract class WebappClassLoaderBase extends URLClassLoader
                 synchronized(queue) {
                     newTasksMayBeScheduledField.setBoolean(thread, false);
                     clearMethod.invoke(queue);
-                    queue.notify();  // In case queue was already empty.
+                    // In case queue was already empty. Should only be one
+                    // thread waiting but use notifyAll() to be safe.
+                    queue.notifyAll();
                 }
 
             }catch (NoSuchFieldException nfe){
diff --git a/java/org/apache/catalina/realm/JAASRealm.java b/java/org/apache/catalina/realm/JAASRealm.java
index 62bb73a..2a85652 100644
--- a/java/org/apache/catalina/realm/JAASRealm.java
+++ b/java/org/apache/catalina/realm/JAASRealm.java
@@ -219,8 +219,7 @@ public class JAASRealm extends RealmBase {
      * @param useContext True means use context ClassLoader
      */
     public void setUseContextClassLoader(boolean useContext) {
-      useContextClassLoader = useContext;
-      log.info("Setting useContextClassLoader = " + useContext);
+        useContextClassLoader = useContext;
     }
 
     /**
@@ -630,6 +629,8 @@ public class JAASRealm extends RealmBase {
      * Load custom JAAS Configuration
      */
     protected Configuration getConfig() {
+        // Local copy to avoid possible NPE due to concurrent change
+        String configFile = this.configFile;
         try {
             if (jaasConfigurationLoaded) {
                 return jaasConfiguration;
@@ -639,12 +640,11 @@ public class JAASRealm extends RealmBase {
                     jaasConfigurationLoaded = true;
                     return null;
                 }
-                URL resource = Thread.currentThread().getContextClassLoader().
-                        getResource(configFile);
+                URL resource = Thread.currentThread().getContextClassLoader().getResource(configFile);
                 URI uri = resource.toURI();
                 @SuppressWarnings("unchecked")
                 Class<Configuration> sunConfigFile = (Class<Configuration>)
-                        Class.forName("com.sun.security.auth.login.ConfigFile");
+                Class.forName("com.sun.security.auth.login.ConfigFile");
                 Constructor<Configuration> constructor =
                         sunConfigFile.getConstructor(URI.class);
                 Configuration config = constructor.newInstance(uri);
@@ -669,6 +669,5 @@ public class JAASRealm extends RealmBase {
         } catch (ClassNotFoundException ex) {
             throw new RuntimeException(ex);
         }
-
     }
 }
diff --git a/java/org/apache/catalina/realm/LockOutRealm.java b/java/org/apache/catalina/realm/LockOutRealm.java
index 2760933..6ec2f79 100644
--- a/java/org/apache/catalina/realm/LockOutRealm.java
+++ b/java/org/apache/catalina/realm/LockOutRealm.java
@@ -93,7 +93,7 @@ public class LockOutRealm extends CombinedRealm {
      *  that prevents this component from being used
      */
     @Override
-    protected void startInternal() throws LifecycleException {
+    protected synchronized void startInternal() throws LifecycleException {
         // Configure the list of failed users to delete the oldest entry once it
         // exceeds the specified size
         failedUsers = new LinkedHashMap<String, LockRecord>(cacheSize, 0.75f,
diff --git a/java/org/apache/catalina/security/SecurityConfig.java b/java/org/apache/catalina/security/SecurityConfig.java
index 5b4cd04..85870ab 100644
--- a/java/org/apache/catalina/security/SecurityConfig.java
+++ b/java/org/apache/catalina/security/SecurityConfig.java
@@ -19,18 +19,20 @@ package org.apache.catalina.security;
 import java.security.Security;
 
 import org.apache.catalina.startup.CatalinaProperties;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
 
 /**
  * Util class to protect Catalina against package access and insertion.
  * The code are been moved from Catalina.java
  * @author the Catalina.java authors
- * @author Jean-Francois Arcand
  */
 public final class SecurityConfig{
-    private static SecurityConfig singleton = null;
 
-    private static final org.apache.juli.logging.Log log=
-        org.apache.juli.logging.LogFactory.getLog( SecurityConfig.class );
+    private static final Object singletonLock = new Object();
+    private static volatile SecurityConfig singleton = null;
+
+    private static final Log log = LogFactory.getLog(SecurityConfig.class);
 
 
     private static final String PACKAGE_ACCESS =  "sun.,"
@@ -49,26 +51,31 @@ public final class SecurityConfig{
     /**
      * List of protected package from conf/catalina.properties
      */
-    private String packageDefinition;
+    private final String packageDefinition;
 
 
     /**
      * List of protected package from conf/catalina.properties
      */
-    private String packageAccess;
+    private final String packageAccess;
 
 
     /**
      * Create a single instance of this class.
      */
-    private SecurityConfig(){
+    private SecurityConfig() {
+        String definition = null;
+        String access = null;
         try{
-            packageDefinition = CatalinaProperties.getProperty("package.definition");
-            packageAccess = CatalinaProperties.getProperty("package.access");
+            definition = CatalinaProperties.getProperty("package.definition");
+            access = CatalinaProperties.getProperty("package.access");
         } catch (java.lang.Exception ex){
             if (log.isDebugEnabled()){
                 log.debug("Unable to load properties using CatalinaProperties", ex);
             }
+        } finally {
+            packageDefinition = definition;
+            packageAccess = access;
         }
     }
 
@@ -78,8 +85,12 @@ public final class SecurityConfig{
      * @return an instance of that class.
      */
     public static SecurityConfig newInstance(){
-        if (singleton == null){
-            singleton = new SecurityConfig();
+        if (singleton == null) {
+            synchronized (singletonLock) {
+                if (singleton == null) {
+                    singleton = new SecurityConfig();
+                }
+            }
         }
         return singleton;
     }
diff --git a/java/org/apache/catalina/session/FileStore.java b/java/org/apache/catalina/session/FileStore.java
index 21a2211..9263bdf 100644
--- a/java/org/apache/catalina/session/FileStore.java
+++ b/java/org/apache/catalina/session/FileStore.java
@@ -25,6 +25,7 @@ import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.util.ArrayList;
+import java.util.List;
 
 import javax.servlet.ServletContext;
 
@@ -76,6 +77,7 @@ public final class FileStore extends StoreBase {
      */
     private static final String storeName = "fileStore";
 
+
     /**
      * Name to register for the background thread.
      */
@@ -118,6 +120,7 @@ public final class FileStore extends StoreBase {
         return threadName;
     }
 
+
     /**
      * Return the name for this Store, used for logging.
      */
@@ -137,7 +140,7 @@ public final class FileStore extends StoreBase {
         // Acquire the list of files in our storage directory
         File file = directory();
         if (file == null) {
-            return (0);
+            return 0;
         }
         String files[] = file.list();
 
@@ -182,18 +185,18 @@ public final class FileStore extends StoreBase {
         // Acquire the list of files in our storage directory
         File file = directory();
         if (file == null) {
-            return (new String[0]);
+            return new String[0];
         }
 
         String files[] = file.list();
 
         // Bugzilla 32130
         if((files == null) || (files.length < 1)) {
-            return (new String[0]);
+            return new String[0];
         }
 
         // Build and return the list of session identifiers
-        ArrayList<String> list = new ArrayList<String>();
+        List<String> list = new ArrayList<String>();
         int n = FILE_EXT.length();
         for (int i = 0; i < files.length; i++) {
             if (files[i].endsWith(FILE_EXT)) {
@@ -298,7 +301,10 @@ public final class FileStore extends StoreBase {
             manager.getContainer().getLogger().debug(sm.getString(getStoreName()+".removing",
                              id, file.getAbsolutePath()));
         }
-        file.delete();
+
+        if (file.exists() && !file.delete()) {
+            throw new IOException(sm.getString("fileStore.deleteSessionFailed", file));
+        }
     }
 
 
@@ -342,7 +348,6 @@ public final class FileStore extends StoreBase {
         } finally {
             oos.close();
         }
-
     }
 
 
diff --git a/java/org/apache/catalina/session/LocalStrings.properties b/java/org/apache/catalina/session/LocalStrings.properties
index f9ddb04..1b55ca9 100644
--- a/java/org/apache/catalina/session/LocalStrings.properties
+++ b/java/org/apache/catalina/session/LocalStrings.properties
@@ -31,6 +31,7 @@ applicationSession.value.iae=null value
 
 fileStore.createFailed=Unable to create directory [{0}] for the storage of session data
 fileStore.deleteFailed=Unable to delete file [{0}] which is preventing the creation of the session storage location
+fileStore.deleteSessionFailed=Unable to delete file [{0}] which is no longer required
 fileStore.loading=Loading Session [{0}] from file [{1}]
 fileStore.removing=Removing Session [{0}] at file [{1}]
 fileStore.saving=Saving Session [{0}] to file [{1}]
@@ -64,6 +65,7 @@ persistentManager.unloading=Saving [{0}] persisted sessions
 
 serverSession.value.iae=null value
 
+standardManager.deletePersistedFileFail=Unable to delete [{0}] after reading the persisted sessions. The continued presence of this file may cause future attempts to persist sessions to fail.
 standardManager.expireException=processsExpire:  Exception during session expiration
 standardManager.loading=Loading persisted sessions from [{0}]
 standardManager.loading.cnfe=ClassNotFoundException while loading persisted sessions: [{0}]
diff --git a/java/org/apache/catalina/session/LocalStrings_es.properties b/java/org/apache/catalina/session/LocalStrings_es.properties
index 9834881..09c7816 100644
--- a/java/org/apache/catalina/session/LocalStrings_es.properties
+++ b/java/org/apache/catalina/session/LocalStrings_es.properties
@@ -53,6 +53,7 @@ persistentManager.unloading=Salvando [{0}] sesiones persistidas
 
 serverSession.value.iae=valor nulo
 
+standardManager.deletePersistedFileFail=Imposible borrar [{0}] luego de leer las sessiones persistentes. La prensencia continua de este archivo causará que los intentos futuros de sesiones persistentes fallen.
 standardManager.expireException=processsExpire: Excepción durante la expiración de sesión
 standardManager.loading=Cargando sesiones persistidas desde [{0}]
 standardManager.loading.cnfe=ClassNotFoundException al cargar sesiones persistidas: [{0}]
diff --git a/java/org/apache/catalina/session/LocalStrings_fr.properties b/java/org/apache/catalina/session/LocalStrings_fr.properties
index 833e8d8..eed03cd 100644
--- a/java/org/apache/catalina/session/LocalStrings_fr.properties
+++ b/java/org/apache/catalina/session/LocalStrings_fr.properties
@@ -31,6 +31,7 @@ applicationSession.value.iae=valeur nulle
 
 fileStore.createFailed=Impossible de créer le répertoire [{0}] pour stocker les données de session
 fileStore.deleteFailed=Impossible d''effacer le fichier [{0}] qui empêche la création du support de stockage de sessions
+fileStore.deleteSessionFailed=Impossible d''effacer le fichier [{0}] qui n''est plus nécessaire
 fileStore.loading=Chargement de la Session [{0}] depuis le fichier [{1}]
 fileStore.removing=Retrait de la Session [{0}] du fichier [{1}]
 fileStore.saving=Sauvegarde de la Session [{0}] vers le fichier [{1}]
@@ -61,6 +62,7 @@ persistentManager.unloading=Sauvegarde de [{0}] sessions persistantes
 
 serverSession.value.iae=valeur nulle
 
+standardManager.deletePersistedFileFail=Impossible de supprimer [{0}] après avoir lu les sessions persistées, cela pourrait empêcher la future persistance des sessions
 standardManager.expireException="processsExpire":  Exception lors de l''expiration de la session
 standardManager.loading=Chargement des sessions qui ont persisté depuis [{0}]
 standardManager.loading.cnfe="ClassNotFoundException" lors du chargement de sessions persistantes: [{0}]
diff --git a/java/org/apache/catalina/session/LocalStrings_ja.properties b/java/org/apache/catalina/session/LocalStrings_ja.properties
index df84370..8f008b7 100644
--- a/java/org/apache/catalina/session/LocalStrings_ja.properties
+++ b/java/org/apache/catalina/session/LocalStrings_ja.properties
@@ -31,6 +31,7 @@ applicationSession.value.iae=null値です
 
 fileStore.createFailed=セッションデータを格納するディレクトリ[{0}]を作成できません
 fileStore.deleteFailed=ファイル [{0}] を削除できなかったため、セッションストレージを作成できません。
+fileStore.deleteSessionFailed=不要になったファイル[{0}]を削除できません
 fileStore.loading=セッション [{0}] をファイル [{1}] からロードします
 fileStore.removing=セッション [{0}] をファイル [{1}] から削除します
 fileStore.saving=セッション [{0}] をファイル [{1}] に保存します
@@ -61,6 +62,7 @@ persistentManager.unloading=[{0}] の持続されたセッションを保存し
 
 serverSession.value.iae=null値です
 
+standardManager.deletePersistedFileFail=永続化セッションを読み込んだ [{0}] を削減できません。ファイルが残っていると将来セッションの永続化に失敗する可能性があります。
 standardManager.expireException=processsExpire: セッションの終了処理中の例外です
 standardManager.loading=[{0}] から持続されたセッションをロードしています
 standardManager.loading.cnfe=持続されたセッションをロード中にClassNotFoundExceptionが発生しました: [{0}]
diff --git a/java/org/apache/catalina/session/LocalStrings_ko.properties b/java/org/apache/catalina/session/LocalStrings_ko.properties
index af13bdf..e8057d5 100644
--- a/java/org/apache/catalina/session/LocalStrings_ko.properties
+++ b/java/org/apache/catalina/session/LocalStrings_ko.properties
@@ -28,6 +28,7 @@ JDBCStore.wrongDataSource=JNDI DataSource [{0}]을(를) 열 수 없습니다.
 
 fileStore.createFailed=세션 데이터 저장소를 위한 디렉토리[{0}]을(를) 생성할 수 없습니다.
 fileStore.deleteFailed=파일 [{0}]을(를) 삭제할 수 없습니다. 이는 세션 저장소 위치의 생성을 방해하고 있습니다.
+fileStore.deleteSessionFailed=더 이상 필요하지 않은 파일 [{0}]을(를) 삭제할 수 없습니다.
 fileStore.loading=파일 [{1}](으)로부터 세션 [{0}]을(를) 로드합니다.
 fileStore.removing=파일 [{1}]에 저장된 세션 [{0}]을(를) 제거합니다.
 fileStore.saving=세션 [{0}]을(를) 파일 [{1}]에 저장합니다.
@@ -52,6 +53,7 @@ persistentManager.swapTooManyActive=[{1}]초 동안 비활성화 상태에 있
 persistentManager.tooManyActive=활성화된 세션들이 너무 많습니다: [{0}]. 세션 저장소로 내보낼 만한 유휴 세션들을 찾습니다.
 persistentManager.unloading=[{0}]개의 세션들을 저장합니다.
 
+standardManager.deletePersistedFileFail=저장된 세션들을 읽은 후 [{0}]을(를) 삭제할 수 없습니다. 이 파일이 계속 존재한다면, 이후 세션을 저장하려는 시도들이 이로 인해 실패할 수 있습니다.
 standardManager.loading=[{0}](으)로부터 저장된 세션들을 로드합니다.
 standardManager.managerLoad=세션 저장소로부터 세션들을 로드하는 중 예외 발생
 standardManager.managerUnload=세션들을 저장소로 언로드하는 중 예외 발생
diff --git a/java/org/apache/catalina/session/LocalStrings_zh_CN.properties b/java/org/apache/catalina/session/LocalStrings_zh_CN.properties
index b84f45e..a98f87e 100644
--- a/java/org/apache/catalina/session/LocalStrings_zh_CN.properties
+++ b/java/org/apache/catalina/session/LocalStrings_zh_CN.properties
@@ -23,6 +23,7 @@ JDBCStore.saving=保存Session [{0}] 到数据库 [{1}]
 JDBCStore.wrongDataSource=无法打开 JNDI 数据源 [{0}]
 
 fileStore.deleteFailed=无法删除阻止创建会话存储位置的文件 [{0}]
+fileStore.deleteSessionFailed=无法删除不再需要的文件[{0}]
 
 managerBase.createSession.ise=createSession:活跃session过多
 managerBase.setContextNotNew=如果Manager未处于NEW状态,则调用setContext()以更改与Manager关联的Context是非法的
@@ -34,6 +35,7 @@ persistentManager.swapIn=在表单存储中,交换会话[{0}]
 persistentManager.swapMaxIdle=交换会话[{0}]以存储,空闲为[{1}]秒
 persistentManager.swapTooManyActive=太多活跃会话,替换闲置 [{1}] 秒的会话 [{0}]
 
+standardManager.deletePersistedFileFail=读取持久会话后无法删除[{0}]。 此文件的持续存在可能导致将来尝试持续会话失败。
 standardManager.managerLoad=从持久化存储加载会话发生异常
 standardManager.managerUnload=卸载会话到持久存储的异常
 standardManager.unloading.nosessions=没有要卸载的持久会话
diff --git a/java/org/apache/catalina/session/StandardManager.java b/java/org/apache/catalina/session/StandardManager.java
index ef6ea91..1a6917d 100644
--- a/java/org/apache/catalina/session/StandardManager.java
+++ b/java/org/apache/catalina/session/StandardManager.java
@@ -30,6 +30,7 @@ import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.util.ArrayList;
 import java.util.Iterator;
+import java.util.List;
 
 import javax.servlet.ServletContext;
 
@@ -55,7 +56,6 @@ import org.apache.tomcat.util.ExceptionUtils;
  * <code>stop()</code> methods of this class at the correct times.
  *
  * @author Craig R. McClanahan
- * @author Jean-Francois Arcand
  */
 public class StandardManager extends ManagerBase {
 
@@ -294,7 +294,9 @@ public class StandardManager extends ManagerBase {
 
                 // Delete the persistent storage file
                 if (file.exists()) {
-                    file.delete();
+                        if (!file.delete()) {
+                            log.warn(sm.getString("standardManager.deletePersistedFileFail", file));
+                        }
                 }
             }
         }
@@ -389,7 +391,7 @@ public class StandardManager extends ManagerBase {
         }
 
         // Write the number of active sessions, followed by the details
-        ArrayList<StandardSession> list = new ArrayList<StandardSession>();
+        List<StandardSession> list = new ArrayList<StandardSession>();
         synchronized (sessions) {
             if (log.isDebugEnabled()) {
                 log.debug("Unloading " + sessions.size() + " sessions");
diff --git a/java/org/apache/catalina/startup/Bootstrap.java b/java/org/apache/catalina/startup/Bootstrap.java
index a8a6822..acb3b51 100644
--- a/java/org/apache/catalina/startup/Bootstrap.java
+++ b/java/org/apache/catalina/startup/Bootstrap.java
@@ -48,14 +48,11 @@ public final class Bootstrap {
 
     private static final Log log = LogFactory.getLog(Bootstrap.class);
 
-
-    // ------------------------------------------------------- Static Variables
-
-
     /**
      * Daemon object used by main.
      */
-    private static Bootstrap daemon = null;
+    private static final Object daemonLock = new Object();
+    private static volatile Bootstrap daemon = null;
 
 
     // -------------------------------------------------------------- Variables
@@ -66,7 +63,6 @@ public final class Bootstrap {
      */
     private Object catalinaDaemon = null;
 
-
     ClassLoader commonLoader = null;
     ClassLoader catalinaLoader = null;
     ClassLoader sharedLoader = null;
@@ -78,9 +74,9 @@ public final class Bootstrap {
     private void initClassLoaders() {
         try {
             commonLoader = createClassLoader("common", null);
-            if( commonLoader == null ) {
+            if (commonLoader == null) {
                 // no config file, default to this loader - we might be in a 'single' env.
-                commonLoader=this.getClass().getClassLoader();
+                commonLoader = this.getClass().getClassLoader();
             }
             catalinaLoader = createClassLoader("server", commonLoader);
             sharedLoader = createClassLoader("shared", commonLoader);
@@ -114,8 +110,7 @@ public final class Bootstrap {
             try {
                 @SuppressWarnings("unused")
                 URL url = new URL(repository);
-                repositories.add(
-                        new Repository(repository, RepositoryType.URL));
+                repositories.add(new Repository(repository, RepositoryType.URL));
                 continue;
             } catch (MalformedURLException e) {
                 // Ignore
@@ -125,20 +120,18 @@ public final class Bootstrap {
             if (repository.endsWith("*.jar")) {
                 repository = repository.substring
                     (0, repository.length() - "*.jar".length());
-                repositories.add(
-                        new Repository(repository, RepositoryType.GLOB));
+                repositories.add(new Repository(repository, RepositoryType.GLOB));
             } else if (repository.endsWith(".jar")) {
-                repositories.add(
-                        new Repository(repository, RepositoryType.JAR));
+                repositories.add(new Repository(repository, RepositoryType.JAR));
             } else {
-                repositories.add(
-                        new Repository(repository, RepositoryType.DIR));
+                repositories.add(new Repository(repository, RepositoryType.DIR));
             }
         }
 
         return ClassLoaderFactory.createClassLoader(repositories, parent);
     }
 
+
     /**
      * System property replacement in the given string.
      *
@@ -187,10 +180,9 @@ public final class Bootstrap {
 
     /**
      * Initialize daemon.
+     * @throws Exception Fatal initialization error
      */
-    public void init()
-        throws Exception
-    {
+    public void init() throws Exception {
 
         // Set Catalina path
         setCatalinaHome();
@@ -223,15 +215,13 @@ public final class Bootstrap {
         method.invoke(startupInstance, paramValues);
 
         catalinaDaemon = startupInstance;
-
     }
 
 
     /**
      * Load daemon.
      */
-    private void load(String[] arguments)
-        throws Exception {
+    private void load(String[] arguments) throws Exception {
 
         // Call the load() method
         String methodName = "load";
@@ -248,10 +238,10 @@ public final class Bootstrap {
         }
         Method method =
             catalinaDaemon.getClass().getMethod(methodName, paramTypes);
-        if (log.isDebugEnabled())
+        if (log.isDebugEnabled()) {
             log.debug("Calling startup class " + method);
+        }
         method.invoke(catalinaDaemon, param);
-
     }
 
 
@@ -261,10 +251,8 @@ public final class Bootstrap {
     private Object getServer() throws Exception {
 
         String methodName = "getServer";
-        Method method =
-            catalinaDaemon.getClass().getMethod(methodName);
+        Method method = catalinaDaemon.getClass().getMethod(methodName);
         return method.invoke(catalinaDaemon);
-
     }
 
 
@@ -273,63 +261,62 @@ public final class Bootstrap {
 
     /**
      * Load the Catalina daemon.
+     * @param arguments Initialization arguments
+     * @throws Exception Fatal initialization error
      */
-    public void init(String[] arguments)
-        throws Exception {
+    public void init(String[] arguments) throws Exception {
 
         init();
         load(arguments);
-
     }
 
 
     /**
      * Start the Catalina daemon.
+     * @throws Exception Fatal start error
      */
-    public void start()
-        throws Exception {
-        if( catalinaDaemon==null ) init();
+    public void start() throws Exception {
+        if (catalinaDaemon == null) {
+            init();
+        }
 
-        Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
+        Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null);
         method.invoke(catalinaDaemon, (Object [])null);
-
     }
 
 
     /**
      * Stop the Catalina Daemon.
+     * @throws Exception Fatal stop error
      */
-    public void stop()
-        throws Exception {
-
-        Method method = catalinaDaemon.getClass().getMethod("stop", (Class [] ) null);
-        method.invoke(catalinaDaemon, (Object [] ) null);
-
+    public void stop() throws Exception {
+        Method method = catalinaDaemon.getClass().getMethod("stop", (Class []) null);
+        method.invoke(catalinaDaemon, (Object []) null);
     }
 
 
     /**
      * Stop the standalone server.
+     * @throws Exception Fatal stop error
      */
-    public void stopServer()
-        throws Exception {
+    public void stopServer() throws Exception {
 
         Method method =
             catalinaDaemon.getClass().getMethod("stopServer", (Class []) null);
         method.invoke(catalinaDaemon, (Object []) null);
-
     }
 
 
    /**
      * Stop the standalone server.
+     * @param arguments Command line arguments
+     * @throws Exception Fatal stop error
      */
-    public void stopServer(String[] arguments)
-        throws Exception {
+    public void stopServer(String[] arguments) throws Exception {
 
         Object param[];
         Class<?> paramTypes[];
-        if (arguments==null || arguments.length==0) {
+        if (arguments == null || arguments.length == 0) {
             paramTypes = null;
             param = null;
         } else {
@@ -341,12 +328,13 @@ public final class Bootstrap {
         Method method =
             catalinaDaemon.getClass().getMethod("stopServer", paramTypes);
         method.invoke(catalinaDaemon, param);
-
     }
 
 
     /**
      * Set flag.
+     * @param await <code>true</code> if the daemon should block
+     * @throws Exception Reflection error
      */
     public void setAwait(boolean await)
         throws Exception {
@@ -358,12 +346,9 @@ public final class Bootstrap {
         Method method =
             catalinaDaemon.getClass().getMethod("setAwait", paramTypes);
         method.invoke(catalinaDaemon, paramValues);
-
     }
 
-    public boolean getAwait()
-        throws Exception
-    {
+    public boolean getAwait() throws Exception {
         Class<?> paramTypes[] = new Class[0];
         Object paramValues[] = new Object[0];
         Method method =
@@ -391,22 +376,24 @@ public final class Bootstrap {
      */
     public static void main(String args[]) {
 
-        if (daemon == null) {
-            // Don't set daemon until init() has completed
-            Bootstrap bootstrap = new Bootstrap();
-            try {
-                bootstrap.init();
-            } catch (Throwable t) {
-                handleThrowable(t);
-                t.printStackTrace();
-                return;
+        synchronized (daemonLock) {
+            if (daemon == null) {
+                // Don't set daemon until init() has completed
+                Bootstrap bootstrap = new Bootstrap();
+                try {
+                    bootstrap.init();
+                } catch (Throwable t) {
+                    handleThrowable(t);
+                    t.printStackTrace();
+                    return;
+                }
+                daemon = bootstrap;
+            } else {
+                // When running as a service the call to stop will be on a new
+                // thread so make sure the correct class loader is used to
+                // prevent a range of class not found exceptions.
+                Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
             }
-            daemon = bootstrap;
-        } else {
-            // When running as a service the call to stop will be on a new
-            // thread so make sure the correct class loader is used to prevent
-            // a range of class not found exceptions.
-            Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
         }
 
         try {
@@ -450,7 +437,6 @@ public final class Bootstrap {
             t.printStackTrace();
             System.exit(1);
         }
-
     }
 
     public void setCatalinaHome(String s) {
diff --git a/java/org/apache/catalina/startup/ContextConfig.java b/java/org/apache/catalina/startup/ContextConfig.java
index b29ce97..030c800 100644
--- a/java/org/apache/catalina/startup/ContextConfig.java
+++ b/java/org/apache/catalina/startup/ContextConfig.java
@@ -212,7 +212,7 @@ public class ContextConfig implements LifecycleListener {
     /**
      * The Context we are associated with.
      */
-    protected Context context = null;
+    protected volatile Context context = null;
 
 
     /**
@@ -833,7 +833,7 @@ public class ContextConfig implements LifecycleListener {
     /**
      * Process a "init" event for this Context.
      */
-    protected void init() {
+    protected synchronized void init() {
         // Called from StandardContext.init()
 
         Digester contextDigester = createContextDigester();
@@ -2821,7 +2821,7 @@ public class ContextConfig implements LifecycleListener {
         @Override
         public void lifecycleEvent(LifecycleEvent event) {
 
-            if (event.getType() == Lifecycle.AFTER_DESTROY_EVENT) {
+            if (Lifecycle.AFTER_DESTROY_EVENT.equals(event.getType())) {
                 Host host = (Host) event.getSource();
                 hostWebXmlCache.remove(host);
             }
diff --git a/java/org/apache/catalina/startup/LocalStrings.properties b/java/org/apache/catalina/startup/LocalStrings.properties
index a405f28..7e26451 100644
--- a/java/org/apache/catalina/startup/LocalStrings.properties
+++ b/java/org/apache/catalina/startup/LocalStrings.properties
@@ -151,6 +151,8 @@ tldConfig.webxmlStart=Scanning <taglib> elements in web.xml
 
 tomcat.addWebapp.conflictChild=Unable to deploy WAR at [{0}] to context path [{1}] because of existing context [{2}]
 tomcat.addWebapp.conflictFile=Unable to deploy WAR at [{0}] to context path [{1}] because of existing file [{2}]
+tomcat.baseDirMakeFail=Unable to create the directory [{0}] to use as the base directory
+tomcat.baseDirNotDir=The location [{0}] specified for the base directory is not a directory
 
 userConfig.database=Exception loading user database
 userConfig.deploy=Deploying web application for user [{0}]
diff --git a/java/org/apache/catalina/startup/LocalStrings_fr.properties b/java/org/apache/catalina/startup/LocalStrings_fr.properties
index 906ba1a..1c2640a 100644
--- a/java/org/apache/catalina/startup/LocalStrings_fr.properties
+++ b/java/org/apache/catalina/startup/LocalStrings_fr.properties
@@ -125,6 +125,8 @@ passwdUserDatabase.readFail=Echec d'obtention de la liste complète des utilisat
 
 tomcat.addWebapp.conflictChild=Impossible de déployer le WAR à [{0}] sur le chemin de contexte [{1}] à cause du contexte existant [{2}]
 tomcat.addWebapp.conflictFile=Impossible de déployer le WAR à [{0}] sur le chemin de contexte [{1}] à cause du fichier existant [{2}]
+tomcat.baseDirMakeFail=Impossible de créer le répertoire [{0}] pour utiliser comme répertoire de base
+tomcat.baseDirNotDir=L''emplacement [{0}] spécifié comme répertoire de base n''est pas un répertoire
 
 userConfig.database=Exception lors du chargement de la base de données utilisateur
 userConfig.deploy=Déploiement de l''application web pour l''utilisateur [{0}]
diff --git a/java/org/apache/catalina/startup/LocalStrings_ja.properties b/java/org/apache/catalina/startup/LocalStrings_ja.properties
index 5d55ff7..8fed6ba 100644
--- a/java/org/apache/catalina/startup/LocalStrings_ja.properties
+++ b/java/org/apache/catalina/startup/LocalStrings_ja.properties
@@ -128,6 +128,8 @@ passwdUserDatabase.readFail=/etc/passwd から全てのユーザーセットを
 
 tomcat.addWebapp.conflictChild=コンテキスト [{2}] が存在するためWAR ファイル [{0}] をコンテキストパス [{1}] へ配備できません。
 tomcat.addWebapp.conflictFile=[{2}] へファイルまたはディレクトリが存在するため WAR ファイル [{0}] をコンテキストパス [{1}] へ配備できません。
+tomcat.baseDirMakeFail=基本ディレクトリとして使用する [{0}] を作成できません。
+tomcat.baseDirNotDir=基本ディレクトリに指定された [{0}] はディレクトリではありません。
 
 userConfig.database=ユーザデータベースのロード中の例外です
 userConfig.deploy=ユーザ [{0}] のWebアプリケーションを配備します
diff --git a/java/org/apache/catalina/startup/LocalStrings_ko.properties b/java/org/apache/catalina/startup/LocalStrings_ko.properties
index bb8c763..fe3870f 100644
--- a/java/org/apache/catalina/startup/LocalStrings_ko.properties
+++ b/java/org/apache/catalina/startup/LocalStrings_ko.properties
@@ -124,6 +124,8 @@ passwdUserDatabase.readFail=/etc/passwd로부터 사용자들의 전체 집합
 
 tomcat.addWebapp.conflictChild=이미 존재하는 컨텍스트 [{2}](으)로 인하여, [{0}]에 위치한 WAR를 컨텍스트 경로 [{1}](으)로 배치할 수 없습니다.
 tomcat.addWebapp.conflictFile=이미 존재하는 파일 [{2}](으)로 인하여, [{0}]에 위치한 WAR를 컨텍스트 경로 [{1}](으)로 배치할 수 없습니다.
+tomcat.baseDirMakeFail=Base 디렉토리로서 사용하기 위한, 디렉토리 [{0}]을(를) 생성할 수 없습니다.
+tomcat.baseDirNotDir=base 디렉토리를 위해 지정된 위치 [{0}]은(는) 디렉토리가 아닙니다.
 
 userConfig.database=사용자 데이터베이스를 로드하는 중 예외 발생
 userConfig.deploy=사용자 [{0}]을(를) 위해 웹 애플리케이션을 배치합니다.
diff --git a/java/org/apache/catalina/startup/LocalStrings_zh_CN.properties b/java/org/apache/catalina/startup/LocalStrings_zh_CN.properties
index 5f73ff9..9e4b10e 100644
--- a/java/org/apache/catalina/startup/LocalStrings_zh_CN.properties
+++ b/java/org/apache/catalina/startup/LocalStrings_zh_CN.properties
@@ -89,6 +89,7 @@ hostConfig.stop=:)Host配置:停止处理
 
 tomcat.addWebapp.conflictChild=无法在[{0}]处部署到上下文路径[{1}],因为存在上下文[{2}]
 tomcat.addWebapp.conflictFile=由于现有文件[{2}]的存在,无法在[{0}]将战争部署到上下文路径[{1}]
+tomcat.baseDirNotDir=基本目录指定的位置[{0}]不是一个目录
 
 userConfig.database=加载用户数据库异常
 userConfig.deploy.threaded.error=等待用户目录的多线程部署完成时出错
diff --git a/java/org/apache/catalina/startup/Tomcat.java b/java/org/apache/catalina/startup/Tomcat.java
index 3dd0a23..ea2db1c 100644
--- a/java/org/apache/catalina/startup/Tomcat.java
+++ b/java/org/apache/catalina/startup/Tomcat.java
@@ -813,6 +813,7 @@ public class Tomcat {
         };
     }
 
+
     protected void initBaseDir() {
         String catalinaHome = System.getProperty(Globals.CATALINA_HOME_PROP);
         if (basedir == null) {
@@ -823,8 +824,7 @@ public class Tomcat {
         }
         if (basedir == null) {
             // Create a temp dir.
-            basedir = System.getProperty("user.dir") +
-                "/tomcat." + port;
+            basedir = System.getProperty("user.dir") + "/tomcat." + port;
             File home = new File(basedir);
             home.mkdir();
             if (!home.isAbsolute()) {
diff --git a/java/org/apache/catalina/tribes/ChannelListener.java b/java/org/apache/catalina/tribes/ChannelListener.java
index 8af0437..2428268 100644
--- a/java/org/apache/catalina/tribes/ChannelListener.java
+++ b/java/org/apache/catalina/tribes/ChannelListener.java
@@ -29,7 +29,6 @@ import java.io.Serializable;
  * was processed by an above application or if it was just received and forgot about, a feature required
  * to support message-response(RPC) calls<br>
  *
- * @author Filip Hanik
  * @version 1.0
  */
 
diff --git a/java/org/apache/catalina/tribes/group/ChannelCoordinator.java b/java/org/apache/catalina/tribes/group/ChannelCoordinator.java
index 2e30499..2a06e98 100644
--- a/java/org/apache/catalina/tribes/group/ChannelCoordinator.java
+++ b/java/org/apache/catalina/tribes/group/ChannelCoordinator.java
@@ -34,12 +34,10 @@ import org.apache.catalina.tribes.transport.nio.NioReceiver;
 import org.apache.catalina.tribes.util.Arrays;
 import org.apache.catalina.tribes.util.Logs;
 
-
 /**
  * The channel coordinator object coordinates the membership service,
  * the sender and the receiver.
  * This is the last interceptor in the chain.
- * @author Filip Hanik
  */
 public class ChannelCoordinator extends ChannelInterceptorBase implements MessageListener {
     private ChannelReceiver clusterReceiver = new NioReceiver();
@@ -161,7 +159,6 @@ public class ChannelCoordinator extends ChannelInterceptorBase implements Messag
                             getClusterReceiver().getPort(),
                             getClusterReceiver().getSecurePort(),
                             getClusterReceiver().getUdpPort());
-
                 }
                 valid = true;
             }
@@ -247,12 +244,9 @@ public class ChannelCoordinator extends ChannelInterceptorBase implements Messag
 
             startLevel = (startLevel & (~svc));
             setChannel(null);
-        }catch ( Exception x ) {
+        } catch (Exception x) {
             throw new ChannelException(x);
-        } finally {
-
         }
-
     }
 
     @Override
diff --git a/java/org/apache/catalina/tribes/group/GroupChannel.java b/java/org/apache/catalina/tribes/group/GroupChannel.java
index d3eb103..74526a1 100644
--- a/java/org/apache/catalina/tribes/group/GroupChannel.java
+++ b/java/org/apache/catalina/tribes/group/GroupChannel.java
@@ -240,9 +240,8 @@ public class GroupChannel extends ChannelInterceptorBase implements ManagedChann
             }
 
             return new UniqueId(data.getUniqueId());
-        }catch ( Exception x ) {
-            if ( x instanceof ChannelException ) throw (ChannelException)x;
-            throw new ChannelException(x);
+        } catch (Exception e) {
+            throw new ChannelException(e);
         } finally {
             if ( buffer != null ) BufferPool.getBufferPool().returnBuffer(buffer);
         }
diff --git a/java/org/apache/catalina/tribes/group/interceptors/TcpPingInterceptor.java b/java/org/apache/catalina/tribes/group/interceptors/TcpPingInterceptor.java
index 6198162..2a75bf8 100644
--- a/java/org/apache/catalina/tribes/group/interceptors/TcpPingInterceptor.java
+++ b/java/org/apache/catalina/tribes/group/interceptors/TcpPingInterceptor.java
@@ -90,9 +90,9 @@ public class TcpPingInterceptor extends ChannelInterceptorBase {
     }
 
     @Override
-    public void stop(int svc) throws ChannelException {
+    public synchronized void stop(int svc) throws ChannelException {
         running = false;
-        if ( thread != null ) {
+        if (thread != null) {
             thread.interrupt();
             thread = null;
         }
diff --git a/java/org/apache/catalina/tribes/group/interceptors/ThroughputInterceptor.java b/java/org/apache/catalina/tribes/group/interceptors/ThroughputInterceptor.java
index 7000976..58e0d25 100644
--- a/java/org/apache/catalina/tribes/group/interceptors/ThroughputInterceptor.java
+++ b/java/org/apache/catalina/tribes/group/interceptors/ThroughputInterceptor.java
@@ -30,14 +30,6 @@ import org.apache.catalina.tribes.io.XByteBuffer;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 
-
-
-/**
- *
- *
- * @author Filip Hanik
- * @version 1.0
- */
 public class ThroughputInterceptor extends ChannelInterceptorBase {
     private static final Log log = LogFactory.getLog(ThroughputInterceptor.class);
 
@@ -72,7 +64,7 @@ public class ThroughputInterceptor extends ChannelInterceptorBase {
         if ( access.addAndGet(-1) == 0 ) {
             long stop = System.currentTimeMillis();
             timeTx += (stop - txStart) / 1000d;
-            if ((msgTxCnt.get() / interval) >= lastCnt) {
+            if ((msgTxCnt.get() / (double) interval) >= lastCnt) {
                 lastCnt++;
                 report(timeTx);
             }
diff --git a/java/org/apache/catalina/tribes/io/ChannelData.java b/java/org/apache/catalina/tribes/io/ChannelData.java
index f1d938e..9bf1f6b 100644
--- a/java/org/apache/catalina/tribes/io/ChannelData.java
+++ b/java/org/apache/catalina/tribes/io/ChannelData.java
@@ -31,7 +31,6 @@ import org.apache.catalina.tribes.util.UUIDGenerator;
  * to another node. While the message is being processed by the different
  * interceptors, the message data can be manipulated as each interceptor seems appropriate.
  * @author Peter Rossbach
- * @author Filip Hanik
  */
 public class ChannelData implements ChannelMessage {
     private static final long serialVersionUID = 1L;
@@ -219,7 +218,6 @@ public class ChannelData implements ChannelMessage {
         XByteBuffer.toBytes(message.getLength(),data,offset);
         offset += 4; //message.length
         System.arraycopy(message.getBytesDirect(),0,data,offset,message.getLength());
-        offset += message.getLength(); //message data
         return data;
     }
 
@@ -303,15 +301,17 @@ public class ChannelData implements ChannelMessage {
      * @return ClusterData
      */
     @Override
-    public Object clone() {
-//        byte[] d = this.getDataPackage();
-//        return ClusterData.getDataFromPackage(d);
-        ChannelData clone = new ChannelData(false);
-        clone.options = this.options;
-        clone.message = new XByteBuffer(this.message.getBytesDirect(),false);
-        clone.timestamp = this.timestamp;
-        clone.uniqueId = this.uniqueId;
-        clone.address = this.address;
+    public ChannelData clone() {
+        ChannelData clone;
+        try {
+            clone = (ChannelData) super.clone();
+        } catch (CloneNotSupportedException e) {
+            // Cannot happen
+            throw new AssertionError();
+        }
+        if (this.message != null) {
+            clone.message = new XByteBuffer(this.message.getBytesDirect(),false);
+        }
         return clone;
     }
 
diff --git a/java/org/apache/catalina/tribes/io/XByteBuffer.java b/java/org/apache/catalina/tribes/io/XByteBuffer.java
index 8517e1d..8650a41 100644
--- a/java/org/apache/catalina/tribes/io/XByteBuffer.java
+++ b/java/org/apache/catalina/tribes/io/XByteBuffer.java
@@ -42,9 +42,10 @@ import java.util.concurrent.atomic.AtomicInteger;
  * <li><b>DATA</b>      - should be as many bytes as the prev SIZE</li>
  * <li><b>END_DATA</b>  - 7 bytes - <i>TLF2003</i></li>
  * </ul>
- * @author Filip Hanik
  */
-public class XByteBuffer {
+public class XByteBuffer implements Serializable {
+
+    private static final long serialVersionUID = 1L;
 
     private static final org.apache.juli.logging.Log log =
         org.apache.juli.logging.LogFactory.getLog( XByteBuffer.class );
@@ -467,7 +468,7 @@ public class XByteBuffer {
     }
 
     /**
-     * Converts an long to eight bytes
+     * Converts a long to eight bytes.
      * @param n - the long
      * @return - eight bytes in an array
      * @deprecated use toBytes(long,byte[],int)
diff --git a/java/org/apache/catalina/tribes/membership/McastServiceImpl.java b/java/org/apache/catalina/tribes/membership/McastServiceImpl.java
index 2481b08..1393e6d 100644
--- a/java/org/apache/catalina/tribes/membership/McastServiceImpl.java
+++ b/java/org/apache/catalina/tribes/membership/McastServiceImpl.java
@@ -46,7 +46,6 @@ import org.apache.catalina.tribes.util.ExecutorFactory;
  * This is the low level implementation that handles the multicasting sockets.
  * Need to fix this, could use java.nio and only need one thread to send and receive, or
  * just use a timeout on the receive
- * @author Filip Hanik
  */
 public class McastServiceImpl
 {
@@ -59,7 +58,7 @@ public class McastServiceImpl
      */
     protected volatile boolean doRunSender = false;
     protected volatile boolean doRunReceiver = false;
-    protected int startLevel = 0;
+    protected volatile int startLevel = 0;
     /**
      * Socket that we intend to listen to
      */
diff --git a/java/org/apache/catalina/tribes/membership/Membership.java b/java/org/apache/catalina/tribes/membership/Membership.java
index ef84215..20f149e 100644
--- a/java/org/apache/catalina/tribes/membership/Membership.java
+++ b/java/org/apache/catalina/tribes/membership/Membership.java
@@ -14,10 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.catalina.tribes.membership;
 
-
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -34,18 +32,17 @@ import org.apache.catalina.tribes.Member;
  * This class is responsible for maintaining a list of active cluster nodes in the cluster.
  * If a node fails to send out a heartbeat, the node will be dismissed.
  *
- * @author Filip Hanik
  * @author Peter Rossbach
  */
 public class Membership implements Cloneable {
 
     protected static final MemberImpl[] EMPTY_MEMBERS = new MemberImpl[0];
 
-    private final Object membersLock = new Object();
+    // Non-final to support clone()
+    private Object membersLock = new Object();
 
     /**
-     * The name of this membership, has to be the same as the name for the local
-     * member
+     * The local member.
      */
     protected MemberImpl local;
 
@@ -65,14 +62,29 @@ public class Membership implements Cloneable {
     protected Comparator<Member> memberComparator = new MemberComparator();
 
     @Override
-    public Object clone() {
+    public Membership clone() {
         synchronized (membersLock) {
-            Membership clone = new Membership(local, memberComparator);
-            @SuppressWarnings("unchecked") // map is correct type already
+            Membership clone;
+            try {
+                clone = (Membership) super.clone();
+            } catch (CloneNotSupportedException e) {
+                // Can't happen
+                throw new AssertionError();
+            }
+
+            // Standard clone() method will copy the map object. Replace that
+            // with a new map but with the same contents.
+            @SuppressWarnings("unchecked")
             final HashMap<MemberImpl, MbrEntry> tmpclone = (HashMap<MemberImpl, MbrEntry>) map.clone();
             clone.map = tmpclone;
-            clone.members = new MemberImpl[members.length];
-            System.arraycopy(members,0,clone.members,0,members.length);
+
+            // Standard clone() method will copy the array object. Replace that
+            // with a new array but with the same contents.
+            clone.members = members.clone();
+
+            // Standard clone() method will copy the lock object. Replace that
+            // with a new object.
+            clone.membersLock = new Object();
             return clone;
         }
     }
diff --git a/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java b/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java
index 7693e7b..83e8b9d 100644
--- a/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java
+++ b/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java
@@ -46,12 +46,13 @@ import org.apache.catalina.tribes.group.RpcChannel;
 import org.apache.catalina.tribes.io.XByteBuffer;
 import org.apache.catalina.tribes.membership.MemberImpl;
 import org.apache.catalina.tribes.util.Arrays;
+import org.apache.catalina.tribes.util.StringManager;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 
 /**
- *
- * @version 1.0
+ * @param <K> The type of Key
+ * @param <V> The type of Value
  */
 public abstract class AbstractReplicatedMap<K,V>
         implements Map<K,V>, Serializable, RpcCallback, ChannelListener,
@@ -59,6 +60,8 @@ public abstract class AbstractReplicatedMap<K,V>
 
     private static final long serialVersionUID = 1L;
 
+    protected static final StringManager sm = StringManager.getManager(AbstractReplicatedMap.class);
+
     private final Log log = LogFactory.getLog(AbstractReplicatedMap.class); // must not be static
 
     /**
@@ -1613,11 +1616,13 @@ public abstract class AbstractReplicatedMap<K,V>
          * @return Object
          */
         @Override
-        public Object clone() {
-            MapMessage msg = new MapMessage(this.mapId, this.msgtype, this.diff, this.key, this.value, this.diffvalue, this.primary, this.nodes);
-            msg.keydata = this.keydata;
-            msg.valuedata = this.valuedata;
-            return msg;
+        public MapMessage clone() {
+            try {
+                return (MapMessage) super.clone();
+            } catch (CloneNotSupportedException e) {
+                // Not possible
+                throw new AssertionError();
+            }
         }
     } //MapMessage
 
@@ -1694,4 +1699,4 @@ public abstract class AbstractReplicatedMap<K,V>
             return available;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/java/org/apache/catalina/tribes/tipis/LazyReplicatedMap.java b/java/org/apache/catalina/tribes/tipis/LazyReplicatedMap.java
index 1837e88..59cfafd 100644
--- a/java/org/apache/catalina/tribes/tipis/LazyReplicatedMap.java
+++ b/java/org/apache/catalina/tribes/tipis/LazyReplicatedMap.java
@@ -63,13 +63,11 @@ import org.apache.juli.logging.LogFactory;
  *
  * @param <K> The type of Key
  * @param <V> The type of Value
- *
- * @author Filip Hanik
- * @version 1.0
  */
 public class LazyReplicatedMap<K,V> extends AbstractReplicatedMap<K,V> {
     private static final long serialVersionUID = 1L;
-    private final Log log = LogFactory.getLog(LazyReplicatedMap.class); // must not be static
+    // Lazy init to support serialization
+    private transient volatile Log log;
 
 
 //------------------------------------------------------------------------------
@@ -151,6 +149,7 @@ public class LazyReplicatedMap<K,V> extends AbstractReplicatedMap<K,V> {
      */
     @Override
     protected Member[] publishEntryInfo(Object key, Object value) throws ChannelException {
+        Log log = getLog();
         if  (! (key instanceof Serializable && value instanceof Serializable)  ) return new Member[0];
         Member[] members = getMapMembers();
         int firstIdx = getNextBackupIndex();
@@ -187,7 +186,7 @@ public class LazyReplicatedMap<K,V> extends AbstractReplicatedMap<K,V> {
                 success = true;
                 backup = tmpBackup;
             }catch ( ChannelException x ) {
-                log.error("Unable to replicate backup key:"+key+" to backup:"+next+". Reason:"+x.getMessage(),x);
+                log.error(sm.getString("lazyReplicatedMap.unableReplicate.backup", key, next, x.getMessage()), x);
                 continue;
             }
             try {
@@ -204,11 +203,21 @@ public class LazyReplicatedMap<K,V> extends AbstractReplicatedMap<K,V> {
                 //log the error, but proceed, this should only happen if a node went down,
                 //and if the node went down, then it can't receive the message, the others
                 //should still get it.
-                log.error("Unable to replicate proxy key:"+key+" to backup:"+next+". Reason:"+x.getMessage(),x);
+                log.error(sm.getString("lazyReplicatedMap.unableReplicate.proxy", key, next, x.getMessage()), x);
             }
         } while ( !success && (firstIdx!=nextIdx));
         return backup;
     }
 
 
+    private Log getLog() {
+        if (log == null) {
+            synchronized (this) {
+                if (log == null) {
+                    log = LogFactory.getLog(LazyReplicatedMap.class);
+                }
+            }
+        }
+        return log;
+    }
 }
diff --git a/java/org/apache/catalina/tribes/tipis/LocalStrings.properties b/java/org/apache/catalina/tribes/tipis/LocalStrings.properties
new file mode 100644
index 0000000..3c83580
--- /dev/null
+++ b/java/org/apache/catalina/tribes/tipis/LocalStrings.properties
@@ -0,0 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+lazyReplicatedMap.unableReplicate.backup=Unable to replicate backup key:[{0}] to backup:[{1}]. Reason:[{2}]
+lazyReplicatedMap.unableReplicate.proxy=Unable to replicate proxy key:[{0}] to backup:[{1}]. Reason:[{2}]
+
+replicatedMap.member.disappeared=Member[{0}] disappeared. Related map entries will be relocated to the new node.
+replicatedMap.relocate.complete=Relocation of map entries was complete in [{0}] ms.
+replicatedMap.unable.relocate=Unable to relocate[{0}] to a new backup node
+replicatedMap.unableReplicate.completely=Unable to replicate backup key:[{0}]. Success nodes:[{1}]. Failed nodes:[{2}].
diff --git a/java/org/apache/catalina/tribes/tipis/LocalStrings_de.properties b/java/org/apache/catalina/tribes/tipis/LocalStrings_de.properties
new file mode 100644
index 0000000..736baea
--- /dev/null
+++ b/java/org/apache/catalina/tribes/tipis/LocalStrings_de.properties
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+replicatedMap.relocate.complete=Das Verschieben der Map Einträge ist fertig und hat [{0}] ms gedauert.
+replicatedMap.unable.relocate=[{0}]  kann nicht auch einen Backup-Node umgezogen werden
diff --git a/java/org/apache/catalina/tribes/tipis/LocalStrings_es.properties b/java/org/apache/catalina/tribes/tipis/LocalStrings_es.properties
new file mode 100644
index 0000000..a138ccf
--- /dev/null
+++ b/java/org/apache/catalina/tribes/tipis/LocalStrings_es.properties
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+lazyReplicatedMap.unableReplicate.proxy=Imposible replicar llave de proxy:[{0}] hacia el respaldo:[{1}]. Motivo:[{2}]
+
+replicatedMap.relocate.complete=La reubicación de las entradas de mapas fue completada en [{0}] ms.
+replicatedMap.unable.relocate=No se pudo mover [{0}] a un nuevo nodo de respaldo
diff --git a/java/org/apache/catalina/tribes/tipis/LocalStrings_fr.properties b/java/org/apache/catalina/tribes/tipis/LocalStrings_fr.properties
new file mode 100644
index 0000000..024ac65
--- /dev/null
+++ b/java/org/apache/catalina/tribes/tipis/LocalStrings_fr.properties
@@ -0,0 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+lazyReplicatedMap.unableReplicate.backup=Impossible de répliquer la clé de sauvegarde: [{0}]
+lazyReplicatedMap.unableReplicate.proxy=Incapable de répliquer la clé de proxy : [{0}] vers le secours (backup) : [{1}]. Raison : [{2}]
+
+replicatedMap.member.disappeared=Le membre [{0}] a disparu, les entrées correspondantes seront déplacées sur un nouveau nœud
+replicatedMap.relocate.complete=La relocation des entrées de la structure répliquée a été accomplie en [{0}] ms
+replicatedMap.unable.relocate=Impossible de déplacer [{0}] sur un nouveau noeud auxiliaire.
+replicatedMap.unableReplicate.completely=Impossible de répliquer la clé de sauvegarde: [{0}], succès pour les nœuds: [{1}], échec pour les nœuds: [{2}]
diff --git a/java/org/apache/catalina/tribes/tipis/LocalStrings_ja.properties b/java/org/apache/catalina/tribes/tipis/LocalStrings_ja.properties
new file mode 100644
index 0000000..1312cd1
--- /dev/null
+++ b/java/org/apache/catalina/tribes/tipis/LocalStrings_ja.properties
@@ -0,0 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+lazyReplicatedMap.unableReplicate.backup=[{2}] により、バックアップキー [{0}] をメンバー [{1}] へ複製できません。
+lazyReplicatedMap.unableReplicate.proxy=[{2}] のため、プロキシキーを [{0}] からバックアップの [{1}] へ複製できません。
+
+replicatedMap.member.disappeared=メンバー[{0}]が消えました。 関連するマップエントリは、新しいノードに再配置されます。
+replicatedMap.relocate.complete=マップ要素の再配置は [{0}] ms で完了しました。
+replicatedMap.unable.relocate=[{0}]を新しいバックアップノードに再配置できません
+replicatedMap.unableReplicate.completely=バックアップキー[{0}]を複製できません。 成功ノード:[{1}]。 障害ノード:[{2}]。
diff --git a/java/org/apache/catalina/tribes/tipis/LocalStrings_ko.properties b/java/org/apache/catalina/tribes/tipis/LocalStrings_ko.properties
new file mode 100644
index 0000000..4285348
--- /dev/null
+++ b/java/org/apache/catalina/tribes/tipis/LocalStrings_ko.properties
@@ -0,0 +1,22 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+lazyReplicatedMap.unableReplicate.backup=백업 키 [{0}]을(를) 백업 [{1}]에 복제할 수 없습니다. 사유:[{2}]
+lazyReplicatedMap.unableReplicate.proxy=프록시 키 [{0}]을(를) 백업인 [{1}](으)로 복제할 수 없습니다. 사유: [{2}]
+
+replicatedMap.member.disappeared=멤버 [{0}]이(가) 사라졌습니다. 관련 Map의 엔트리들은 새 노드로 다시 위치시킬 것입니다.
+replicatedMap.relocate.complete=Map의 엔트리들 모두 다시 위치시켰습니다. 소요시간: [{0}] 밀리초.
+replicatedMap.unable.relocate=멤버 [{0}]에 새로운 백업 노드를 다시 지정할 수 없습니다.
+replicatedMap.unableReplicate.completely=백업 키 [{0}]을(를) 복제할 수 없습니다. 성공 노드들: [{1}]. 실패 노드들: [{2}]
diff --git a/java/org/apache/catalina/tribes/tipis/LocalStrings_zh_CN.properties b/java/org/apache/catalina/tribes/tipis/LocalStrings_zh_CN.properties
new file mode 100644
index 0000000..83c0148
--- /dev/null
+++ b/java/org/apache/catalina/tribes/tipis/LocalStrings_zh_CN.properties
@@ -0,0 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+lazyReplicatedMap.unableReplicate.proxy=不能复制proxy key:[{0}]到备份:[{1}]. 原因是:[{2}]
+
+replicatedMap.member.disappeared=成员[{0}]消失,关联的键值实体会重新关联到一个新的节点。
+replicatedMap.relocate.complete=map 条目的重定位在 [{0}] ms内完成。
+replicatedMap.unable.relocate=不能为一个新的备份节点重启定位[{0}]
diff --git a/java/org/apache/catalina/tribes/tipis/ReplicatedMap.java b/java/org/apache/catalina/tribes/tipis/ReplicatedMap.java
index 10d74de..ed7f5ad 100644
--- a/java/org/apache/catalina/tribes/tipis/ReplicatedMap.java
+++ b/java/org/apache/catalina/tribes/tipis/ReplicatedMap.java
@@ -19,8 +19,7 @@ package org.apache.catalina.tribes.tipis;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Iterator;
-import java.util.Map;
+import java.util.List;
 
 import org.apache.catalina.tribes.Channel;
 import org.apache.catalina.tribes.ChannelException;
@@ -51,25 +50,28 @@ import org.apache.juli.logging.LogFactory;
  * TODO memberDisappeared, should do nothing except change map membership
  *       by default it relocates the primary objects
  *
- * @author Filip Hanik
- * @version 1.0
+ * @param <K> The type of Key
+ * @param <V> The type of Value
  */
 public class ReplicatedMap<K,V> extends AbstractReplicatedMap<K,V> {
 
     private static final long serialVersionUID = 1L;
 
-    private final Log log = LogFactory.getLog(ReplicatedMap.class); // must not be static
+    // Lazy init to support serialization
+    private transient volatile Log log;
 
     //--------------------------------------------------------------------------
     //              CONSTRUCTORS / DESTRUCTORS
     //--------------------------------------------------------------------------
     /**
      * 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 cls Class loaders
      */
     public ReplicatedMap(MapOwner owner, Channel channel, long timeout, String mapContextName, int initialCapacity,float loadFactor, ClassLoader[] cls) {
         super(owner,channel, timeout, mapContextName, initialCapacity, loadFactor, Channel.SEND_OPTIONS_DEFAULT, cls, true);
@@ -77,10 +79,12 @@ public class ReplicatedMap<K,V> extends 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 cls Class loaders
      */
     public ReplicatedMap(MapOwner owner, Channel channel, long timeout, String mapContextName, int initialCapacity, ClassLoader[] cls) {
         super(owner,channel, timeout, mapContextName, initialCapacity, AbstractReplicatedMap.DEFAULT_LOAD_FACTOR,Channel.SEND_OPTIONS_DEFAULT, cls, true);
@@ -88,9 +92,11 @@ public class ReplicatedMap<K,V> extends 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 cls Class loaders
      */
     public ReplicatedMap(MapOwner owner, Channel channel, long timeout, String mapContextName, ClassLoader[] cls) {
         super(owner, channel, timeout, mapContextName,AbstractReplicatedMap.DEFAULT_INITIAL_CAPACITY, AbstractReplicatedMap.DEFAULT_LOAD_FACTOR, Channel.SEND_OPTIONS_DEFAULT, cls, true);
@@ -98,9 +104,11 @@ public class ReplicatedMap<K,V> extends 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 cls Class loaders
      * @param terminate boolean - Flag for whether to terminate this map that failed to start.
      */
     public ReplicatedMap(MapOwner owner, Channel channel, long timeout, String mapContextName, ClassLoader[] cls, boolean terminate) {
@@ -126,7 +134,7 @@ public class ReplicatedMap<K,V> extends AbstractReplicatedMap<K,V> {
      * @param key Object
      * @param value Object
      * @return Member - the backup node
-     * @throws ChannelException
+     * @throws ChannelException Cluster error
      */
     @Override
     protected Member[] publishEntryInfo(Object key, Object value) throws ChannelException {
@@ -137,7 +145,6 @@ public class ReplicatedMap<K,V> extends AbstractReplicatedMap<K,V> {
         if (backup == null || backup.length == 0) return null;
 
         try {
-
             //publish the data out to all nodes
             MapMessage msg = new MapMessage(getMapContextName(), MapMessage.MSG_COPY, false,
                     (Serializable) key, (Serializable) value, null,channel.getLocalMember(false), backup);
@@ -146,7 +153,7 @@ public class ReplicatedMap<K,V> extends AbstractReplicatedMap<K,V> {
         } catch (ChannelException e) {
             FaultyMember[] faultyMembers = e.getFaultyMembers();
             if (faultyMembers.length == 0) throw e;
-            ArrayList<Member> faulty = new ArrayList<Member>();
+            List<Member> faulty = new ArrayList<Member>();
             for (FaultyMember faultyMember : faultyMembers) {
                 if (!(faultyMember.getCause() instanceof RemoteProcessException)) {
                     faulty.add(faultyMember.getMember());
@@ -158,10 +165,9 @@ public class ReplicatedMap<K,V> extends AbstractReplicatedMap<K,V> {
                 if (backup.length == 0) {
                     throw e;
                 } else {
-                    if (log.isWarnEnabled()) {
-                        log.warn("Unable to replicate backup key:" + key
-                                + ". Success nodes:" + Arrays.toString(backup)
-                                + ". Failed nodes:" + Arrays.toString(realFaultyMembers), e);
+                    if (getLog().isWarnEnabled()) {
+                        getLog().warn(sm.getString("replicatedMap.unableReplicate.completely", key,
+                                Arrays.toString(backup), Arrays.toString(realFaultyMembers)), e);
                     }
                 }
             }
@@ -172,6 +178,7 @@ public class ReplicatedMap<K,V> extends AbstractReplicatedMap<K,V> {
     @Override
     public void memberDisappeared(Member member) {
         boolean removed = false;
+        Log log = getLog();
         synchronized (mapMembers) {
             removed = (mapMembers.remove(member) != null );
             if (!removed) {
@@ -180,11 +187,9 @@ public class ReplicatedMap<K,V> extends AbstractReplicatedMap<K,V> {
             }
         }
         if (log.isInfoEnabled())
-            log.info("Member["+member+"] disappeared. Related map entries will be relocated to the new node.");
+            log.info(sm.getString("replicatedMap.member.disappeared", member));
         long start = System.currentTimeMillis();
-        Iterator<Map.Entry<K,MapEntry<K,V>>> i = innerMap.entrySet().iterator();
-        while (i.hasNext()) {
-            Map.Entry<K,MapEntry<K,V>> e = i.next();
+        for (Entry<K, MapEntry<K, V>> e : innerMap.entrySet()) {
             MapEntry<K,V> entry = innerMap.get(e.getKey());
             if (entry==null) continue;
             if (entry.isPrimary()) {
@@ -198,7 +203,7 @@ public class ReplicatedMap<K,V> extends AbstractReplicatedMap<K,V> {
                     entry.setBackupNodes(backup);
                     entry.setPrimary(channel.getLocalMember(false));
                 } catch (ChannelException x) {
-                    log.error("Unable to relocate[" + entry.getKey() + "] to a new backup node", x);
+                    log.error(sm.getString("replicatedMap.unable.relocate", entry.getKey()), x);
                 }
             } else if (member.equals(entry.getPrimary())) {
                 entry.setPrimary(null);
@@ -224,13 +229,14 @@ public class ReplicatedMap<K,V> extends AbstractReplicatedMap<K,V> {
                     if ( mapOwner!=null ) mapOwner.objectMadePrimay(entry.getKey(),entry.getValue());
 
                 } catch (ChannelException x) {
-                    log.error("Unable to relocate[" + entry.getKey() + "] to a new backup node", x);
+                    log.error(sm.getString("replicatedMap.unable.relocate", entry.getKey()), x);
                 }
             }
 
         } //while
         long complete = System.currentTimeMillis() - start;
-        if (log.isInfoEnabled()) log.info("Relocation of map entries was complete in " + complete + " ms.");
+        if (log.isInfoEnabled()) log.info(sm.getString("replicatedMap.relocate.complete",
+                Long.toString(complete)));
     }
 
     @Override
@@ -246,9 +252,7 @@ public class ReplicatedMap<K,V> extends AbstractReplicatedMap<K,V> {
         if ( memberAdded ) {
             synchronized (stateMutex) {
                 Member[] backup = getMapMembers();
-                Iterator<Map.Entry<K,MapEntry<K,V>>> i = innerMap.entrySet().iterator();
-                while (i.hasNext()) {
-                    Map.Entry<K,MapEntry<K,V>> e = i.next();
+                for (Entry<K, MapEntry<K, V>> e : innerMap.entrySet()) {
                     MapEntry<K,V> entry = innerMap.get(e.getKey());
                     if ( entry == null ) continue;
                     if (entry.isPrimary() && !inSet(member,entry.getBackupNodes())) {
@@ -259,4 +263,15 @@ public class ReplicatedMap<K,V> extends AbstractReplicatedMap<K,V> {
         }
     }
 
-}
\ No newline at end of file
+
+    private Log getLog() {
+        if (log == null) {
+            synchronized (this) {
+                if (log == null) {
+                    log = LogFactory.getLog(ReplicatedMap.class);
+                }
+            }
+        }
+        return log;
+    }
+}
diff --git a/java/org/apache/catalina/tribes/transport/AbstractRxTask.java b/java/org/apache/catalina/tribes/transport/AbstractRxTask.java
index 5f78143..78d6731 100644
--- a/java/org/apache/catalina/tribes/transport/AbstractRxTask.java
+++ b/java/org/apache/catalina/tribes/transport/AbstractRxTask.java
@@ -19,10 +19,6 @@ package org.apache.catalina.tribes.transport;
 
 import org.apache.catalina.tribes.io.ListenCallback;
 
-
-/**
- * @author Filip Hanik
- */
 public abstract class AbstractRxTask implements Runnable
 {
 
@@ -70,10 +66,8 @@ public abstract class AbstractRxTask implements Runnable
         return doRun;
     }
 
-    public void close()
-    {
+    public void close() {
         doRun = false;
-        notify();
     }
 
     public void setUseBufferPool(boolean usebufpool) {
diff --git a/java/org/apache/catalina/tribes/transport/MultiPointSender.java b/java/org/apache/catalina/tribes/transport/MultiPointSender.java
index ffd1066..0eb409e 100644
--- a/java/org/apache/catalina/tribes/transport/MultiPointSender.java
+++ b/java/org/apache/catalina/tribes/transport/MultiPointSender.java
@@ -21,7 +21,6 @@ import org.apache.catalina.tribes.ChannelMessage;
 import org.apache.catalina.tribes.Member;
 
 /**
- * @author Filip Hanik
  * @since 5.5.16
  */
 public interface MultiPointSender extends DataSender
diff --git a/java/org/apache/catalina/tribes/transport/PooledSender.java b/java/org/apache/catalina/tribes/transport/PooledSender.java
index 9acb917..ff476f7 100644
--- a/java/org/apache/catalina/tribes/transport/PooledSender.java
+++ b/java/org/apache/catalina/tribes/transport/PooledSender.java
@@ -24,23 +24,13 @@ import org.apache.catalina.tribes.util.StringManager;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 
-/**
- * <p>Title: </p>
- *
- * <p>Description: </p>
- *
- * <p>Company: </p>
- *
- * @author not attributable
- * @version 1.0
- */
 public abstract class PooledSender extends AbstractSender implements MultiPointSender {
 
     private static final Log log = LogFactory.getLog(PooledSender.class);
     protected static final StringManager sm =
         StringManager.getManager(Constants.Package);
 
-    private SenderQueue queue = null;
+    private final SenderQueue queue;
     private int poolSize = 25;
     private long maxWait = 3000;
     public PooledSender() {
@@ -209,7 +199,7 @@ public abstract class PooledSender extends AbstractSender implements MultiPointS
                                 "PooledSender.senderDisconnectFail"), e);
                     }
                 }
-            notify();
+            notifyAll();
         }
 
         public synchronized void close() {
@@ -226,14 +216,14 @@ public abstract class PooledSender extends AbstractSender implements MultiPointS
             }//for
             notinuse.clear();
             inuse.clear();
-            notify();
+            notifyAll();
 
 
         }
 
         public synchronized void open() {
             isOpen = true;
-            notify();
+            notifyAll();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/java/org/apache/catalina/tribes/transport/RxTaskPool.java b/java/org/apache/catalina/tribes/transport/RxTaskPool.java
index 9aa6813..b0af9a2 100644
--- a/java/org/apache/catalina/tribes/transport/RxTaskPool.java
+++ b/java/org/apache/catalina/tribes/transport/RxTaskPool.java
@@ -21,17 +21,12 @@ import java.util.LinkedList;
 import java.util.List;
 
 /**
- * @author not attributable
+ * 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.
  * @version 1.0
  */
-
-public class RxTaskPool
-{
-    /**
-     * 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.
-     */
+public class RxTaskPool {
 
     List<AbstractRxTask> idle = new LinkedList<AbstractRxTask>();
     List<AbstractRxTask> used = new LinkedList<AbstractRxTask>();
@@ -42,7 +37,7 @@ public class RxTaskPool
     private int maxTasks;
     private int minTasks;
 
-    private TaskCreator creator = null;
+    private final TaskCreator creator;
 
 
     public RxTaskPool (int maxTasks, int minTasks, TaskCreator creator) throws Exception {
@@ -64,6 +59,7 @@ public class RxTaskPool
 
     /**
      * Find an idle worker thread, if any.  Could return null.
+     * @return a worker
      */
     public AbstractRxTask getRxTask()
     {
@@ -90,7 +86,7 @@ public class RxTaskPool
             }//while
             if ( worker != null ) used.add(worker);
         }
-        return (worker);
+        return worker;
     }
 
     public int available() {
@@ -100,6 +96,7 @@ public class RxTaskPool
     /**
      * Called by the worker thread to return itself to the
      * idle pool.
+     * @param worker The worker
      */
     public void returnWorker (AbstractRxTask worker) {
         if ( running ) {
@@ -109,13 +106,13 @@ public class RxTaskPool
                 if ( idle.size() < maxTasks && !idle.contains(worker)) idle.add(worker); //let max be the upper limit
                 else {
                     worker.setDoRun(false);
-                    synchronized (worker){worker.notify();}
+                    synchronized (worker){worker.notifyAll();}
                 }
-                mutex.notify();
+                mutex.notifyAll();
             }
-        }else {
+        } else {
             worker.setDoRun(false);
-            synchronized (worker){worker.notify();}
+            synchronized (worker){worker.notifyAll();}
         }
     }
 
diff --git a/java/org/apache/catalina/tribes/transport/bio/MultipointBioSender.java b/java/org/apache/catalina/tribes/transport/bio/MultipointBioSender.java
index bd4213b..d6a106b 100644
--- a/java/org/apache/catalina/tribes/transport/bio/MultipointBioSender.java
+++ b/java/org/apache/catalina/tribes/transport/bio/MultipointBioSender.java
@@ -30,10 +30,6 @@ import org.apache.catalina.tribes.io.XByteBuffer;
 import org.apache.catalina.tribes.transport.AbstractSender;
 import org.apache.catalina.tribes.transport.MultiPointSender;
 
-/**
- *
- * @author Filip Hanik
- */
 public class MultipointBioSender extends AbstractSender implements MultiPointSender {
     public MultipointBioSender() {
         // NO-OP
@@ -44,8 +40,7 @@ public class MultipointBioSender extends AbstractSender implements MultiPointSen
      */
     @Deprecated
     protected final long selectTimeout = 1000;
-    protected HashMap<Member, BioSender> bioSenders =
-        new HashMap<Member, BioSender>();
+    protected HashMap<Member, BioSender> bioSenders = new HashMap<Member, BioSender>();
 
     @Override
     public synchronized void sendMessage(Member[] destination, ChannelMessage msg) throws ChannelException {
@@ -130,22 +125,29 @@ public class MultipointBioSender extends AbstractSender implements MultiPointSen
 
     @Override
     public synchronized void disconnect() {
-        try {close(); }catch (Exception x){/* Ignore */}
+        try {
+            close();
+        } catch (Exception x) {
+            // Ignore
+        }
         setConnected(false);
     }
 
     @Override
-    public void finalize() throws Throwable {
-        try {disconnect(); }catch ( Exception e){/* Ignore */}
+    protected void finalize() throws Throwable {
+        try {
+            disconnect();
+        } catch (Exception e) {
+            // Ignore
+        }
         super.finalize();
     }
 
 
     @Override
     public boolean keepalive() {
-        //throw new UnsupportedOperationException("Method ParallelBioSender.checkKeepAlive() not implemented");
         boolean result = false;
-        @SuppressWarnings("unchecked") // bioSenders is of type HashMap<Member, BioSender>
+        @SuppressWarnings("unchecked")
         Map.Entry<Member,BioSender>[] entries = bioSenders.entrySet().toArray(new Map.Entry[bioSenders.size()]);
         for ( int i=0; i<entries.length; i++ ) {
             BioSender sender = entries[i].getValue();
@@ -156,4 +158,4 @@ public class MultipointBioSender extends AbstractSender implements MultiPointSen
         return result;
     }
 
-}
\ No newline at end of file
+}
diff --git a/java/org/apache/catalina/tribes/transport/nio/ParallelNioSender.java b/java/org/apache/catalina/tribes/transport/nio/ParallelNioSender.java
index 1c0c376..4a5db3e 100644
--- a/java/org/apache/catalina/tribes/transport/nio/ParallelNioSender.java
+++ b/java/org/apache/catalina/tribes/transport/nio/ParallelNioSender.java
@@ -16,7 +16,6 @@
  */
 package org.apache.catalina.tribes.transport.nio;
 
-
 import java.io.IOException;
 import java.net.UnknownHostException;
 import java.nio.channels.SelectionKey;
@@ -42,23 +41,12 @@ import org.apache.catalina.tribes.util.Logs;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 
-/**
- * <p>Title: </p>
- *
- * <p>Description: </p>
- *
- * <p>Company: </p>
- *
- * @author not attributable
- * @version 1.0
- */
 public class ParallelNioSender extends AbstractSender implements MultiPointSender {
 
     private static final Log log = LogFactory.getLog(ParallelNioSender.class);
     protected long selectTimeout = 5000; //default 5 seconds, same as send timeout
     protected Selector selector;
-    protected HashMap<Member, NioSender> nioSenders =
-        new HashMap<Member, NioSender>();
+    protected HashMap<Member, NioSender> nioSenders = new HashMap<Member, NioSender>();
 
     public ParallelNioSender() throws IOException {
         synchronized (Selector.class) {
@@ -72,7 +60,8 @@ public class ParallelNioSender extends AbstractSender implements MultiPointSende
 
 
     @Override
-    public synchronized void sendMessage(Member[] destination, ChannelMessage msg) throws ChannelException {
+    public synchronized void sendMessage(Member[] destination, ChannelMessage msg)
+            throws ChannelException {
         long start = System.currentTimeMillis();
         this.setUdpBased((msg.getOptions()&Channel.SEND_OPTIONS_UDP) == Channel.SEND_OPTIONS_UDP);
         byte[] data = XByteBuffer.createDataPackage((ChannelData)msg);
@@ -85,7 +74,8 @@ public class ParallelNioSender extends AbstractSender implements MultiPointSende
         try {
             //loop until complete, an error happens, or we timeout
             long delta = System.currentTimeMillis() - start;
-            boolean waitForAck = (Channel.SEND_OPTIONS_USE_ACK & msg.getOptions()) == Channel.SEND_OPTIONS_USE_ACK;
+            boolean waitForAck = (Channel.SEND_OPTIONS_USE_ACK &
+                    msg.getOptions()) == Channel.SEND_OPTIONS_USE_ACK;
             while ( (remaining>0) && (delta<getTimeout()) ) {
                 try {
                     SendResult result = doLoop(selectTimeout, getMaxRetryAttempts(),waitForAck,msg);
@@ -123,14 +113,19 @@ public class ParallelNioSender extends AbstractSender implements MultiPointSende
                 throw cx;
             }
         } catch (Exception x ) {
-            try { this.disconnect(); } catch (Exception e) {/*Ignore*/}
+            try {
+                this.disconnect();
+            } catch (Exception e) {
+                // Ignore
+            }
             if ( x instanceof ChannelException ) throw (ChannelException)x;
             else throw new ChannelException(x);
         }
 
     }
 
-    private SendResult doLoop(long selectTimeOut, int maxAttempts, boolean waitForAck, ChannelMessage msg) throws ChannelException {
+    private SendResult doLoop(long selectTimeOut, int maxAttempts, boolean waitForAck, ChannelMessage msg)
+            throws ChannelException {
         SendResult result = new SendResult();
         int selectedKeys;
         try {
@@ -318,7 +313,11 @@ public class ParallelNioSender extends AbstractSender implements MultiPointSende
     @Override
     public synchronized void disconnect() {
         setConnected(false);
-        try {close(); }catch (Exception x){/*Ignore*/}
+        try {
+            close();
+        } catch (Exception x) {
+            // Ignore
+        }
     }
 
     @Override
@@ -337,7 +336,7 @@ public class ParallelNioSender extends AbstractSender implements MultiPointSende
     @Override
     public boolean keepalive() {
         boolean result = false;
-        for ( Iterator<Entry<Member, NioSender>> i = nioSenders.entrySet().iterator(); i.hasNext();) {
+        for (Iterator<Entry<Member,NioSender>> i = nioSenders.entrySet().iterator(); i.hasNext();) {
             Map.Entry<Member, NioSender> entry = i.next();
             NioSender sender = entry.getValue();
             if ( sender.keepalive() ) {
@@ -362,5 +361,4 @@ public class ParallelNioSender extends AbstractSender implements MultiPointSende
         if ( result ) try { selector.selectNow(); }catch (Exception e){/*Ignore*/}
         return result;
     }
-
-}
\ No newline at end of file
+}
diff --git a/java/org/apache/catalina/tribes/util/ExecutorFactory.java b/java/org/apache/catalina/tribes/util/ExecutorFactory.java
index 2f28dbb..facb259 100644
--- a/java/org/apache/catalina/tribes/util/ExecutorFactory.java
+++ b/java/org/apache/catalina/tribes/util/ExecutorFactory.java
@@ -81,7 +81,7 @@ public class ExecutorFactory {
     private static class TaskQueue extends LinkedBlockingQueue<Runnable> {
         private static final long serialVersionUID = 1L;
 
-        ThreadPoolExecutor parent = null;
+        transient ThreadPoolExecutor parent = null;
 
         public TaskQueue() {
             super();


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org