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:48 UTC

[tomcat] branch 8.5.x updated (f056ef1 -> 36291e6)

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

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


    from f056ef1  Properly calculate dynamic parts of ErrorReportValve response for TestHttp2InitialConnection
     new f001c56  Align with 9.0.x, improve i18n
     new 3fe5742  Back-port FindBugs fixes from 9.0.x
     new b46f44c  Fix SpotBugs warnings in o.a.catalina
     new fce6e65  Fix SportBugs warnings for Coyote and EL
     new 36291e6  SpotBugs fixes (incomplete) for Jasper

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../catalina/core/ApplicationFilterConfig.java     |   2 +-
 java/org/apache/catalina/ha/ClusterListener.java   |  10 -
 .../catalina/ha/deploy/FileMessageFactory.java     |  50 ++--
 .../catalina/ha/deploy/LocalStrings.properties     |   6 +
 .../catalina/ha/deploy/LocalStrings_de.properties  |   2 +
 .../catalina/ha/deploy/LocalStrings_es.properties  |   2 +
 .../catalina/ha/deploy/LocalStrings_fr.properties  |   6 +
 .../catalina/ha/deploy/LocalStrings_ja.properties  |   6 +
 .../catalina/ha/deploy/LocalStrings_ko.properties  |   6 +
 .../ha/deploy/LocalStrings_zh_CN.properties        |   2 +
 .../apache/catalina/ha/tcp/ReplicationValve.java   |  46 ++--
 .../catalina/loader/WebappClassLoaderBase.java     |  10 +-
 .../catalina/manager/LocalStrings.properties       |   1 +
 .../catalina/manager/LocalStrings_fr.properties    |   1 +
 .../catalina/manager/LocalStrings_ja.properties    |   1 +
 .../catalina/manager/LocalStrings_ko.properties    |   1 +
 .../catalina/manager/LocalStrings_ru.properties    |   1 +
 .../catalina/manager/LocalStrings_zh_CN.properties |   1 +
 .../apache/catalina/manager/ManagerServlet.java    |   8 +-
 .../catalina/manager/StatusManagerServlet.java     |   7 -
 .../mbeans/JmxRemoteLifecycleListener.java         |  27 ++
 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 +
 .../LocalStrings_zh_CN.properties                  |   3 +-
 .../catalina/storeconfig/StoreFileMover.java       |  23 +-
 java/org/apache/catalina/tribes/Member.java        |   4 +-
 .../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 +-
 .../apache/coyote/http2/Http2UpgradeHandler.java   |  12 -
 java/org/apache/el/util/ReflectionUtil.java        |  24 ++
 java/org/apache/jasper/compiler/AntCompiler.java   |   5 +-
 java/org/apache/jasper/compiler/Compiler.java      |   3 +-
 java/org/apache/jasper/compiler/JDTCompiler.java   |   5 +-
 res/findbugs/filter-false-positives.xml            | 294 ++++++++++++++++++++-
 70 files changed, 699 insertions(+), 262 deletions(-)
 copy java/org/apache/catalina/{ha/authenticator => storeconfig}/LocalStrings_zh_CN.properties (86%)


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


[tomcat] 01/05: Align with 9.0.x, improve i18n

Posted by ma...@apache.org.
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 f001c56662adee32631699a19e544ea748986b0f
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Nov 13 18:22:06 2019 +0000

    Align with 9.0.x, improve i18n
---
 .../catalina/ha/deploy/FileMessageFactory.java     | 50 ++++++++--------------
 .../catalina/ha/deploy/LocalStrings.properties     |  6 +++
 .../catalina/ha/deploy/LocalStrings_de.properties  |  2 +
 .../catalina/ha/deploy/LocalStrings_es.properties  |  2 +
 .../catalina/ha/deploy/LocalStrings_fr.properties  |  6 +++
 .../catalina/ha/deploy/LocalStrings_ja.properties  |  6 +++
 .../catalina/ha/deploy/LocalStrings_ko.properties  |  6 +++
 .../ha/deploy/LocalStrings_zh_CN.properties        |  2 +
 8 files changed, 49 insertions(+), 31 deletions(-)

diff --git a/java/org/apache/catalina/ha/deploy/FileMessageFactory.java b/java/org/apache/catalina/ha/deploy/FileMessageFactory.java
index 5c8c47e..4c4ab70 100644
--- a/java/org/apache/catalina/ha/deploy/FileMessageFactory.java
+++ b/java/org/apache/catalina/ha/deploy/FileMessageFactory.java
@@ -235,36 +235,26 @@ public class FileMessageFactory {
      */
     public boolean writeMessage(FileMessage msg)
             throws IllegalArgumentException, IOException {
-        if (!openForWrite)
-            throw new IllegalArgumentException(
-                    "Can't write message, this factory is reading.");
+        if (!openForWrite) {
+            throw new IllegalArgumentException(sm.getString("fileMessageFactory.cannotWrite"));
+        }
         if (log.isDebugEnabled())
             log.debug("Message " + msg + " data " + HexUtils.toHexString(msg.getData())
                     + " data length " + msg.getDataLength() + " out " + out);
 
         if (msg.getMessageNumber() <= lastMessageProcessed.get()) {
             // Duplicate of message already processed
-            log.warn("Receive Message again -- Sender ActTimeout too short [ name: "
-                    + msg.getContextName()
-                    + " war: "
-                    + msg.getFileName()
-                    + " data: "
-                    + HexUtils.toHexString(msg.getData())
-                    + " data length: " + msg.getDataLength() + " ]");
+            log.warn(sm.getString("fileMessageFactory.duplicateMessage", msg.getContextName(), msg.getFileName(),
+                    HexUtils.toHexString(msg.getData()), Integer.valueOf(msg.getDataLength())));
             return false;
         }
 
         FileMessage previous =
             msgBuffer.put(Long.valueOf(msg.getMessageNumber()), msg);
-        if (previous !=null) {
+        if (previous != null) {
             // Duplicate of message not yet processed
-            log.warn("Receive Message again -- Sender ActTimeout too short [ name: "
-                    + msg.getContextName()
-                    + " war: "
-                    + msg.getFileName()
-                    + " data: "
-                    + HexUtils.toHexString(msg.getData())
-                    + " data length: " + msg.getDataLength() + " ]");
+            log.warn(sm.getString("fileMessageFactory.duplicateMessage", msg.getContextName(), msg.getFileName(),
+                    HexUtils.toHexString(msg.getData()), Integer.valueOf(msg.getDataLength())));
             return false;
         }
 
@@ -340,16 +330,15 @@ public class FileMessageFactory {
             throws IllegalArgumentException {
         if (this.openForWrite != openForWrite) {
             cleanup();
-            if (openForWrite)
-                throw new IllegalArgumentException(
-                        "Can't write message, this factory is reading.");
-            else
-                throw new IllegalArgumentException(
-                        "Can't read message, this factory is writing.");
+            if (openForWrite) {
+                throw new IllegalArgumentException(sm.getString("fileMessageFactory.cannotWrite"));
+            } else {
+                throw new IllegalArgumentException(sm.getString("fileMessageFactory.cannotRead"));
+            }
         }
         if (this.closed) {
             cleanup();
-            throw new IllegalArgumentException("Factory has been closed.");
+            throw new IllegalArgumentException(sm.getString("fileMessageFactory.closed"));
         }
     }
 
@@ -362,11 +351,8 @@ public class FileMessageFactory {
      * @throws Exception An error occurred
      */
     public static void main(String[] args) throws Exception {
-
-        System.out
-                .println("Usage: FileMessageFactory fileToBeRead fileToBeWritten");
-        System.out
-                .println("Usage: This will make a copy of the file on the local file system");
+        System.out.println("Usage: FileMessageFactory fileToBeRead fileToBeWritten");
+        System.out.println("Usage: This will make a copy of the file on the local file system");
         FileMessageFactory read = getInstance(new File(args[0]), false);
         FileMessageFactory write = getInstance(new File(args[1]), true);
         FileMessage msg = new FileMessage(null, args[0], args[0]);
@@ -396,7 +382,9 @@ public class FileMessageFactory {
             int timeIdle = (int) ((timeNow - creationTime) / 1000L);
             if (timeIdle > maxValidTime) {
                 cleanup();
-                if (file.exists()) file.delete();
+                if (file.exists() && !file.delete()) {
+                    log.warn(sm.getString("fileMessageFactory.deleteFail", file));
+                }
                 return false;
             }
         }
diff --git a/java/org/apache/catalina/ha/deploy/LocalStrings.properties b/java/org/apache/catalina/ha/deploy/LocalStrings.properties
index 400593e..a774859 100644
--- a/java/org/apache/catalina/ha/deploy/LocalStrings.properties
+++ b/java/org/apache/catalina/ha/deploy/LocalStrings.properties
@@ -44,6 +44,12 @@ farmWarDeployer.undeployEnd=Undeployment from [{0}] finished.
 farmWarDeployer.undeployLocal=Undeploy local context [{0}]
 farmWarDeployer.watchDir=Cluster deployment is watching [{0}] for changes.
 
+fileMessageFactory.cannotRead=Cannot read message, this factory is writing
+fileMessageFactory.cannotWrite=Cannot write message, this factory is reading
+fileMessageFactory.closed=Factory has been closed
+fileMessageFactory.deleteFail=Failed to delete [{0}]
+fileMessageFactory.duplicateMessage=Received duplicate message. Is the Sender timeout too low? context: [{0}] filename: [{1}] data: [{2}] data length: [{3}]
+
 fileNewFail=Unable to create [{0}]
 
 warWatcher.cantListWatchDir=Cannot list files in WatchDir [{0}]: check to see if it is a directory and has read permissions.
diff --git a/java/org/apache/catalina/ha/deploy/LocalStrings_de.properties b/java/org/apache/catalina/ha/deploy/LocalStrings_de.properties
index 362b1a1..d09bce9 100644
--- a/java/org/apache/catalina/ha/deploy/LocalStrings_de.properties
+++ b/java/org/apache/catalina/ha/deploy/LocalStrings_de.properties
@@ -19,5 +19,7 @@ farmWarDeployer.msgIoe=Die Farm-Deploy-Datei-Nachricht kann nicht gelesen werden
 farmWarDeployer.servicingUndeploy=Applikation [{0}] ist noch aktiv und kann nicht vom Backup-Cluster-Knoten entfernt werden
 farmWarDeployer.undeployEnd=Undeployment von [{0}] beendet.
 
+fileMessageFactory.duplicateMessage=Doppelte Nachricht empfangen. Ist der Timeout für den Sender zu niedrig? Context: [{0}] Dateiname: [{1}] Daten: [{2}] Datenlänge [{3}]
+
 warWatcher.cantListWatchDir=Dateien in WatchDir [{0}] können nicht gelistet werdenm: Prüfen Sie dass Lesezugriff auf das Verzeichnis besteht
 warWatcher.checkingWar=WAR-Datei [{0}] wird geprüft.
diff --git a/java/org/apache/catalina/ha/deploy/LocalStrings_es.properties b/java/org/apache/catalina/ha/deploy/LocalStrings_es.properties
index d886cce..77e9273 100644
--- a/java/org/apache/catalina/ha/deploy/LocalStrings_es.properties
+++ b/java/org/apache/catalina/ha/deploy/LocalStrings_es.properties
@@ -24,6 +24,8 @@ farmWarDeployer.sendFragment=Fragmento war enviado al cluster con camino [{0}],
 farmWarDeployer.servicingUndeploy=La applicación [{0}] esta en servicion y no pude ser removida del nodo de respaldo del cluster
 farmWarDeployer.undeployEnd=El revertimiendo del despliegue de [{0}] ha terminado.\n
 
+fileMessageFactory.deleteFail=Fallo al borrar [{0}]\n
+
 warWatcher.cantListWatchDir=No se pueden listar archivos en WatchDir [{0}]: verifique si es un directorio y tiene permisos de lectura.\n
 warWatcher.checkWarResult=WarInfo.check() devolvió [{0}] para [{1}]
 warWatcher.checkingWar=Verificando archivo WAR [{0}]
diff --git a/java/org/apache/catalina/ha/deploy/LocalStrings_fr.properties b/java/org/apache/catalina/ha/deploy/LocalStrings_fr.properties
index efdded8..133a41e 100644
--- a/java/org/apache/catalina/ha/deploy/LocalStrings_fr.properties
+++ b/java/org/apache/catalina/ha/deploy/LocalStrings_fr.properties
@@ -43,6 +43,12 @@ farmWarDeployer.undeployEnd=Retrait de [{0}] terminé
 farmWarDeployer.undeployLocal=Le contexte local [{0}] est retiré
 farmWarDeployer.watchDir=Le déploiement du cluster surveille [{0}] pour des modifications
 
+fileMessageFactory.cannotRead=Impossible de lire un message, cette fabrique est en train d'écrire
+fileMessageFactory.cannotWrite=Impossible d'écrire un message, cette fabrique est en train de lire
+fileMessageFactory.closed=La fabrique a été fermée
+fileMessageFactory.deleteFail=Impossible de supprimer [{0}]
+fileMessageFactory.duplicateMessage=Réception de message en double, le délai d''attente maximum de l''expéditeur pourrait être trop court; contexte: [{0}] nom de fichier: [{1}] données: [{2}] longueur des données: [{3}]
+
 fileNewFail=Impossible de créer [{0}]
 
 warWatcher.cantListWatchDir=Incapacité de lister les fichiers dans le répertoire WatchDir [{0}]: vérifiez qu''il s''agit d''un répertoire et qu''il a la permission de lecture.
diff --git a/java/org/apache/catalina/ha/deploy/LocalStrings_ja.properties b/java/org/apache/catalina/ha/deploy/LocalStrings_ja.properties
index 3fd5af8..887abe8 100644
--- a/java/org/apache/catalina/ha/deploy/LocalStrings_ja.properties
+++ b/java/org/apache/catalina/ha/deploy/LocalStrings_ja.properties
@@ -43,6 +43,12 @@ farmWarDeployer.undeployEnd=コンテキスト [{0}] の配置解除が完了し
 farmWarDeployer.undeployLocal=ローカルコンテキスト [{0}] を配置解除します。
 farmWarDeployer.watchDir=クラスタデプロイメントの監視[{0}]が変更されています。
 
+fileMessageFactory.cannotRead=メッセージを読むことができません。このFactoryは書き込み中です。
+fileMessageFactory.cannotWrite=メッセージを書き込めません、このFactoryは読み込み中です。
+fileMessageFactory.closed=FileMessageFactoryはクローズされています。
+fileMessageFactory.deleteFail=[{0}]を削除できませんでした
+fileMessageFactory.duplicateMessage=メッセージをもう一度受信します。SenderのActTimeoutが短すぎます。 名前:[{0}] war:[{1}] データ:[{2}] データ長:[{3}]
+
 fileNewFail=[{0}]を作成できません。
 
 warWatcher.cantListWatchDir=監視ディレクトリ [{0}] のファイル一覧を取得できません : ディレクトリの読み取り権限を確認してください。
diff --git a/java/org/apache/catalina/ha/deploy/LocalStrings_ko.properties b/java/org/apache/catalina/ha/deploy/LocalStrings_ko.properties
index 5bc13cd..0f816aa 100644
--- a/java/org/apache/catalina/ha/deploy/LocalStrings_ko.properties
+++ b/java/org/apache/catalina/ha/deploy/LocalStrings_ko.properties
@@ -43,6 +43,12 @@ farmWarDeployer.undeployEnd=컨텍스트 [{0}]의 배치를 제거했습니다.
 farmWarDeployer.undeployLocal=로컬 컨텍스트 [{0}]의 배치를 제거합니다.
 farmWarDeployer.watchDir=클러스터 배치관리자가 변경사항들을 탐지하기 위해 [{0}]을(를) 감시합니다.
 
+fileMessageFactory.cannotRead=팩토리가 쓰고 있는 중이라서, 메시지를 읽을 수 없습니다.
+fileMessageFactory.cannotWrite=팩토리가 읽고 있는 중이라서, 메시지를 쓸 수 없습니다.
+fileMessageFactory.closed=팩토리가 이미 닫혀 있습니다.
+fileMessageFactory.deleteFail=[{0}]을(를) 삭제하지 못했습니다.
+fileMessageFactory.duplicateMessage=중복된 메시지를 받았습니다. Sender의 제한 시간 초과 값이 너무 작게 설정되었나요? 컨텍스트: [{0}], 파일명: [{1}], 데이터: [{2}], 데이터 길이: [{3}]
+
 fileNewFail=[{0}]을(를) 생성할 수 없습니다.
 
 warWatcher.cantListWatchDir=WatchDir [{0}] 내의 파일 목록을 구할 수 없습니다. 해당 디렉토리가 존재하는지 그리고 읽기 권한이 있는지 점검하십시오.
diff --git a/java/org/apache/catalina/ha/deploy/LocalStrings_zh_CN.properties b/java/org/apache/catalina/ha/deploy/LocalStrings_zh_CN.properties
index 0fbf775..f65f96a 100644
--- a/java/org/apache/catalina/ha/deploy/LocalStrings_zh_CN.properties
+++ b/java/org/apache/catalina/ha/deploy/LocalStrings_zh_CN.properties
@@ -30,6 +30,8 @@ farmWarDeployer.servicingUndeploy=正在处理应用程序[{0}],无法从备
 farmWarDeployer.undeployEnd=从[{0}]取消部署完成。
 farmWarDeployer.undeployLocal=不能部署本地上下文[{0}]
 
+fileMessageFactory.deleteFail=无法删除 [{0}]
+
 warWatcher.cantListWatchDir=无法列出WatchDir文件夹 [{0}] 中的文件:检查该路径是否为目录且应用具有读取权限。
 warWatcher.checkWarResult=WarInfo.check() 为[{1}]返回[{0}]
 warWatcher.checkingWar=检查 WAR 文件 [{0}]


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


[tomcat] 02/05: Back-port FindBugs fixes from 9.0.x

Posted by ma...@apache.org.
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 3fe5742da6d2b803b4f71242982ce34045d5f396
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Nov 13 19:22:42 2019 +0000

    Back-port FindBugs fixes from 9.0.x
    
    (and a few obvious alignment fixes spotted along the way)
---
 .../catalina/core/ApplicationFilterConfig.java     |   2 +-
 .../apache/catalina/ha/tcp/ReplicationValve.java   |  46 +++++----
 .../catalina/manager/LocalStrings.properties       |   1 +
 .../catalina/manager/LocalStrings_fr.properties    |   1 +
 .../catalina/manager/LocalStrings_ja.properties    |   1 +
 .../catalina/manager/LocalStrings_ko.properties    |   1 +
 .../catalina/manager/LocalStrings_ru.properties    |   1 +
 .../catalina/manager/LocalStrings_zh_CN.properties |   1 +
 .../apache/catalina/manager/ManagerServlet.java    |   8 +-
 .../catalina/manager/StatusManagerServlet.java     |   7 --
 .../mbeans/JmxRemoteLifecycleListener.java         |  27 +++++
 java/org/apache/catalina/tribes/Member.java        |   4 +-
 res/findbugs/filter-false-positives.xml            | 115 +++++++++++++++++++--
 13 files changed, 176 insertions(+), 39 deletions(-)

diff --git a/java/org/apache/catalina/core/ApplicationFilterConfig.java b/java/org/apache/catalina/core/ApplicationFilterConfig.java
index a8f960c..dc146fc 100644
--- a/java/org/apache/catalina/core/ApplicationFilterConfig.java
+++ b/java/org/apache/catalina/core/ApplicationFilterConfig.java
@@ -62,7 +62,7 @@ public final class ApplicationFilterConfig implements FilterConfig, Serializable
     static final StringManager sm =
         StringManager.getManager(Constants.Package);
 
-    private final Log log = LogFactory.getLog(ApplicationFilterConfig.class); // must not be static
+    private transient Log log = LogFactory.getLog(ApplicationFilterConfig.class); // must not be static
 
     /**
      * Empty String collection to serve as the basis for empty enumerations.
diff --git a/java/org/apache/catalina/ha/tcp/ReplicationValve.java b/java/org/apache/catalina/ha/tcp/ReplicationValve.java
index 8fac6b2..30308b5 100644
--- a/java/org/apache/catalina/ha/tcp/ReplicationValve.java
+++ b/java/org/apache/catalina/ha/tcp/ReplicationValve.java
@@ -93,13 +93,21 @@ public class ReplicationValve
      */
     protected boolean doProcessingStats = false;
 
-    protected long totalRequestTime = 0;
-    protected long totalSendTime = 0;
-    protected long nrOfRequests = 0;
-    protected long lastSendTime = 0;
-    protected long nrOfFilterRequests = 0;
-    protected long nrOfSendRequests = 0;
-    protected long nrOfCrossContextSendRequests = 0;
+    /*
+     * Note: The statistics are volatile to ensure the concurrent updates do not
+     *       corrupt them but it is still possible that:
+     *       - some updates may be lost;
+     *       - the individual statistics may not be consistent which each other.
+     *       This is a deliberate design choice to reduce the requirement for
+     *       synchronization.
+     */
+    protected volatile long totalRequestTime = 0;
+    protected volatile long totalSendTime = 0;
+    protected volatile long nrOfRequests = 0;
+    protected volatile long lastSendTime = 0;
+    protected volatile long nrOfFilterRequests = 0;
+    protected volatile long nrOfSendRequests = 0;
+    protected volatile long nrOfCrossContextSendRequests = 0;
 
     /**
      * must primary change indicator set
@@ -354,11 +362,11 @@ public class ReplicationValve
      * reset the active statistics
      */
     public void resetStatistics() {
-        totalRequestTime = 0 ;
-        totalSendTime = 0 ;
-        lastSendTime = 0 ;
-        nrOfFilterRequests = 0 ;
-        nrOfRequests = 0 ;
+        totalRequestTime = 0;
+        totalSendTime = 0;
+        lastSendTime = 0;
+        nrOfFilterRequests = 0;
+        nrOfRequests = 0;
         nrOfSendRequests = 0;
         nrOfCrossContextSendRequests = 0;
     }
@@ -422,8 +430,7 @@ public class ReplicationValve
     protected void sendCrossContextSession() {
         List<DeltaSession> sessions = crossContextSessions.get();
         if(sessions != null && sessions.size() >0) {
-            for(Iterator<DeltaSession> iter = sessions.iterator(); iter.hasNext() ;) {
-                Session session = iter.next();
+            for (DeltaSession session : sessions) {
                 if(log.isDebugEnabled()) {
                     log.debug(sm.getString("ReplicationValve.crossContext.sendDelta",
                             session.getManager().getContext().getName() ));
@@ -564,12 +571,11 @@ public class ReplicationValve
     protected  void updateStats(long requestTime, long clusterTime) {
         // TODO: Async requests may trigger multiple replication requests. How,
         //       if at all, should the stats handle this?
-        synchronized(this) {
-            lastSendTime=System.currentTimeMillis();
-            totalSendTime+=lastSendTime - clusterTime;
-            totalRequestTime+=lastSendTime - requestTime;
-            nrOfRequests++;
-        }
+        long currentTime = System.currentTimeMillis();
+        lastSendTime = currentTime;
+        totalSendTime += currentTime - clusterTime;
+        totalRequestTime += currentTime - requestTime;
+        nrOfRequests++;
         if(log.isInfoEnabled()) {
             if ( (nrOfRequests % 100) == 0 ) {
                  log.info(sm.getString("ReplicationValve.stats",
diff --git a/java/org/apache/catalina/manager/LocalStrings.properties b/java/org/apache/catalina/manager/LocalStrings.properties
index fac641c..556e0c1 100644
--- a/java/org/apache/catalina/manager/LocalStrings.properties
+++ b/java/org/apache/catalina/manager/LocalStrings.properties
@@ -141,6 +141,7 @@ managerServlet.notSslConnector=SSL is not enabled for this connector
 managerServlet.objectNameFail=FAIL - Unable to register object name [{0}] for Manager Servlet
 managerServlet.postCommand=FAIL - Tried to use command [{0}] via a GET request but POST is required
 managerServlet.reloaded=OK - Reloaded application at context path [{0}]
+managerServlet.renameFail=FAIL - Unable to rename [{0}] to [{1}]. This may cause problems for future deployments.
 managerServlet.resourcesAll=OK - Listed global resources of all types
 managerServlet.resourcesType=OK - Listed global resources of type [{0}]
 managerServlet.saveFail=FAIL - Configuration save failed: [{0}]
diff --git a/java/org/apache/catalina/manager/LocalStrings_fr.properties b/java/org/apache/catalina/manager/LocalStrings_fr.properties
index 03ce4d1..fc2baef 100644
--- a/java/org/apache/catalina/manager/LocalStrings_fr.properties
+++ b/java/org/apache/catalina/manager/LocalStrings_fr.properties
@@ -139,6 +139,7 @@ managerServlet.notSslConnector=SSL n'est pas activé pour ce connecteur
 managerServlet.objectNameFail=ECHEC - Le nom d''objet [{0}] n''a pas pu être enregistré pour le Servlet de Gestion
 managerServlet.postCommand=ECHEC - Tentative d''utilisation de la commande [{0}] via une requête GET, mais POST est requis
 managerServlet.reloaded=OK - L''application associée au chemin de contexte [{0}] a été rechargée
+managerServlet.renameFail=ECHEC - N''a pas pu renommer [{0}] vers [{1}], cela pourrait causer des problèmes pour de prochains déploiements
 managerServlet.resourcesAll=OK - Liste des ressources globales de tout type
 managerServlet.resourcesType=OK - Liste des ressources globales de type [{0}]
 managerServlet.saveFail=ECHEC - La sauvegarde de la configuration a échoué: [{0}]
diff --git a/java/org/apache/catalina/manager/LocalStrings_ja.properties b/java/org/apache/catalina/manager/LocalStrings_ja.properties
index 8007ddf..662e25a 100644
--- a/java/org/apache/catalina/manager/LocalStrings_ja.properties
+++ b/java/org/apache/catalina/manager/LocalStrings_ja.properties
@@ -141,6 +141,7 @@ managerServlet.notSslConnector=このコネクターでは SSL が有効化さ
 managerServlet.objectNameFail=FAIL - オブジェクト名 [{0}] を ManagerServlet として登録できません。
 managerServlet.postCommand=FAIL - コマンド [{0}] を GET リクエストで実行しようとしましたが、POST リクエストでなければなりません。
 managerServlet.reloaded=OK - コンテキストパス [{0}] のアプリケーションを再ロードしました
+managerServlet.renameFail=FAIL  -  [{0}]の名前を[{1}]に変更できません。 これにより、今後の展開で問題が発生する可能性があります。
 managerServlet.resourcesAll=OK - すべてのタイプのグローバルリソースを列挙しました
 managerServlet.resourcesType=OK - タイプ [{0}] のグローバルリソースを列挙しました
 managerServlet.saveFail=FAIL - 設定の保存に失敗しました: [{0}]
diff --git a/java/org/apache/catalina/manager/LocalStrings_ko.properties b/java/org/apache/catalina/manager/LocalStrings_ko.properties
index 9d34ac1..bab468d 100644
--- a/java/org/apache/catalina/manager/LocalStrings_ko.properties
+++ b/java/org/apache/catalina/manager/LocalStrings_ko.properties
@@ -139,6 +139,7 @@ managerServlet.notSslConnector=SSL이 이 connector를 위해 사용 가능 상
 managerServlet.objectNameFail=실패 - 매니저 서블릿을 위한 객체 이름 [{0}]을(를) 등록할 수 없습니다.
 managerServlet.postCommand=실패 - GET 요청을 통해 명령 [{0}]을(를) 사용하려 시도했으나, POST 요청이 요구됩니다.
 managerServlet.reloaded=OK - 컨텍스트 경로 [{0}]의 애플리케이션을 다시 로드했습니다.
+managerServlet.renameFail=실패 - [{0}]을(를) [{1}](으)로 이름을 변경할 수 없습니다. 이는 이후의 배치 작업들에서 문제들을 일으킬 수 있습니다.
 managerServlet.resourcesAll=OK - 모든 타입들의 글로벌 리소스들이 목록으로 표시되었습니다.
 managerServlet.resourcesType=OK - 타입이 [{0}]인 글로벌 리소스들의 목록을 표시했습니다.
 managerServlet.saveFail=실패 - 설정을 저장하지 못했습니다: [{0}]
diff --git a/java/org/apache/catalina/manager/LocalStrings_ru.properties b/java/org/apache/catalina/manager/LocalStrings_ru.properties
index 4f0ab23..02bb71e 100644
--- a/java/org/apache/catalina/manager/LocalStrings_ru.properties
+++ b/java/org/apache/catalina/manager/LocalStrings_ru.properties
@@ -141,6 +141,7 @@ managerServlet.notSslConnector=Протокол SSL/TLS для этого кон
 managerServlet.objectNameFail=ОШИБКА - Не удалось зарегистрировать имя объекта [{0}] для Manager Servlet
 managerServlet.postCommand=ОШИБКА - Попытка использовать команду [{0}] через запрос GET но требуется POST
 managerServlet.reloaded=OK - Приложение по пути контекста [{0}] было перезагружено
+managerServlet.renameFail=ОШИБКА - Невозможно переименовать [{0}] в [{1}]. Это может вызвать проблемы для будущих развертываний.
 managerServlet.resourcesAll=OK - Перечислены глобальные ресурсы всех видов
 managerServlet.resourcesType=OK - Перечислены глобальные ресурсы вида [{0}]
 managerServlet.saveFail=ОШИБКА - Не удалось сохранить настройки: [{0}]
diff --git a/java/org/apache/catalina/manager/LocalStrings_zh_CN.properties b/java/org/apache/catalina/manager/LocalStrings_zh_CN.properties
index 93d1a00..b3b1a40 100644
--- a/java/org/apache/catalina/manager/LocalStrings_zh_CN.properties
+++ b/java/org/apache/catalina/manager/LocalStrings_zh_CN.properties
@@ -138,6 +138,7 @@ managerServlet.notSslConnector=不允许SSL连接
 managerServlet.objectNameFail=FAIL - 不能将为Manager Servlet 注册 object name  [{0}]
 managerServlet.postCommand=失败 - 尝试通过GET请求使用命令[{0}],但需要POST
 managerServlet.reloaded=OK - 上下文路径[{0}]重新加载应用程序
+managerServlet.renameFail=失败 - 无法重命名[{0}]为[{1}],这可能这未来部署时出现问题。
 managerServlet.resourcesAll=OK - 列出所有类型的全部资源
 managerServlet.resourcesType=OK - [{0}]类型全局资源列入清单
 managerServlet.saveFail=失败 - 配置保存失败:[{0}]
diff --git a/java/org/apache/catalina/manager/ManagerServlet.java b/java/org/apache/catalina/manager/ManagerServlet.java
index b3d84b0..73f3593 100644
--- a/java/org/apache/catalina/manager/ManagerServlet.java
+++ b/java/org/apache/catalina/manager/ManagerServlet.java
@@ -690,7 +690,6 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
                 log("managerServlet.storeConfig", e);
                 writer.println(smClient.getString("managerServlet.exception",
                         e.toString()));
-                return;
             }
         } else {
             String contextPath = path;
@@ -713,7 +712,6 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
                 log("managerServlet.save[" + path + "]", e);
                 writer.println(smClient.getString("managerServlet.exception",
                         e.toString()));
-                return;
             }
         }
     }
@@ -802,7 +800,11 @@ public class ManagerServlet extends HttpServlet implements ContainerServlet {
                             return;
                         }
                         // Rename uploaded WAR file
-                        uploadedWar.renameTo(deployedWar);
+                        if (!uploadedWar.renameTo(deployedWar)) {
+                            writer.println(smClient.getString("managerServlet.renameFail",
+                                    uploadedWar, deployedWar));
+                            return;
+                        }
                     }
                     if (tag != null) {
                         // Copy WAR to the host's appBase
diff --git a/java/org/apache/catalina/manager/StatusManagerServlet.java b/java/org/apache/catalina/manager/StatusManagerServlet.java
index 71806b9..1fc7be2 100644
--- a/java/org/apache/catalina/manager/StatusManagerServlet.java
+++ b/java/org/apache/catalina/manager/StatusManagerServlet.java
@@ -401,14 +401,7 @@ public class StatusManagerServlet
                         requestProcessors.removeElement(objectName);
                     }
                 }
-                String j2eeType = objectName.getKeyProperty("j2eeType");
-                if (j2eeType != null) {
-
-                }
             }
         }
-
     }
-
-
 }
diff --git a/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java b/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java
index 5795ec5..f3aefde 100644
--- a/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java
+++ b/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java
@@ -464,5 +464,32 @@ public class JmxRemoteLifecycleListener implements LifecycleListener {
             sslServerSocket.setNeedClientAuth(getNeedClientAuth());
             return sslServerSocket;
         }
+
+        // Super class defines hashCode() and equals(). Probably not used in
+        // Tomcat but for safety, override them here.
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = super.hashCode();
+            result = prime * result + ((bindAddress == null) ? 0 : bindAddress.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (!super.equals(obj))
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            SslRmiServerBindSocketFactory other = (SslRmiServerBindSocketFactory) obj;
+            if (bindAddress == null) {
+                if (other.bindAddress != null)
+                    return false;
+            } else if (!bindAddress.equals(other.bindAddress))
+                return false;
+            return true;
+        }
     }
 }
diff --git a/java/org/apache/catalina/tribes/Member.java b/java/org/apache/catalina/tribes/Member.java
index 11484eb..638abf8 100644
--- a/java/org/apache/catalina/tribes/Member.java
+++ b/java/org/apache/catalina/tribes/Member.java
@@ -17,6 +17,8 @@
 
 package org.apache.catalina.tribes;
 
+import java.io.Serializable;
+
 /**
  * The Member interface, defines a member in the group.
  * Each member can carry a set of properties, defined by the actual implementation.<BR>
@@ -27,7 +29,7 @@ package org.apache.catalina.tribes;
  * since a member that has crashed and the starts up again on the same port/host is
  * not guaranteed to be the same member, so no state transfers will ever be confused
  */
-public interface Member {
+public interface Member extends Serializable {
 
     /**
      * When a member leaves the cluster, the payload of the memberDisappeared member
diff --git a/res/findbugs/filter-false-positives.xml b/res/findbugs/filter-false-positives.xml
index f441fdf..659f87d 100644
--- a/res/findbugs/filter-false-positives.xml
+++ b/res/findbugs/filter-false-positives.xml
@@ -83,12 +83,7 @@
     <Bug code="REC"/>
   </Match>
   <Match>
-    <Class name="org.apache.catalina.ant.jmx.JMXAccessorCondition"/>
-    <Method name="accessJMXValue"/>
-    <Bug code="REC"/>
-  </Match>
-  <Match>
-    <Class name="org.apache.catalina.ant.jmx.JMXAccessorEqualsCondition"/>
+    <Class name="org.apache.catalina.ant.jmx.JMXAccessorConditionBase"/>
     <Method name="accessJMXValue"/>
     <Bug code="REC"/>
   </Match>
@@ -127,6 +122,12 @@
     <Bug code="RCN"/>
   </Match>
   <Match>
+    <!-- False positive. It is lifecycle state that is being protected -->
+    <Class name="org.apache.catalina.authenticator.SingleSignOn" />
+    <Field name="engine" />
+    <Bug pattern="IS2_INCONSISTENT_SYNC" />
+  </Match>
+  <Match>
     <!-- req.getRemoteUser(), req.getAuthType(), request.getQueryString() can
     return null because o.a.t.util.buf.MessageBytes.toString() can return NULL
     -->
@@ -173,12 +174,53 @@
     <Bug code="RCN"/>
   </Match>
   <Match>
+    <!-- Exception caught deliberately -->
+    <Class name="org.apache.catalina.core.NamingContextListener" />
+    <Method name="constructEnvEntry" />
+    <Bug pattern="REC_CATCH_EXCEPTION" />
+  </Match>
+  <Match>
+    <!-- Code uses same approach as CopyOnWriteArrayList -->
+    <Class name="org.apache.catalina.core.StandardContext" />
+    <Field name="constraints" />
+    <Bug pattern="VO_VOLATILE_REFERENCE_TO_ARRAY" />
+  </Match>
+  <Match>
+    <!-- Sync is for lifecycle state, not CookieProcessor -->
+    <Class name="org.apache.catalina.core.StandardContext" />
+    <Field name="cookieProcessor" />
+    <Bug pattern="IS2_INCONSISTENT_SYNC" />
+  </Match>
+  <Match>
+    <!-- Calling sleep while holding a lock is deliberate -->
+    <Class name="org.apache.catalina.core.StandardContext" />
+    <Method name="stopInternal" />
+    <Bug pattern="SWL_SLEEP_WITH_LOCK_HELD" />
+  </Match>
+  <Match>
     <!-- Have to trigger GC for leak detection to work. Clearly documented -->
     <Class name="org.apache.catalina.core.StandardHost" />
     <Method name="findReloadedContextMemoryLeaks" />
     <Bug code="Dm" />
   </Match>
   <Match>
+    <!-- Sync not targeting these fields -->
+    <Class name="org.apache.catalina.core.StandardWrapper" />
+    <Or>
+      <Field name="multipartConfigElement" />
+      <Field name="servletClass" />
+      <Field name="swallowOutput" />
+      <Field name="unloadDelay" />
+    </Or>
+    <Bug pattern="IS2_INCONSISTENT_SYNC" />
+  </Match>
+  <Match>
+    <!-- There is only a single wait condition -->
+    <Class name="org.apache.catalina.core.StandardWrapper" />
+    <Method name="deallocate" />
+    <Bug pattern="NO_NOTIFY_NOT_NOTIFYALL" />
+  </Match>
+  <Match>
     <!-- Sleep is of short duration and lock is required -->
     <Class name="org.apache.catalina.core.StandardWrapper" />
     <Method name="unload" />
@@ -204,6 +246,12 @@
     <Bug code="DE" />
   </Match>
   <Match>
+    <!-- False positive. It is lifecycle state that is being protected -->
+    <Class name="org.apache.catalina.ha.authenticator.ClusterSingleSignOn" />
+    <Field name="cluster" />
+    <Bug pattern="IS2_INCONSISTENT_SYNC" />
+  </Match>
+  <Match>
     <!-- shost will not be null in normal usage -->
     <Class name="org.apache.catalina.ha.backend.CollectedInfo" />
     <Method name="init" />
@@ -225,6 +273,29 @@
     <Bug code="DE" />
   </Match>
   <Match>
+    <!-- False positive caused by additional method syncs -->
+    <Class name="org.apache.catalina.ha.session.DeltaManager" />
+    <Field name="receiverQueue" />
+    <Pattern code="IS2_INCONSISTENT_SYNC" />
+  </Match>
+  <Match>
+    <!-- False positive caused by method syncs -->
+    <Class name="org.apache.catalina.ha.session.JvmRouteBinderValve" />
+    <Field name="cluster" />
+    <Pattern code="IS2_INCONSISTENT_SYNC" />
+  </Match>
+  <Match>
+    <!-- Design choice to reduce need for syncs -->
+    <Class name="org.apache.catalina.ha.tcp.ReplicationValve" />
+    <Or>
+      <Field name="nrOfCrossContextSendRequests" />
+      <Field name="nrOfFilterRequests" />
+      <Field name="nrOfRequests" />
+      <Field name="nrOfSendRequests" />
+    </Or>
+    <Pattern code="VO_VOLATILE_INCREMENT" />
+  </Match>
+  <Match>
     <!-- Field is only modified during Servlet load -->
     <Class name="org.apache.catalina.manager.host.HostManagerServlet" />
     <Bug code="MSF" />
@@ -236,6 +307,19 @@
     <Bug code="REC" />
   </Match>
   <Match>
+    <!-- The fields are only set in setWrapper() which Tomcat calls once during
+         initialisation. All other accesses are reads. -->
+    <Class name="org.apache.catalina.manager.ManagerServlet" />
+    <Or>
+      <Field name="context" />
+      <Field name="host" />
+      <Field name="mBeanServer" />
+      <Field name="oname" />
+      <Field name="wrapper" />
+    </Or>
+    <Bug pattern="MSF_MUTABLE_SERVLET_FIELD" />
+  </Match>
+  <Match>
     <!-- SQL construction is safe since it is from trusted config -->
     <Or>
       <Class name="org.apache.catalina.realm.DataSourceRealm" />
@@ -243,6 +327,8 @@
     </Or>
     <Or>
       <Method name="credentials" />
+      <Method name="getPassword" />
+      <Method name="getRoles" />
       <Method name="roles" />
     </Or>
     <Bug pattern="SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING" />
@@ -253,6 +339,15 @@
     <Bug code="IS" />
   </Match>
   <Match>
+    <!-- Sync is protecting preparedRoles, not these fields -->
+    <Class name="org.apache.catalina.realm.JDBCRealm" />
+    <Or>
+      <Field name="roleNameCol" />
+      <Field name="userRoleTable" />
+    </Or>
+    <Bug pattern="IS2_INCONSISTENT_SYNC " />
+  </Match>
+  <Match>
     <!-- roles will be initialized in addAttributeValues -->
     <Class name="org.apache.catalina.realm.JNDIRealm" />
     <Or>
@@ -262,6 +357,12 @@
     <Bug code="NP" />
   </Match>
   <Match>
+    <!-- Sync is protecting authenticate90, not this field -->
+    <Class name="org.apache.catalina.realm.JNDIRealm" />
+    <Field name="userPatternFormatArray" />
+    <Bug pattern="IS2_INCONSISTENT_SYNC " />
+  </Match>
+  <Match>
     <!-- request.getRequestPathMB(), request.getQueryString() can be null because
     o.a.t.util.buf.MessageBytes.toString() can return NULL -->
     <Class name="org.apache.catalina.realm.RealmBase"/>
@@ -1320,4 +1421,4 @@
     </Or>
     <Bug pattern="DLS_DEAD_LOCAL_STORE"/>
   </Match>
-</FindBugsFilter>
\ No newline at end of file
+</FindBugsFilter>


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


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

Posted by ma...@apache.org.
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


[tomcat] 05/05: SpotBugs fixes (incomplete) for Jasper

Posted by ma...@apache.org.
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 36291e6af5629a4bb019f74fd0be829e3287b7fa
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Nov 13 22:48:44 2019 +0000

    SpotBugs fixes (incomplete) for Jasper
---
 java/org/apache/jasper/compiler/AntCompiler.java | 5 ++++-
 java/org/apache/jasper/compiler/Compiler.java    | 3 ++-
 java/org/apache/jasper/compiler/JDTCompiler.java | 5 ++++-
 3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/java/org/apache/jasper/compiler/AntCompiler.java b/java/org/apache/jasper/compiler/AntCompiler.java
index bf2a2f8..0d0bcb4 100644
--- a/java/org/apache/jasper/compiler/AntCompiler.java
+++ b/java/org/apache/jasper/compiler/AntCompiler.java
@@ -249,7 +249,10 @@ public class AntCompiler extends Compiler {
 
         if (!ctxt.keepGenerated()) {
             File javaFile = new File(javaFileName);
-            javaFile.delete();
+            if (!javaFile.delete()) {
+                throw new JasperException(Localizer.getMessage(
+                        "jsp.warning.compiler.javafile.delete.fail", javaFile));
+            }
         }
 
         if (be != null) {
diff --git a/java/org/apache/jasper/compiler/Compiler.java b/java/org/apache/jasper/compiler/Compiler.java
index 9cf955a..02278b5 100644
--- a/java/org/apache/jasper/compiler/Compiler.java
+++ b/java/org/apache/jasper/compiler/Compiler.java
@@ -77,6 +77,7 @@ public abstract class Compiler {
         this.options = ctxt.getOptions();
     }
 
+
     // --------------------------------------------------------- Public Methods
 
     /**
@@ -264,7 +265,7 @@ public abstract class Compiler {
                         + " generate=" + (t4 - t3) + " validate=" + (t2 - t1));
             }
 
-        } catch (Exception e) {
+        } catch (RuntimeException e) {
             // Remove the generated .java file
             File file = new File(javaFileName);
             if (file.exists()) {
diff --git a/java/org/apache/jasper/compiler/JDTCompiler.java b/java/org/apache/jasper/compiler/JDTCompiler.java
index 4950f3f..1d0f0b7 100644
--- a/java/org/apache/jasper/compiler/JDTCompiler.java
+++ b/java/org/apache/jasper/compiler/JDTCompiler.java
@@ -540,7 +540,10 @@ public class JDTCompiler extends org.apache.jasper.compiler.Compiler {
 
         if (!ctxt.keepGenerated()) {
             File javaFile = new File(ctxt.getServletJavaFileName());
-            javaFile.delete();
+            if (!javaFile.delete()) {
+                throw new JasperException(Localizer.getMessage(
+                        "jsp.warning.compiler.javafile.delete.fail", javaFile));
+            }
         }
 
         if (!problemList.isEmpty()) {


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


[tomcat] 04/05: Fix SportBugs warnings for Coyote and EL

Posted by ma...@apache.org.
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 fce6e651665ab2ca72c3d9fe2420db2ac14c0d2c
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Nov 13 22:36:56 2019 +0000

    Fix SportBugs warnings for Coyote and EL
---
 .../apache/coyote/http2/Http2UpgradeHandler.java   | 12 -----------
 java/org/apache/el/util/ReflectionUtil.java        | 24 ++++++++++++++++++++++
 res/findbugs/filter-false-positives.xml            | 18 ++++++++++++++++
 3 files changed, 42 insertions(+), 12 deletions(-)

diff --git a/java/org/apache/coyote/http2/Http2UpgradeHandler.java b/java/org/apache/coyote/http2/Http2UpgradeHandler.java
index 159e5d4..40a379b 100644
--- a/java/org/apache/coyote/http2/Http2UpgradeHandler.java
+++ b/java/org/apache/coyote/http2/Http2UpgradeHandler.java
@@ -160,18 +160,6 @@ public class Http2UpgradeHandler extends AbstractStream implements InternalHttpU
     private volatile int lastWindowUpdate;
 
 
-    /**
-     * @param adapter       The adapter to use to process the upgrade
-     * @param coyoteRequest The request to use to process the upgrade
-     *
-     * @deprecated This will be removed in Tomcat 9 onwards.
-     *             Use {@link #Http2UpgradeHandler(Http2Protocol, Adapter, Request)}
-     */
-    @Deprecated
-    public Http2UpgradeHandler(Adapter adapter, Request coyoteRequest) {
-        this(null, adapter, coyoteRequest);
-    }
-
     public Http2UpgradeHandler(Http2Protocol protocol, Adapter adapter, Request coyoteRequest) {
         super (STREAM_ID_ZERO);
         this.protocol = protocol;
diff --git a/java/org/apache/el/util/ReflectionUtil.java b/java/org/apache/el/util/ReflectionUtil.java
index f59a61c..acf2271 100644
--- a/java/org/apache/el/util/ReflectionUtil.java
+++ b/java/org/apache/el/util/ReflectionUtil.java
@@ -557,5 +557,29 @@ public class ReflectionUtil {
             }
             return cmp;
         }
+
+        @Override
+        public boolean equals(Object o)
+        {
+            return o == this
+                    || (null != o
+                    && this.getClass().equals(o.getClass())
+                    && ((MatchResult)o).getExact() == this.getExact()
+                    && ((MatchResult)o).getAssignable() == this.getAssignable()
+                    && ((MatchResult)o).getCoercible() == this.getCoercible()
+                    && ((MatchResult)o).isBridge() == this.isBridge()
+                    )
+                    ;
+        }
+
+        @Override
+        public int hashCode()
+        {
+            return (this.isBridge() ? 1 << 24 : 0)
+                    ^ this.getExact() << 16
+                    ^ this.getAssignable() << 8
+                    ^ this.getCoercible()
+                    ;
+        }
     }
 }
diff --git a/res/findbugs/filter-false-positives.xml b/res/findbugs/filter-false-positives.xml
index f8b59f8..eb037f8 100644
--- a/res/findbugs/filter-false-positives.xml
+++ b/res/findbugs/filter-false-positives.xml
@@ -823,12 +823,30 @@
     <Bug pattern="NN_NAKED_NOTIFY" />
   </Match>
   <Match>
+    <!-- Monitor is used for a single condition. -->
+    <Class name="org.apache.coyote.http2.WindowAllocationManager" />
+    <Method name="notify" />
+    <Bug pattern="NO_NOTIFY_NOT_NOTIFYALL" />
+  </Match>
+  <Match>
+    <!-- Monitor is used for a single condition. -->
+    <Class name="org.apache.coyote.http2.WindowAllocationManager" />
+    <Method name="waitFor" />
+    <Bug pattern="WA_NOT_IN_LOOP" />
+  </Match>
+  <Match>
     <!-- Returning null is required by the EL specification -->
     <Class name="org.apache.el.lang.ELSupport" />
     <Method name="coerceToBoolean"/>
     <Bug pattern="NP_BOOLEAN_RETURN_NULL"/>
   </Match>
   <Match>
+    <!-- Result is negated because arguments have to be swapped -->
+    <Class name="org.apache.el.lang.ELSupport" />
+    <Method name="compare"/>
+    <Bug pattern="RV_NEGATING_RESULT_OF_COMPARETO"/>
+  </Match>
+  <Match>
     <!-- JspC will not be used under a security manager -->
     <Class name="org.apache.jasper.JspC"/>
     <Method name="initClassLoader"/>


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