init
This commit is contained in:
31
java/org/apache/catalina/ha/tcp/Constants.java
Normal file
31
java/org/apache/catalina/ha/tcp/Constants.java
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package org.apache.catalina.ha.tcp;
|
||||
|
||||
/**
|
||||
* Manifest constants for the <code>org.apache.catalina.ha.tcp</code>
|
||||
* package.
|
||||
*
|
||||
* @author Peter Rossbach
|
||||
*/
|
||||
public class Constants {
|
||||
|
||||
public static final String Package = "org.apache.catalina.ha.tcp";
|
||||
|
||||
}
|
||||
42
java/org/apache/catalina/ha/tcp/LocalStrings.properties
Normal file
42
java/org/apache/catalina/ha/tcp/LocalStrings.properties
Normal file
@@ -0,0 +1,42 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
ReplicationValve.crossContext.add=add Cross Context session replication container to replicationValve threadlocal
|
||||
ReplicationValve.crossContext.registerSession=register Cross context session id=[{0}] from context [{1}]
|
||||
ReplicationValve.crossContext.remove=remove Cross Context session replication container from replicationValve threadlocal
|
||||
ReplicationValve.crossContext.sendDelta=send Cross Context session delta from context [{0}].
|
||||
ReplicationValve.filter.failure=Unable to compile filter=[{0}]
|
||||
ReplicationValve.filter.loading=Loading request filter=[{0}]
|
||||
ReplicationValve.invoke.uri=Invoking replication request on [{0}]
|
||||
ReplicationValve.nocluster=No cluster configured for this request.
|
||||
ReplicationValve.resetDeltaRequest=Cluster is standalone: reset Session Request Delta at context [{0}]
|
||||
ReplicationValve.send.failure=Unable to perform replication request.
|
||||
ReplicationValve.send.invalid.failure=Unable to send session [id={0}] invalid message over cluster.
|
||||
ReplicationValve.session.found=Context [{0}]: Found session [{1}] but it isn''t a ClusterSession.
|
||||
ReplicationValve.session.indicator=Context [{0}]: Primarity of session [{1}] in request attribute [{2}] is [{3}].
|
||||
ReplicationValve.session.invalid=Context [{0}]: Requested session [{1}] is invalid, removed or not replicated at this node.
|
||||
ReplicationValve.stats=Average request time=[{0}] ms with cluster overhead time=[{1}] ms for [{2}] requests, [{3}] send requests, [{4}] cross context requests, and [{5}] filter requests (Total request=[{6}] ms, total cluster request=[{7}] ms).
|
||||
|
||||
simpleTcpCluster.clustermanager.cloneFailed=Unable to clone cluster manager, defaulting to org.apache.catalina.ha.session.DeltaManager
|
||||
simpleTcpCluster.clustermanager.notImplement=Manager [{0}] does not implement ClusterManager, addition to cluster has been aborted.
|
||||
simpleTcpCluster.member.addFailed=Unable to connect to replication system.
|
||||
simpleTcpCluster.member.added=Replication member added:[{0}]
|
||||
simpleTcpCluster.member.disappeared=Received member disappeared:[{0}]
|
||||
simpleTcpCluster.member.removeFailed=Unable remove cluster node from replication system.
|
||||
simpleTcpCluster.sendFailed=Unable to send message through cluster sender.
|
||||
simpleTcpCluster.start=Cluster is about to start
|
||||
simpleTcpCluster.startUnable=Unable to start cluster.
|
||||
simpleTcpCluster.stopUnable=Unable to stop cluster.
|
||||
simpleTcpCluster.unableSend.localMember=Unable to send message to local member [{0}]
|
||||
20
java/org/apache/catalina/ha/tcp/LocalStrings_de.properties
Normal file
20
java/org/apache/catalina/ha/tcp/LocalStrings_de.properties
Normal file
@@ -0,0 +1,20 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
ReplicationValve.filter.failure=Kann Filter [{0}] nicht kompilieren
|
||||
ReplicationValve.session.indicator=Context [{0}]: Primärität der Session [{1}] in Request Attribut [{2}] ist [{3}].
|
||||
|
||||
simpleTcpCluster.clustermanager.notImplement=Manager [{0}] implementiert nicht ClusterManager. Das Hinzufügen dieses Managers zum Cluster wurde daher abgebrochen.
|
||||
simpleTcpCluster.stopUnable=Cluster kann nicht gestoppt werden.
|
||||
35
java/org/apache/catalina/ha/tcp/LocalStrings_es.properties
Normal file
35
java/org/apache/catalina/ha/tcp/LocalStrings_es.properties
Normal file
@@ -0,0 +1,35 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
ReplicationValve.crossContext.add=añadir contenedor de réplica de sesión de Contexto Cruzado a replicationValve threadlocal
|
||||
ReplicationValve.crossContext.registerSession=retistrar id de sesión de Contexto Cruzado=[{0}] desde contexto [{1}]
|
||||
ReplicationValve.crossContext.remove=quitar contenedor de réplica de sesión de Contexto Cruzado a replicationValve threadlocal
|
||||
ReplicationValve.crossContext.sendDelta=enviar delta de sesión de Contexto Cruzado desde contexto [{0}].
|
||||
ReplicationValve.filter.failure=No puedo compilar filtror=[{0}]
|
||||
ReplicationValve.filter.loading=Cargando filtros de requerimiento=[{0}]
|
||||
ReplicationValve.invoke.uri=Invocando requerimiento de réplica en [{0}]
|
||||
ReplicationValve.nocluster=No cluster configured for this request.
|
||||
ReplicationValve.resetDeltaRequest=Cluster is standalone: reset Session Request Delta at context [{0}]
|
||||
ReplicationValve.send.failure=Unable to perform replication request.
|
||||
ReplicationValve.send.invalid.failure=Unable to send session [id={0}] invalid message over cluster.
|
||||
ReplicationValve.session.found=Context [{0}]: Found session [{1}] but it isn''t a ClusterSession.
|
||||
ReplicationValve.session.indicator=Context [{0}]: Primarity of session [{0}] in request attribute [{1}] is [{2}].
|
||||
ReplicationValve.session.invalid=Context [{0}]: Requested session [{1}] is invalid, removed or not replicated at this node.
|
||||
ReplicationValve.stats=Average request time= [{0}] ms for Cluster overhead time=[{1}] ms for [{2}] requests [{3}] filter requests [{4}] send requests [{5}] cross context requests (Request=[{6}] ms Cluster=[{7}] ms).
|
||||
|
||||
simpleTcpCluster.clustermanager.notImplement=Manejador [{0}] no implementa ClusterManager, la adición al cluster ha sido abortada.\n
|
||||
simpleTcpCluster.member.addFailed=Incapaz de conectar con el sistema de replicación
|
||||
simpleTcpCluster.member.removeFailed=Imposible remover el nodo del sistema de replicación
|
||||
simpleTcpCluster.stopUnable=Inmposible deterner el cluster
|
||||
42
java/org/apache/catalina/ha/tcp/LocalStrings_fr.properties
Normal file
42
java/org/apache/catalina/ha/tcp/LocalStrings_fr.properties
Normal file
@@ -0,0 +1,42 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
ReplicationValve.crossContext.add=Ajout du conteneur de réplication de la session multi contexte au ThreadLocal de replicationValve
|
||||
ReplicationValve.crossContext.registerSession=enregistrement de la session multi contexte id=[{0}] du contexte [{1}]
|
||||
ReplicationValve.crossContext.remove=Retrait du conteneur de réplication de la session multi contexte au ThreadLocal de replicationValve
|
||||
ReplicationValve.crossContext.sendDelta=Envoi du delta de la session multi contexte du contexte [{0}]
|
||||
ReplicationValve.filter.failure=Incapacité de compiler le filtre=[{0}]
|
||||
ReplicationValve.filter.loading=Chargement du filtre de requête [{0}]
|
||||
ReplicationValve.invoke.uri=Invocation de la requête de réplication sur [{0}]
|
||||
ReplicationValve.nocluster=Aucun cluster de configuré pour cette requête
|
||||
ReplicationValve.resetDeltaRequest=Le cluster se suffit à lui-même: réinitialisation du delta de la requête de session [{0}]
|
||||
ReplicationValve.send.failure=Impossible d'effectuer la requête de réplication
|
||||
ReplicationValve.send.invalid.failure=Incapable d'envoyer le message invalide de la session [id={0}] sur le cluster
|
||||
ReplicationValve.session.found=Le Contexte [{0}] a touvé la session [{1}] mais ce n''est pas une ClusterSession.
|
||||
ReplicationValve.session.indicator=Contexte [{0}] : la primarité de la session [{1}] dans l''attribut de requête [{2}] est [{3}].
|
||||
ReplicationValve.session.invalid=Contexte [{0}]: la session demandée [{1}] est invalide, non répliquée, ou enlevée sur ce nœud
|
||||
ReplicationValve.stats=Temps de requête moyen= [{0}] ms pour le Cluster le temps ajouté est de=[{1}] ms pour [{2}] requêtes [{3}] requêtes d''envoi [{4}] requêtes multi contextes et [{5}] requêtes fitrées (Total requêtes=[{6}] ms total requêtes du cluster=[{7}] ms)
|
||||
|
||||
simpleTcpCluster.clustermanager.cloneFailed=Impossible de cloner le gestionnaire du cluster, le org.apache.catalina.ha.session.DeltaManager par défaut sera utilisé
|
||||
simpleTcpCluster.clustermanager.notImplement=Le gestionnaire ("Manager") [{0}] n''implémente pas ClusterManager. Son ajout au cluster a été abandonné.
|
||||
simpleTcpCluster.member.addFailed=Impossible de se connecter au système de réplication
|
||||
simpleTcpCluster.member.added=Membre de réplication ajouté : [{0}]
|
||||
simpleTcpCluster.member.disappeared=Le membre recu a disparu: [{0}]
|
||||
simpleTcpCluster.member.removeFailed=Impossible d'enlever un nœud du cluster du système de réplication
|
||||
simpleTcpCluster.sendFailed=Impossible d'envoyer un message à travers l'expéditeur du cluster
|
||||
simpleTcpCluster.start=Le cluster va démarrer
|
||||
simpleTcpCluster.startUnable=Impossible de démarre le cluster
|
||||
simpleTcpCluster.stopUnable=Incapable d'arrêter le cluster
|
||||
simpleTcpCluster.unableSend.localMember=Impossible d''envoyer un message au membre local [{0}]
|
||||
42
java/org/apache/catalina/ha/tcp/LocalStrings_ja.properties
Normal file
42
java/org/apache/catalina/ha/tcp/LocalStrings_ja.properties
Normal file
@@ -0,0 +1,42 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
ReplicationValve.crossContext.add=クロスコンテキストセッションレプリケーションコンテナをreplicationValveスレッドローカルに追加
|
||||
ReplicationValve.crossContext.registerSession=コンテキスト[{1}]からクロスコンテキストセッションID = [{0}]を登録する
|
||||
ReplicationValve.crossContext.remove=replication Contextセッションレプリケーションコンテナをスレッドローカルから削除します。
|
||||
ReplicationValve.crossContext.sendDelta=コンテキスト[{0}]からのクロスコンテキストセッションデルタを送信します。
|
||||
ReplicationValve.filter.failure=フィルター文字列=[{0}] がコンパイルできません。
|
||||
ReplicationValve.filter.loading=リクエストフィルタ= [{0}]のロード
|
||||
ReplicationValve.invoke.uri=[{0}]のレプリケーションリクエストを呼び出します。
|
||||
ReplicationValve.nocluster=このリクエストに対して構成されたクラスタはありません。
|
||||
ReplicationValve.resetDeltaRequest=クラスタはスタンドアロンである:コンテキスト[{0}]でセッションのデルタリクエストをリセットします。
|
||||
ReplicationValve.send.failure=レプリケーションリクエストを実行できません。
|
||||
ReplicationValve.send.invalid.failure=セッション[id = {0}]無効メッセージをクラスタに送信できません。
|
||||
ReplicationValve.session.found=コンテキスト [{0}]: セッション [{1}] は ClusterSession ではありません。
|
||||
ReplicationValve.session.indicator=Context [{0}]:リクエスト属性[{2}]のセッション[{1}]のプライマリは[{3}]です。
|
||||
ReplicationValve.session.invalid=コンテキスト [{0}]: 不正なセッション [{1}] が要求されました。消去された、あるいは、このノードに複製されなかった可能性があります。
|
||||
ReplicationValve.stats=[{2}]リクエストの平均要求時間= [{0}] ms、クラスタオーバーヘッド時間= [{1}] ms、[{3}]リクエストの送信、[{4}]クロスコンテキストリクエスト、[{5} }]フィルタリクエスト(合計リクエスト= [{6}] ms、クラスタ全体リクエスト= [{7}] ms)。
|
||||
|
||||
simpleTcpCluster.clustermanager.cloneFailed=クラスタマネージャをクローンできません。デフォルトはorg.apache.catalina.ha.session.DeltaManagerです。
|
||||
simpleTcpCluster.clustermanager.notImplement=クラス [{0}] は ClusterManager を実装していません。それにクラスターはすでに停止しています。
|
||||
simpleTcpCluster.member.addFailed=レプリケーションシステムに接続できません。
|
||||
simpleTcpCluster.member.added=レプリケーションメンバーを追加しました: [{0}]
|
||||
simpleTcpCluster.member.disappeared=メッセージ消失を受信しました: [{0}]
|
||||
simpleTcpCluster.member.removeFailed=レプリケーションシステムからクラスターノードを削除できませんでした。
|
||||
simpleTcpCluster.sendFailed=クラスタセンダ経由でメッセージを送信できませんでした。
|
||||
simpleTcpCluster.start=Clusterを起動します。
|
||||
simpleTcpCluster.startUnable=クラスタを起動出来ません。
|
||||
simpleTcpCluster.stopUnable=クラスタを停止できません。
|
||||
simpleTcpCluster.unableSend.localMember=ローカルメンバー [{0}] にメッセージを送信できません。
|
||||
42
java/org/apache/catalina/ha/tcp/LocalStrings_ko.properties
Normal file
42
java/org/apache/catalina/ha/tcp/LocalStrings_ko.properties
Normal file
@@ -0,0 +1,42 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
ReplicationValve.crossContext.add=교차 컨텍스트 세션 복제 컨테이너를 replicationValve의 threadlocal에 추가합니다.
|
||||
ReplicationValve.crossContext.registerSession=컨텍스트 [{1}](으)로부터 세션 ID가 [{0}]인 교차 컨텍스트 세션을 등록합니다.
|
||||
ReplicationValve.crossContext.remove=replicationValve의 threadlocal로부터, 교차 컨텍스트 세션 복제 컨테이너를 제거합니다.
|
||||
ReplicationValve.crossContext.sendDelta=컨텍스트 [{0}](으)로부터 교차 컨텍스트 세션 델타를 보냅니다.
|
||||
ReplicationValve.filter.failure=필터 컴파일을 할 수 없습니다. filter=[{0}]
|
||||
ReplicationValve.filter.loading=요청 필터를 로드합니다: [{0}]
|
||||
ReplicationValve.invoke.uri=[{0}]에 복제 요청을 호출합니다.
|
||||
ReplicationValve.nocluster=이 요청을 위해 설정된 클러스터가 없습니다.
|
||||
ReplicationValve.resetDeltaRequest=클러스터가 독립형(standalone)입니다: 컨텍스트 [{0}]에서 세션 요청 델타를 재설정(reset)합니다.
|
||||
ReplicationValve.send.failure=복제 요청을 수행 할 수 없습니다.
|
||||
ReplicationValve.send.invalid.failure=세션 [id={0}] 유효하지 않음 메시지를 클러스터에 전송할 수 없습니다.
|
||||
ReplicationValve.session.found=컨텍스트 [{0}]에서 세션 [{1}]을(를) 발견했으나, 이는 ClusterSession이 아닙니다.
|
||||
ReplicationValve.session.indicator=컨텍스트 [{0}]: 요청 속성 [{2}]에 있는 세션 [{1}]의 Primary 여부: [{3}]
|
||||
ReplicationValve.session.invalid=컨텍스트 [{0}]: 요청된 세션 [{1}]이(가), 유효하지 않거나, 제거되었거나, 또는 이 클러스터 노드로 복제되지 않았습니다.
|
||||
ReplicationValve.stats=[{2}]개의 요청들, [{3}]개의 전송 요청들, [{4}]개의 교차 컨텍스트 요청들, 그리고 [{5}]개의 필터 요청들을 처리하는 동안, 평균 요청 시간=[{0}] 밀리초, 클러스터 오버헤드 시간=[{1}] 밀리초가 소요되었습니다. (총 요청 처리 시간=[{6}] 밀리초, 총 클러스터 요청 처리 시간=[{7}] 밀리초)
|
||||
|
||||
simpleTcpCluster.clustermanager.cloneFailed=클러스터 매니저를 복제할 수 없습니다. 기본 값인 org.apache.catalina.ha.session.DeltaManager를 사용합니다.
|
||||
simpleTcpCluster.clustermanager.notImplement=매니저 [{0}]이(가) ClusterManager 인터페이스를 구현하지 않습니다. 클러스터에 추가하려는 시도는 중단됩니다.
|
||||
simpleTcpCluster.member.addFailed=복제 시스템에 연결할 수 없습니다.
|
||||
simpleTcpCluster.member.added=복제 멤버가 추가됨: [{0}]
|
||||
simpleTcpCluster.member.disappeared=멤버 사라짐 메시지를 수신했습니다: [{0}]
|
||||
simpleTcpCluster.member.removeFailed=복제 시스템으로부터 클러스터 노드를 제거할 수 없습니다.
|
||||
simpleTcpCluster.sendFailed=클러스터 sender를 통해 메시지를 보낼 수 없습니다.
|
||||
simpleTcpCluster.start=클러스터가 막 시작하려 합니다.
|
||||
simpleTcpCluster.startUnable=클러스터를 시작할 수 없습니다.
|
||||
simpleTcpCluster.stopUnable=클러스터를 중지시킬 수 없습니다.
|
||||
simpleTcpCluster.unableSend.localMember=로컬 멤버 [{0}]에게 메시지를 보낼 수 없습니다.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
ReplicationValve.filter.failure=无法编译 filter = [{0}]
|
||||
ReplicationValve.session.found=上下文[{0}]:找到会话[{1}]但它不是ClusterSession。
|
||||
ReplicationValve.session.invalid=上下文[{0}]:请求的会话[{1}]在此节点上无效,已删除或未复制。
|
||||
|
||||
simpleTcpCluster.clustermanager.notImplement=连接器 [{0}] 不能继承 ClusterManager,除非集群被停止。
|
||||
simpleTcpCluster.member.addFailed=无法连接到复制系统。
|
||||
simpleTcpCluster.member.disappeared=收到成员消失:[{0}]
|
||||
simpleTcpCluster.member.removeFailed=无法从复制系统中移除集群节点
|
||||
simpleTcpCluster.stopUnable=无法停止集群
|
||||
631
java/org/apache/catalina/ha/tcp/ReplicationValve.java
Normal file
631
java/org/apache/catalina/ha/tcp/ReplicationValve.java
Normal file
@@ -0,0 +1,631 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.catalina.ha.tcp;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.apache.catalina.Cluster;
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.Manager;
|
||||
import org.apache.catalina.Session;
|
||||
import org.apache.catalina.connector.Request;
|
||||
import org.apache.catalina.connector.Response;
|
||||
import org.apache.catalina.core.StandardContext;
|
||||
import org.apache.catalina.ha.CatalinaCluster;
|
||||
import org.apache.catalina.ha.ClusterManager;
|
||||
import org.apache.catalina.ha.ClusterMessage;
|
||||
import org.apache.catalina.ha.ClusterSession;
|
||||
import org.apache.catalina.ha.ClusterValve;
|
||||
import org.apache.catalina.ha.session.DeltaManager;
|
||||
import org.apache.catalina.ha.session.DeltaSession;
|
||||
import org.apache.catalina.valves.ValveBase;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* <p>Implementation of a Valve that logs interesting contents from the
|
||||
* specified Request (before processing) and the corresponding Response
|
||||
* (after processing). It is especially useful in debugging problems
|
||||
* related to headers and cookies.</p>
|
||||
*
|
||||
* <p>This Valve may be attached to any Container, depending on the granularity
|
||||
* of the logging you wish to perform.</p>
|
||||
*
|
||||
* <p>primaryIndicator=true, then the request attribute <i>org.apache.catalina.ha.tcp.isPrimarySession.</i>
|
||||
* is set true, when request processing is at sessions primary node.
|
||||
* </p>
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
* @author Peter Rossbach
|
||||
*/
|
||||
public class ReplicationValve
|
||||
extends ValveBase implements ClusterValve {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ReplicationValve.class);
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
/**
|
||||
* The StringManager for this package.
|
||||
*/
|
||||
protected static final StringManager sm =
|
||||
StringManager.getManager(Constants.Package);
|
||||
|
||||
private CatalinaCluster cluster = null ;
|
||||
|
||||
/**
|
||||
* Filter expression
|
||||
*/
|
||||
protected Pattern filter = null;
|
||||
|
||||
/**
|
||||
* crossContext session container
|
||||
*/
|
||||
protected final ThreadLocal<ArrayList<DeltaSession>> crossContextSessions =
|
||||
new ThreadLocal<>() ;
|
||||
|
||||
/**
|
||||
* doProcessingStats (default = off)
|
||||
*/
|
||||
protected boolean doProcessingStats = false;
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
protected boolean primaryIndicator = false ;
|
||||
|
||||
/**
|
||||
* Name of primary change indicator as request attribute
|
||||
*/
|
||||
protected String primaryIndicatorName = "org.apache.catalina.ha.tcp.isPrimarySession";
|
||||
|
||||
// ------------------------------------------------------------- Properties
|
||||
|
||||
public ReplicationValve() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the cluster.
|
||||
*/
|
||||
@Override
|
||||
public CatalinaCluster getCluster() {
|
||||
return cluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cluster The cluster to set.
|
||||
*/
|
||||
@Override
|
||||
public void setCluster(CatalinaCluster cluster) {
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the filter
|
||||
*/
|
||||
public String getFilter() {
|
||||
if (filter == null) {
|
||||
return null;
|
||||
}
|
||||
return filter.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* compile filter string to regular expression
|
||||
* @see Pattern#compile(java.lang.String)
|
||||
* @param filter
|
||||
* The filter to set.
|
||||
*/
|
||||
public void setFilter(String filter) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("ReplicationValve.filter.loading", filter));
|
||||
}
|
||||
|
||||
if (filter == null || filter.length() == 0) {
|
||||
this.filter = null;
|
||||
} else {
|
||||
try {
|
||||
this.filter = Pattern.compile(filter);
|
||||
} catch (PatternSyntaxException pse) {
|
||||
log.error(sm.getString("ReplicationValve.filter.failure",
|
||||
filter), pse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the primaryIndicator.
|
||||
*/
|
||||
public boolean isPrimaryIndicator() {
|
||||
return primaryIndicator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param primaryIndicator The primaryIndicator to set.
|
||||
*/
|
||||
public void setPrimaryIndicator(boolean primaryIndicator) {
|
||||
this.primaryIndicator = primaryIndicator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the primaryIndicatorName.
|
||||
*/
|
||||
public String getPrimaryIndicatorName() {
|
||||
return primaryIndicatorName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param primaryIndicatorName The primaryIndicatorName to set.
|
||||
*/
|
||||
public void setPrimaryIndicatorName(String primaryIndicatorName) {
|
||||
this.primaryIndicatorName = primaryIndicatorName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calc processing stats
|
||||
* @return <code>true</code> if statistics are enabled
|
||||
*/
|
||||
public boolean doStatistics() {
|
||||
return doProcessingStats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Calc processing stats
|
||||
*
|
||||
* @param doProcessingStats New flag value
|
||||
* @see #resetStatistics()
|
||||
*/
|
||||
public void setStatistics(boolean doProcessingStats) {
|
||||
this.doProcessingStats = doProcessingStats;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the lastSendTime.
|
||||
*/
|
||||
public long getLastSendTime() {
|
||||
return lastSendTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the nrOfRequests.
|
||||
*/
|
||||
public long getNrOfRequests() {
|
||||
return nrOfRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the nrOfFilterRequests.
|
||||
*/
|
||||
public long getNrOfFilterRequests() {
|
||||
return nrOfFilterRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the nrOfCrossContextSendRequests.
|
||||
*/
|
||||
public long getNrOfCrossContextSendRequests() {
|
||||
return nrOfCrossContextSendRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the nrOfSendRequests.
|
||||
*/
|
||||
public long getNrOfSendRequests() {
|
||||
return nrOfSendRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the totalRequestTime.
|
||||
*/
|
||||
public long getTotalRequestTime() {
|
||||
return totalRequestTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the totalSendTime.
|
||||
*/
|
||||
public long getTotalSendTime() {
|
||||
return totalSendTime;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
/**
|
||||
* Register all cross context sessions inside endAccess.
|
||||
* Use a list with contains check, that the Portlet API can include a lot of fragments from same or
|
||||
* different applications with session changes.
|
||||
*
|
||||
* @param session cross context session
|
||||
*/
|
||||
public void registerReplicationSession(DeltaSession session) {
|
||||
List<DeltaSession> sessions = crossContextSessions.get();
|
||||
if(sessions != null) {
|
||||
if(!sessions.contains(session)) {
|
||||
if(log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("ReplicationValve.crossContext.registerSession",
|
||||
session.getIdInternal(),
|
||||
session.getManager().getContext().getName()));
|
||||
}
|
||||
sessions.add(session);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the interesting request parameters, invoke the next Valve in the
|
||||
* sequence, and log the interesting response parameters.
|
||||
*
|
||||
* @param request The servlet request to be processed
|
||||
* @param response The servlet response to be created
|
||||
*
|
||||
* @exception IOException if an input/output error occurs
|
||||
* @exception ServletException if a servlet error occurs
|
||||
*/
|
||||
@Override
|
||||
public void invoke(Request request, Response response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
long totalstart = 0;
|
||||
|
||||
//this happens before the request
|
||||
if(doStatistics()) {
|
||||
totalstart = System.currentTimeMillis();
|
||||
}
|
||||
if (primaryIndicator) {
|
||||
createPrimaryIndicator(request) ;
|
||||
}
|
||||
Context context = request.getContext();
|
||||
boolean isCrossContext = context != null
|
||||
&& context instanceof StandardContext
|
||||
&& ((StandardContext) context).getCrossContext();
|
||||
try {
|
||||
if(isCrossContext) {
|
||||
if(log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("ReplicationValve.crossContext.add"));
|
||||
}
|
||||
//FIXME add Pool of Arraylists
|
||||
crossContextSessions.set(new ArrayList<DeltaSession>());
|
||||
}
|
||||
getNext().invoke(request, response);
|
||||
if(context != null && cluster != null
|
||||
&& context.getManager() instanceof ClusterManager) {
|
||||
ClusterManager clusterManager = (ClusterManager) context.getManager();
|
||||
|
||||
// valve cluster can access manager - other cluster handle replication
|
||||
// at host level - hopefully!
|
||||
if(cluster.getManager(clusterManager.getName()) == null) {
|
||||
return ;
|
||||
}
|
||||
if(cluster.hasMembers()) {
|
||||
sendReplicationMessage(request, totalstart, isCrossContext, clusterManager);
|
||||
} else {
|
||||
resetReplicationRequest(request,isCrossContext);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// Array must be remove: Current master request send endAccess at recycle.
|
||||
// Don't register this request session again!
|
||||
if(isCrossContext) {
|
||||
if(log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("ReplicationValve.crossContext.remove"));
|
||||
}
|
||||
// crossContextSessions.remove() only exist at Java 5
|
||||
// register ArrayList at a pool
|
||||
crossContextSessions.set(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* reset the active statistics
|
||||
*/
|
||||
public void resetStatistics() {
|
||||
totalRequestTime = 0;
|
||||
totalSendTime = 0;
|
||||
lastSendTime = 0;
|
||||
nrOfFilterRequests = 0;
|
||||
nrOfRequests = 0;
|
||||
nrOfSendRequests = 0;
|
||||
nrOfCrossContextSendRequests = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start this component and implement the requirements
|
||||
* of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
|
||||
*
|
||||
* @exception LifecycleException if this component detects a fatal error
|
||||
* that prevents this component from being used
|
||||
*/
|
||||
@Override
|
||||
protected synchronized void startInternal() throws LifecycleException {
|
||||
if (cluster == null) {
|
||||
Cluster containerCluster = getContainer().getCluster();
|
||||
if (containerCluster instanceof CatalinaCluster) {
|
||||
setCluster((CatalinaCluster)containerCluster);
|
||||
} else {
|
||||
if (log.isWarnEnabled()) {
|
||||
log.warn(sm.getString("ReplicationValve.nocluster"));
|
||||
}
|
||||
}
|
||||
}
|
||||
super.startInternal();
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Protected Methods
|
||||
|
||||
protected void sendReplicationMessage(Request request, long totalstart, boolean isCrossContext, ClusterManager clusterManager) {
|
||||
//this happens after the request
|
||||
long start = 0;
|
||||
if(doStatistics()) {
|
||||
start = System.currentTimeMillis();
|
||||
}
|
||||
try {
|
||||
// send invalid sessions
|
||||
// DeltaManager returns String[0]
|
||||
if (!(clusterManager instanceof DeltaManager)) {
|
||||
sendInvalidSessions(clusterManager);
|
||||
}
|
||||
// send replication
|
||||
sendSessionReplicationMessage(request, clusterManager);
|
||||
if(isCrossContext) {
|
||||
sendCrossContextSession();
|
||||
}
|
||||
} catch (Exception x) {
|
||||
// FIXME we have a lot of sends, but the trouble with one node stops the correct replication to other nodes!
|
||||
log.error(sm.getString("ReplicationValve.send.failure"), x);
|
||||
} finally {
|
||||
// FIXME this stats update are not cheap!!
|
||||
if(doStatistics()) {
|
||||
updateStats(totalstart,start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send all changed cross context sessions to backups
|
||||
*/
|
||||
protected void sendCrossContextSession() {
|
||||
List<DeltaSession> sessions = crossContextSessions.get();
|
||||
if(sessions != null && sessions.size() >0) {
|
||||
for (DeltaSession session : sessions) {
|
||||
if(log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("ReplicationValve.crossContext.sendDelta",
|
||||
session.getManager().getContext().getName() ));
|
||||
}
|
||||
sendMessage(session,(ClusterManager)session.getManager());
|
||||
if(doStatistics()) {
|
||||
nrOfCrossContextSendRequests++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix memory leak for long sessions with many changes, when no backup member exists!
|
||||
* @param request current request after response is generated
|
||||
* @param isCrossContext check crosscontext threadlocal
|
||||
*/
|
||||
protected void resetReplicationRequest(Request request, boolean isCrossContext) {
|
||||
Session contextSession = request.getSessionInternal(false);
|
||||
if(contextSession instanceof DeltaSession){
|
||||
resetDeltaRequest(contextSession);
|
||||
((DeltaSession)contextSession).setPrimarySession(true);
|
||||
}
|
||||
if(isCrossContext) {
|
||||
List<DeltaSession> sessions = crossContextSessions.get();
|
||||
if(sessions != null && sessions.size() >0) {
|
||||
Iterator<DeltaSession> iter = sessions.iterator();
|
||||
for(; iter.hasNext() ;) {
|
||||
Session session = iter.next();
|
||||
resetDeltaRequest(session);
|
||||
if(session instanceof DeltaSession) {
|
||||
((DeltaSession)contextSession).setPrimarySession(true);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset DeltaRequest from session
|
||||
* @param session HttpSession from current request or cross context session
|
||||
*/
|
||||
protected void resetDeltaRequest(Session session) {
|
||||
if(log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("ReplicationValve.resetDeltaRequest" ,
|
||||
session.getManager().getContext().getName() ));
|
||||
}
|
||||
((DeltaSession)session).resetDeltaRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send Cluster Replication Request
|
||||
* @param request current request
|
||||
* @param manager session manager
|
||||
*/
|
||||
protected void sendSessionReplicationMessage(Request request,
|
||||
ClusterManager manager) {
|
||||
Session session = request.getSessionInternal(false);
|
||||
if (session != null) {
|
||||
String uri = request.getDecodedRequestURI();
|
||||
// request without session change
|
||||
if (!isRequestWithoutSessionChange(uri)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("ReplicationValve.invoke.uri", uri));
|
||||
}
|
||||
sendMessage(session,manager);
|
||||
} else
|
||||
if(doStatistics()) {
|
||||
nrOfFilterRequests++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Send message delta message from request session
|
||||
* @param session current session
|
||||
* @param manager session manager
|
||||
*/
|
||||
protected void sendMessage(Session session,
|
||||
ClusterManager manager) {
|
||||
String id = session.getIdInternal();
|
||||
if (id != null) {
|
||||
send(manager, id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* send manager requestCompleted message to cluster
|
||||
* @param manager SessionManager
|
||||
* @param sessionId sessionid from the manager
|
||||
* @see DeltaManager#requestCompleted(String)
|
||||
* @see SimpleTcpCluster#send(ClusterMessage)
|
||||
*/
|
||||
protected void send(ClusterManager manager, String sessionId) {
|
||||
ClusterMessage msg = manager.requestCompleted(sessionId);
|
||||
if (msg != null && cluster != null) {
|
||||
cluster.send(msg);
|
||||
if(doStatistics()) {
|
||||
nrOfSendRequests++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check for session invalidations
|
||||
* @param manager Associated manager
|
||||
*/
|
||||
protected void sendInvalidSessions(ClusterManager manager) {
|
||||
String[] invalidIds=manager.getInvalidatedSessions();
|
||||
if ( invalidIds.length > 0 ) {
|
||||
for ( int i=0;i<invalidIds.length; i++ ) {
|
||||
try {
|
||||
send(manager,invalidIds[i]);
|
||||
} catch ( Exception x ) {
|
||||
log.error(sm.getString("ReplicationValve.send.invalid.failure",invalidIds[i]),x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* is request without possible session change
|
||||
* @param uri The request uri
|
||||
* @return True if no session change
|
||||
*/
|
||||
protected boolean isRequestWithoutSessionChange(String uri) {
|
||||
Pattern f = filter;
|
||||
return f != null && f.matcher(uri).matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* Protocol cluster replications stats
|
||||
* @param requestTime Request time
|
||||
* @param clusterTime Cluster time
|
||||
*/
|
||||
protected void updateStats(long requestTime, long clusterTime) {
|
||||
// TODO: Async requests may trigger multiple replication requests. How,
|
||||
// if at all, should the stats handle this?
|
||||
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",
|
||||
new Object[]{
|
||||
Long.valueOf(totalRequestTime/nrOfRequests),
|
||||
Long.valueOf(totalSendTime/nrOfRequests),
|
||||
Long.valueOf(nrOfRequests),
|
||||
Long.valueOf(nrOfSendRequests),
|
||||
Long.valueOf(nrOfCrossContextSendRequests),
|
||||
Long.valueOf(nrOfFilterRequests),
|
||||
Long.valueOf(totalRequestTime),
|
||||
Long.valueOf(totalSendTime)}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Mark Request that processed at primary node with attribute
|
||||
* primaryIndicatorName
|
||||
*
|
||||
* @param request The Servlet request
|
||||
* @throws IOException IO error finding session
|
||||
*/
|
||||
protected void createPrimaryIndicator(Request request) throws IOException {
|
||||
String id = request.getRequestedSessionId();
|
||||
if ((id != null) && (id.length() > 0)) {
|
||||
Manager manager = request.getContext().getManager();
|
||||
Session session = manager.findSession(id);
|
||||
if (session instanceof ClusterSession) {
|
||||
ClusterSession cses = (ClusterSession) session;
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString(
|
||||
"ReplicationValve.session.indicator", request.getContext().getName(),id,
|
||||
primaryIndicatorName,
|
||||
Boolean.valueOf(cses.isPrimarySession())));
|
||||
}
|
||||
request.setAttribute(primaryIndicatorName, cses.isPrimarySession()?Boolean.TRUE:Boolean.FALSE);
|
||||
} else {
|
||||
if (log.isDebugEnabled()) {
|
||||
if (session != null) {
|
||||
log.debug(sm.getString(
|
||||
"ReplicationValve.session.found", request.getContext().getName(),id));
|
||||
} else {
|
||||
log.debug(sm.getString(
|
||||
"ReplicationValve.session.invalid", request.getContext().getName(),id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
63
java/org/apache/catalina/ha/tcp/SendMessageData.java
Normal file
63
java/org/apache/catalina/ha/tcp/SendMessageData.java
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.catalina.ha.tcp;
|
||||
|
||||
import org.apache.catalina.tribes.Member;
|
||||
|
||||
/**
|
||||
* @author Peter Rossbach
|
||||
*/
|
||||
public class SendMessageData {
|
||||
|
||||
private Object message ;
|
||||
private Member destination ;
|
||||
private Exception exception ;
|
||||
|
||||
|
||||
/**
|
||||
* @param message The message to send
|
||||
* @param destination Member destination
|
||||
* @param exception Associated error
|
||||
*/
|
||||
public SendMessageData(Object message, Member destination,
|
||||
Exception exception) {
|
||||
super();
|
||||
this.message = message;
|
||||
this.destination = destination;
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the destination.
|
||||
*/
|
||||
public Member getDestination() {
|
||||
return destination;
|
||||
}
|
||||
/**
|
||||
* @return the exception.
|
||||
*/
|
||||
public Exception getException() {
|
||||
return exception;
|
||||
}
|
||||
/**
|
||||
* @return the message.
|
||||
*/
|
||||
public Object getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
853
java/org/apache/catalina/ha/tcp/SimpleTcpCluster.java
Normal file
853
java/org/apache/catalina/ha/tcp/SimpleTcpCluster.java
Normal file
@@ -0,0 +1,853 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.catalina.ha.tcp;
|
||||
|
||||
import java.beans.PropertyChangeSupport;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.apache.catalina.Container;
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.Engine;
|
||||
import org.apache.catalina.Host;
|
||||
import org.apache.catalina.Lifecycle;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.LifecycleState;
|
||||
import org.apache.catalina.Manager;
|
||||
import org.apache.catalina.Valve;
|
||||
import org.apache.catalina.ha.CatalinaCluster;
|
||||
import org.apache.catalina.ha.ClusterDeployer;
|
||||
import org.apache.catalina.ha.ClusterListener;
|
||||
import org.apache.catalina.ha.ClusterManager;
|
||||
import org.apache.catalina.ha.ClusterMessage;
|
||||
import org.apache.catalina.ha.ClusterValve;
|
||||
import org.apache.catalina.ha.session.ClusterSessionListener;
|
||||
import org.apache.catalina.ha.session.DeltaManager;
|
||||
import org.apache.catalina.ha.session.JvmRouteBinderValve;
|
||||
import org.apache.catalina.ha.session.SessionMessage;
|
||||
import org.apache.catalina.tribes.Channel;
|
||||
import org.apache.catalina.tribes.ChannelListener;
|
||||
import org.apache.catalina.tribes.Member;
|
||||
import org.apache.catalina.tribes.MembershipListener;
|
||||
import org.apache.catalina.tribes.group.GroupChannel;
|
||||
import org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor;
|
||||
import org.apache.catalina.tribes.group.interceptors.TcpFailureDetector;
|
||||
import org.apache.catalina.util.LifecycleMBeanBase;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* A <b>Cluster </b> implementation using simple multicast. Responsible for
|
||||
* setting up a cluster and provides callers with a valid multicast
|
||||
* receiver/sender.
|
||||
*
|
||||
* FIXME wrote testcases
|
||||
*
|
||||
* @author Remy Maucherat
|
||||
* @author Peter Rossbach
|
||||
*/
|
||||
public class SimpleTcpCluster extends LifecycleMBeanBase
|
||||
implements CatalinaCluster, MembershipListener, ChannelListener{
|
||||
|
||||
public static final Log log = LogFactory.getLog(SimpleTcpCluster.class);
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
public static final String BEFORE_MEMBERREGISTER_EVENT = "before_member_register";
|
||||
|
||||
public static final String AFTER_MEMBERREGISTER_EVENT = "after_member_register";
|
||||
|
||||
public static final String BEFORE_MANAGERREGISTER_EVENT = "before_manager_register";
|
||||
|
||||
public static final String AFTER_MANAGERREGISTER_EVENT = "after_manager_register";
|
||||
|
||||
public static final String BEFORE_MANAGERUNREGISTER_EVENT = "before_manager_unregister";
|
||||
|
||||
public static final String AFTER_MANAGERUNREGISTER_EVENT = "after_manager_unregister";
|
||||
|
||||
public static final String BEFORE_MEMBERUNREGISTER_EVENT = "before_member_unregister";
|
||||
|
||||
public static final String AFTER_MEMBERUNREGISTER_EVENT = "after_member_unregister";
|
||||
|
||||
public static final String SEND_MESSAGE_FAILURE_EVENT = "send_message_failure";
|
||||
|
||||
public static final String RECEIVE_MESSAGE_FAILURE_EVENT = "receive_message_failure";
|
||||
|
||||
/**
|
||||
* Group channel.
|
||||
*/
|
||||
protected Channel channel = new GroupChannel();
|
||||
|
||||
|
||||
/**
|
||||
* The string manager for this package.
|
||||
*/
|
||||
protected static final StringManager sm = StringManager.getManager(Constants.Package);
|
||||
|
||||
/**
|
||||
* The cluster name to join
|
||||
*/
|
||||
protected String clusterName ;
|
||||
|
||||
/**
|
||||
* call Channel.heartbeat() at container background thread
|
||||
* @see org.apache.catalina.tribes.group.GroupChannel#heartbeat()
|
||||
*/
|
||||
protected boolean heartbeatBackgroundEnabled =false ;
|
||||
|
||||
/**
|
||||
* The Container associated with this Cluster.
|
||||
*/
|
||||
protected Container container = null;
|
||||
|
||||
/**
|
||||
* The property change support for this component.
|
||||
*/
|
||||
protected final PropertyChangeSupport support = new PropertyChangeSupport(this);
|
||||
|
||||
/**
|
||||
* The context name <-> manager association for distributed contexts.
|
||||
*/
|
||||
protected final Map<String, ClusterManager> managers = new HashMap<>();
|
||||
|
||||
protected ClusterManager managerTemplate = new DeltaManager();
|
||||
|
||||
private final List<Valve> valves = new ArrayList<>();
|
||||
|
||||
private ClusterDeployer clusterDeployer;
|
||||
private ObjectName onameClusterDeployer;
|
||||
|
||||
/**
|
||||
* Listeners of messages
|
||||
*/
|
||||
protected final List<ClusterListener> clusterListeners = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Comment for <code>notifyLifecycleListenerOnFailure</code>
|
||||
*/
|
||||
private boolean notifyLifecycleListenerOnFailure = false;
|
||||
|
||||
private int channelSendOptions = Channel.SEND_OPTIONS_ASYNCHRONOUS;
|
||||
|
||||
private int channelStartOptions = Channel.DEFAULT;
|
||||
|
||||
private final Map<Member,ObjectName> memberOnameMap = new ConcurrentHashMap<>();
|
||||
|
||||
// ------------------------------------------------------------- Properties
|
||||
|
||||
public SimpleTcpCluster() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
/**
|
||||
* Return heartbeat enable flag (default false)
|
||||
* @return the heartbeatBackgroundEnabled
|
||||
*/
|
||||
public boolean isHeartbeatBackgroundEnabled() {
|
||||
return heartbeatBackgroundEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* enabled that container backgroundThread call heartbeat at channel
|
||||
* @param heartbeatBackgroundEnabled the heartbeatBackgroundEnabled to set
|
||||
*/
|
||||
public void setHeartbeatBackgroundEnabled(boolean heartbeatBackgroundEnabled) {
|
||||
this.heartbeatBackgroundEnabled = heartbeatBackgroundEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the cluster to join, if no cluster with this name is
|
||||
* present create one.
|
||||
*
|
||||
* @param clusterName
|
||||
* The clustername to join
|
||||
*/
|
||||
@Override
|
||||
public void setClusterName(String clusterName) {
|
||||
this.clusterName = clusterName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the cluster that this Server is currently configured
|
||||
* to operate within.
|
||||
*
|
||||
* @return The name of the cluster associated with this server
|
||||
*/
|
||||
@Override
|
||||
public String getClusterName() {
|
||||
if(clusterName == null && container != null)
|
||||
return container.getName() ;
|
||||
return clusterName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Container associated with our Cluster
|
||||
*
|
||||
* @param container
|
||||
* The Container to use
|
||||
*/
|
||||
@Override
|
||||
public void setContainer(Container container) {
|
||||
Container oldContainer = this.container;
|
||||
this.container = container;
|
||||
support.firePropertyChange("container", oldContainer, this.container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Container associated with our Cluster
|
||||
*
|
||||
* @return The Container associated with our Cluster
|
||||
*/
|
||||
@Override
|
||||
public Container getContainer() {
|
||||
return this.container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the notifyLifecycleListenerOnFailure.
|
||||
*/
|
||||
public boolean isNotifyLifecycleListenerOnFailure() {
|
||||
return notifyLifecycleListenerOnFailure;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param notifyListenerOnFailure
|
||||
* The notifyLifecycleListenerOnFailure to set.
|
||||
*/
|
||||
public void setNotifyLifecycleListenerOnFailure(
|
||||
boolean notifyListenerOnFailure) {
|
||||
boolean oldNotifyListenerOnFailure = this.notifyLifecycleListenerOnFailure;
|
||||
this.notifyLifecycleListenerOnFailure = notifyListenerOnFailure;
|
||||
support.firePropertyChange("notifyLifecycleListenerOnFailure",
|
||||
oldNotifyListenerOnFailure,
|
||||
this.notifyLifecycleListenerOnFailure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add cluster valve
|
||||
* Cluster Valves are only add to container when cluster is started!
|
||||
* @param valve The new cluster Valve.
|
||||
*/
|
||||
@Override
|
||||
public void addValve(Valve valve) {
|
||||
if (valve instanceof ClusterValve && (!valves.contains(valve)))
|
||||
valves.add(valve);
|
||||
}
|
||||
|
||||
/**
|
||||
* get all cluster valves
|
||||
* @return current cluster valves
|
||||
*/
|
||||
@Override
|
||||
public Valve[] getValves() {
|
||||
return valves.toArray(new Valve[valves.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cluster listeners associated with this cluster. If this Array has
|
||||
* no listeners registered, a zero-length array is returned.
|
||||
* @return the listener array
|
||||
*/
|
||||
public ClusterListener[] findClusterListeners() {
|
||||
if (clusterListeners.size() > 0) {
|
||||
ClusterListener[] listener = new ClusterListener[clusterListeners.size()];
|
||||
clusterListeners.toArray(listener);
|
||||
return listener;
|
||||
} else
|
||||
return new ClusterListener[0];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add cluster message listener and register cluster to this listener.
|
||||
*
|
||||
* @param listener The new listener
|
||||
* @see org.apache.catalina.ha.CatalinaCluster#addClusterListener(org.apache.catalina.ha.ClusterListener)
|
||||
*/
|
||||
@Override
|
||||
public void addClusterListener(ClusterListener listener) {
|
||||
if (listener != null && !clusterListeners.contains(listener)) {
|
||||
clusterListeners.add(listener);
|
||||
listener.setCluster(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove message listener and deregister Cluster from listener.
|
||||
*
|
||||
* @param listener The listener to remove
|
||||
* @see org.apache.catalina.ha.CatalinaCluster#removeClusterListener(org.apache.catalina.ha.ClusterListener)
|
||||
*/
|
||||
@Override
|
||||
public void removeClusterListener(ClusterListener listener) {
|
||||
if (listener != null) {
|
||||
clusterListeners.remove(listener);
|
||||
listener.setCluster(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current Deployer
|
||||
*/
|
||||
@Override
|
||||
public ClusterDeployer getClusterDeployer() {
|
||||
return clusterDeployer;
|
||||
}
|
||||
|
||||
/**
|
||||
* set a new Deployer, must be set before cluster started!
|
||||
* @param clusterDeployer The associated deployer
|
||||
*/
|
||||
@Override
|
||||
public void setClusterDeployer(ClusterDeployer clusterDeployer) {
|
||||
this.clusterDeployer = clusterDeployer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChannel(Channel channel) {
|
||||
this.channel = channel;
|
||||
}
|
||||
|
||||
public void setManagerTemplate(ClusterManager managerTemplate) {
|
||||
this.managerTemplate = managerTemplate;
|
||||
}
|
||||
|
||||
public void setChannelSendOptions(int channelSendOptions) {
|
||||
this.channelSendOptions = channelSendOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* has members
|
||||
*/
|
||||
protected boolean hasMembers = false;
|
||||
@Override
|
||||
public boolean hasMembers() {
|
||||
return hasMembers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all current cluster members
|
||||
* @return all members or empty array
|
||||
*/
|
||||
@Override
|
||||
public Member[] getMembers() {
|
||||
return channel.getMembers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the member that represents this node.
|
||||
*
|
||||
* @return Member
|
||||
*/
|
||||
@Override
|
||||
public Member getLocalMember() {
|
||||
return channel.getLocalMember(true);
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
/**
|
||||
* @return Returns the managers.
|
||||
*/
|
||||
@Override
|
||||
public Map<String, ClusterManager> getManagers() {
|
||||
return managers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Channel getChannel() {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public ClusterManager getManagerTemplate() {
|
||||
return managerTemplate;
|
||||
}
|
||||
|
||||
public int getChannelSendOptions() {
|
||||
return channelSendOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new Manager without add to cluster (comes with start the manager)
|
||||
*
|
||||
* @param name
|
||||
* Context Name of this manager
|
||||
* @see org.apache.catalina.Cluster#createManager(java.lang.String)
|
||||
* @see DeltaManager#start()
|
||||
*/
|
||||
@Override
|
||||
public synchronized Manager createManager(String name) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Creating ClusterManager for context " + name +
|
||||
" using class " + getManagerTemplate().getClass().getName());
|
||||
}
|
||||
ClusterManager manager = null;
|
||||
try {
|
||||
manager = managerTemplate.cloneFromTemplate();
|
||||
manager.setName(name);
|
||||
} catch (Exception x) {
|
||||
log.error(sm.getString("simpleTcpCluster.clustermanager.cloneFailed"), x);
|
||||
manager = new org.apache.catalina.ha.session.DeltaManager();
|
||||
} finally {
|
||||
if ( manager != null) manager.setCluster(this);
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerManager(Manager manager) {
|
||||
|
||||
if (! (manager instanceof ClusterManager)) {
|
||||
log.warn(sm.getString("simpleTcpCluster.clustermanager.notImplement", manager));
|
||||
return;
|
||||
}
|
||||
ClusterManager cmanager = (ClusterManager) manager;
|
||||
// Notify our interested LifecycleListeners
|
||||
fireLifecycleEvent(BEFORE_MANAGERREGISTER_EVENT, manager);
|
||||
String clusterName = getManagerName(cmanager.getName(), manager);
|
||||
cmanager.setName(clusterName);
|
||||
cmanager.setCluster(this);
|
||||
|
||||
managers.put(clusterName, cmanager);
|
||||
// Notify our interested LifecycleListeners
|
||||
fireLifecycleEvent(AFTER_MANAGERREGISTER_EVENT, manager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an application from cluster replication bus.
|
||||
*
|
||||
* @param manager The manager
|
||||
* @see org.apache.catalina.Cluster#removeManager(Manager)
|
||||
*/
|
||||
@Override
|
||||
public void removeManager(Manager manager) {
|
||||
if (manager instanceof ClusterManager) {
|
||||
ClusterManager cmgr = (ClusterManager) manager;
|
||||
// Notify our interested LifecycleListeners
|
||||
fireLifecycleEvent(BEFORE_MANAGERUNREGISTER_EVENT,manager);
|
||||
managers.remove(getManagerName(cmgr.getName(),manager));
|
||||
cmgr.setCluster(null);
|
||||
// Notify our interested LifecycleListeners
|
||||
fireLifecycleEvent(AFTER_MANAGERUNREGISTER_EVENT, manager);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getManagerName(String name, Manager manager) {
|
||||
String clusterName = name ;
|
||||
if (clusterName == null) clusterName = manager.getContext().getName();
|
||||
if (getContainer() instanceof Engine) {
|
||||
Context context = manager.getContext();
|
||||
Container host = context.getParent();
|
||||
if (host instanceof Host && clusterName != null &&
|
||||
!(clusterName.startsWith(host.getName() +"#"))) {
|
||||
clusterName = host.getName() +"#" + clusterName ;
|
||||
}
|
||||
}
|
||||
return clusterName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Manager getManager(String name) {
|
||||
return managers.get(name);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------ Lifecycle Methods
|
||||
|
||||
/**
|
||||
* Execute a periodic task, such as reloading, etc. This method will be
|
||||
* invoked inside the classloading context of this container. Unexpected
|
||||
* throwables will be caught and logged.
|
||||
* @see org.apache.catalina.ha.deploy.FarmWarDeployer#backgroundProcess()
|
||||
* @see org.apache.catalina.tribes.group.GroupChannel#heartbeat()
|
||||
* @see org.apache.catalina.tribes.group.GroupChannel.HeartbeatThread#run()
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void backgroundProcess() {
|
||||
if (clusterDeployer != null) clusterDeployer.backgroundProcess();
|
||||
|
||||
//send a heartbeat through the channel
|
||||
if ( isHeartbeatBackgroundEnabled() && channel !=null ) channel.heartbeat();
|
||||
|
||||
// periodic event
|
||||
fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------ public
|
||||
|
||||
@Override
|
||||
protected void initInternal() throws LifecycleException {
|
||||
super.initInternal();
|
||||
if (clusterDeployer != null) {
|
||||
StringBuilder name = new StringBuilder("type=Cluster");
|
||||
Container container = getContainer();
|
||||
if (container != null) {
|
||||
name.append(container.getMBeanKeyProperties());
|
||||
}
|
||||
name.append(",component=Deployer");
|
||||
onameClusterDeployer = register(clusterDeployer, name.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start Cluster and implement the requirements
|
||||
* of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
|
||||
*
|
||||
* @exception LifecycleException if this component detects a fatal error
|
||||
* that prevents this component from being used
|
||||
*/
|
||||
@Override
|
||||
protected void startInternal() throws LifecycleException {
|
||||
|
||||
if (log.isInfoEnabled()) log.info(sm.getString("simpleTcpCluster.start"));
|
||||
|
||||
try {
|
||||
checkDefaults();
|
||||
registerClusterValve();
|
||||
channel.addMembershipListener(this);
|
||||
channel.addChannelListener(this);
|
||||
channel.setName(getClusterName() + "-Channel");
|
||||
channel.start(channelStartOptions);
|
||||
if (clusterDeployer != null) clusterDeployer.start();
|
||||
registerMember(channel.getLocalMember(false));
|
||||
} catch (Exception x) {
|
||||
log.error(sm.getString("simpleTcpCluster.startUnable"), x);
|
||||
throw new LifecycleException(x);
|
||||
}
|
||||
|
||||
setState(LifecycleState.STARTING);
|
||||
}
|
||||
|
||||
protected void checkDefaults() {
|
||||
if ( clusterListeners.size() == 0 && managerTemplate instanceof DeltaManager ) {
|
||||
addClusterListener(new ClusterSessionListener());
|
||||
}
|
||||
if ( valves.size() == 0 ) {
|
||||
addValve(new JvmRouteBinderValve());
|
||||
addValve(new ReplicationValve());
|
||||
}
|
||||
if ( clusterDeployer != null ) clusterDeployer.setCluster(this);
|
||||
if ( channel == null ) channel = new GroupChannel();
|
||||
if ( channel instanceof GroupChannel && !((GroupChannel)channel).getInterceptors().hasNext()) {
|
||||
channel.addInterceptor(new MessageDispatchInterceptor());
|
||||
channel.addInterceptor(new TcpFailureDetector());
|
||||
}
|
||||
if (heartbeatBackgroundEnabled) channel.setHeartbeat(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* register all cluster valve to host or engine
|
||||
*/
|
||||
protected void registerClusterValve() {
|
||||
if(container != null ) {
|
||||
for (Iterator<Valve> iter = valves.iterator(); iter.hasNext();) {
|
||||
ClusterValve valve = (ClusterValve) iter.next();
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("Invoking addValve on " + getContainer()
|
||||
+ " with class=" + valve.getClass().getName());
|
||||
if (valve != null) {
|
||||
container.getPipeline().addValve(valve);
|
||||
valve.setCluster(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* unregister all cluster valve to host or engine
|
||||
*/
|
||||
protected void unregisterClusterValve() {
|
||||
for (Iterator<Valve> iter = valves.iterator(); iter.hasNext();) {
|
||||
ClusterValve valve = (ClusterValve) iter.next();
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("Invoking removeValve on " + getContainer()
|
||||
+ " with class=" + valve.getClass().getName());
|
||||
if (valve != null) {
|
||||
container.getPipeline().removeValve(valve);
|
||||
valve.setCluster(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stop Cluster and implement the requirements
|
||||
* of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}.
|
||||
*
|
||||
* @exception LifecycleException if this component detects a fatal error
|
||||
* that prevents this component from being used
|
||||
*/
|
||||
@Override
|
||||
protected void stopInternal() throws LifecycleException {
|
||||
|
||||
setState(LifecycleState.STOPPING);
|
||||
|
||||
unregisterMember(channel.getLocalMember(false));
|
||||
if (clusterDeployer != null) clusterDeployer.stop();
|
||||
this.managers.clear();
|
||||
try {
|
||||
if ( clusterDeployer != null ) clusterDeployer.setCluster(null);
|
||||
channel.stop(channelStartOptions);
|
||||
channel.removeChannelListener(this);
|
||||
channel.removeMembershipListener(this);
|
||||
this.unregisterClusterValve();
|
||||
} catch (Exception x) {
|
||||
log.error(sm.getString("simpleTcpCluster.stopUnable"), x);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void destroyInternal() throws LifecycleException {
|
||||
if (onameClusterDeployer != null) {
|
||||
unregister(onameClusterDeployer);
|
||||
onameClusterDeployer = null;
|
||||
}
|
||||
super.destroyInternal();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a String rendering of this object.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(this.getClass().getName());
|
||||
sb.append('[');
|
||||
if (container == null) {
|
||||
sb.append("Container is null");
|
||||
} else {
|
||||
sb.append(container.getName());
|
||||
}
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* send message to all cluster members
|
||||
* @param msg message to transfer
|
||||
*
|
||||
* @see org.apache.catalina.ha.CatalinaCluster#send(org.apache.catalina.ha.ClusterMessage)
|
||||
*/
|
||||
@Override
|
||||
public void send(ClusterMessage msg) {
|
||||
send(msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* send a cluster message to one member
|
||||
*
|
||||
* @param msg message to transfer
|
||||
* @param dest Receiver member
|
||||
* @see org.apache.catalina.ha.CatalinaCluster#send(org.apache.catalina.ha.ClusterMessage,
|
||||
* org.apache.catalina.tribes.Member)
|
||||
*/
|
||||
@Override
|
||||
public void send(ClusterMessage msg, Member dest) {
|
||||
try {
|
||||
msg.setAddress(getLocalMember());
|
||||
int sendOptions = channelSendOptions;
|
||||
if (msg instanceof SessionMessage
|
||||
&& ((SessionMessage)msg).getEventType() == SessionMessage.EVT_ALL_SESSION_DATA) {
|
||||
sendOptions = Channel.SEND_OPTIONS_SYNCHRONIZED_ACK|Channel.SEND_OPTIONS_USE_ACK;
|
||||
}
|
||||
if (dest != null) {
|
||||
if (!getLocalMember().equals(dest)) {
|
||||
channel.send(new Member[] {dest}, msg, sendOptions);
|
||||
} else
|
||||
log.error(sm.getString("simpleTcpCluster.unableSend.localMember", msg));
|
||||
} else {
|
||||
Member[] destmembers = channel.getMembers();
|
||||
if (destmembers.length>0)
|
||||
channel.send(destmembers,msg, sendOptions);
|
||||
else if (log.isDebugEnabled())
|
||||
log.debug("No members in cluster, ignoring message:"+msg);
|
||||
}
|
||||
} catch (Exception x) {
|
||||
log.error(sm.getString("simpleTcpCluster.sendFailed"), x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* New cluster member is registered
|
||||
*
|
||||
* @see org.apache.catalina.tribes.MembershipListener#memberAdded(org.apache.catalina.tribes.Member)
|
||||
*/
|
||||
@Override
|
||||
public void memberAdded(Member member) {
|
||||
try {
|
||||
hasMembers = channel.hasMembers();
|
||||
if (log.isInfoEnabled()) log.info(sm.getString("simpleTcpCluster.member.added", member));
|
||||
// Notify our interested LifecycleListeners
|
||||
fireLifecycleEvent(BEFORE_MEMBERREGISTER_EVENT, member);
|
||||
|
||||
registerMember(member);
|
||||
|
||||
// Notify our interested LifecycleListeners
|
||||
fireLifecycleEvent(AFTER_MEMBERREGISTER_EVENT, member);
|
||||
} catch (Exception x) {
|
||||
log.error(sm.getString("simpleTcpCluster.member.addFailed"), x);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Cluster member is gone
|
||||
*
|
||||
* @see org.apache.catalina.tribes.MembershipListener#memberDisappeared(org.apache.catalina.tribes.Member)
|
||||
*/
|
||||
@Override
|
||||
public void memberDisappeared(Member member) {
|
||||
try {
|
||||
hasMembers = channel.hasMembers();
|
||||
if (log.isInfoEnabled()) log.info(sm.getString("simpleTcpCluster.member.disappeared", member));
|
||||
// Notify our interested LifecycleListeners
|
||||
fireLifecycleEvent(BEFORE_MEMBERUNREGISTER_EVENT, member);
|
||||
|
||||
unregisterMember(member);
|
||||
|
||||
// Notify our interested LifecycleListeners
|
||||
fireLifecycleEvent(AFTER_MEMBERUNREGISTER_EVENT, member);
|
||||
} catch (Exception x) {
|
||||
log.error(sm.getString("simpleTcpCluster.member.removeFailed"), x);
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------- receiver
|
||||
// messages
|
||||
|
||||
/**
|
||||
* notify all listeners from receiving a new message is not ClusterMessage
|
||||
* emit Failure Event to LifecycleListener
|
||||
*
|
||||
* @param msg
|
||||
* received Message
|
||||
*/
|
||||
@Override
|
||||
public boolean accept(Serializable msg, Member sender) {
|
||||
return (msg instanceof ClusterMessage);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void messageReceived(Serializable message, Member sender) {
|
||||
ClusterMessage fwd = (ClusterMessage)message;
|
||||
fwd.setAddress(sender);
|
||||
messageReceived(fwd);
|
||||
}
|
||||
|
||||
public void messageReceived(ClusterMessage message) {
|
||||
|
||||
if (log.isDebugEnabled() && message != null)
|
||||
log.debug("Assuming clocks are synched: Replication for "
|
||||
+ message.getUniqueId() + " took="
|
||||
+ (System.currentTimeMillis() - (message).getTimestamp())
|
||||
+ " ms.");
|
||||
|
||||
//invoke all the listeners
|
||||
boolean accepted = false;
|
||||
if (message != null) {
|
||||
for (Iterator<ClusterListener> iter = clusterListeners.iterator();
|
||||
iter.hasNext();) {
|
||||
ClusterListener listener = iter.next();
|
||||
if (listener.accept(message)) {
|
||||
accepted = true;
|
||||
listener.messageReceived(message);
|
||||
}
|
||||
}
|
||||
if (!accepted && notifyLifecycleListenerOnFailure) {
|
||||
Member dest = message.getAddress();
|
||||
// Notify our interested LifecycleListeners
|
||||
fireLifecycleEvent(RECEIVE_MESSAGE_FAILURE_EVENT,
|
||||
new SendMessageData(message, dest, null));
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Message " + message.toString() + " from type "
|
||||
+ message.getClass().getName()
|
||||
+ " transferred but no listener registered");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getChannelStartOptions() {
|
||||
return channelStartOptions;
|
||||
}
|
||||
|
||||
public void setChannelStartOptions(int channelStartOptions) {
|
||||
this.channelStartOptions = channelStartOptions;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------- JMX
|
||||
|
||||
@Override
|
||||
protected String getDomainInternal() {
|
||||
Container container = getContainer();
|
||||
if (container == null) {
|
||||
return null;
|
||||
}
|
||||
return container.getDomain();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getObjectNameKeyProperties() {
|
||||
StringBuilder name = new StringBuilder("type=Cluster");
|
||||
|
||||
Container container = getContainer();
|
||||
if (container != null) {
|
||||
name.append(container.getMBeanKeyProperties());
|
||||
}
|
||||
|
||||
return name.toString();
|
||||
}
|
||||
|
||||
private void registerMember(Member member) {
|
||||
// JMX registration
|
||||
StringBuilder name = new StringBuilder("type=Cluster");
|
||||
Container container = getContainer();
|
||||
if (container != null) {
|
||||
name.append(container.getMBeanKeyProperties());
|
||||
}
|
||||
name.append(",component=Member,name=");
|
||||
name.append(ObjectName.quote(member.getName()));
|
||||
|
||||
ObjectName oname = register(member, name.toString());
|
||||
memberOnameMap.put(member, oname);
|
||||
}
|
||||
|
||||
private void unregisterMember(Member member) {
|
||||
if (member == null) return;
|
||||
ObjectName oname = memberOnameMap.remove(member);
|
||||
if (oname != null) {
|
||||
unregister(oname);
|
||||
}
|
||||
}
|
||||
}
|
||||
152
java/org/apache/catalina/ha/tcp/mbeans-descriptors.xml
Normal file
152
java/org/apache/catalina/ha/tcp/mbeans-descriptors.xml
Normal file
@@ -0,0 +1,152 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<!DOCTYPE mbeans-descriptors PUBLIC
|
||||
"-//Apache Software Foundation//DTD Model MBeans Configuration File"
|
||||
"http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
|
||||
<mbeans-descriptors>
|
||||
<mbean
|
||||
name="SimpleTcpCluster"
|
||||
description="Tcp Cluster implementation"
|
||||
domain="Catalina"
|
||||
group="Cluster"
|
||||
type="org.apache.catalina.ha.tcp.SimpleTcpCluster">
|
||||
<attribute
|
||||
name="channelSendOptions"
|
||||
description="This sets channel behaviour on sent messages."
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="channelStartOptions"
|
||||
description="This sets channel start behaviour."
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="clusterName"
|
||||
description="name of cluster"
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="heartbeatBackgroundEnabled"
|
||||
description="enable that container background thread call channel heartbeat, default is that channel manage heartbeat itself."
|
||||
is="true"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="notifyLifecycleListenerOnFailure"
|
||||
description="notify lifecycleListener from message transfer failure"
|
||||
is="true"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="stateName"
|
||||
description="The name of the LifecycleState that this component is currently in"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
<operation
|
||||
name="send"
|
||||
description="send message to all cluster members"
|
||||
impact="ACTION"
|
||||
returnType="void">
|
||||
<parameter
|
||||
name="message"
|
||||
description="replication message"
|
||||
type="org.apache.catalina.ha.ClusterMessage"/>
|
||||
</operation>
|
||||
<operation
|
||||
name="start"
|
||||
description="Start the cluster"
|
||||
impact="ACTION"
|
||||
returnType="void"/>
|
||||
<operation
|
||||
name="stop"
|
||||
description="Stop the cluster"
|
||||
impact="ACTION"
|
||||
returnType="void"/>
|
||||
</mbean>
|
||||
<mbean
|
||||
name="ReplicationValve"
|
||||
description="Valve for simple tcp replication"
|
||||
domain="Catalina"
|
||||
group="Valve"
|
||||
type="org.apache.catalina.ha.tcp.ReplicationValve">
|
||||
<attribute
|
||||
name="asyncSupported"
|
||||
description="Does this valve support async reporting?"
|
||||
is="true"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="doProcessingStats"
|
||||
getMethod="doStatistics"
|
||||
setMethod="setStatistics"
|
||||
description="active statistics counting"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="filter"
|
||||
description="resource filter to disable session replication check"
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="lastSendTime"
|
||||
description="last replicated request time"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="nrOfCrossContextSendRequests"
|
||||
description="number of send cross context session requests"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="nrOfFilterRequests"
|
||||
description="number of filtered requests"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="nrOfSendRequests"
|
||||
description="number of send requests"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="nrOfRequests"
|
||||
description="number of replicated requests"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="primaryIndicator"
|
||||
is="true"
|
||||
description="set indicator that request processing is at primary session node"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="primaryIndicatorName"
|
||||
description="Request attribute name to indicate that request processing is at primary session node"
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="stateName"
|
||||
description="The name of the LifecycleState that this component is currently in"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="totalSendTime"
|
||||
description="total replicated send time"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="totalRequestTime"
|
||||
description="total replicated request time"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<operation
|
||||
name="resetStatistics"
|
||||
description="Reset all statistics"
|
||||
impact="ACTION"
|
||||
returnType="void"/>
|
||||
</mbean>
|
||||
</mbeans-descriptors>
|
||||
Reference in New Issue
Block a user