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 09:35:51 UTC

[tomcat] 03/05: Fix SpotBugs warnings in o.a.catalina

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

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

commit b46f44cb028e456f6b9c6a2f5dde33c71a040e00
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Nov 13 22:06:45 2019 +0000

    Fix SpotBugs warnings in o.a.catalina
    
    Additional clean-up / alignment spotted while reviewing
    9.0.x/8.5.x/7.0.x diff
---
 java/org/apache/catalina/ha/ClusterListener.java   |  10 --
 .../catalina/loader/WebappClassLoaderBase.java     |  10 +-
 java/org/apache/catalina/realm/JAASRealm.java      |   9 +-
 java/org/apache/catalina/realm/LockOutRealm.java   |   2 +-
 .../apache/catalina/security/SecurityConfig.java   |  12 +-
 java/org/apache/catalina/session/FileStore.java    |  10 +-
 .../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   |   7 +-
 java/org/apache/catalina/startup/Bootstrap.java    | 104 ++++++-------
 .../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       |  22 ++-
 .../catalina/storeconfig/LocalStrings.properties   |   3 +
 .../storeconfig/LocalStrings_fr.properties         |   3 +
 .../storeconfig/LocalStrings_ja.properties         |   3 +
 .../storeconfig/LocalStrings_ko.properties         |   3 +
 ...gs.properties => LocalStrings_zh_CN.properties} |   9 +-
 .../catalina/storeconfig/StoreFileMover.java       |  23 +--
 .../catalina/tribes/group/ChannelCoordinator.java  |   1 -
 .../apache/catalina/tribes/group/GroupChannel.java |   6 +-
 .../group/interceptors/TcpPingInterceptor.java     |   4 +-
 .../group/interceptors/ThroughputInterceptor.java  |  14 +-
 .../org/apache/catalina/tribes/io/ChannelData.java |  21 +--
 .../org/apache/catalina/tribes/io/XByteBuffer.java |   6 +-
 .../tribes/membership/McastServiceImpl.java        |   2 +-
 .../catalina/tribes/membership/Membership.java     |  23 ++-
 .../tribes/tipis/AbstractReplicatedMap.java        |  16 +-
 .../catalina/tribes/tipis/LazyReplicatedMap.java   |  16 +-
 .../catalina/tribes/tipis/ReplicatedMap.java       |  25 +++-
 .../catalina/tribes/transport/AbstractRxTask.java  |   4 +-
 .../catalina/tribes/transport/PooledSender.java    |   8 +-
 .../catalina/tribes/transport/RxTaskPool.java      |   8 +-
 .../tribes/transport/bio/MultipointBioSender.java  |  16 +-
 .../tribes/transport/nio/ParallelNioSender.java    |  16 +-
 .../catalina/tribes/util/ExecutorFactory.java      |   2 +-
 res/findbugs/filter-false-positives.xml            | 161 ++++++++++++++++++++-
 45 files changed, 422 insertions(+), 183 deletions(-)

diff --git a/java/org/apache/catalina/ha/ClusterListener.java b/java/org/apache/catalina/ha/ClusterListener.java
index 5ab903e..348b136 100644
--- a/java/org/apache/catalina/ha/ClusterListener.java
+++ b/java/org/apache/catalina/ha/ClusterListener.java
@@ -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 ee79208..9d1e0de 100644
--- a/java/org/apache/catalina/loader/WebappClassLoaderBase.java
+++ b/java/org/apache/catalina/loader/WebappClassLoaderBase.java
@@ -699,9 +699,7 @@ public abstract class WebappClassLoaderBase extends URLClassLoader
         if (this.transformers.remove(transformer)) {
             log.info(sm.getString("webappClassLoader.removeTransformer",
                     transformer, getContextName()));
-            return;
         }
-
     }
 
     protected void copyStateWithoutTransformers(WebappClassLoaderBase base) {
@@ -1741,7 +1739,7 @@ public abstract class WebappClassLoaderBase extends URLClassLoader
                                 getContextName(), threadName, getStackTrace(thread)));
                     }
 
-                    // 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;
@@ -1772,7 +1770,7 @@ public abstract class WebappClassLoaderBase extends URLClassLoader
                         // so all implementations are similar
                         if (target != null && target.getClass().getCanonicalName() != null &&
                                 target.getClass().getCanonicalName().equals(
-                                "java.util.concurrent.ThreadPoolExecutor.Worker")) {
+                                        "java.util.concurrent.ThreadPoolExecutor.Worker")) {
                             Field executorField = target.getClass().getDeclaredField("this$0");
                             executorField.setAccessible(true);
                             Object executor = executorField.get(target);
@@ -1886,7 +1884,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 7f84952..a62fd9a 100644
--- a/java/org/apache/catalina/realm/JAASRealm.java
+++ b/java/org/apache/catalina/realm/JAASRealm.java
@@ -172,7 +172,7 @@ public class JAASRealm extends RealmBase {
      */
     protected String configFile;
 
-    protected Configuration jaasConfiguration;
+    protected volatile Configuration jaasConfiguration;
     protected volatile boolean jaasConfigurationLoaded = false;
 
     /**
@@ -225,7 +225,6 @@ public class JAASRealm extends RealmBase {
      */
     public void setUseContextClassLoader(boolean useContext) {
         useContextClassLoader = useContext;
-        log.info("Setting useContextClassLoader = " + useContext);
     }
 
     /**
@@ -649,6 +648,8 @@ public class JAASRealm extends RealmBase {
      * @return the loaded configuration
      */
     protected Configuration getConfig() {
+        // Local copy to avoid possible NPE due to concurrent change
+        String configFile = this.configFile;
         try {
             if (jaasConfigurationLoaded) {
                 return jaasConfiguration;
@@ -658,8 +659,7 @@ 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>)
@@ -688,7 +688,6 @@ public class JAASRealm extends RealmBase {
         } catch (ClassNotFoundException ex) {
             throw new RuntimeException(ex);
         }
-
     }
 
     @Override
diff --git a/java/org/apache/catalina/realm/LockOutRealm.java b/java/org/apache/catalina/realm/LockOutRealm.java
index b2dc29e..8bf0691 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 5fd0b0a..85870ab 100644
--- a/java/org/apache/catalina/security/SecurityConfig.java
+++ b/java/org/apache/catalina/security/SecurityConfig.java
@@ -28,7 +28,9 @@ import org.apache.juli.logging.LogFactory;
  * @author the Catalina.java authors
  */
 public final class SecurityConfig{
-    private static SecurityConfig singleton = null;
+
+    private static final Object singletonLock = new Object();
+    private static volatile SecurityConfig singleton = null;
 
     private static final Log log = LogFactory.getLog(SecurityConfig.class);
 
@@ -83,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 1843c3d..a1916dc 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;
 
@@ -128,7 +129,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();
 
@@ -184,7 +185,7 @@ public final class FileStore extends StoreBase {
         }
 
         // Build and return the list of session identifiers
-        ArrayList<String> list = new ArrayList<>();
+        List<String> list = new ArrayList<>();
         int n = FILE_EXT.length();
         for (int i = 0; i < files.length; i++) {
             if (files[i].endsWith(FILE_EXT)) {
@@ -263,7 +264,10 @@ public final class FileStore extends StoreBase {
             manager.getContext().getLogger().debug(sm.getString(getStoreName() + ".removing",
                              id, file.getAbsolutePath()));
         }
-        file.delete();
+
+        if (file.exists() && !file.delete()) {
+            throw new IOException(sm.getString("fileStore.deleteSessionFailed", file));
+        }
     }
 
 
diff --git a/java/org/apache/catalina/session/LocalStrings.properties b/java/org/apache/catalina/session/LocalStrings.properties
index e98748b..ba4d560 100644
--- a/java/org/apache/catalina/session/LocalStrings.properties
+++ b/java/org/apache/catalina/session/LocalStrings.properties
@@ -28,6 +28,7 @@ JDBCStore.wrongDataSource=Cannot open JNDI DataSource [{0}]
 
 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}]
@@ -54,6 +55,7 @@ persistentManager.swapTooManyActive=Swapping out session [{0}], idle for [{1}] s
 persistentManager.tooManyActive=Too many active sessions, [{0}], looking for idle sessions to swap out
 persistentManager.unloading=Saving [{0}] persisted sessions
 
+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.loading=Loading persisted sessions from [{0}]
 standardManager.loading.exception=Exception while loading persisted sessions
 standardManager.managerLoad=Exception loading sessions from persistent storage
diff --git a/java/org/apache/catalina/session/LocalStrings_es.properties b/java/org/apache/catalina/session/LocalStrings_es.properties
index a5d4aa4..fe1a98e 100644
--- a/java/org/apache/catalina/session/LocalStrings_es.properties
+++ b/java/org/apache/catalina/session/LocalStrings_es.properties
@@ -45,6 +45,7 @@ persistentManager.swapTooManyActive=Intercambiando sesión [{0}] a fuera, ociosa
 persistentManager.tooManyActive=Demasiadas sesiones activas, [{0}], buscando sesiones ociosas para intercambiar
 persistentManager.unloading=Salvando [{0}] sesiones persistidas
 
+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.loading=Cargando sesiones persistidas desde [{0}]
 standardManager.loading.exception=Exception al cargar sesiones persistidas
 standardManager.managerLoad=Excepción cargando sesiones desde almacenamiento persistente
diff --git a/java/org/apache/catalina/session/LocalStrings_fr.properties b/java/org/apache/catalina/session/LocalStrings_fr.properties
index 5ed0af4..a9b7852 100644
--- a/java/org/apache/catalina/session/LocalStrings_fr.properties
+++ b/java/org/apache/catalina/session/LocalStrings_fr.properties
@@ -28,6 +28,7 @@ JDBCStore.wrongDataSource=Impossible d''ouvrir la DataSource JNDI [{0}]
 
 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}]
@@ -54,6 +55,7 @@ persistentManager.swapTooManyActive=Basculement vers stockage (swap out) de la s
 persistentManager.tooManyActive=Trop de sessions actives, [{0}], à la recherche de sessions en attente pour basculement vers stockage (swap out)
 persistentManager.unloading=Sauvegarde de [{0}] sessions persistantes
 
+standardManager.deletePersistedFileFail=Impossible de supprimer [{0}] après avoir lu les sessions persistées, cela pourrait empêcher la future persistance des sessions
 standardManager.loading=Chargement des sessions qui ont persisté depuis [{0}]
 standardManager.loading.exception="Exception" lors du chargement de sessions persistantes
 standardManager.managerLoad=Exception au chargement des sessions depuis le stockage persistant (persistent storage)
diff --git a/java/org/apache/catalina/session/LocalStrings_ja.properties b/java/org/apache/catalina/session/LocalStrings_ja.properties
index fada6bc..1a38b51 100644
--- a/java/org/apache/catalina/session/LocalStrings_ja.properties
+++ b/java/org/apache/catalina/session/LocalStrings_ja.properties
@@ -28,6 +28,7 @@ JDBCStore.wrongDataSource=JNDIデータソース[{0}]を開くことができま
 
 fileStore.createFailed=セッションデータを格納するディレクトリ[{0}]を作成できません
 fileStore.deleteFailed=ファイル [{0}] を削除できなかったため、セッションストレージを作成できません。
+fileStore.deleteSessionFailed=不要になったファイル[{0}]を削除できません
 fileStore.loading=セッション [{0}] をファイル [{1}] からロードします
 fileStore.removing=セッション [{0}] をファイル [{1}] から削除します
 fileStore.saving=セッション [{0}] をファイル [{1}] に保存します
@@ -54,6 +55,7 @@ persistentManager.swapTooManyActive=セッションが多すぎるので、[{1}]
 persistentManager.tooManyActive=アクティブセッションが多すぎます、[{0}]、スワップアウトするためにアイドルセッションを探しています
 persistentManager.unloading=[{0}] の持続されたセッションを保存します
 
+standardManager.deletePersistedFileFail=永続化セッションを読み込んだ [{0}] を削減できません。ファイルが残っていると将来セッションの永続化に失敗する可能性があります。
 standardManager.loading=[{0}] から持続されたセッションをロードしています
 standardManager.loading.exception=持続されたセッションをロード中にExceptionが発生しました
 standardManager.managerLoad=永続記憶装置からセッションをロード中の例外です
diff --git a/java/org/apache/catalina/session/LocalStrings_ko.properties b/java/org/apache/catalina/session/LocalStrings_ko.properties
index f03b53f..cf4142b 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}]에 저장합니다.
@@ -54,6 +55,7 @@ persistentManager.swapTooManyActive=[{1}]초 동안 비활성화 상태에 있
 persistentManager.tooManyActive=활성화된 세션들이 너무 많습니다: [{0}]. 세션 저장소로 내보낼 만한 유휴 세션들을 찾습니다.
 persistentManager.unloading=[{0}]개의 세션들을 저장합니다.
 
+standardManager.deletePersistedFileFail=저장된 세션들을 읽은 후 [{0}]을(를) 삭제할 수 없습니다. 이 파일이 계속 존재한다면, 이후 세션을 저장하려는 시도들이 이로 인해 실패할 수 있습니다.
 standardManager.loading=[{0}](으)로부터 저장된 세션들을 로드합니다.
 standardManager.loading.exception=저장된 세션들을 로드하는 중 예외 발생
 standardManager.managerLoad=세션 저장소로부터 세션들을 로드하는 중 예외 발생
diff --git a/java/org/apache/catalina/session/LocalStrings_zh_CN.properties b/java/org/apache/catalina/session/LocalStrings_zh_CN.properties
index b6f7033..fc55f23 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.contextNull=使用 Manager 之前,必须将 Context 设置为非 null 值
 managerBase.createSession.ise=createSession:活跃session过多
@@ -35,6 +36,7 @@ persistentManager.swapIn=在表单存储中,交换会话[{0}]
 persistentManager.swapMaxIdle=交换会话[{0}]以存储,空闲为[{1}]秒
 persistentManager.swapTooManyActive=太多活跃会话,替换闲置 [{1}] 秒的会话 [{0}]
 
+standardManager.deletePersistedFileFail=读取持久会话后无法删除[{0}]。 此文件的持续存在可能导致将来尝试持续会话失败。
 standardManager.loading.exception=加载持久化会话时发生异常
 standardManager.managerLoad=从持久化存储加载会话发生异常
 standardManager.managerUnload=卸载会话到持久存储的异常
diff --git a/java/org/apache/catalina/session/StandardManager.java b/java/org/apache/catalina/session/StandardManager.java
index ecdd46d..caef4f5 100644
--- a/java/org/apache/catalina/session/StandardManager.java
+++ b/java/org/apache/catalina/session/StandardManager.java
@@ -29,6 +29,7 @@ import java.security.AccessController;
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.util.ArrayList;
+import java.util.List;
 
 import javax.servlet.ServletContext;
 
@@ -229,7 +230,9 @@ public class StandardManager extends ManagerBase {
                 } finally {
                     // Delete the persistent storage file
                     if (file.exists()) {
-                        file.delete();
+                        if (!file.delete()) {
+                            log.warn(sm.getString("standardManager.deletePersistedFileFail", file));
+                        }
                     }
                 }
             }
@@ -293,7 +296,7 @@ public class StandardManager extends ManagerBase {
         }
 
         // Keep a note of sessions that are expired
-        ArrayList<StandardSession> list = new ArrayList<>();
+        List<StandardSession> list = new ArrayList<>();
 
         try (FileOutputStream fos = new FileOutputStream(file.getAbsolutePath());
                 BufferedOutputStream bos = new BufferedOutputStream(fos);
diff --git a/java/org/apache/catalina/startup/Bootstrap.java b/java/org/apache/catalina/startup/Bootstrap.java
index 7d76dc0..e554886 100644
--- a/java/org/apache/catalina/startup/Bootstrap.java
+++ b/java/org/apache/catalina/startup/Bootstrap.java
@@ -34,7 +34,6 @@ import org.apache.catalina.startup.ClassLoaderFactory.RepositoryType;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 
-
 /**
  * Bootstrap loader for Catalina.  This application constructs a class loader
  * for use in loading the Catalina internal classes (by accumulating all of the
@@ -54,7 +53,8 @@ public final class Bootstrap {
     /**
      * Daemon object used by main.
      */
-    private static Bootstrap daemon = null;
+    private static final Object daemonLock = new Object();
+    private static volatile Bootstrap daemon = null;
 
     private static final File catalinaBaseFile;
     private static final File catalinaHomeFile;
@@ -132,7 +132,6 @@ public final class Bootstrap {
      */
     private Object catalinaDaemon = null;
 
-
     ClassLoader commonLoader = null;
     ClassLoader catalinaLoader = null;
     ClassLoader sharedLoader = null;
@@ -144,9 +143,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);
@@ -176,8 +175,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
@@ -187,14 +185,11 @@ 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));
             }
         }
 
@@ -279,15 +274,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";
@@ -304,10 +297,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);
-
     }
 
 
@@ -317,10 +310,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);
-
     }
 
 
@@ -332,12 +323,10 @@ public final class Bootstrap {
      * @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);
-
     }
 
 
@@ -345,13 +334,13 @@ public final class Bootstrap {
      * 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);
-
     }
 
 
@@ -359,12 +348,9 @@ public final class Bootstrap {
      * 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);
     }
 
 
@@ -372,13 +358,11 @@ public final class Bootstrap {
      * 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);
-
     }
 
 
@@ -387,12 +371,11 @@ public final class Bootstrap {
      * @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 {
@@ -404,7 +387,6 @@ public final class Bootstrap {
         Method method =
             catalinaDaemon.getClass().getMethod("stopServer", paramTypes);
         method.invoke(catalinaDaemon, param);
-
     }
 
 
@@ -423,12 +405,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 =
@@ -456,22 +435,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 {
@@ -515,7 +496,6 @@ public final class Bootstrap {
             t.printStackTrace();
             System.exit(1);
         }
-
     }
 
 
diff --git a/java/org/apache/catalina/startup/ContextConfig.java b/java/org/apache/catalina/startup/ContextConfig.java
index fb87502..25f2e1d 100644
--- a/java/org/apache/catalina/startup/ContextConfig.java
+++ b/java/org/apache/catalina/startup/ContextConfig.java
@@ -182,7 +182,7 @@ public class ContextConfig implements LifecycleListener {
     /**
      * The Context we are associated with.
      */
-    protected Context context = null;
+    protected volatile Context context = null;
 
 
     /**
@@ -724,7 +724,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();
@@ -2635,7 +2635,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 23fa2d2..0b93147 100644
--- a/java/org/apache/catalina/startup/LocalStrings.properties
+++ b/java/org/apache/catalina/startup/LocalStrings.properties
@@ -132,6 +132,8 @@ passwdUserDatabase.readFail=Failed to obtain a complete set of users from /etc/p
 
 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
 tomcat.homeDirMakeFail=Unable to create the directory [{0}] to use as the home directory
 
 userConfig.database=Exception loading user database
diff --git a/java/org/apache/catalina/startup/LocalStrings_fr.properties b/java/org/apache/catalina/startup/LocalStrings_fr.properties
index 28e560e..1f5c992 100644
--- a/java/org/apache/catalina/startup/LocalStrings_fr.properties
+++ b/java/org/apache/catalina/startup/LocalStrings_fr.properties
@@ -128,6 +128,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
 tomcat.homeDirMakeFail=Impossible de créer le répertoire [{0}] pour l''utiliser comme répertoire d''origine
 
 userConfig.database=Exception lors du chargement de la base de données utilisateur
diff --git a/java/org/apache/catalina/startup/LocalStrings_ja.properties b/java/org/apache/catalina/startup/LocalStrings_ja.properties
index 64b394d..3057730 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}] はディレクトリではありません。
 tomcat.homeDirMakeFail=ホームディレクトリとして使用する [{0}] を作成できません。
 
 userConfig.database=ユーザデータベースのロード中の例外です
diff --git a/java/org/apache/catalina/startup/LocalStrings_ko.properties b/java/org/apache/catalina/startup/LocalStrings_ko.properties
index 2b5559f..96724e3 100644
--- a/java/org/apache/catalina/startup/LocalStrings_ko.properties
+++ b/java/org/apache/catalina/startup/LocalStrings_ko.properties
@@ -128,6 +128,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}]은(는) 디렉토리가 아닙니다.
 tomcat.homeDirMakeFail=홈 디렉토리로 사용할 디렉토리 [{0}]을(를) 생성할 수 없습니다.
 
 userConfig.database=사용자 데이터베이스를 로드하는 중 예외 발생
diff --git a/java/org/apache/catalina/startup/LocalStrings_zh_CN.properties b/java/org/apache/catalina/startup/LocalStrings_zh_CN.properties
index 69e59d0..248d4d2 100644
--- a/java/org/apache/catalina/startup/LocalStrings_zh_CN.properties
+++ b/java/org/apache/catalina/startup/LocalStrings_zh_CN.properties
@@ -91,6 +91,7 @@ hostConfig.stop=:)Host配置:停止处理
 
 tomcat.addWebapp.conflictChild=无法在[{0}]处部署到上下文路径[{1}],因为存在上下文[{2}]
 tomcat.addWebapp.conflictFile=由于现有文件[{2}]的存在,无法在[{0}]将战争部署到上下文路径[{1}]
+tomcat.baseDirNotDir=基本目录指定的位置[{0}]不是一个目录
 tomcat.homeDirMakeFail=无法创建用作主目录的目录 [{0}]
 
 userConfig.database=加载用户数据库异常
diff --git a/java/org/apache/catalina/startup/Tomcat.java b/java/org/apache/catalina/startup/Tomcat.java
index 78f0ae5..5faac9d 100644
--- a/java/org/apache/catalina/startup/Tomcat.java
+++ b/java/org/apache/catalina/startup/Tomcat.java
@@ -779,6 +779,7 @@ public class Tomcat {
         };
     }
 
+
     protected void initBaseDir() {
         String catalinaHome = System.getProperty(Globals.CATALINA_HOME_PROP);
         if (basedir == null) {
@@ -789,12 +790,27 @@ 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 baseFile = new File(basedir);
-        baseFile.mkdirs();
+        if (baseFile.exists()) {
+            if (!baseFile.isDirectory()) {
+                throw new IllegalArgumentException(sm.getString("tomcat.baseDirNotDir", baseFile));
+            }
+        } else {
+            if (!baseFile.mkdirs()) {
+                // Failed to create base directory
+                throw new IllegalStateException(sm.getString("tomcat.baseDirMakeFail", baseFile));
+            }
+            /*
+             * If file permissions were going to be set on the newly created
+             * directory, this is the place to do it. However, even simple
+             * calls such as File.setReadable(boolean,boolean) behaves
+             * differently on different platforms. Therefore, setBaseDir
+             * documents that the user needs to do this.
+             */
+        }
         try {
             baseFile = baseFile.getCanonicalFile();
         } catch (IOException e) {
diff --git a/java/org/apache/catalina/storeconfig/LocalStrings.properties b/java/org/apache/catalina/storeconfig/LocalStrings.properties
index d480d22..a6bdd6d 100644
--- a/java/org/apache/catalina/storeconfig/LocalStrings.properties
+++ b/java/org/apache/catalina/storeconfig/LocalStrings.properties
@@ -20,3 +20,6 @@ factory.storeNoDescriptor=Descriptor for element class [{0}] not configured!
 factory.storeTag=store tag [{0}] ( Object: [{1}] )
 
 storeConfigListener.notServer=The listener was added to component other than the Server and will therefore be ignored
+
+storeFileMover.directoryCreationError=Cannot create directory [{0}]
+storeFileMover.renameError=Cannot rename [{0}] to [{1}]
diff --git a/java/org/apache/catalina/storeconfig/LocalStrings_fr.properties b/java/org/apache/catalina/storeconfig/LocalStrings_fr.properties
index ab682e8..3066d5b 100644
--- a/java/org/apache/catalina/storeconfig/LocalStrings_fr.properties
+++ b/java/org/apache/catalina/storeconfig/LocalStrings_fr.properties
@@ -20,3 +20,6 @@ factory.storeNoDescriptor=Le descripteur pour l''élément de la classe [{0}] n'
 factory.storeTag=enregistrement du tag [{0}] (objet: [{1}])
 
 storeConfigListener.notServer=L'écouteur a été ajouté à un composant autre que le Server et sera donc ignoré
+
+storeFileMover.directoryCreationError=Impossible de créer le répertoire [{0}]
+storeFileMover.renameError=Impossible de renommer [{0}] en [{1}]
diff --git a/java/org/apache/catalina/storeconfig/LocalStrings_ja.properties b/java/org/apache/catalina/storeconfig/LocalStrings_ja.properties
index 3de1921..221d60d 100644
--- a/java/org/apache/catalina/storeconfig/LocalStrings_ja.properties
+++ b/java/org/apache/catalina/storeconfig/LocalStrings_ja.properties
@@ -20,3 +20,6 @@ factory.storeNoDescriptor=要素クラス[{0}]の記述子が構成されてい
 factory.storeTag=ストアタグ[{0}](オブジェクト:[{1}])
 
 storeConfigListener.notServer=Server 以外のコンポーネントに指定されたリスナーは無視します。
+
+storeFileMover.directoryCreationError=ディレクトリを作成できません。[{0}]
+storeFileMover.renameError=ファイル名 [{0}] を [{1}] に変更できません。
diff --git a/java/org/apache/catalina/storeconfig/LocalStrings_ko.properties b/java/org/apache/catalina/storeconfig/LocalStrings_ko.properties
index f0f2dd8..6c8105c 100644
--- a/java/org/apache/catalina/storeconfig/LocalStrings_ko.properties
+++ b/java/org/apache/catalina/storeconfig/LocalStrings_ko.properties
@@ -20,3 +20,6 @@ factory.storeNoDescriptor=엘리먼트 클래스 [{0}]을(를) 위한 descriptor
 factory.storeTag=태그 [{0}]을(를) 저장합니다. ( 객체: [{1}] )
 
 storeConfigListener.notServer=서버가 아닌 다른 구성요소에 리스너가 추가되었으므로, 이 리스너는 무시될 것입니다.
+
+storeFileMover.directoryCreationError=디렉토리 [{0}]을(를) 생성할 수 없습니다.
+storeFileMover.renameError=[{0}]을(를) [{1}](으)로 이름을 변경할 수 없습니다.
diff --git a/java/org/apache/catalina/storeconfig/LocalStrings.properties b/java/org/apache/catalina/storeconfig/LocalStrings_zh_CN.properties
similarity index 69%
copy from java/org/apache/catalina/storeconfig/LocalStrings.properties
copy to java/org/apache/catalina/storeconfig/LocalStrings_zh_CN.properties
index d480d22..3c4bdd7 100644
--- a/java/org/apache/catalina/storeconfig/LocalStrings.properties
+++ b/java/org/apache/catalina/storeconfig/LocalStrings_zh_CN.properties
@@ -13,10 +13,5 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-config.storeContextError=Error storing context [{0}]
-config.storeServerError=Error storing server
-
-factory.storeNoDescriptor=Descriptor for element class [{0}] not configured!
-factory.storeTag=store tag [{0}] ( Object: [{1}] )
-
-storeConfigListener.notServer=The listener was added to component other than the Server and will therefore be ignored
+storeFileMover.directoryCreationError=无法创建目录 [{0}]
+storeFileMover.renameError=无法将 [{0}] 重命名为 [{1}]
diff --git a/java/org/apache/catalina/storeconfig/StoreFileMover.java b/java/org/apache/catalina/storeconfig/StoreFileMover.java
index 99a5c24..a59b9c1 100644
--- a/java/org/apache/catalina/storeconfig/StoreFileMover.java
+++ b/java/org/apache/catalina/storeconfig/StoreFileMover.java
@@ -23,6 +23,8 @@ import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.sql.Timestamp;
 
+import org.apache.tomcat.util.res.StringManager;
+
 /**
  * Move server.xml or context.xml as backup
  *
@@ -30,6 +32,8 @@ import java.sql.Timestamp;
  */
 public class StoreFileMover {
 
+    protected static final StringManager sm = StringManager.getManager(Constants.Package);
+
     private String filename = "conf/server.xml";
 
     private String encoding = "UTF-8";
@@ -140,7 +144,9 @@ public class StoreFileMover {
             configNew = new File(getBasename(), configFile + ".new");
         }
         if (!configNew.getParentFile().exists()) {
-            configNew.getParentFile().mkdirs();
+            if (!configNew.getParentFile().mkdirs()) {
+                throw new IllegalStateException(sm.getString("storeFileMover.directoryCreationError", configNew));
+            }
         }
         String sb = getTimeTag();
         configSave = new File(configFile + sb);
@@ -158,21 +164,18 @@ public class StoreFileMover {
         if (configOld.renameTo(configSave)) {
             if (!configNew.renameTo(configOld)) {
                 configSave.renameTo(configOld);
-                throw new IOException("Cannot rename "
-                        + configNew.getAbsolutePath() + " to "
-                        + configOld.getAbsolutePath());
+                throw new IOException(sm.getString("storeFileMover.renameError",
+                        configNew.getAbsolutePath(), configOld.getAbsolutePath()));
             }
         } else {
             if (!configOld.exists()) {
                 if (!configNew.renameTo(configOld)) {
-                    throw new IOException("Cannot move "
-                            + configNew.getAbsolutePath() + " to "
-                            + configOld.getAbsolutePath());
+                    throw new IOException(sm.getString("storeFileMover.renameError",
+                            configNew.getAbsolutePath(), configOld.getAbsolutePath()));
                 }
             } else {
-                throw new IOException("Cannot rename "
-                    + configOld.getAbsolutePath() + " to "
-                    + configSave.getAbsolutePath());
+                throw new IOException(sm.getString("storeFileMover.renameError",
+                        configOld.getAbsolutePath(), configSave.getAbsolutePath()));
             }
         }
     }
diff --git a/java/org/apache/catalina/tribes/group/ChannelCoordinator.java b/java/org/apache/catalina/tribes/group/ChannelCoordinator.java
index ec55dc8..c2d162d 100644
--- a/java/org/apache/catalina/tribes/group/ChannelCoordinator.java
+++ b/java/org/apache/catalina/tribes/group/ChannelCoordinator.java
@@ -34,7 +34,6 @@ import org.apache.catalina.tribes.util.Arrays;
 import org.apache.catalina.tribes.util.Logs;
 import org.apache.catalina.tribes.util.StringManager;
 
-
 /**
  * The channel coordinator object coordinates the membership service,
  * the sender and the receiver.
diff --git a/java/org/apache/catalina/tribes/group/GroupChannel.java b/java/org/apache/catalina/tribes/group/GroupChannel.java
index e5535e7..7b72b43 100644
--- a/java/org/apache/catalina/tribes/group/GroupChannel.java
+++ b/java/org/apache/catalina/tribes/group/GroupChannel.java
@@ -17,6 +17,7 @@
 package org.apache.catalina.tribes.group;
 
 
+import java.io.IOException;
 import java.io.Serializable;
 import java.util.Iterator;
 import java.util.List;
@@ -269,9 +270,8 @@ public class GroupChannel extends ChannelInterceptorBase
             }
 
             return new UniqueId(data.getUniqueId());
-        }catch ( Exception x ) {
-            if ( x instanceof ChannelException ) throw (ChannelException)x;
-            throw new ChannelException(x);
+        } catch (RuntimeException | IOException 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 5217496..725f5d3 100644
--- a/java/org/apache/catalina/tribes/group/interceptors/TcpPingInterceptor.java
+++ b/java/org/apache/catalina/tribes/group/interceptors/TcpPingInterceptor.java
@@ -88,9 +88,9 @@ public class TcpPingInterceptor extends ChannelInterceptorBase implements TcpPin
     }
 
     @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 c805d59..4516ff9 100644
--- a/java/org/apache/catalina/tribes/group/interceptors/ThroughputInterceptor.java
+++ b/java/org/apache/catalina/tribes/group/interceptors/ThroughputInterceptor.java
@@ -31,13 +31,6 @@ import org.apache.catalina.tribes.util.StringManager;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 
-
-
-/**
- *
- *
- * @version 1.0
- */
 public class ThroughputInterceptor extends ChannelInterceptorBase
         implements ThroughputInterceptorMBean {
 
@@ -75,7 +68,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);
             }
@@ -98,8 +91,9 @@ public class ThroughputInterceptor extends ChannelInterceptorBase
     public void report(double timeTx) {
         if ( log.isInfoEnabled() )
             log.info(sm.getString("throughputInterceptor.report",
-                    msgTxCnt, df.format(mbTx), df.format(mbAppTx), df.format(timeTx), df.format(mbTx/timeTx),
-                    df.format(mbAppTx/timeTx), msgTxErr, msgRxCnt, df.format(mbRx/((System.currentTimeMillis()-rxStart)/1000)),
+                    msgTxCnt, df.format(mbTx), df.format(mbAppTx), df.format(timeTx),
+                    df.format(mbTx/timeTx), df.format(mbAppTx/timeTx), msgTxErr, msgRxCnt,
+                    df.format(mbRx/((System.currentTimeMillis()-rxStart)/(double)1000)),
                     df.format(mbRx)));
     }
 
diff --git a/java/org/apache/catalina/tribes/io/ChannelData.java b/java/org/apache/catalina/tribes/io/ChannelData.java
index 885c696..17cdb1d 100644
--- a/java/org/apache/catalina/tribes/io/ChannelData.java
+++ b/java/org/apache/catalina/tribes/io/ChannelData.java
@@ -218,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;
     }
 
@@ -302,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 7f86682..c915552 100644
--- a/java/org/apache/catalina/tribes/io/XByteBuffer.java
+++ b/java/org/apache/catalina/tribes/io/XByteBuffer.java
@@ -47,7 +47,9 @@ import org.apache.juli.logging.LogFactory;
  * <li><b>END_DATA</b>  - 7 bytes - <i>TLF2003</i></li>
  * </ul>
  */
-public class XByteBuffer {
+public class XByteBuffer implements Serializable {
+
+    private static final long serialVersionUID = 1L;
 
     private static final Log log = LogFactory.getLog(XByteBuffer.class);
     protected static final StringManager sm = StringManager.getManager(XByteBuffer.class);
@@ -461,7 +463,7 @@ public class XByteBuffer {
     }
 
     /**
-     * Converts an long to eight bytes.
+     * Converts a long to eight bytes.
      * @param n the long
      * @param b the byte buffer in which the integer will be placed
      * @param offset the offset in the byte array
diff --git a/java/org/apache/catalina/tribes/membership/McastServiceImpl.java b/java/org/apache/catalina/tribes/membership/McastServiceImpl.java
index c6219d0..ff8360e 100644
--- a/java/org/apache/catalina/tribes/membership/McastServiceImpl.java
+++ b/java/org/apache/catalina/tribes/membership/McastServiceImpl.java
@@ -62,7 +62,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 0bbe3a7..1a5cce5 100644
--- a/java/org/apache/catalina/tribes/membership/Membership.java
+++ b/java/org/apache/catalina/tribes/membership/Membership.java
@@ -36,7 +36,8 @@ public class Membership implements Cloneable {
 
     protected static final Member[] EMPTY_MEMBERS = new Member[0];
 
-    private final Object membersLock = new Object();
+    // Non-final to support clone()
+    private Object membersLock = new Object();
 
     /**
      * The local member.
@@ -59,13 +60,29 @@ public class Membership implements Cloneable {
     protected final Comparator<Member> memberComparator;
 
     @Override
-    public Object clone() {
+    public Membership clone() {
         synchronized (membersLock) {
-            Membership clone = new Membership(local, memberComparator);
+            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<Member, MbrEntry> tmpclone = (HashMap<Member, MbrEntry>) map.clone();
             clone.map = tmpclone;
+
+            // 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 b271834..4f2cc04 100644
--- a/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java
+++ b/java/org/apache/catalina/tribes/tipis/AbstractReplicatedMap.java
@@ -1032,7 +1032,7 @@ public abstract class AbstractReplicatedMap<K,V>
                 entry.setCopy(false);
                 if ( getMapOwner()!=null ) getMapOwner().objectMadePrimary(key, entry.getValue());
 
-            } catch (Exception x) {
+            } catch (RuntimeException | ChannelException | ClassNotFoundException | IOException x) {
                 log.error(sm.getString("abstractReplicatedMap.unable.get"), x);
                 return null;
             }
@@ -1555,11 +1555,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
 
@@ -1636,4 +1638,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 0c97570..59cfafd 100644
--- a/java/org/apache/catalina/tribes/tipis/LazyReplicatedMap.java
+++ b/java/org/apache/catalina/tribes/tipis/LazyReplicatedMap.java
@@ -66,7 +66,8 @@ import org.apache.juli.logging.LogFactory;
  */
 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;
 
 
 //------------------------------------------------------------------------------
@@ -148,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();
@@ -208,4 +210,14 @@ public class LazyReplicatedMap<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(LazyReplicatedMap.class);
+                }
+            }
+        }
+        return log;
+    }
+}
diff --git a/java/org/apache/catalina/tribes/tipis/ReplicatedMap.java b/java/org/apache/catalina/tribes/tipis/ReplicatedMap.java
index ca6845b..a739bd2 100644
--- a/java/org/apache/catalina/tribes/tipis/ReplicatedMap.java
+++ b/java/org/apache/catalina/tribes/tipis/ReplicatedMap.java
@@ -19,6 +19,7 @@ package org.apache.catalina.tribes.tipis;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 import org.apache.catalina.tribes.Channel;
 import org.apache.catalina.tribes.ChannelException;
@@ -56,7 +57,8 @@ 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
@@ -151,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<>();
+            List<Member> faulty = new ArrayList<>();
             for (FaultyMember faultyMember : faultyMembers) {
                 if (!(faultyMember.getCause() instanceof RemoteProcessException)) {
                     faulty.add(faultyMember.getMember());
@@ -163,8 +165,8 @@ public class ReplicatedMap<K,V> extends AbstractReplicatedMap<K,V> {
                 if (backup.length == 0) {
                     throw e;
                 } else {
-                    if (log.isWarnEnabled()) {
-                        log.warn(sm.getString("replicatedMap.unableReplicate.completely", key,
+                    if (getLog().isWarnEnabled()) {
+                        getLog().warn(sm.getString("replicatedMap.unableReplicate.completely", key,
                                 Arrays.toString(backup), Arrays.toString(realFaultyMembers)), e);
                     }
                 }
@@ -176,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) {
@@ -259,4 +262,16 @@ 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 11e52d4..78d6731 100644
--- a/java/org/apache/catalina/tribes/transport/AbstractRxTask.java
+++ b/java/org/apache/catalina/tribes/transport/AbstractRxTask.java
@@ -66,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/PooledSender.java b/java/org/apache/catalina/tribes/transport/PooledSender.java
index afac822..6428bfd 100644
--- a/java/org/apache/catalina/tribes/transport/PooledSender.java
+++ b/java/org/apache/catalina/tribes/transport/PooledSender.java
@@ -199,7 +199,7 @@ public abstract class PooledSender extends AbstractSender implements MultiPointS
                                 "PooledSender.senderDisconnectFail"), e);
                     }
                 }
-            notify();
+            notifyAll();
         }
 
         public synchronized void close() {
@@ -216,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 4a2c5b0..d370fc3 100644
--- a/java/org/apache/catalina/tribes/transport/RxTaskPool.java
+++ b/java/org/apache/catalina/tribes/transport/RxTaskPool.java
@@ -106,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 f18b527..102d89c 100644
--- a/java/org/apache/catalina/tribes/transport/bio/MultipointBioSender.java
+++ b/java/org/apache/catalina/tribes/transport/bio/MultipointBioSender.java
@@ -120,13 +120,21 @@ 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();
     }
 
@@ -145,4 +153,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 55377a2..67328f6 100644
--- a/java/org/apache/catalina/tribes/transport/nio/ParallelNioSender.java
+++ b/java/org/apache/catalina/tribes/transport/nio/ParallelNioSender.java
@@ -116,7 +116,11 @@ 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);
         }
@@ -132,6 +136,7 @@ public class ParallelNioSender extends AbstractSender implements MultiPointSende
         } catch (IOException ioe) {
             throw new ChannelException(sm.getString("parallelNioSender.send.failed"), ioe);
         }
+
         if (selectedKeys == 0) {
             return result;
         }
@@ -204,7 +209,6 @@ public class ParallelNioSender extends AbstractSender implements MultiPointSende
             }
         }
         return result;
-
     }
 
     private static class SendResult {
@@ -319,7 +323,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
@@ -363,4 +371,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 e047b17..956b3a1 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();
diff --git a/res/findbugs/filter-false-positives.xml b/res/findbugs/filter-false-positives.xml
index 659f87d..f8b59f8 100644
--- a/res/findbugs/filter-false-positives.xml
+++ b/res/findbugs/filter-false-positives.xml
@@ -320,6 +320,18 @@
     <Bug pattern="MSF_MUTABLE_SERVLET_FIELD" />
   </Match>
   <Match>
+    <!-- The array contents is never mutated. -->
+    <Class name="org.apache.catalina.mapper.Mapper" />
+    <Field name="hosts" />
+    <Bug pattern="VO_VOLATILE_REFERENCE_TO_ARRAY" />
+  </Match>
+  <Match>
+    <!-- The array contents is never mutated. -->
+    <Class name="org.apache.catalina.mapper.Mapper$MappedContext" />
+    <Field name="versions" />
+    <Bug pattern="VO_VOLATILE_REFERENCE_TO_ARRAY" />
+  </Match>
+  <Match>
     <!-- SQL construction is safe since it is from trusted config -->
     <Or>
       <Class name="org.apache.catalina.realm.DataSourceRealm" />
@@ -373,11 +385,25 @@
     <Bug code="RCN"/>
   </Match>
   <Match>
-    <!-- If encoding is specified it will be used,
-    otherwise platform default encoding will be used -->
     <Class name="org.apache.catalina.realm.RealmBase"/>
     <Method name="Digest"/>
-    <Bug code="Dm" />
+    <Or>
+      <!-- If encoding is specified it will be used,
+      otherwise platform default encoding will be used -->
+      <Bug code="Dm" />
+      <!-- Method has been deprecated -->
+      <Bug pattern="NM_METHOD_NAMING_CONVENTION" />
+    </Or>
+  </Match>
+  <Match>
+    <!--  Name shadowing is intentional -->
+    <Or>
+      <Class name="org.apache.catalina.servlet4preview.AsyncContext"/>
+      <Class name="org.apache.catalina.servlet4preview.RequestDispatcher"/>
+      <Class name="org.apache.catalina.servlet4preview.ServletContext"/>
+      <Class name="org.apache.catalina.servlet4preview.http.HttpServletRequest"/>
+    </Or>
+    <Bug pattern="NM_SAME_SIMPLE_NAME_AS_INTERFACE"/>
   </Match>
   <Match>
     <!--  Name shadowing is intentional -->
@@ -401,6 +427,12 @@
     <Bug code="Dm" />
   </Match>
   <Match>
+    <!-- The use of != with a String is a deliberate hack  -->
+    <Class name="org.apache.catalina.servlets.DefaultServlet" />
+    <Method name="serveResource" />
+    <Bug pattern="ES_COMPARING_STRINGS_WITH_EQ" />
+  </Match>
+  <Match>
     <!-- Non-constant strings are configuration settings rather than client
          supplied -->
     <Class name="org.apache.catalina.session.JDBCStore" />
@@ -415,12 +447,32 @@
     <Bug pattern="SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING" />
   </Match>
   <Match>
+    <!-- Syncs aren't intended to protect these fields -->
+    <Class name="org.apache.catalina.session.JDBCStore" />
+    <Or>
+      <Field name="dataSourceName" />
+      <Field name="sessionAppCol" />
+      <Field name="sessionIdCol" />
+    </Or>
+    <Bug pattern="IS2_INCONSISTENT_SYNC" />
+  </Match>
+  <Match>
     <!-- We can live with the threading issue. See code comment for details. -->
     <Class name="org.apache.catalina.session.ManagerBase" />
     <Method name="generateSessionId" />
     <Bug code="VO" />
   </Match>
   <Match>
+    <!-- These fields should not be serialized with the session -->
+    <Class name="org.apache.catalina.session.StandardSession" />
+    <Or>
+      <Field name="listeners" />
+      <Field name="notes" />
+      <Field name="support" />
+    </Or>
+    <Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED" />
+  </Match>
+  <Match>
     <!-- Use of null is deliberate -->
     <Class name="org.apache.catalina.ssi.ExpressionParseTree" />
     <Method name="pushOpp" />
@@ -441,6 +493,12 @@
     <Bug code="Dm" />
   </Match>
   <Match>
+    <!-- Dead store is deliberate to test URL validity -->
+    <Class name="org.apache.catalina.startup.Bootstrap" />
+    <Method name="createClassLoader" />
+    <Bug pattern="DLS_DEAD_LOCAL_STORE" />
+  </Match>
+  <Match>
     <!-- Failure at this point is fatal -->
     <Class name="org.apache.catalina.startup.Bootstrap" />
     <Method name="initClassLoaders" />
@@ -484,11 +542,39 @@
     <Bug code="NP" />
   </Match>
   <Match>
+    <!-- Deployer instance may implement Listener -->
+    <Class name="org.apache.catalina.storeconfig.CatalinaClusterSF" />
+    <Method name="storeChildren" />
+    <Bug pattern="EC_UNRELATED_TYPES_USING_POINTER_EQUALITY" />
+  </Match>
+  <Match>
+    <!-- If old -> save worked, assume save -> old will to -->
+    <Class name="org.apache.catalina.storeconfig.StoreFileMover" />
+    <Method name="move" />
+    <Bug pattern="RV_RETURN_VALUE_IGNORED_BAD_PRACTICE" />
+  </Match>
+  <Match>
+    <!-- Monitor only used for election -->
+    <Class name="org.apache.catalina.tribes.group.interceptors.NonBlockingCoordinator"/>
+    <Method name="startElection"/>
+    <Bug pattern="WA_NOT_IN_LOOP"/>
+  </Match>
+  <Match>
     <Class name="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
     <Method name="memberAlive"/>
     <Bug code="DE"/>
   </Match>
   <Match>
+    <Class name="org.apache.catalina.tribes.group.ChannelCoordinator"/>
+    <Field name="membershipService"/>
+    <Bug pattern="IS2_INCONSISTENT_SYNC"/>
+  </Match>
+  <Match>
+    <Class name="org.apache.catalina.tribes.group.RpcChannel"/>
+    <Method name="send"/>
+    <Bug pattern="WA_NOT_IN_LOOP"/>
+  </Match>
+  <Match>
     <Class name="org.apache.catalina.tribes.membership.McastServiceImpl"/>
     <Method name="stop"/>
     <Bug code="DE"/>
@@ -519,12 +605,72 @@
     <Bug pattern="UG_SYNC_SET_UNSYNC_GET"/>
   </Match>
   <Match>
+    <Class name="org.apache.catalina.tribes.membership.MemberImpl"/>
+    <Field name="dataPkg"/>
+    <Bug pattern="IS2_INCONSISTENT_SYNC"/>
+  </Match>
+  <Match>
+    <!-- Byte arrays contents are not mutated -->
+    <Class name="org.apache.catalina.tribes.membership.MemberImpl"/>
+    <Or>
+      <Field name="command"/>
+      <Field name="domain"/>
+      <Field name="host"/>
+      <Field name="payload"/>
+      <Field name="uniqueId"/>
+    </Or>
+    <Bug pattern="VO_VOLATILE_REFERENCE_TO_ARRAY"/>
+  </Match>
+  <Match>
+    <!-- lock is in clone so this is safe -->
+    <Class name="org.apache.catalina.tribes.membership.Membership" />
+    <Method name="clone" />
+    <Bug pattern="ML_SYNC_ON_FIELD_TO_GUARD_CHANGING_THAT_FIELD" />
+  </Match>
+  <Match>
+    <!-- Byte arrays contents are not mutated -->
+    <Class name="org.apache.catalina.tribes.membership.Membership" />
+    <Field name="members"/>
+    <Bug pattern="VO_VOLATILE_REFERENCE_TO_ARRAY"/>
+  </Match>
+  <Match>
+    <!--  Fields are always recalculated on access -->
+    <Class name="org.apache.catalina.tribes.tipis.AbstractReplicatedMap$MapMessage" />
+    <Or>
+      <Field name="key" />
+      <Field name="value" />
+    </Or>
+    <Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED" />
+  </Match>
+  <Match>
+    <!-- Sync is not intended to protect access to this field -->
+    <Class name="org.apache.catalina.tribes.transport.ReplicationTransmitter"/>
+    <Field name="oname"/>
+    <Bug pattern="IS2_INCONSISTENT_SYNC"/>
+  </Match>
+  <Match>
     <!-- Intentional in case thread is waiting -->
     <Class name="org.apache.catalina.tribes.transport.RxTaskPool"/>
     <Method name="returnWorker"/>
     <Bug code="NN"/>
   </Match>
   <Match>
+    <!-- Sync is to protect multiple against calls to connect() -->
+    <Class name="org.apache.catalina.tribes.transport.nio.NioSender"/>
+    <Or>
+      <Field name="dataChannel"/>
+      <Field name="socketChannel"/>
+      <Field name="writebuf"/>
+    </Or>
+    <Bug pattern="IS2_INCONSISTENT_SYNC"/>
+  </Match>
+  <Match>
+    <!-- Byte arrays contents are not mutated -->
+    <Class name="org.apache.catalina.tribes.transport.nio.NioSender"/>
+    <Field name="current"/>
+    <Bug pattern="VO_VOLATILE_REFERENCE_TO_ARRAY"/>
+  </Match>
+  <Match>
     <Class name="org.apache.catalina.util.LifecycleBase" />
     <Method name="getState"/>
     <Bug code="UG" />
@@ -571,6 +717,15 @@
     <Bug code="RCN"/>
   </Match>
   <Match>
+    <!-- Array contents is not mutated -->
+    <Class name="org.apache.catalina.webresources.CachedResource"/>
+    <Or>
+      <Field name="webResources"/>
+      <Field name="cachedContent"/>
+    </Or>
+    <Bug pattern="VO_VOLATILE_REFERENCE_TO_ARRAY"/>
+  </Match>
+  <Match>
     <!-- Use of synchronisation is required to make a sequence of calls in   -->
     <!-- one method appear to be atomic.                                     -->
     <Class name="org.apache.coyote.AbstractProcessorLight"/>


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