init
This commit is contained in:
102
java/org/apache/catalina/ha/CatalinaCluster.java
Normal file
102
java/org/apache/catalina/ha/CatalinaCluster.java
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.catalina.Cluster;
|
||||
import org.apache.catalina.Manager;
|
||||
import org.apache.catalina.Valve;
|
||||
import org.apache.catalina.tribes.Channel;
|
||||
import org.apache.catalina.tribes.Member;
|
||||
|
||||
|
||||
/**
|
||||
* A <b>CatalinaCluster</b> interface allows to plug in and out the
|
||||
* different cluster implementations
|
||||
*/
|
||||
public interface CatalinaCluster extends Cluster {
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
/**
|
||||
* Sends a message to all the members in the cluster
|
||||
* @param msg ClusterMessage
|
||||
*/
|
||||
public void send(ClusterMessage msg);
|
||||
|
||||
/**
|
||||
* Sends a message to a specific member in the cluster.
|
||||
*
|
||||
* @param msg ClusterMessage
|
||||
* @param dest Member
|
||||
*/
|
||||
public void send(ClusterMessage msg, Member dest);
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the cluster has members.
|
||||
*/
|
||||
public boolean hasMembers();
|
||||
|
||||
/**
|
||||
* @return an array containing all the members currently participating in the cluster.
|
||||
*/
|
||||
public Member[] getMembers();
|
||||
|
||||
/**
|
||||
* @return the member that represents this node.
|
||||
*/
|
||||
public Member getLocalMember();
|
||||
|
||||
public void addValve(Valve valve);
|
||||
|
||||
public void addClusterListener(ClusterListener listener);
|
||||
|
||||
public void removeClusterListener(ClusterListener listener);
|
||||
|
||||
public void setClusterDeployer(ClusterDeployer deployer);
|
||||
|
||||
public ClusterDeployer getClusterDeployer();
|
||||
|
||||
/**
|
||||
* @return The map of managers
|
||||
*/
|
||||
public Map<String,ClusterManager> getManagers();
|
||||
|
||||
/**
|
||||
* Get Manager
|
||||
* @param name The manager name
|
||||
* @return The manager
|
||||
*/
|
||||
public Manager getManager(String name);
|
||||
|
||||
/**
|
||||
* Get a new cluster name for a manager.
|
||||
* @param name Override name (optional)
|
||||
* @param manager The manager
|
||||
* @return the manager name in the cluster
|
||||
*/
|
||||
public String getManagerName(String name, Manager manager);
|
||||
|
||||
public Valve[] getValves();
|
||||
|
||||
public void setChannel(Channel channel);
|
||||
|
||||
public Channel getChannel();
|
||||
|
||||
|
||||
}
|
||||
105
java/org/apache/catalina/ha/ClusterDeployer.java
Normal file
105
java/org/apache/catalina/ha/ClusterDeployer.java
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.tribes.ChannelListener;
|
||||
|
||||
/**
|
||||
* A <b>ClusterDeployer</b> interface allows to plug in and out the
|
||||
* different deployment implementations
|
||||
*/
|
||||
public interface ClusterDeployer extends ChannelListener {
|
||||
|
||||
/**
|
||||
* Start the cluster deployer, the owning container will invoke this
|
||||
* @throws Exception - if failure to start cluster
|
||||
*/
|
||||
public void start() throws Exception;
|
||||
|
||||
/**
|
||||
* Stops the cluster deployer, the owning container will invoke this
|
||||
* @throws LifecycleException Error stopping cluster deployer
|
||||
*/
|
||||
public void stop() throws LifecycleException;
|
||||
|
||||
/**
|
||||
* Install a new web application, whose web application archive is at the
|
||||
* specified URL, into this container and all the other
|
||||
* members of the cluster with the specified context name.
|
||||
* <p>
|
||||
* If this application is successfully installed locally,
|
||||
* a ContainerEvent of type
|
||||
* <code>INSTALL_EVENT</code> will be sent to all registered listeners,
|
||||
* with the newly created <code>Context</code> as an argument.
|
||||
*
|
||||
* @param contextName The context name to which this application should
|
||||
* be installed (must be unique)
|
||||
* @param webapp A WAR file or unpacked directory structure containing
|
||||
* the web application to be installed
|
||||
*
|
||||
* @exception IllegalArgumentException if the specified context name
|
||||
* is malformed
|
||||
* @exception IllegalStateException if the specified context name
|
||||
* is already attached to an existing web application
|
||||
* @exception IOException if an input/output error was encountered
|
||||
* during installation
|
||||
*/
|
||||
public void install(String contextName, File webapp) throws IOException;
|
||||
|
||||
/**
|
||||
* Remove an existing web application, attached to the specified context
|
||||
* name. If this application is successfully removed, a
|
||||
* ContainerEvent of type <code>REMOVE_EVENT</code> will be sent to all
|
||||
* registered listeners, with the removed <code>Context</code> as
|
||||
* an argument. Deletes the web application war file and/or directory
|
||||
* if they exist in the Host's appBase.
|
||||
*
|
||||
* @param contextName The context name of the application to be removed
|
||||
* @param undeploy boolean flag to remove web application from server
|
||||
*
|
||||
* @exception IllegalArgumentException if the specified context name
|
||||
* is malformed
|
||||
* @exception IllegalArgumentException if the specified context name does
|
||||
* not identify a currently installed web application
|
||||
* @exception IOException if an input/output error occurs during
|
||||
* removal
|
||||
*/
|
||||
public void remove(String contextName, boolean undeploy) throws IOException;
|
||||
|
||||
/**
|
||||
* call from container Background Process
|
||||
*/
|
||||
public void backgroundProcess();
|
||||
|
||||
/**
|
||||
* Returns the cluster the cluster deployer is associated with
|
||||
* @return CatalinaCluster
|
||||
*/
|
||||
public CatalinaCluster getCluster();
|
||||
|
||||
/**
|
||||
* Associates the cluster deployer with a cluster
|
||||
* @param cluster CatalinaCluster
|
||||
*/
|
||||
public void setCluster(CatalinaCluster cluster);
|
||||
|
||||
}
|
||||
105
java/org/apache/catalina/ha/ClusterListener.java
Normal file
105
java/org/apache/catalina/ha/ClusterListener.java
Normal file
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.apache.catalina.tribes.ChannelListener;
|
||||
import org.apache.catalina.tribes.Member;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Receive SessionID cluster change from other backup node after primary session
|
||||
* node is failed.
|
||||
*
|
||||
* @author Peter Rossbach
|
||||
*/
|
||||
public abstract class ClusterListener implements ChannelListener {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ClusterListener.class);
|
||||
|
||||
//--Instance Variables--------------------------------------
|
||||
|
||||
/**
|
||||
* The string manager for this package.
|
||||
*/
|
||||
|
||||
protected CatalinaCluster cluster = null;
|
||||
|
||||
//--Constructor---------------------------------------------
|
||||
|
||||
public ClusterListener() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
//--Instance Getters/Setters--------------------------------
|
||||
|
||||
public CatalinaCluster getCluster() {
|
||||
return cluster;
|
||||
}
|
||||
|
||||
public void setCluster(CatalinaCluster cluster) {
|
||||
if (log.isDebugEnabled()) {
|
||||
if (cluster != null)
|
||||
log.debug("add ClusterListener " + this.toString() +
|
||||
" to cluster" + cluster);
|
||||
else
|
||||
log.debug("remove ClusterListener " + this.toString() +
|
||||
" from cluster");
|
||||
}
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
//--Logic---------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final void messageReceived(Serializable msg, Member member) {
|
||||
if ( msg instanceof ClusterMessage ) messageReceived((ClusterMessage)msg);
|
||||
}
|
||||
@Override
|
||||
public final boolean accept(Serializable msg, Member member) {
|
||||
if ( msg instanceof ClusterMessage ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Callback from the cluster, when a message is received, The cluster will
|
||||
* broadcast it invoking the messageReceived on the receiver.
|
||||
*
|
||||
* @param msg
|
||||
* ClusterMessage - the message received from the cluster
|
||||
*/
|
||||
public abstract void messageReceived(ClusterMessage msg) ;
|
||||
|
||||
|
||||
/**
|
||||
* Accept only SessionIDMessages
|
||||
*
|
||||
* @param msg
|
||||
* ClusterMessage
|
||||
* @return boolean - returns true to indicate that messageReceived should be
|
||||
* invoked. If false is returned, the messageReceived method will
|
||||
* not be invoked.
|
||||
*/
|
||||
public abstract boolean accept(ClusterMessage msg) ;
|
||||
|
||||
}
|
||||
97
java/org/apache/catalina/ha/ClusterManager.java
Normal file
97
java/org/apache/catalina/ha/ClusterManager.java
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.catalina.Manager;
|
||||
import org.apache.catalina.tribes.io.ReplicationStream;
|
||||
|
||||
|
||||
/**
|
||||
* The common interface used by all cluster manager.
|
||||
* This is so that we can have a more pluggable way
|
||||
* of swapping session managers for different algorithms.
|
||||
*
|
||||
* @author Peter Rossbach
|
||||
*/
|
||||
public interface ClusterManager extends Manager {
|
||||
|
||||
/**
|
||||
* A message was received from another node, this
|
||||
* is the callback method to implement if you are interested in
|
||||
* receiving replication messages.
|
||||
* @param msg - the message received.
|
||||
*/
|
||||
public void messageDataReceived(ClusterMessage msg);
|
||||
|
||||
/**
|
||||
* When the request has been completed, the replication valve
|
||||
* will notify the manager, and the manager will decide whether
|
||||
* any replication is needed or not.
|
||||
* If there is a need for replication, the manager will
|
||||
* create a session message and that will be replicated.
|
||||
* The cluster determines where it gets sent.
|
||||
* @param sessionId - the sessionId that just completed.
|
||||
* @return a SessionMessage to be sent.
|
||||
*/
|
||||
public ClusterMessage requestCompleted(String sessionId);
|
||||
|
||||
/**
|
||||
* When the manager expires session not tied to a request.
|
||||
* The cluster will periodically ask for a list of sessions
|
||||
* that should expire and that should be sent across the wire.
|
||||
* @return String[] The invalidated sessions
|
||||
*/
|
||||
public String[] getInvalidatedSessions();
|
||||
|
||||
/**
|
||||
* Return the name of the manager, at host /context name and at engine hostname+/context.
|
||||
* @return String
|
||||
* @since 5.5.10
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Set the name of the manager, at host /context name and at engine hostname+/context
|
||||
* @param name The manager name
|
||||
* @since 5.5.10
|
||||
*/
|
||||
public void setName(String name);
|
||||
|
||||
public CatalinaCluster getCluster();
|
||||
|
||||
public void setCluster(CatalinaCluster cluster);
|
||||
|
||||
/**
|
||||
* Open stream and use correct ClassLoader (Container), switching thread
|
||||
* context class loader.
|
||||
*
|
||||
* @param data The data
|
||||
* @return The object input stream
|
||||
* @throws IOException An error occurred
|
||||
*/
|
||||
public ReplicationStream getReplicationStream(byte[] data) throws IOException;
|
||||
|
||||
public ReplicationStream getReplicationStream(byte[] data, int offset, int length) throws IOException;
|
||||
|
||||
public boolean isNotifyListenersOnReplication();
|
||||
|
||||
public ClusterManager cloneFromTemplate();
|
||||
}
|
||||
29
java/org/apache/catalina/ha/ClusterMessage.java
Normal file
29
java/org/apache/catalina/ha/ClusterMessage.java
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.apache.catalina.tribes.Member;
|
||||
|
||||
public interface ClusterMessage extends Serializable {
|
||||
public Member getAddress();
|
||||
public void setAddress(Member member);
|
||||
public String getUniqueId();
|
||||
public long getTimestamp();
|
||||
public void setTimestamp(long timestamp);
|
||||
}
|
||||
51
java/org/apache/catalina/ha/ClusterMessageBase.java
Normal file
51
java/org/apache/catalina/ha/ClusterMessageBase.java
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.catalina.tribes.Member;
|
||||
|
||||
public abstract class ClusterMessageBase implements ClusterMessage {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private long timestamp;
|
||||
protected transient Member address;
|
||||
|
||||
public ClusterMessageBase() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
@Override
|
||||
public Member getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAddress(Member member) {
|
||||
this.address = member;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
221
java/org/apache/catalina/ha/ClusterRuleSet.java
Normal file
221
java/org/apache/catalina/ha/ClusterRuleSet.java
Normal file
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
|
||||
import org.apache.tomcat.util.digester.Digester;
|
||||
import org.apache.tomcat.util.digester.RuleSetBase;
|
||||
|
||||
|
||||
/**
|
||||
* <p><strong>RuleSet</strong> for processing the contents of a
|
||||
* Cluster definition element. </p>
|
||||
*
|
||||
* @author Peter Rossbach
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ClusterRuleSet extends RuleSetBase {
|
||||
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
|
||||
/**
|
||||
* The matching pattern prefix to use for recognizing our elements.
|
||||
*/
|
||||
protected final String prefix;
|
||||
|
||||
|
||||
// ------------------------------------------------------------ Constructor
|
||||
|
||||
|
||||
/**
|
||||
* Construct an instance of this <code>RuleSet</code> with the default
|
||||
* matching pattern prefix.
|
||||
*/
|
||||
public ClusterRuleSet() {
|
||||
|
||||
this("");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct an instance of this <code>RuleSet</code> with the specified
|
||||
* matching pattern prefix.
|
||||
*
|
||||
* @param prefix Prefix for matching pattern rules (including the
|
||||
* trailing slash character)
|
||||
*/
|
||||
public ClusterRuleSet(String prefix) {
|
||||
super();
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* <p>Add the set of Rule instances defined in this RuleSet to the
|
||||
* specified <code>Digester</code> instance, associating them with
|
||||
* our namespace URI (if any). This method should only be called
|
||||
* by a Digester instance.</p>
|
||||
*
|
||||
* @param digester Digester instance to which the new Rule instances
|
||||
* should be added.
|
||||
*/
|
||||
@Override
|
||||
public void addRuleInstances(Digester digester) {
|
||||
//Cluster configuration start
|
||||
digester.addObjectCreate(prefix + "Manager",
|
||||
null, // MUST be specified in the element
|
||||
"className");
|
||||
digester.addSetProperties(prefix + "Manager");
|
||||
digester.addSetNext(prefix + "Manager",
|
||||
"setManagerTemplate",
|
||||
"org.apache.catalina.ha.ClusterManager");
|
||||
digester.addObjectCreate(prefix + "Manager/SessionIdGenerator",
|
||||
"org.apache.catalina.util.StandardSessionIdGenerator",
|
||||
"className");
|
||||
digester.addSetProperties(prefix + "Manager/SessionIdGenerator");
|
||||
digester.addSetNext(prefix + "Manager/SessionIdGenerator",
|
||||
"setSessionIdGenerator",
|
||||
"org.apache.catalina.SessionIdGenerator");
|
||||
|
||||
digester.addObjectCreate(prefix + "Channel",
|
||||
null, // MUST be specified in the element
|
||||
"className");
|
||||
digester.addSetProperties(prefix + "Channel");
|
||||
digester.addSetNext(prefix + "Channel",
|
||||
"setChannel",
|
||||
"org.apache.catalina.tribes.Channel");
|
||||
|
||||
|
||||
String channelPrefix = prefix + "Channel/";
|
||||
|
||||
//channel properties
|
||||
digester.addObjectCreate(channelPrefix + "Membership",
|
||||
null, // MUST be specified in the element
|
||||
"className");
|
||||
digester.addSetProperties(channelPrefix + "Membership");
|
||||
digester.addSetNext(channelPrefix + "Membership",
|
||||
"setMembershipService",
|
||||
"org.apache.catalina.tribes.MembershipService");
|
||||
|
||||
digester.addObjectCreate(channelPrefix + "MembershipListener",
|
||||
null, // MUST be specified in the element
|
||||
"className");
|
||||
digester.addSetProperties(channelPrefix + "MembershipListener");
|
||||
digester.addSetNext(channelPrefix + "MembershipListener",
|
||||
"addMembershipListener",
|
||||
"org.apache.catalina.tribes.MembershipListener");
|
||||
|
||||
digester.addObjectCreate(channelPrefix + "Sender",
|
||||
null, // MUST be specified in the element
|
||||
"className");
|
||||
digester.addSetProperties(channelPrefix + "Sender");
|
||||
digester.addSetNext(channelPrefix + "Sender",
|
||||
"setChannelSender",
|
||||
"org.apache.catalina.tribes.ChannelSender");
|
||||
|
||||
digester.addObjectCreate(channelPrefix + "Sender/Transport",
|
||||
null, // MUST be specified in the element
|
||||
"className");
|
||||
digester.addSetProperties(channelPrefix + "Sender/Transport");
|
||||
digester.addSetNext(channelPrefix + "Sender/Transport",
|
||||
"setTransport",
|
||||
"org.apache.catalina.tribes.transport.MultiPointSender");
|
||||
|
||||
|
||||
digester.addObjectCreate(channelPrefix + "Receiver",
|
||||
null, // MUST be specified in the element
|
||||
"className");
|
||||
digester.addSetProperties(channelPrefix + "Receiver");
|
||||
digester.addSetNext(channelPrefix + "Receiver",
|
||||
"setChannelReceiver",
|
||||
"org.apache.catalina.tribes.ChannelReceiver");
|
||||
|
||||
digester.addObjectCreate(channelPrefix + "Interceptor",
|
||||
null, // MUST be specified in the element
|
||||
"className");
|
||||
digester.addSetProperties(channelPrefix + "Interceptor");
|
||||
digester.addSetNext(channelPrefix + "Interceptor",
|
||||
"addInterceptor",
|
||||
"org.apache.catalina.tribes.ChannelInterceptor");
|
||||
|
||||
digester.addObjectCreate(channelPrefix + "Interceptor/LocalMember",
|
||||
null, // MUST be specified in the element
|
||||
"className");
|
||||
digester.addSetProperties(channelPrefix + "Interceptor/LocalMember");
|
||||
digester.addSetNext(channelPrefix + "Interceptor/LocalMember",
|
||||
"setLocalMember",
|
||||
"org.apache.catalina.tribes.Member");
|
||||
|
||||
digester.addObjectCreate(channelPrefix + "Interceptor/Member",
|
||||
null, // MUST be specified in the element
|
||||
"className");
|
||||
digester.addSetProperties(channelPrefix + "Interceptor/Member");
|
||||
digester.addSetNext(channelPrefix + "Interceptor/Member",
|
||||
"addStaticMember",
|
||||
"org.apache.catalina.tribes.Member");
|
||||
|
||||
digester.addObjectCreate(channelPrefix + "ChannelListener",
|
||||
null, // MUST be specified in the element
|
||||
"className");
|
||||
digester.addSetProperties(channelPrefix + "ChannelListener");
|
||||
digester.addSetNext(channelPrefix + "ChannelListener",
|
||||
"addChannelListener",
|
||||
"org.apache.catalina.tribes.ChannelListener");
|
||||
|
||||
digester.addObjectCreate(prefix + "Valve",
|
||||
null, // MUST be specified in the element
|
||||
"className");
|
||||
digester.addSetProperties(prefix + "Valve");
|
||||
digester.addSetNext(prefix + "Valve",
|
||||
"addValve",
|
||||
"org.apache.catalina.Valve");
|
||||
|
||||
digester.addObjectCreate(prefix + "Deployer",
|
||||
null, // MUST be specified in the element
|
||||
"className");
|
||||
digester.addSetProperties(prefix + "Deployer");
|
||||
digester.addSetNext(prefix + "Deployer",
|
||||
"setClusterDeployer",
|
||||
"org.apache.catalina.ha.ClusterDeployer");
|
||||
|
||||
digester.addObjectCreate(prefix + "Listener",
|
||||
null, // MUST be specified in the element
|
||||
"className");
|
||||
digester.addSetProperties(prefix + "Listener");
|
||||
digester.addSetNext(prefix + "Listener",
|
||||
"addLifecycleListener",
|
||||
"org.apache.catalina.LifecycleListener");
|
||||
|
||||
digester.addObjectCreate(prefix + "ClusterListener",
|
||||
null, // MUST be specified in the element
|
||||
"className");
|
||||
digester.addSetProperties(prefix + "ClusterListener");
|
||||
digester.addSetNext(prefix + "ClusterListener",
|
||||
"addClusterListener",
|
||||
"org.apache.catalina.ha.ClusterListener");
|
||||
//Cluster configuration end
|
||||
}
|
||||
|
||||
}
|
||||
40
java/org/apache/catalina/ha/ClusterSession.java
Normal file
40
java/org/apache/catalina/ha/ClusterSession.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.catalina.Session;
|
||||
|
||||
public interface ClusterSession extends Session, HttpSession {
|
||||
/**
|
||||
* returns true if this session is the primary session, if that is the
|
||||
* case, the manager can expire it upon timeout.
|
||||
* @return True if this session is primary
|
||||
*/
|
||||
public boolean isPrimarySession();
|
||||
|
||||
/**
|
||||
* Sets whether this is the primary session or not.
|
||||
* @param primarySession Flag value
|
||||
*/
|
||||
public void setPrimarySession(boolean primarySession);
|
||||
|
||||
|
||||
}
|
||||
38
java/org/apache/catalina/ha/ClusterValve.java
Normal file
38
java/org/apache/catalina/ha/ClusterValve.java
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.apache.catalina.Valve;
|
||||
|
||||
/**
|
||||
* Cluster valves are a simple extension to the Tomcat valve architecture
|
||||
* with a small addition of being able to reference the cluster component in the container it sits in.
|
||||
* @author Peter Rossbach
|
||||
*/
|
||||
public interface ClusterValve extends Valve{
|
||||
/**
|
||||
* Returns the cluster the cluster deployer is associated with
|
||||
* @return CatalinaCluster
|
||||
*/
|
||||
public CatalinaCluster getCluster();
|
||||
|
||||
/**
|
||||
* Associates the cluster deployer with a cluster
|
||||
* @param cluster CatalinaCluster
|
||||
*/
|
||||
public void setCluster(CatalinaCluster cluster);
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* 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.authenticator;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import org.apache.catalina.Container;
|
||||
import org.apache.catalina.Host;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.Session;
|
||||
import org.apache.catalina.SessionListener;
|
||||
import org.apache.catalina.authenticator.SingleSignOn;
|
||||
import org.apache.catalina.authenticator.SingleSignOnEntry;
|
||||
import org.apache.catalina.ha.CatalinaCluster;
|
||||
import org.apache.catalina.ha.ClusterValve;
|
||||
import org.apache.catalina.tribes.Channel;
|
||||
import org.apache.catalina.tribes.tipis.AbstractReplicatedMap.MapOwner;
|
||||
import org.apache.catalina.tribes.tipis.ReplicatedMap;
|
||||
import org.apache.tomcat.util.ExceptionUtils;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* A <strong>Valve</strong> that supports a "single sign on" user experience on
|
||||
* each nodes of a cluster, where the security identity of a user who successfully
|
||||
* authenticates to one web application is propagated to other web applications and
|
||||
* to other nodes cluster in the same security domain. For successful use, the following
|
||||
* requirements must be met:
|
||||
* <ul>
|
||||
* <li>This Valve must be configured on the Container that represents a
|
||||
* virtual host (typically an implementation of <code>Host</code>).</li>
|
||||
* <li>The <code>Realm</code> that contains the shared user and role
|
||||
* information must be configured on the same Container (or a higher
|
||||
* one), and not overridden at the web application level.</li>
|
||||
* <li>The web applications themselves must use one of the standard
|
||||
* Authenticators found in the
|
||||
* <code>org.apache.catalina.authenticator</code> package.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author Fabien Carrion
|
||||
*/
|
||||
public class ClusterSingleSignOn extends SingleSignOn implements ClusterValve, MapOwner {
|
||||
|
||||
private static final StringManager sm = StringManager.getManager(ClusterSingleSignOn.class);
|
||||
|
||||
// -------------------------------------------------------------- Properties
|
||||
|
||||
private CatalinaCluster cluster = null;
|
||||
@Override
|
||||
public CatalinaCluster getCluster() { return cluster; }
|
||||
@Override
|
||||
public void setCluster(CatalinaCluster cluster) {
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
|
||||
private long rpcTimeout = 15000;
|
||||
public long getRpcTimeout() {
|
||||
return rpcTimeout;
|
||||
}
|
||||
public void setRpcTimeout(long rpcTimeout) {
|
||||
this.rpcTimeout = rpcTimeout;
|
||||
}
|
||||
|
||||
|
||||
private int mapSendOptions =
|
||||
Channel.SEND_OPTIONS_SYNCHRONIZED_ACK | Channel.SEND_OPTIONS_USE_ACK;
|
||||
public int getMapSendOptions() {
|
||||
return mapSendOptions;
|
||||
}
|
||||
public void setMapSendOptions(int mapSendOptions) {
|
||||
this.mapSendOptions = mapSendOptions;
|
||||
}
|
||||
|
||||
|
||||
private boolean terminateOnStartFailure = false;
|
||||
public boolean getTerminateOnStartFailure() {
|
||||
return terminateOnStartFailure;
|
||||
}
|
||||
|
||||
public void setTerminateOnStartFailure(boolean terminateOnStartFailure) {
|
||||
this.terminateOnStartFailure = terminateOnStartFailure;
|
||||
}
|
||||
|
||||
private long accessTimeout = 5000;
|
||||
public long getAccessTimeout() {
|
||||
return accessTimeout;
|
||||
}
|
||||
|
||||
public void setAccessTimeout(long accessTimeout) {
|
||||
this.accessTimeout = accessTimeout;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------- SingleSignOn Methods
|
||||
|
||||
@Override
|
||||
protected boolean associate(String ssoId, Session session) {
|
||||
boolean result = super.associate(ssoId, session);
|
||||
if (result) {
|
||||
((ReplicatedMap<String,SingleSignOnEntry>) cache).replicate(ssoId, true);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean update(String ssoId, Principal principal, String authType,
|
||||
String username, String password) {
|
||||
boolean result = super.update(ssoId, principal, authType, username, password);
|
||||
if (result) {
|
||||
((ReplicatedMap<String,SingleSignOnEntry>) cache).replicate(ssoId, true);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SessionListener getSessionListener(String ssoId) {
|
||||
return new ClusterSingleSignOnListener(ssoId);
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------- MapOwner Methods
|
||||
|
||||
@Override
|
||||
public void objectMadePrimary(Object key, Object value) {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------- Lifecycle Methods
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
// Load the cluster component, if any
|
||||
try {
|
||||
if(cluster == null) {
|
||||
Container host = getContainer();
|
||||
if(host instanceof Host) {
|
||||
if(host.getCluster() instanceof CatalinaCluster) {
|
||||
setCluster((CatalinaCluster) host.getCluster());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cluster == null) {
|
||||
throw new LifecycleException(sm.getString("clusterSingleSignOn.nocluster"));
|
||||
}
|
||||
|
||||
ClassLoader[] cls = new ClassLoader[] { this.getClass().getClassLoader() };
|
||||
|
||||
ReplicatedMap<String,SingleSignOnEntry> cache = new ReplicatedMap<>(
|
||||
this, cluster.getChannel(), rpcTimeout, cluster.getClusterName() + "-SSO-cache",
|
||||
cls, terminateOnStartFailure);
|
||||
cache.setChannelSendOptions(mapSendOptions);
|
||||
cache.setAccessTimeout(accessTimeout);
|
||||
this.cache = cache;
|
||||
} catch (Throwable t) {
|
||||
ExceptionUtils.handleThrowable(t);
|
||||
throw new LifecycleException(sm.getString("clusterSingleSignOn.clusterLoad.fail"), t);
|
||||
}
|
||||
|
||||
super.startInternal();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stop this component 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 synchronized void stopInternal() throws LifecycleException {
|
||||
|
||||
super.stopInternal();
|
||||
|
||||
if (getCluster() != null) {
|
||||
((ReplicatedMap<?,?>) cache).breakdown();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
package org.apache.catalina.ha.authenticator;
|
||||
|
||||
import org.apache.catalina.authenticator.SingleSignOnListener;
|
||||
import org.apache.catalina.ha.session.ReplicatedSessionListener;
|
||||
|
||||
/**
|
||||
* Cluster extension of {@link SingleSignOnListener} that simply adds the marker
|
||||
* interface {@link ReplicatedSessionListener} which allows the listener to be
|
||||
* replicated across the cluster along with the session.
|
||||
*/
|
||||
public class ClusterSingleSignOnListener extends SingleSignOnListener implements
|
||||
ReplicatedSessionListener {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ClusterSingleSignOnListener(String ssoId) {
|
||||
super(ssoId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
clusterSingleSignOn.clusterLoad.fail=ClusterSingleSignOn exception during clusterLoad
|
||||
clusterSingleSignOn.nocluster=There is no Cluster for ClusterSingleSignOn
|
||||
@@ -0,0 +1,16 @@
|
||||
# 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.
|
||||
|
||||
clusterSingleSignOn.clusterLoad.fail=ClusterSingleSignOn Fehler bei clusterLoad
|
||||
@@ -0,0 +1,16 @@
|
||||
# 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.
|
||||
|
||||
clusterSingleSignOn.clusterLoad.fail=ClusterSingleSignOn excepción durante clusterLoad
|
||||
@@ -0,0 +1,17 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
clusterSingleSignOn.clusterLoad.fail=Exception ClusterSingleSignOn pendant clusterLoad
|
||||
clusterSingleSignOn.nocluster=Il n'y a pas de cluster pour ClusterSingleSignOn
|
||||
@@ -0,0 +1,17 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
clusterSingleSignOn.clusterLoad.fail=ClusterSingleSignOnでクラスタロード中に例外が発生しました
|
||||
clusterSingleSignOn.nocluster=ClusterSingleSignOnに関連するクラスタがありません。
|
||||
@@ -0,0 +1,17 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
clusterSingleSignOn.clusterLoad.fail=ClusterSingleSignOn에서 clusterLoad 오퍼레이션 수행 중 예외 발생
|
||||
clusterSingleSignOn.nocluster=ClusterSingleSignOn을 위한 클러스터가 없습니다.
|
||||
@@ -0,0 +1,16 @@
|
||||
# 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.
|
||||
|
||||
clusterSingleSignOn.clusterLoad.fail=在集群加载时, 集群单点登录异常
|
||||
@@ -0,0 +1,61 @@
|
||||
<?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.
|
||||
-->
|
||||
<mbeans-descriptors>
|
||||
<mbean
|
||||
name="ClusterSingleSignOn"
|
||||
description="A Valve that supports a 'single signon' user experience on a whole cluster"
|
||||
domain="Catalina"
|
||||
group="Valve"
|
||||
type="org.apache.catalina.ha.authenticator.ClusterSingleSignOn">
|
||||
<attribute
|
||||
name="asyncSupported"
|
||||
description="Does this valve support async reporting?"
|
||||
is="true"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="className"
|
||||
description="Fully qualified class name of the managed object"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="requireReauthentication"
|
||||
description="Should we attempt to reauthenticate each request against the security Realm?"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="cookieDomain"
|
||||
description="(Optional) Domain to be used by sso cookies"
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="mapSendOptions"
|
||||
description="mapSendOptions"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="rpcTimeout"
|
||||
description="Timeout for RPC messages, how long we will wait for a reply"
|
||||
type="long"/>
|
||||
<attribute
|
||||
name="terminateOnStartFailure"
|
||||
description="Flag for whether to terminate this map that failed to start."
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="accessTimeout"
|
||||
description="The timeout for a ping message in replication map."
|
||||
type="long"/>
|
||||
</mbean>
|
||||
</mbeans-descriptors>
|
||||
103
java/org/apache/catalina/ha/backend/CollectedInfo.java
Normal file
103
java/org/apache/catalina/ha/backend/CollectedInfo.java
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* 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.backend;
|
||||
|
||||
/* for MBean to read ready and busy */
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectInstance;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.apache.tomcat.util.modeler.Registry;
|
||||
|
||||
/*
|
||||
* Listener to provider informations to mod_heartbeat.c
|
||||
* *msg_format = "v=%u&ready=%u&busy=%u"; (message to send).
|
||||
* send the multicast message using the format...
|
||||
* what about the bind(IP. port) only IP makes sense (for the moment).
|
||||
* BTW:v = version :-)
|
||||
*/
|
||||
public class CollectedInfo {
|
||||
|
||||
/* Collect info via JMX */
|
||||
protected MBeanServer mBeanServer = null;
|
||||
protected ObjectName objName = null;
|
||||
|
||||
int ready;
|
||||
int busy;
|
||||
|
||||
int port = 0;
|
||||
String host = null;
|
||||
|
||||
public CollectedInfo(String host, int port) throws Exception {
|
||||
init(host, port);
|
||||
}
|
||||
public void init(String host, int port) throws Exception {
|
||||
int iport = 0;
|
||||
String shost = null;
|
||||
mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
|
||||
String onStr = "*:type=ThreadPool,*";
|
||||
ObjectName objectName = new ObjectName(onStr);
|
||||
Set<ObjectInstance> set = mBeanServer.queryMBeans(objectName, null);
|
||||
for (ObjectInstance oi : set) {
|
||||
objName = oi.getObjectName();
|
||||
String name = objName.getKeyProperty("name");
|
||||
|
||||
/* Name are:
|
||||
* http-8080
|
||||
* jk-10.33.144.3-8009
|
||||
* jk-jfcpc%2F10.33.144.3-8009
|
||||
*/
|
||||
String [] elenames = name.split("-");
|
||||
String sport = elenames[elenames.length-1];
|
||||
iport = Integer.parseInt(sport);
|
||||
String [] shosts = elenames[1].split("%2F");
|
||||
shost = shosts[0];
|
||||
|
||||
if (port==0 && host==null)
|
||||
break; /* Take the first one */
|
||||
if (host==null && iport==port)
|
||||
break; /* Only port done */
|
||||
if (shost.compareTo(host) == 0)
|
||||
break; /* Done port and host are the expected ones */
|
||||
}
|
||||
if (objName == null)
|
||||
throw new Exception("Can't find connector for " + host + ":" + port);
|
||||
this.port = iport;
|
||||
this.host = shost;
|
||||
|
||||
}
|
||||
|
||||
public void refresh() throws Exception {
|
||||
if (mBeanServer == null || objName == null) {
|
||||
throw new Exception("Not initialized!!!");
|
||||
}
|
||||
Integer imax = (Integer) mBeanServer.getAttribute(objName, "maxThreads");
|
||||
|
||||
// the currentThreadCount could be 0 before the threads are created...
|
||||
// Integer iready = (Integer) mBeanServer.getAttribute(objName, "currentThreadCount");
|
||||
|
||||
Integer ibusy = (Integer) mBeanServer.getAttribute(objName, "currentThreadsBusy");
|
||||
|
||||
busy = ibusy.intValue();
|
||||
ready = imax.intValue() - ibusy.intValue();
|
||||
}
|
||||
}
|
||||
125
java/org/apache/catalina/ha/backend/HeartbeatListener.java
Normal file
125
java/org/apache/catalina/ha/backend/HeartbeatListener.java
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* 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.backend;
|
||||
|
||||
import org.apache.catalina.ContainerEvent;
|
||||
import org.apache.catalina.ContainerListener;
|
||||
import org.apache.catalina.Lifecycle;
|
||||
import org.apache.catalina.LifecycleEvent;
|
||||
import org.apache.catalina.LifecycleListener;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
/*
|
||||
* Listener to provider informations to mod_heartbeat.c
|
||||
* *msg_format = "v=%u&ready=%u&busy=%u"; (message to send).
|
||||
* send the multicast message using the format...
|
||||
* what about the bind(IP. port) only IP makes sense (for the moment).
|
||||
* BTW:v = version :-)
|
||||
*/
|
||||
public class HeartbeatListener implements LifecycleListener, ContainerListener {
|
||||
|
||||
private static final Log log = LogFactory.getLog(HeartbeatListener.class);
|
||||
|
||||
/* To allow to select the connector */
|
||||
private int port = 0;
|
||||
private String host = null;
|
||||
|
||||
/* for multicasting stuff */
|
||||
private final String ip = "224.0.1.105"; /* Multicast IP */
|
||||
private final int multiport = 23364; /* Multicast Port */
|
||||
private final int ttl = 16;
|
||||
|
||||
public String getHost() { return host; }
|
||||
public String getGroup() { return ip; }
|
||||
public int getMultiport() { return multiport; }
|
||||
public int getTtl() { return ttl; }
|
||||
|
||||
/**
|
||||
* Proxy list, format "address:port,address:port".
|
||||
*/
|
||||
private final String proxyList = null;
|
||||
public String getProxyList() { return proxyList; }
|
||||
|
||||
/**
|
||||
* URL prefix.
|
||||
*/
|
||||
private final String proxyURL = "/HeartbeatListener";
|
||||
public String getProxyURL() { return proxyURL; }
|
||||
|
||||
private CollectedInfo coll = null;
|
||||
|
||||
private Sender sender = null;
|
||||
|
||||
@Override
|
||||
public void containerEvent(ContainerEvent event) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void lifecycleEvent(LifecycleEvent event) {
|
||||
|
||||
if (Lifecycle.PERIODIC_EVENT.equals(event.getType())) {
|
||||
if (sender == null) {
|
||||
if (proxyList == null)
|
||||
sender = new MultiCastSender();
|
||||
else
|
||||
sender = new TcpSender();
|
||||
}
|
||||
|
||||
/* Read busy and ready */
|
||||
if (coll == null) {
|
||||
try {
|
||||
coll = new CollectedInfo(host, port);
|
||||
this.port = coll.port;
|
||||
this.host = coll.host;
|
||||
} catch (Exception ex) {
|
||||
log.error("Unable to initialize info collection: " + ex);
|
||||
coll = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Start or restart sender */
|
||||
try {
|
||||
sender.init(this);
|
||||
} catch (Exception ex) {
|
||||
log.error("Unable to initialize Sender: " + ex);
|
||||
sender = null;
|
||||
return;
|
||||
}
|
||||
|
||||
/* refresh the connector information and send it */
|
||||
try {
|
||||
coll.refresh();
|
||||
} catch (Exception ex) {
|
||||
log.error("Unable to collect load information: " + ex);
|
||||
coll = null;
|
||||
return;
|
||||
}
|
||||
String output = "v=1&ready=" + coll.ready + "&busy=" + coll.busy +
|
||||
"&port=" + port;
|
||||
try {
|
||||
sender.send(output);
|
||||
} catch (Exception ex) {
|
||||
log.error("Unable to send collected load information: " + ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
84
java/org/apache/catalina/ha/backend/MultiCastSender.java
Normal file
84
java/org/apache/catalina/ha/backend/MultiCastSender.java
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.backend;
|
||||
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.MulticastSocket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
/*
|
||||
* Sender to proxies using multicast socket.
|
||||
*/
|
||||
public class MultiCastSender
|
||||
implements Sender {
|
||||
|
||||
private static final Log log = LogFactory.getLog(HeartbeatListener.class);
|
||||
|
||||
HeartbeatListener config = null;
|
||||
|
||||
/* for multicasting stuff */
|
||||
MulticastSocket s = null;
|
||||
InetAddress group = null;
|
||||
|
||||
@Override
|
||||
public void init(HeartbeatListener config) throws Exception {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int send(String mess) throws Exception {
|
||||
if (s == null) {
|
||||
try {
|
||||
group = InetAddress.getByName(config.getGroup());
|
||||
if (config.getHost() != null) {
|
||||
InetAddress addr = InetAddress.getByName(config.getHost());
|
||||
InetSocketAddress addrs = new InetSocketAddress(addr, config.getMultiport());
|
||||
s = new MulticastSocket(addrs);
|
||||
} else
|
||||
s = new MulticastSocket(config.getMultiport());
|
||||
|
||||
s.setTimeToLive(config.getTtl());
|
||||
s.joinGroup(group);
|
||||
} catch (Exception ex) {
|
||||
log.error("Unable to use multicast: " + ex);
|
||||
s = null;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] buf;
|
||||
buf = mess.getBytes(StandardCharsets.US_ASCII);
|
||||
DatagramPacket data = new DatagramPacket(buf, buf.length, group, config.getMultiport());
|
||||
try {
|
||||
s.send(data);
|
||||
} catch (Exception ex) {
|
||||
log.error("Unable to send collected load information: " + ex);
|
||||
s.close();
|
||||
s = null;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
31
java/org/apache/catalina/ha/backend/Proxy.java
Normal file
31
java/org/apache/catalina/ha/backend/Proxy.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.backend;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/*
|
||||
* This class represents a front-end httpd server.
|
||||
*
|
||||
*/
|
||||
public class Proxy {
|
||||
|
||||
public InetAddress address = null;
|
||||
public int port = 80;
|
||||
}
|
||||
40
java/org/apache/catalina/ha/backend/Sender.java
Normal file
40
java/org/apache/catalina/ha/backend/Sender.java
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.backend;
|
||||
|
||||
/**
|
||||
* Interface to send data to proxies.
|
||||
*/
|
||||
public interface Sender {
|
||||
|
||||
/**
|
||||
* Set the configuration parameters
|
||||
* @param config The heartbeat listener configuration
|
||||
* @throws Exception An error occurred
|
||||
*/
|
||||
public void init(HeartbeatListener config) throws Exception;
|
||||
|
||||
/**
|
||||
* Send the message to the proxies
|
||||
* @param mess The message that will be sent
|
||||
* @return <code>0</code> if no error occurred, <code>-1</code> otherwise
|
||||
* @throws Exception An error occurred
|
||||
*/
|
||||
public int send(String mess) throws Exception;
|
||||
}
|
||||
208
java/org/apache/catalina/ha/backend/TcpSender.java
Normal file
208
java/org/apache/catalina/ha/backend/TcpSender.java
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* 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.backend;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
|
||||
/*
|
||||
* Sender to proxies using multicast socket.
|
||||
*/
|
||||
public class TcpSender
|
||||
implements Sender {
|
||||
|
||||
private static final Log log = LogFactory.getLog(HeartbeatListener.class);
|
||||
|
||||
HeartbeatListener config = null;
|
||||
|
||||
/**
|
||||
* Proxies.
|
||||
*/
|
||||
protected Proxy[] proxies = null;
|
||||
|
||||
|
||||
/**
|
||||
* Active connections.
|
||||
*/
|
||||
|
||||
protected Socket[] connections = null;
|
||||
protected BufferedReader[] connectionReaders = null;
|
||||
protected BufferedWriter[] connectionWriters = null;
|
||||
|
||||
|
||||
@Override
|
||||
public void init(HeartbeatListener config) throws Exception {
|
||||
this.config = config;
|
||||
StringTokenizer tok = new StringTokenizer(config.getProxyList(), ",");
|
||||
proxies = new Proxy[tok.countTokens()];
|
||||
int i = 0;
|
||||
while (tok.hasMoreTokens()) {
|
||||
String token = tok.nextToken().trim();
|
||||
int pos = token.indexOf(':');
|
||||
if (pos <=0)
|
||||
throw new Exception("bad ProxyList");
|
||||
proxies[i] = new Proxy();
|
||||
proxies[i].port = Integer.parseInt(token.substring(pos + 1));
|
||||
try {
|
||||
proxies[i].address = InetAddress.getByName(token.substring(0, pos));
|
||||
} catch (Exception e) {
|
||||
throw new Exception("bad ProxyList");
|
||||
}
|
||||
i++;
|
||||
}
|
||||
connections = new Socket[proxies.length];
|
||||
connectionReaders = new BufferedReader[proxies.length];
|
||||
connectionWriters = new BufferedWriter[proxies.length];
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int send(String mess) throws Exception {
|
||||
if (connections == null) {
|
||||
log.error("Not initialized");
|
||||
return -1;
|
||||
}
|
||||
String requestLine = "POST " + config.getProxyURL() + " HTTP/1.0";
|
||||
|
||||
for (int i = 0; i < connections.length; i++) {
|
||||
if (connections[i] == null) {
|
||||
try {
|
||||
if (config.getHost() != null) {
|
||||
connections[i] = new Socket();
|
||||
InetAddress addr = InetAddress.getByName(config.getHost());
|
||||
InetSocketAddress addrs = new InetSocketAddress(addr, 0);
|
||||
connections[i].setReuseAddress(true);
|
||||
connections[i].bind(addrs);
|
||||
addrs = new InetSocketAddress(proxies[i].address, proxies[i].port);
|
||||
connections[i].connect(addrs);
|
||||
} else
|
||||
connections[i] = new Socket(proxies[i].address, proxies[i].port);
|
||||
connectionReaders[i] = new BufferedReader(new InputStreamReader(connections[i].getInputStream()));
|
||||
connectionWriters[i] = new BufferedWriter(new OutputStreamWriter(connections[i].getOutputStream()));
|
||||
} catch (Exception ex) {
|
||||
log.error("Unable to connect to proxy: " + ex);
|
||||
close(i);
|
||||
}
|
||||
}
|
||||
if (connections[i] == null)
|
||||
continue; // try next proxy in the list
|
||||
BufferedWriter writer = connectionWriters[i];
|
||||
try {
|
||||
writer.write(requestLine);
|
||||
writer.write("\r\n");
|
||||
writer.write("Content-Length: " + mess.length() + "\r\n");
|
||||
writer.write("User-Agent: HeartbeatListener/1.0\r\n");
|
||||
writer.write("Connection: Keep-Alive\r\n");
|
||||
writer.write("\r\n");
|
||||
writer.write(mess);
|
||||
writer.write("\r\n");
|
||||
writer.flush();
|
||||
} catch (Exception ex) {
|
||||
log.error("Unable to send collected load information to proxy: " + ex);
|
||||
close(i);
|
||||
}
|
||||
if (connections[i] == null)
|
||||
continue; // try next proxy in the list
|
||||
|
||||
/* Read httpd answer */
|
||||
String responseStatus = connectionReaders[i].readLine();
|
||||
if (responseStatus == null) {
|
||||
log.error("Unable to read response from proxy");
|
||||
close(i);
|
||||
continue;
|
||||
} else {
|
||||
responseStatus = responseStatus.substring(responseStatus.indexOf(' ') + 1, responseStatus.indexOf(' ', responseStatus.indexOf(' ') + 1));
|
||||
int status = Integer.parseInt(responseStatus);
|
||||
if (status != 200) {
|
||||
log.error("Status is " + status);
|
||||
close(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
// read all the headers.
|
||||
String header = connectionReaders[i].readLine();
|
||||
int contentLength = 0;
|
||||
while (!"".equals(header)) {
|
||||
int colon = header.indexOf(':');
|
||||
String headerName = header.substring(0, colon).trim();
|
||||
String headerValue = header.substring(colon + 1).trim();
|
||||
if ("content-length".equalsIgnoreCase(headerName)) {
|
||||
contentLength = Integer.parseInt(headerValue);
|
||||
}
|
||||
header = connectionReaders[i].readLine();
|
||||
}
|
||||
if (contentLength > 0) {
|
||||
char[] buf = new char[512];
|
||||
while (contentLength > 0) {
|
||||
int thisTime = (contentLength > buf.length) ? buf.length : contentLength;
|
||||
int n = connectionReaders[i].read(buf, 0, thisTime);
|
||||
if (n <= 0) {
|
||||
log.error("Read content failed");
|
||||
close(i);
|
||||
break;
|
||||
} else {
|
||||
contentLength -= n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close connection.
|
||||
* @param i The index of the connection that will be closed
|
||||
*/
|
||||
protected void close(int i) {
|
||||
try {
|
||||
if (connectionReaders[i] != null) {
|
||||
connectionReaders[i].close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
}
|
||||
connectionReaders[i] = null;
|
||||
try {
|
||||
if (connectionWriters[i] != null) {
|
||||
connectionWriters[i].close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
}
|
||||
connectionWriters[i] = null;
|
||||
try {
|
||||
if (connections[i] != null) {
|
||||
connections[i].close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
}
|
||||
connections[i] = null;
|
||||
}
|
||||
}
|
||||
19
java/org/apache/catalina/ha/context/LocalStrings.properties
Normal file
19
java/org/apache/catalina/ha/context/LocalStrings.properties
Normal file
@@ -0,0 +1,19 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
applicationContext.setAttribute.namenull=Name cannot be null
|
||||
|
||||
replicatedContext.startFailed=Failed to start ReplicatedContext: [{0}]
|
||||
replicatedContext.startUnable=Unable to start ReplicatedContext: [{0}]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
applicationContext.setAttribute.namenull=Le nom ne peut être null
|
||||
|
||||
replicatedContext.startFailed=Echec de démarrage du ReplicatedContext: [{0}]
|
||||
replicatedContext.startUnable=Impossible de démarrer le ReplicatedContext: [{0}]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
applicationContext.setAttribute.namenull=名前はnullにできません
|
||||
|
||||
replicatedContext.startFailed=ReplicatedContext: [{0}]の起動に失敗しました。
|
||||
replicatedContext.startUnable=ReplicatedContext:[{0}]を開始できません。
|
||||
@@ -0,0 +1,19 @@
|
||||
# Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
# contributor license agreements. See the NOTICE file distributed with
|
||||
# this work for additional information regarding copyright ownership.
|
||||
# The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
# (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
applicationContext.setAttribute.namenull=이름이 널일 수 없습니다.
|
||||
|
||||
replicatedContext.startFailed=ReplicatedContext를 시작하지 못했습니다: [{0}]
|
||||
replicatedContext.startUnable=ReplicatedContext [{0}]을(를) 시작할 수 없습니다.
|
||||
226
java/org/apache/catalina/ha/context/ReplicatedContext.java
Normal file
226
java/org/apache/catalina/ha/context/ReplicatedContext.java
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* 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.context;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.apache.catalina.Globals;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.Loader;
|
||||
import org.apache.catalina.core.ApplicationContext;
|
||||
import org.apache.catalina.core.StandardContext;
|
||||
import org.apache.catalina.ha.CatalinaCluster;
|
||||
import org.apache.catalina.tribes.Channel;
|
||||
import org.apache.catalina.tribes.tipis.AbstractReplicatedMap.MapOwner;
|
||||
import org.apache.catalina.tribes.tipis.ReplicatedMap;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* @version 1.0
|
||||
*/
|
||||
public class ReplicatedContext extends StandardContext implements MapOwner {
|
||||
private int mapSendOptions = Channel.SEND_OPTIONS_DEFAULT;
|
||||
private static final Log log = LogFactory.getLog(ReplicatedContext.class);
|
||||
protected static final long DEFAULT_REPL_TIMEOUT = 15000;//15 seconds
|
||||
private static final StringManager sm = StringManager.getManager(ReplicatedContext.class);
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
super.startInternal();
|
||||
try {
|
||||
CatalinaCluster catclust = (CatalinaCluster)this.getCluster();
|
||||
if ( catclust != null ) {
|
||||
ReplicatedMap<String,Object> map = new ReplicatedMap<>(
|
||||
this, catclust.getChannel(),DEFAULT_REPL_TIMEOUT,
|
||||
getName(),getClassLoaders());
|
||||
map.setChannelSendOptions(mapSendOptions);
|
||||
((ReplApplContext)this.context).setAttributeMap(map);
|
||||
}
|
||||
} catch ( Exception x ) {
|
||||
log.error(sm.getString("replicatedContext.startUnable", getName()),x);
|
||||
throw new LifecycleException(sm.getString("replicatedContext.startFailed", getName()),x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop this component 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 synchronized void stopInternal() throws LifecycleException {
|
||||
|
||||
Map<String, Object> map = ((ReplApplContext) this.context)
|
||||
.getAttributeMap();
|
||||
|
||||
super.stopInternal();
|
||||
|
||||
if (map instanceof ReplicatedMap) {
|
||||
((ReplicatedMap<?, ?>) map).breakdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void setMapSendOptions(int mapSendOptions) {
|
||||
this.mapSendOptions = mapSendOptions;
|
||||
}
|
||||
|
||||
public int getMapSendOptions() {
|
||||
return mapSendOptions;
|
||||
}
|
||||
|
||||
public ClassLoader[] getClassLoaders() {
|
||||
Loader loader = null;
|
||||
ClassLoader classLoader = null;
|
||||
loader = this.getLoader();
|
||||
if (loader != null) classLoader = loader.getClassLoader();
|
||||
if ( classLoader == null ) classLoader = Thread.currentThread().getContextClassLoader();
|
||||
if ( classLoader == Thread.currentThread().getContextClassLoader() ) {
|
||||
return new ClassLoader[] {classLoader};
|
||||
} else {
|
||||
return new ClassLoader[] {classLoader,Thread.currentThread().getContextClassLoader()};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServletContext getServletContext() {
|
||||
if (context == null) {
|
||||
context = new ReplApplContext(this);
|
||||
if (getAltDDName() != null)
|
||||
context.setAttribute(Globals.ALT_DD_ATTR,getAltDDName());
|
||||
}
|
||||
|
||||
return ((ReplApplContext)context).getFacade();
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected static class ReplApplContext extends ApplicationContext {
|
||||
protected final Map<String, Object> tomcatAttributes = new ConcurrentHashMap<>();
|
||||
|
||||
public ReplApplContext(ReplicatedContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
protected ReplicatedContext getParent() {
|
||||
return (ReplicatedContext)getContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServletContext getFacade() {
|
||||
return super.getFacade();
|
||||
}
|
||||
|
||||
public Map<String,Object> getAttributeMap() {
|
||||
return this.attributes;
|
||||
}
|
||||
public void setAttributeMap(Map<String,Object> map) {
|
||||
this.attributes = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
tomcatAttributes.remove(name);
|
||||
//do nothing
|
||||
super.removeAttribute(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, Object value) {
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException(sm.getString("applicationContext.setAttribute.namenull"));
|
||||
}
|
||||
if (value == null) {
|
||||
removeAttribute(name);
|
||||
return;
|
||||
}
|
||||
if ( (!getParent().getState().isAvailable()) || "org.apache.jasper.runtime.JspApplicationContextImpl".equals(name) ){
|
||||
tomcatAttributes.put(name,value);
|
||||
} else
|
||||
super.setAttribute(name,value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String name) {
|
||||
Object obj = tomcatAttributes.get(name);
|
||||
if (obj == null) {
|
||||
return super.getAttribute(name);
|
||||
} else {
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Enumeration<String> getAttributeNames() {
|
||||
Set<String> names = new HashSet<>();
|
||||
names.addAll(attributes.keySet());
|
||||
|
||||
return new MultiEnumeration<>(new Enumeration[] {
|
||||
super.getAttributeNames(),
|
||||
Collections.enumeration(names) });
|
||||
}
|
||||
}
|
||||
|
||||
protected static class MultiEnumeration<T> implements Enumeration<T> {
|
||||
private final Enumeration<T>[] e;
|
||||
public MultiEnumeration(Enumeration<T>[] lists) {
|
||||
e = lists;
|
||||
}
|
||||
@Override
|
||||
public boolean hasMoreElements() {
|
||||
for ( int i=0; i<e.length; i++ ) {
|
||||
if ( e[i].hasMoreElements() ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public T nextElement() {
|
||||
for ( int i=0; i<e.length; i++ ) {
|
||||
if ( e[i].hasMoreElements() ) return e[i].nextElement();
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void objectMadePrimary(Object key, Object value) {
|
||||
//noop
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
787
java/org/apache/catalina/ha/deploy/FarmWarDeployer.java
Normal file
787
java/org/apache/catalina/ha/deploy/FarmWarDeployer.java
Normal file
@@ -0,0 +1,787 @@
|
||||
/*
|
||||
* 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.deploy;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
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.LifecycleException;
|
||||
import org.apache.catalina.ha.ClusterDeployer;
|
||||
import org.apache.catalina.ha.ClusterListener;
|
||||
import org.apache.catalina.ha.ClusterMessage;
|
||||
import org.apache.catalina.tribes.Member;
|
||||
import org.apache.catalina.util.ContextName;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.modeler.Registry;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A farm war deployer is a class that is able to deploy/undeploy web
|
||||
* applications in WAR from within the cluster.
|
||||
* </p>
|
||||
* Any host can act as the admin, and will have three directories
|
||||
* <ul>
|
||||
* <li>watchDir - the directory where we watch for changes</li>
|
||||
* <li>deployDir - the directory where we install applications</li>
|
||||
* <li>tempDir - a temporaryDirectory to store binary data when downloading a
|
||||
* war from the cluster</li>
|
||||
* </ul>
|
||||
* Currently we only support deployment of WAR files since they are easier to
|
||||
* send across the wire.
|
||||
*
|
||||
* @author Peter Rossbach
|
||||
*/
|
||||
public class FarmWarDeployer extends ClusterListener
|
||||
implements ClusterDeployer, FileChangeListener {
|
||||
/*--Static Variables----------------------------------------*/
|
||||
private static final Log log = LogFactory.getLog(FarmWarDeployer.class);
|
||||
private static final StringManager sm = StringManager.getManager(FarmWarDeployer.class);
|
||||
|
||||
/*--Instance Variables--------------------------------------*/
|
||||
protected boolean started = false;
|
||||
|
||||
protected final HashMap<String, FileMessageFactory> fileFactories =
|
||||
new HashMap<>();
|
||||
|
||||
/**
|
||||
* Deployment directory.
|
||||
*/
|
||||
protected String deployDir;
|
||||
private File deployDirFile = null;
|
||||
|
||||
/**
|
||||
* Temporary directory.
|
||||
*/
|
||||
protected String tempDir;
|
||||
private File tempDirFile = null;
|
||||
|
||||
/**
|
||||
* Watch directory.
|
||||
*/
|
||||
protected String watchDir;
|
||||
private File watchDirFile = null;
|
||||
|
||||
protected boolean watchEnabled = false;
|
||||
|
||||
protected WarWatcher watcher = null;
|
||||
|
||||
/**
|
||||
* Iteration count for background processing.
|
||||
*/
|
||||
private int count = 0;
|
||||
|
||||
/**
|
||||
* Frequency of the Farm watchDir check. Cluster wide deployment will be
|
||||
* done once for the specified amount of backgroundProcess calls (ie, the
|
||||
* lower the amount, the most often the checks will occur).
|
||||
*/
|
||||
protected int processDeployFrequency = 2;
|
||||
|
||||
/**
|
||||
* Path where context descriptors should be deployed.
|
||||
*/
|
||||
protected File configBase = null;
|
||||
|
||||
/**
|
||||
* The associated host.
|
||||
*/
|
||||
protected Host host = null;
|
||||
|
||||
/**
|
||||
* MBean server.
|
||||
*/
|
||||
protected MBeanServer mBeanServer = null;
|
||||
|
||||
/**
|
||||
* The associated deployer ObjectName.
|
||||
*/
|
||||
protected ObjectName oname = null;
|
||||
|
||||
/**
|
||||
* The maximum valid time(in seconds) for FileMessageFactory.
|
||||
*/
|
||||
protected int maxValidTime = 5 * 60;
|
||||
|
||||
/*--Constructor---------------------------------------------*/
|
||||
public FarmWarDeployer() {
|
||||
}
|
||||
|
||||
/*--Logic---------------------------------------------------*/
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
if (started)
|
||||
return;
|
||||
Container hcontainer = getCluster().getContainer();
|
||||
if(!(hcontainer instanceof Host)) {
|
||||
log.error(sm.getString("farmWarDeployer.hostOnly"));
|
||||
return ;
|
||||
}
|
||||
host = (Host) hcontainer;
|
||||
|
||||
// Check to correct engine and host setup
|
||||
Container econtainer = host.getParent();
|
||||
if(!(econtainer instanceof Engine)) {
|
||||
log.error(sm.getString("farmWarDeployer.hostParentEngine",
|
||||
host.getName()));
|
||||
return ;
|
||||
}
|
||||
Engine engine = (Engine) econtainer;
|
||||
String hostname = null;
|
||||
hostname = host.getName();
|
||||
try {
|
||||
oname = new ObjectName(engine.getName() + ":type=Deployer,host="
|
||||
+ hostname);
|
||||
} catch (Exception e) {
|
||||
log.error(sm.getString("farmWarDeployer.mbeanNameFail",
|
||||
engine.getName(), hostname),e);
|
||||
return;
|
||||
}
|
||||
if (watchEnabled) {
|
||||
watcher = new WarWatcher(this, getWatchDirFile());
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info(sm.getString(
|
||||
"farmWarDeployer.watchDir", getWatchDir()));
|
||||
}
|
||||
}
|
||||
|
||||
configBase = host.getConfigBaseFile();
|
||||
|
||||
// Retrieve the MBean server
|
||||
mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
|
||||
|
||||
started = true;
|
||||
count = 0;
|
||||
|
||||
getCluster().addClusterListener(this);
|
||||
|
||||
if (log.isInfoEnabled())
|
||||
log.info(sm.getString("farmWarDeployer.started"));
|
||||
}
|
||||
|
||||
/*
|
||||
* stop cluster wide deployments
|
||||
*
|
||||
* @see org.apache.catalina.ha.ClusterDeployer#stop()
|
||||
*/
|
||||
@Override
|
||||
public void stop() throws LifecycleException {
|
||||
started = false;
|
||||
getCluster().removeClusterListener(this);
|
||||
count = 0;
|
||||
if (watcher != null) {
|
||||
watcher.clear();
|
||||
watcher = null;
|
||||
|
||||
}
|
||||
if (log.isInfoEnabled())
|
||||
log.info(sm.getString("farmWarDeployer.stopped"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback from the cluster, when a message is received, The cluster will
|
||||
* broadcast it invoking the messageReceived on the receiver.
|
||||
*
|
||||
* @param msg
|
||||
* ClusterMessage - the message received from the cluster
|
||||
*/
|
||||
@Override
|
||||
public void messageReceived(ClusterMessage msg) {
|
||||
try {
|
||||
if (msg instanceof FileMessage) {
|
||||
FileMessage fmsg = (FileMessage) msg;
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("farmWarDeployer.msgRxDeploy",
|
||||
fmsg.getContextName(), fmsg.getFileName()));
|
||||
FileMessageFactory factory = getFactory(fmsg);
|
||||
// TODO correct second try after app is in service!
|
||||
if (factory.writeMessage(fmsg)) {
|
||||
//last message received war file is completed
|
||||
String name = factory.getFile().getName();
|
||||
if (!name.endsWith(".war"))
|
||||
name = name + ".war";
|
||||
File deployable = new File(getDeployDirFile(), name);
|
||||
try {
|
||||
String contextName = fmsg.getContextName();
|
||||
if (!isServiced(contextName)) {
|
||||
addServiced(contextName);
|
||||
try {
|
||||
remove(contextName);
|
||||
if (!factory.getFile().renameTo(deployable)) {
|
||||
log.error(sm.getString(
|
||||
"farmWarDeployer.renameFail",
|
||||
factory.getFile(), deployable));
|
||||
}
|
||||
check(contextName);
|
||||
} finally {
|
||||
removeServiced(contextName);
|
||||
}
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString(
|
||||
"farmWarDeployer.deployEnd",
|
||||
contextName));
|
||||
} else
|
||||
log.error(sm.getString(
|
||||
"farmWarDeployer.servicingDeploy",
|
||||
contextName, name));
|
||||
} catch (Exception ex) {
|
||||
log.error(ex);
|
||||
} finally {
|
||||
removeFactory(fmsg);
|
||||
}
|
||||
}
|
||||
} else if (msg instanceof UndeployMessage) {
|
||||
try {
|
||||
UndeployMessage umsg = (UndeployMessage) msg;
|
||||
String contextName = umsg.getContextName();
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("farmWarDeployer.msgRxUndeploy",
|
||||
contextName));
|
||||
if (!isServiced(contextName)) {
|
||||
addServiced(contextName);
|
||||
try {
|
||||
remove(contextName);
|
||||
} finally {
|
||||
removeServiced(contextName);
|
||||
}
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString(
|
||||
"farmWarDeployer.undeployEnd",
|
||||
contextName));
|
||||
} else
|
||||
log.error(sm.getString(
|
||||
"farmWarDeployer.servicingUndeploy",
|
||||
contextName));
|
||||
} catch (Exception ex) {
|
||||
log.error(ex);
|
||||
}
|
||||
}
|
||||
} catch (java.io.IOException x) {
|
||||
log.error(sm.getString("farmWarDeployer.msgIoe"), x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create factory for all transported war files
|
||||
*
|
||||
* @param msg The file
|
||||
* @return Factory for all app message (war files)
|
||||
* @throws java.io.FileNotFoundException Missing file error
|
||||
* @throws java.io.IOException Other IO error
|
||||
*/
|
||||
public synchronized FileMessageFactory getFactory(FileMessage msg)
|
||||
throws java.io.FileNotFoundException, java.io.IOException {
|
||||
File writeToFile = new File(getTempDirFile(), msg.getFileName());
|
||||
FileMessageFactory factory = fileFactories.get(msg.getFileName());
|
||||
if (factory == null) {
|
||||
factory = FileMessageFactory.getInstance(writeToFile, true);
|
||||
factory.setMaxValidTime(maxValidTime);
|
||||
fileFactories.put(msg.getFileName(), factory);
|
||||
}
|
||||
return factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove file (war) from messages
|
||||
*
|
||||
* @param msg The file
|
||||
*/
|
||||
public void removeFactory(FileMessage msg) {
|
||||
fileFactories.remove(msg.getFileName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Before the cluster invokes messageReceived the cluster will ask the
|
||||
* receiver to accept or decline the message, In the future, when messages
|
||||
* get big, the accept method will only take a message header
|
||||
*
|
||||
* @param msg ClusterMessage
|
||||
* @return boolean - returns true to indicate that messageReceived should be
|
||||
* invoked. If false is returned, the messageReceived method will
|
||||
* not be invoked.
|
||||
*/
|
||||
@Override
|
||||
public boolean accept(ClusterMessage msg) {
|
||||
return (msg instanceof FileMessage) || (msg instanceof UndeployMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Install a new web application, whose web application archive is at the
|
||||
* specified URL, into this container and all the other members of the
|
||||
* cluster with the specified context name.
|
||||
* <p>
|
||||
* If this application is successfully installed locally, a ContainerEvent
|
||||
* of type <code>INSTALL_EVENT</code> will be sent to all registered
|
||||
* listeners, with the newly created <code>Context</code> as an argument.
|
||||
*
|
||||
* @param contextName
|
||||
* The context name to which this application should be installed
|
||||
* (must be unique)
|
||||
* @param webapp
|
||||
* A WAR file or unpacked directory structure containing the web
|
||||
* application to be installed
|
||||
*
|
||||
* @exception IllegalArgumentException
|
||||
* if the specified context name is malformed
|
||||
* @exception IllegalStateException
|
||||
* if the specified context name is already deployed
|
||||
* @exception IOException
|
||||
* if an input/output error was encountered during
|
||||
* installation
|
||||
*/
|
||||
@Override
|
||||
public void install(String contextName, File webapp) throws IOException {
|
||||
Member[] members = getCluster().getMembers();
|
||||
if (members.length == 0) return;
|
||||
|
||||
Member localMember = getCluster().getLocalMember();
|
||||
FileMessageFactory factory =
|
||||
FileMessageFactory.getInstance(webapp, false);
|
||||
FileMessage msg = new FileMessage(localMember, webapp.getName(),
|
||||
contextName);
|
||||
if(log.isDebugEnabled())
|
||||
log.debug(sm.getString("farmWarDeployer.sendStart", contextName,
|
||||
webapp));
|
||||
msg = factory.readMessage(msg);
|
||||
while (msg != null) {
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("farmWarDeployer.sendFragment",
|
||||
contextName, webapp, members[i]));
|
||||
getCluster().send(msg, members[i]);
|
||||
}
|
||||
msg = factory.readMessage(msg);
|
||||
}
|
||||
if(log.isDebugEnabled())
|
||||
log.debug(sm.getString(
|
||||
"farmWarDeployer.sendEnd", contextName, webapp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an existing web application, attached to the specified context
|
||||
* name. If this application is successfully removed, a ContainerEvent of
|
||||
* type <code>REMOVE_EVENT</code> will be sent to all registered
|
||||
* listeners, with the removed <code>Context</code> as an argument.
|
||||
* Deletes the web application war file and/or directory if they exist in
|
||||
* the Host's appBase.
|
||||
*
|
||||
* @param contextName
|
||||
* The context name of the application to be removed
|
||||
* @param undeploy
|
||||
* boolean flag to remove web application from server
|
||||
*
|
||||
* @exception IllegalArgumentException
|
||||
* if the specified context name is malformed
|
||||
* @exception IllegalArgumentException
|
||||
* if the specified context name does not identify a
|
||||
* currently installed web application
|
||||
* @exception IOException
|
||||
* if an input/output error occurs during removal
|
||||
*/
|
||||
@Override
|
||||
public void remove(String contextName, boolean undeploy)
|
||||
throws IOException {
|
||||
if (getCluster().getMembers().length > 0) {
|
||||
if (log.isInfoEnabled())
|
||||
log.info(sm.getString("farmWarDeployer.removeStart", contextName));
|
||||
Member localMember = getCluster().getLocalMember();
|
||||
UndeployMessage msg = new UndeployMessage(localMember, System
|
||||
.currentTimeMillis(), "Undeploy:" + contextName + ":"
|
||||
+ System.currentTimeMillis(), contextName);
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("farmWarDeployer.removeTxMsg", contextName));
|
||||
cluster.send(msg);
|
||||
}
|
||||
// remove locally
|
||||
if (undeploy) {
|
||||
try {
|
||||
if (!isServiced(contextName)) {
|
||||
addServiced(contextName);
|
||||
try {
|
||||
remove(contextName);
|
||||
} finally {
|
||||
removeServiced(contextName);
|
||||
}
|
||||
} else
|
||||
log.error(sm.getString("farmWarDeployer.removeFailRemote",
|
||||
contextName));
|
||||
|
||||
} catch (Exception ex) {
|
||||
log.error(sm.getString("farmWarDeployer.removeFailLocal",
|
||||
contextName), ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Modification from watchDir war detected!
|
||||
*
|
||||
* @see org.apache.catalina.ha.deploy.FileChangeListener#fileModified(File)
|
||||
*/
|
||||
@Override
|
||||
public void fileModified(File newWar) {
|
||||
try {
|
||||
File deployWar = new File(getDeployDirFile(), newWar.getName());
|
||||
ContextName cn = new ContextName(deployWar.getName(), true);
|
||||
if (deployWar.exists() && deployWar.lastModified() > newWar.lastModified()) {
|
||||
if (log.isInfoEnabled())
|
||||
log.info(sm.getString("farmWarDeployer.alreadyDeployed", cn.getName()));
|
||||
return;
|
||||
}
|
||||
if (log.isInfoEnabled())
|
||||
log.info(sm.getString("farmWarDeployer.modInstall",
|
||||
cn.getName(), deployWar.getAbsolutePath()));
|
||||
// install local
|
||||
if (!isServiced(cn.getName())) {
|
||||
addServiced(cn.getName());
|
||||
try {
|
||||
copy(newWar, deployWar);
|
||||
check(cn.getName());
|
||||
} finally {
|
||||
removeServiced(cn.getName());
|
||||
}
|
||||
} else {
|
||||
log.error(sm.getString("farmWarDeployer.servicingDeploy",
|
||||
cn.getName(), deployWar.getName()));
|
||||
}
|
||||
install(cn.getName(), deployWar);
|
||||
} catch (Exception x) {
|
||||
log.error(sm.getString("farmWarDeployer.modInstallFail"), x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* War remove from watchDir
|
||||
*
|
||||
* @see org.apache.catalina.ha.deploy.FileChangeListener#fileRemoved(File)
|
||||
*/
|
||||
@Override
|
||||
public void fileRemoved(File removeWar) {
|
||||
try {
|
||||
ContextName cn = new ContextName(removeWar.getName(), true);
|
||||
if (log.isInfoEnabled())
|
||||
log.info(sm.getString("farmWarDeployer.removeLocal",
|
||||
cn.getName()));
|
||||
remove(cn.getName(), true);
|
||||
} catch (Exception x) {
|
||||
log.error(sm.getString("farmWarDeployer.removeLocalFail"), x);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the remove method on the deployer.
|
||||
* @param contextName The context to remove
|
||||
* @throws Exception If an error occurs removing the context
|
||||
*/
|
||||
protected void remove(String contextName) throws Exception {
|
||||
// TODO Handle remove also work dir content !
|
||||
// Stop the context first to be nicer
|
||||
Context context = (Context) host.findChild(contextName);
|
||||
if (context != null) {
|
||||
if(log.isDebugEnabled())
|
||||
log.debug(sm.getString("farmWarDeployer.undeployLocal",
|
||||
contextName));
|
||||
context.stop();
|
||||
String baseName = context.getBaseName();
|
||||
File war = new File(host.getAppBaseFile(), baseName + ".war");
|
||||
File dir = new File(host.getAppBaseFile(), baseName);
|
||||
File xml = new File(configBase, baseName + ".xml");
|
||||
if (war.exists()) {
|
||||
if (!war.delete()) {
|
||||
log.error(sm.getString("farmWarDeployer.deleteFail", war));
|
||||
}
|
||||
} else if (dir.exists()) {
|
||||
undeployDir(dir);
|
||||
} else {
|
||||
if (!xml.delete()) {
|
||||
log.error(sm.getString("farmWarDeployer.deleteFail", xml));
|
||||
}
|
||||
}
|
||||
// Perform new deployment and remove internal HostConfig state
|
||||
check(contextName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the specified directory, including all of its contents and
|
||||
* subdirectories recursively.
|
||||
*
|
||||
* @param dir
|
||||
* File object representing the directory to be deleted
|
||||
*/
|
||||
protected void undeployDir(File dir) {
|
||||
|
||||
String files[] = dir.list();
|
||||
if (files == null) {
|
||||
files = new String[0];
|
||||
}
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
File file = new File(dir, files[i]);
|
||||
if (file.isDirectory()) {
|
||||
undeployDir(file);
|
||||
} else {
|
||||
if (!file.delete()) {
|
||||
log.error(sm.getString("farmWarDeployer.deleteFail", file));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!dir.delete()) {
|
||||
log.error(sm.getString("farmWarDeployer.deleteFail", dir));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call watcher to check for deploy changes
|
||||
*
|
||||
* @see org.apache.catalina.ha.ClusterDeployer#backgroundProcess()
|
||||
*/
|
||||
@Override
|
||||
public void backgroundProcess() {
|
||||
if (started) {
|
||||
if (watchEnabled) {
|
||||
count = (count + 1) % processDeployFrequency;
|
||||
if (count == 0) {
|
||||
watcher.check();
|
||||
}
|
||||
}
|
||||
removeInvalidFileFactories();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*--Deployer Operations ------------------------------------*/
|
||||
|
||||
/**
|
||||
* Check a context for deployment operations.
|
||||
* @param name The context name
|
||||
* @throws Exception Error invoking the deployer
|
||||
*/
|
||||
protected void check(String name) throws Exception {
|
||||
String[] params = { name };
|
||||
String[] signature = { "java.lang.String" };
|
||||
mBeanServer.invoke(oname, "check", params, signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verified if a context is being services.
|
||||
* @param name The context name
|
||||
* @return <code>true</code> if the context is being serviced
|
||||
* @throws Exception Error invoking the deployer
|
||||
*/
|
||||
protected boolean isServiced(String name) throws Exception {
|
||||
String[] params = { name };
|
||||
String[] signature = { "java.lang.String" };
|
||||
Boolean result = (Boolean) mBeanServer.invoke(oname, "isServiced",
|
||||
params, signature);
|
||||
return result.booleanValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a context as being services.
|
||||
* @param name The context name
|
||||
* @throws Exception Error invoking the deployer
|
||||
*/
|
||||
protected void addServiced(String name) throws Exception {
|
||||
String[] params = { name };
|
||||
String[] signature = { "java.lang.String" };
|
||||
mBeanServer.invoke(oname, "addServiced", params, signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a context as no longer being serviced.
|
||||
* @param name The context name
|
||||
* @throws Exception Error invoking the deployer
|
||||
*/
|
||||
protected void removeServiced(String name) throws Exception {
|
||||
String[] params = { name };
|
||||
String[] signature = { "java.lang.String" };
|
||||
mBeanServer.invoke(oname, "removeServiced", params, signature);
|
||||
}
|
||||
|
||||
/*--Instance Getters/Setters--------------------------------*/
|
||||
@Override
|
||||
public boolean equals(Object listener) {
|
||||
return super.equals(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
public String getDeployDir() {
|
||||
return deployDir;
|
||||
}
|
||||
|
||||
public File getDeployDirFile() {
|
||||
if (deployDirFile != null) return deployDirFile;
|
||||
|
||||
File dir = getAbsolutePath(getDeployDir());
|
||||
this.deployDirFile = dir;
|
||||
return dir;
|
||||
}
|
||||
|
||||
public void setDeployDir(String deployDir) {
|
||||
this.deployDir = deployDir;
|
||||
}
|
||||
|
||||
public String getTempDir() {
|
||||
return tempDir;
|
||||
}
|
||||
|
||||
public File getTempDirFile() {
|
||||
if (tempDirFile != null) return tempDirFile;
|
||||
|
||||
File dir = getAbsolutePath(getTempDir());
|
||||
this.tempDirFile = dir;
|
||||
return dir;
|
||||
}
|
||||
|
||||
public void setTempDir(String tempDir) {
|
||||
this.tempDir = tempDir;
|
||||
}
|
||||
|
||||
public String getWatchDir() {
|
||||
return watchDir;
|
||||
}
|
||||
|
||||
public File getWatchDirFile() {
|
||||
if (watchDirFile != null) return watchDirFile;
|
||||
|
||||
File dir = getAbsolutePath(getWatchDir());
|
||||
this.watchDirFile = dir;
|
||||
return dir;
|
||||
}
|
||||
|
||||
public void setWatchDir(String watchDir) {
|
||||
this.watchDir = watchDir;
|
||||
}
|
||||
|
||||
public boolean isWatchEnabled() {
|
||||
return watchEnabled;
|
||||
}
|
||||
|
||||
public boolean getWatchEnabled() {
|
||||
return watchEnabled;
|
||||
}
|
||||
|
||||
public void setWatchEnabled(boolean watchEnabled) {
|
||||
this.watchEnabled = watchEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the frequency of watcher checks.
|
||||
*/
|
||||
public int getProcessDeployFrequency() {
|
||||
return this.processDeployFrequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the watcher checks frequency.
|
||||
*
|
||||
* @param processExpiresFrequency
|
||||
* the new manager checks frequency
|
||||
*/
|
||||
public void setProcessDeployFrequency(int processExpiresFrequency) {
|
||||
|
||||
if (processExpiresFrequency <= 0) {
|
||||
return;
|
||||
}
|
||||
this.processDeployFrequency = processExpiresFrequency;
|
||||
}
|
||||
|
||||
public int getMaxValidTime() {
|
||||
return maxValidTime;
|
||||
}
|
||||
|
||||
public void setMaxValidTime(int maxValidTime) {
|
||||
this.maxValidTime = maxValidTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy a file to the specified temp directory.
|
||||
* @param from copy from temp
|
||||
* @param to to host appBase directory
|
||||
* @return true, copy successful
|
||||
*/
|
||||
protected boolean copy(File from, File to) {
|
||||
try {
|
||||
if (!to.exists()) {
|
||||
if (!to.createNewFile()) {
|
||||
log.error(sm.getString("fileNewFail", to));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error(sm.getString("farmWarDeployer.fileCopyFail",
|
||||
from, to), e);
|
||||
return false;
|
||||
}
|
||||
|
||||
try (java.io.FileInputStream is = new java.io.FileInputStream(from);
|
||||
java.io.FileOutputStream os = new java.io.FileOutputStream(to, false);) {
|
||||
byte[] buf = new byte[4096];
|
||||
while (true) {
|
||||
int len = is.read(buf);
|
||||
if (len < 0)
|
||||
break;
|
||||
os.write(buf, 0, len);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error(sm.getString("farmWarDeployer.fileCopyFail",
|
||||
from, to), e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void removeInvalidFileFactories() {
|
||||
String[] fileNames = fileFactories.keySet().toArray(new String[0]);
|
||||
for (String fileName : fileNames) {
|
||||
FileMessageFactory factory = fileFactories.get(fileName);
|
||||
if (!factory.isValid()) {
|
||||
fileFactories.remove(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private File getAbsolutePath(String path) {
|
||||
File dir = new File(path);
|
||||
if (!dir.isAbsolute()) {
|
||||
dir = new File(getCluster().getContainer().getCatalinaBase(),
|
||||
dir.getPath());
|
||||
}
|
||||
try {
|
||||
dir = dir.getCanonicalFile();
|
||||
} catch (IOException e) {// ignore
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
}
|
||||
24
java/org/apache/catalina/ha/deploy/FileChangeListener.java
Normal file
24
java/org/apache/catalina/ha/deploy/FileChangeListener.java
Normal file
@@ -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.
|
||||
*/
|
||||
|
||||
package org.apache.catalina.ha.deploy;
|
||||
import java.io.File;
|
||||
|
||||
public interface FileChangeListener {
|
||||
public void fileModified(File f);
|
||||
public void fileRemoved(File f);
|
||||
}
|
||||
88
java/org/apache/catalina/ha/deploy/FileMessage.java
Normal file
88
java/org/apache/catalina/ha/deploy/FileMessage.java
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.deploy;
|
||||
|
||||
import org.apache.catalina.ha.ClusterMessageBase;
|
||||
import org.apache.catalina.tribes.Member;
|
||||
|
||||
/**
|
||||
* Contains the data for a file being transferred over TCP, this is
|
||||
* essentially a fragment of a file, read and written by the FileMessageFactory
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
public class FileMessage extends ClusterMessageBase {
|
||||
private static final long serialVersionUID = 2L;
|
||||
|
||||
private int messageNumber;
|
||||
private byte[] data;
|
||||
private int dataLength;
|
||||
|
||||
private long totalNrOfMsgs;
|
||||
private final String fileName;
|
||||
private final String contextName;
|
||||
|
||||
public FileMessage(Member source,
|
||||
String fileName,
|
||||
String contextName) {
|
||||
this.address=source;
|
||||
this.fileName=fileName;
|
||||
this.contextName=contextName;
|
||||
}
|
||||
|
||||
public int getMessageNumber() {
|
||||
return messageNumber;
|
||||
}
|
||||
public void setMessageNumber(int messageNumber) {
|
||||
this.messageNumber = messageNumber;
|
||||
}
|
||||
public long getTotalNrOfMsgs() {
|
||||
return totalNrOfMsgs;
|
||||
}
|
||||
public void setTotalNrOfMsgs(long totalNrOfMsgs) {
|
||||
this.totalNrOfMsgs = totalNrOfMsgs;
|
||||
}
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
public void setData(byte[] data, int length) {
|
||||
this.data = data;
|
||||
this.dataLength = length;
|
||||
}
|
||||
public int getDataLength() {
|
||||
return dataLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueId() {
|
||||
StringBuilder result = new StringBuilder(getFileName());
|
||||
result.append("#-#");
|
||||
result.append(getMessageNumber());
|
||||
result.append("#-#");
|
||||
result.append(System.currentTimeMillis());
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
public String getContextName() {
|
||||
return contextName;
|
||||
}
|
||||
}
|
||||
402
java/org/apache/catalina/ha/deploy/FileMessageFactory.java
Normal file
402
java/org/apache/catalina/ha/deploy/FileMessageFactory.java
Normal file
@@ -0,0 +1,402 @@
|
||||
/*
|
||||
* 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.deploy;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.buf.HexUtils;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* This factory is used to read files and write files by splitting them up into
|
||||
* smaller messages. So that entire files don't have to be read into memory.
|
||||
* <BR>
|
||||
* The factory can be used as a reader or writer but not both at the same time.
|
||||
* When done reading or writing the factory will close the input or output
|
||||
* streams and mark the factory as closed. It is not possible to use it after
|
||||
* that. <BR>
|
||||
* To force a cleanup, call cleanup() from the calling object. <BR>
|
||||
* This class is not thread safe.
|
||||
*
|
||||
* @version 1.0
|
||||
*/
|
||||
public class FileMessageFactory {
|
||||
/*--Static Variables----------------------------------------*/
|
||||
private static final Log log = LogFactory.getLog(FileMessageFactory.class);
|
||||
private static final StringManager sm = StringManager.getManager(FileMessageFactory.class);
|
||||
|
||||
/**
|
||||
* The number of bytes that we read from file
|
||||
*/
|
||||
public static final int READ_SIZE = 1024 * 10; //10kb
|
||||
|
||||
/**
|
||||
* The file that we are reading/writing
|
||||
*/
|
||||
protected final File file;
|
||||
|
||||
/**
|
||||
* True means that we are writing with this factory. False means that we are
|
||||
* reading with this factory
|
||||
*/
|
||||
protected final boolean openForWrite;
|
||||
|
||||
/**
|
||||
* Once the factory is used, it cannot be reused.
|
||||
*/
|
||||
protected boolean closed = false;
|
||||
|
||||
/**
|
||||
* When openForWrite=false, the input stream is held by this variable
|
||||
*/
|
||||
protected FileInputStream in;
|
||||
|
||||
/**
|
||||
* When openForWrite=true, the output stream is held by this variable
|
||||
*/
|
||||
protected FileOutputStream out;
|
||||
|
||||
/**
|
||||
* The number of messages we have written
|
||||
*/
|
||||
protected int nrOfMessagesProcessed = 0;
|
||||
|
||||
/**
|
||||
* The total size of the file
|
||||
*/
|
||||
protected long size = 0;
|
||||
|
||||
/**
|
||||
* The total number of packets that we split this file into
|
||||
*/
|
||||
protected long totalNrOfMessages = 0;
|
||||
|
||||
/**
|
||||
* The number of the last message processed. Message IDs are 1 based.
|
||||
*/
|
||||
protected AtomicLong lastMessageProcessed = new AtomicLong(0);
|
||||
|
||||
/**
|
||||
* Messages received out of order are held in the buffer until required. If
|
||||
* everything is worked as expected, messages will spend very little time in
|
||||
* the buffer.
|
||||
*/
|
||||
protected final Map<Long, FileMessage> msgBuffer = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* The bytes that we hold the data in, not thread safe.
|
||||
*/
|
||||
protected byte[] data = new byte[READ_SIZE];
|
||||
|
||||
/**
|
||||
* Flag that indicates if a thread is writing messages to disk. Access to
|
||||
* this flag must be synchronised.
|
||||
*/
|
||||
protected boolean isWriting = false;
|
||||
|
||||
/**
|
||||
* The time this instance was created. (in milliseconds)
|
||||
*/
|
||||
protected long creationTime = 0;
|
||||
|
||||
/**
|
||||
* The maximum valid time(in seconds) from creationTime.
|
||||
*/
|
||||
protected int maxValidTime = -1;
|
||||
|
||||
/**
|
||||
* Private constructor, either instantiates a factory to read or write. <BR>
|
||||
* When openForWrite==true, then a the file, f, will be created and an
|
||||
* output stream is opened to write to it. <BR>
|
||||
* When openForWrite==false, an input stream is opened, the file has to
|
||||
* exist.
|
||||
*
|
||||
* @param f
|
||||
* File - the file to be read/written
|
||||
* @param openForWrite
|
||||
* boolean - true means we are writing to the file, false means
|
||||
* we are reading from the file
|
||||
* @throws FileNotFoundException -
|
||||
* if the file to be read doesn't exist
|
||||
* @throws IOException -
|
||||
* if the system fails to open input/output streams to the file
|
||||
* or if it fails to create the file to be written to.
|
||||
*/
|
||||
private FileMessageFactory(File f, boolean openForWrite)
|
||||
throws FileNotFoundException, IOException {
|
||||
this.file = f;
|
||||
this.openForWrite = openForWrite;
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("open file " + f + " write " + openForWrite);
|
||||
if (openForWrite) {
|
||||
if (!file.exists())
|
||||
if (!file.createNewFile()) {
|
||||
throw new IOException(sm.getString("fileNewFail", file));
|
||||
}
|
||||
out = new FileOutputStream(f);
|
||||
} else {
|
||||
size = file.length();
|
||||
totalNrOfMessages = (size / READ_SIZE) + 1;
|
||||
in = new FileInputStream(f);
|
||||
}//end if
|
||||
creationTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a factory to read or write from a file. When opening for read,
|
||||
* the readMessage can be invoked, and when opening for write the
|
||||
* writeMessage can be invoked.
|
||||
*
|
||||
* @param f
|
||||
* File - the file to be read or written
|
||||
* @param openForWrite
|
||||
* boolean - true, means we are writing to the file, false means
|
||||
* we are reading from it
|
||||
* @throws FileNotFoundException -
|
||||
* if the file to be read doesn't exist
|
||||
* @throws IOException -
|
||||
* if it fails to create the file that is to be written
|
||||
* @return FileMessageFactory
|
||||
*/
|
||||
public static FileMessageFactory getInstance(File f, boolean openForWrite)
|
||||
throws FileNotFoundException, IOException {
|
||||
return new FileMessageFactory(f, openForWrite);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads file data into the file message and sets the size, totalLength,
|
||||
* totalNrOfMsgs and the message number <BR>
|
||||
* If EOF is reached, the factory returns null, and closes itself, otherwise
|
||||
* the same message is returned as was passed in. This makes sure that not
|
||||
* more memory is ever used. To remember, neither the file message or the
|
||||
* factory are thread safe. dont hand off the message to one thread and read
|
||||
* the same with another.
|
||||
*
|
||||
* @param f
|
||||
* FileMessage - the message to be populated with file data
|
||||
* @throws IllegalArgumentException -
|
||||
* if the factory is for writing or is closed
|
||||
* @throws IOException -
|
||||
* if a file read exception occurs
|
||||
* @return FileMessage - returns the same message passed in as a parameter,
|
||||
* or null if EOF
|
||||
*/
|
||||
public FileMessage readMessage(FileMessage f)
|
||||
throws IllegalArgumentException, IOException {
|
||||
checkState(false);
|
||||
int length = in.read(data);
|
||||
if (length == -1) {
|
||||
cleanup();
|
||||
return null;
|
||||
} else {
|
||||
f.setData(data, length);
|
||||
f.setTotalNrOfMsgs(totalNrOfMessages);
|
||||
f.setMessageNumber(++nrOfMessagesProcessed);
|
||||
return f;
|
||||
}//end if
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a message to file. If (msg.getMessageNumber() ==
|
||||
* msg.getTotalNrOfMsgs()) the output stream will be closed after writing.
|
||||
*
|
||||
* @param msg
|
||||
* FileMessage - message containing data to be written
|
||||
* @throws IllegalArgumentException -
|
||||
* if the factory is opened for read or closed
|
||||
* @throws IOException -
|
||||
* if a file write error occurs
|
||||
* @return returns true if the file is complete and outputstream is closed,
|
||||
* false otherwise.
|
||||
*/
|
||||
public boolean writeMessage(FileMessage msg)
|
||||
throws IllegalArgumentException, IOException {
|
||||
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(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) {
|
||||
// Duplicate of message not yet processed
|
||||
log.warn(sm.getString("fileMessageFactory.duplicateMessage", msg.getContextName(), msg.getFileName(),
|
||||
HexUtils.toHexString(msg.getData()), Integer.valueOf(msg.getDataLength())));
|
||||
return false;
|
||||
}
|
||||
|
||||
FileMessage next = null;
|
||||
synchronized (this) {
|
||||
if (!isWriting) {
|
||||
next = msgBuffer.get(Long.valueOf(lastMessageProcessed.get() + 1));
|
||||
if (next != null) {
|
||||
isWriting = true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
while (next != null) {
|
||||
out.write(next.getData(), 0, next.getDataLength());
|
||||
lastMessageProcessed.incrementAndGet();
|
||||
out.flush();
|
||||
if (next.getMessageNumber() == next.getTotalNrOfMsgs()) {
|
||||
out.close();
|
||||
cleanup();
|
||||
return true;
|
||||
}
|
||||
synchronized(this) {
|
||||
next =
|
||||
msgBuffer.get(Long.valueOf(lastMessageProcessed.get() + 1));
|
||||
if (next == null) {
|
||||
isWriting = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}//writeMessage
|
||||
|
||||
/**
|
||||
* Closes the factory, its streams and sets all its references to null
|
||||
*/
|
||||
public void cleanup() {
|
||||
if (in != null)
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException ignore) {
|
||||
}
|
||||
if (out != null)
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException ignore) {
|
||||
}
|
||||
in = null;
|
||||
out = null;
|
||||
size = 0;
|
||||
closed = true;
|
||||
data = null;
|
||||
nrOfMessagesProcessed = 0;
|
||||
totalNrOfMessages = 0;
|
||||
msgBuffer.clear();
|
||||
lastMessageProcessed = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to make sure the factory is able to perform the function it is
|
||||
* asked to do. Invoked by readMessage/writeMessage before those methods
|
||||
* proceed.
|
||||
*
|
||||
* @param openForWrite The value to check
|
||||
* @throws IllegalArgumentException if the state is not the expected one
|
||||
*/
|
||||
protected void checkState(boolean openForWrite)
|
||||
throws IllegalArgumentException {
|
||||
if (this.openForWrite != openForWrite) {
|
||||
cleanup();
|
||||
if (openForWrite) {
|
||||
throw new IllegalArgumentException(sm.getString("fileMessageFactory.cannotWrite"));
|
||||
} else {
|
||||
throw new IllegalArgumentException(sm.getString("fileMessageFactory.cannotRead"));
|
||||
}
|
||||
}
|
||||
if (this.closed) {
|
||||
cleanup();
|
||||
throw new IllegalArgumentException(sm.getString("fileMessageFactory.closed"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Example usage.
|
||||
*
|
||||
* @param args
|
||||
* String[], args[0] - read from filename, args[1] write to
|
||||
* filename
|
||||
* @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");
|
||||
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]);
|
||||
msg = read.readMessage(msg);
|
||||
if (msg == null) {
|
||||
System.out.println("Empty input file : " + args[0]);
|
||||
return;
|
||||
}
|
||||
System.out.println("Expecting to write " + msg.getTotalNrOfMsgs()
|
||||
+ " messages.");
|
||||
int cnt = 0;
|
||||
while (msg != null) {
|
||||
write.writeMessage(msg);
|
||||
cnt++;
|
||||
msg = read.readMessage(msg);
|
||||
}//while
|
||||
System.out.println("Actually wrote " + cnt + " messages.");
|
||||
}///main
|
||||
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
if (maxValidTime > 0) {
|
||||
long timeNow = System.currentTimeMillis();
|
||||
int timeIdle = (int) ((timeNow - creationTime) / 1000L);
|
||||
if (timeIdle > maxValidTime) {
|
||||
cleanup();
|
||||
if (file.exists() && !file.delete()) {
|
||||
log.warn(sm.getString("fileMessageFactory.deleteFail", file));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getMaxValidTime() {
|
||||
return maxValidTime;
|
||||
}
|
||||
|
||||
public void setMaxValidTime(int maxValidTime) {
|
||||
this.maxValidTime = maxValidTime;
|
||||
}
|
||||
|
||||
}
|
||||
59
java/org/apache/catalina/ha/deploy/LocalStrings.properties
Normal file
59
java/org/apache/catalina/ha/deploy/LocalStrings.properties
Normal file
@@ -0,0 +1,59 @@
|
||||
# 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.
|
||||
|
||||
farmWarDeployer.alreadyDeployed=webapp [{0}] are already deployed.
|
||||
farmWarDeployer.deleteFail=Failed to delete [{0}]
|
||||
farmWarDeployer.deployEnd=Deployment from [{0}] finished.
|
||||
farmWarDeployer.fileCopyFail=Unable to copy from [{0}] to [{1}]
|
||||
farmWarDeployer.hostOnly=FarmWarDeployer can only work as host cluster subelement!
|
||||
farmWarDeployer.hostParentEngine=FarmWarDeployer can only work if parent of [{0}] is an engine!
|
||||
farmWarDeployer.mbeanNameFail=Cannot construct MBean object name for engine [{0}] and host [{1}]
|
||||
farmWarDeployer.modInstall=Installing webapp [{0}] from [{1}]
|
||||
farmWarDeployer.modInstallFail=Unable to install WAR file
|
||||
farmWarDeployer.modRemoveFail=No removal
|
||||
farmWarDeployer.msgIoe=Unable to read farm deploy file message.
|
||||
farmWarDeployer.msgRxDeploy=Receive cluster deployment path [{0}], war [{1}]
|
||||
farmWarDeployer.msgRxUndeploy=Receive cluster undeployment from path [{0}]
|
||||
farmWarDeployer.removeFailLocal=Local remove from [{0}] failed
|
||||
farmWarDeployer.removeFailRemote=Local remove from [{0}] failed, other manager has app in service!
|
||||
farmWarDeployer.removeLocal=Removing webapp [{0}]
|
||||
farmWarDeployer.removeLocalFail=Unable to remove WAR file
|
||||
farmWarDeployer.removeStart=Cluster wide remove of web app [{0}]
|
||||
farmWarDeployer.removeTxMsg=Send cluster wide undeployment from [{0}]
|
||||
farmWarDeployer.renameFail=Failed to rename [{0}] to [{1}]
|
||||
farmWarDeployer.sendEnd=Send cluster war deployment path [{0}], war [{1}] finished.
|
||||
farmWarDeployer.sendFragment=Send cluster war fragment path [{0}], war [{1}] to [{2}]
|
||||
farmWarDeployer.sendStart=Send cluster war deployment path [{0}], war [{1}] started.
|
||||
farmWarDeployer.servicingDeploy=Application [{0}] is being serviced. Touch war file [{1}] again!
|
||||
farmWarDeployer.servicingUndeploy=Application [{0}] is being serviced and can''t be removed from backup cluster node
|
||||
farmWarDeployer.started=Cluster FarmWarDeployer started.
|
||||
farmWarDeployer.stopped=Cluster FarmWarDeployer stopped.
|
||||
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.
|
||||
warWatcher.checkWarResult=WarInfo.check() returned [{0}] for [{1}]
|
||||
warWatcher.checkingWar=Checking WAR file [{0}]
|
||||
warWatcher.checkingWars=Checking WARs in [{0}]
|
||||
warWatcher.listedFileDoesNotExist=[{0}] was detected in [{1}] but does not exist. Check directory permissions on [{1}]?
|
||||
@@ -0,0 +1,25 @@
|
||||
# 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.
|
||||
|
||||
farmWarDeployer.modInstall=Installiere Webapplikation [{0}] von [{1}]
|
||||
farmWarDeployer.modInstallFail=WAR-Datei konnte nicht installiert werden
|
||||
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.
|
||||
@@ -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.
|
||||
|
||||
farmWarDeployer.hostOnly=FarmWarDeployer sólo puede operar como un subelemento de una máquina del cluster!
|
||||
farmWarDeployer.modInstall=Installando webapp [{0}] desde [{1}]\n
|
||||
farmWarDeployer.modInstallFail=Incapaz de instalar WAR file
|
||||
farmWarDeployer.msgIoe=Incapáz de leer el archivo de despliegue de la granja
|
||||
farmWarDeployer.msgRxDeploy=Recibe el camino de despliegue del cluster [{0}], war [{1}]
|
||||
farmWarDeployer.removeFailLocal=Borrado local de [{0}] fallido
|
||||
farmWarDeployer.removeFailRemote=El borrado local de [{0}] falló, otro manager tiene la aplicación en servicio!
|
||||
farmWarDeployer.sendFragment=Fragmento war enviado al cluster con camino [{0}], war [{1}] a [{2}]\n
|
||||
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}]
|
||||
@@ -0,0 +1,58 @@
|
||||
# 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.
|
||||
|
||||
farmWarDeployer.alreadyDeployed=l''application web [{0}] est déjà déployée
|
||||
farmWarDeployer.deleteFail=Pas réussi à supprimer [{0}]
|
||||
farmWarDeployer.deployEnd=Le déploiement de [{0}] est terminé
|
||||
farmWarDeployer.fileCopyFail=Impossible de copier depuis [{0}] vers [{1}]
|
||||
farmWarDeployer.hostOnly=Le FarmWarDeployer ne fonctionne qu'en tant que sous-élément d'un "host cluster" !
|
||||
farmWarDeployer.hostParentEngine=FarmWarDeployer peut fonctionner uniquement si le parent de [{0}] est un moteur
|
||||
farmWarDeployer.mbeanNameFail=Impossible de construire le nom d''objet du mbean pour le moteur [{0}] et l''hôte [{1}]
|
||||
farmWarDeployer.modInstall=Installation en cours pour la webapp [{0}] depuis [{1}]
|
||||
farmWarDeployer.modInstallFail=Incapable d'installer le fichier WAR
|
||||
farmWarDeployer.msgIoe=Incapable de lire le message de déploiement dans la ferme
|
||||
farmWarDeployer.msgRxDeploy=Recu le chemin de déploiement [{0}] du cluster, war [{1}]
|
||||
farmWarDeployer.msgRxUndeploy=Réception d''un retrait de cluster ("cluster undeployment") du chemin [{0}]
|
||||
farmWarDeployer.removeFailLocal=Impossible d''enlever localement de [{0}]
|
||||
farmWarDeployer.removeFailRemote=La suppression locale de [{0}] a échouée, l''autre gestionnaire (manager) a l''app en fonction !
|
||||
farmWarDeployer.removeLocal=Retrait de l''application web [{0}]
|
||||
farmWarDeployer.removeLocalFail=Impossible d'enlever le fichier WAR
|
||||
farmWarDeployer.removeStart=Retrait de l''application web [{0}] dans tout le cluster
|
||||
farmWarDeployer.removeTxMsg=Envoi à tout le cluster du déploiement à partir de [{0}]
|
||||
farmWarDeployer.renameFail=Echec du renommage de [{0}] en [{1}]
|
||||
farmWarDeployer.sendEnd=Envoi du chemin de déploiement du war au cluster, war [{1}] terminé
|
||||
farmWarDeployer.sendFragment=Envoi du chemin du fragment du war du cluster [{0}], war [{1}] vers [{2}]
|
||||
farmWarDeployer.sendStart=Envoi du déploiement war en cluster chemin [{0}], war [{1}] démarré
|
||||
farmWarDeployer.servicingDeploy=L''application [{0}] est en cours de maintenance, mettez de nouveau à jour la date du fichier war [{1}]
|
||||
farmWarDeployer.servicingUndeploy=L''application [{0}] est en maintenance et ne peut être retirée du node backup du cluster
|
||||
farmWarDeployer.started=Le FarmWarDeployer du cluster a démarré
|
||||
farmWarDeployer.stopped=Le FarmWarDeployer du cluster a été arrêté
|
||||
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.
|
||||
warWatcher.checkWarResult=WarInfo.check() a retourné [{0}] pour [{1}]
|
||||
warWatcher.checkingWar=Vérification du fichier WAR [{0}]
|
||||
warWatcher.checkingWars=Vérification des WARs dans [{0}]
|
||||
warWatcher.listedFileDoesNotExist=[{0}] a été détecté dans [{1}] mais n''existe pas, les permissions du répertoire pourraient être incorrectes
|
||||
@@ -0,0 +1,58 @@
|
||||
# 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.
|
||||
|
||||
farmWarDeployer.alreadyDeployed=webapp [{0}]は既にデプロイされています。
|
||||
farmWarDeployer.deleteFail=[{0}] を削除できません。
|
||||
farmWarDeployer.deployEnd=[{0}]からの配備が完了しました。
|
||||
farmWarDeployer.fileCopyFail=[{0}] から [{1}] へコピーできません。
|
||||
farmWarDeployer.hostOnly=FarmWarDeployer はHostクラスタのサブエレメントとしてのみ機能します
|
||||
farmWarDeployer.hostParentEngine=FarmWarDeployer は親 [{0}] が Engine のインスタンスでなければ機能しません。
|
||||
farmWarDeployer.mbeanNameFail=エンジン[{0}]とホスト[{1}]のMBeanオブジェクト名を構築できません
|
||||
farmWarDeployer.modInstall=[{1}]からwebapp [{0}]をインストールしています。
|
||||
farmWarDeployer.modInstallFail=WAR ファイルをインストールできませんでした。
|
||||
farmWarDeployer.msgIoe=ファームデプロイファイルメッセージの読み取りに失敗しました。
|
||||
farmWarDeployer.msgRxDeploy=クラスタ展開パス[{0}]、WAR[{1}]を受信しました。
|
||||
farmWarDeployer.msgRxUndeploy=パス[{0}]からクラスタの展開解除を受信しました。
|
||||
farmWarDeployer.removeFailLocal=[{0}]からのローカル削除に失敗しました
|
||||
farmWarDeployer.removeFailRemote=ローカルの [{0}] を削除できませんでした。他のマネージャーノードでサービス中です !
|
||||
farmWarDeployer.removeLocal=webapp [{0}]を削除しています
|
||||
farmWarDeployer.removeLocalFail=WAR ファイルを削除できません。
|
||||
farmWarDeployer.removeStart=Webアプリケーション[{0}]のクラスタ削除。
|
||||
farmWarDeployer.removeTxMsg=コンテキスト [{0}] からクラスターに配置解除メッセージを送信しました。
|
||||
farmWarDeployer.renameFail=[{0}] から [{1}] へ名前を変更できません。
|
||||
farmWarDeployer.sendEnd=クラスタWarデプロイメント パス[{0}]を送信しました。WAR[{1}]を完了しました。
|
||||
farmWarDeployer.sendFragment=コンテキスト [{0}] の war [{1}] をクラスターメンバー [{2}] へ送信します。
|
||||
farmWarDeployer.sendStart=クラスタWar展開パス[{0}]を送信し、War[{1}]を開始しました。
|
||||
farmWarDeployer.servicingDeploy=アプリケーション [{0}] はすでにサービスを開始しています。もう一度 WAR ファイル [{1}] を更新してください。
|
||||
farmWarDeployer.servicingUndeploy=アプリケーション [{0}] はサービス中のためバックアップクラスタノードから削除できません。
|
||||
farmWarDeployer.started=クラスターの FarmWarDeployer を開始しました。
|
||||
farmWarDeployer.stopped=Cluster FarmWarDeployer が停止しました。
|
||||
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}] のファイル一覧を取得できません : ディレクトリの読み取り権限を確認してください。
|
||||
warWatcher.checkWarResult=WAR ファイル [{1}] について WarInfo.check() は [{0}] を返しました。
|
||||
warWatcher.checkingWar=WAR ファイル [{0}] をチェックしています。
|
||||
warWatcher.checkingWars=[{0}]のWARを確認します
|
||||
warWatcher.listedFileDoesNotExist=[{1}] にあるはずの [{0}] が存在しません。[{1}] のディレクトリ権限を確認してください。
|
||||
@@ -0,0 +1,58 @@
|
||||
# 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.
|
||||
|
||||
farmWarDeployer.alreadyDeployed=webapp [{0}](들)이 이미 배치되어 있습니다.
|
||||
farmWarDeployer.deleteFail=[{0}]을(를) 삭제하지 못했습니다.
|
||||
farmWarDeployer.deployEnd=[{0}](으)로부터의 배치 작업이 완료됐습니다.
|
||||
farmWarDeployer.fileCopyFail=[{0}](으)로부터 [{1}](으)로 복사할 수 없습니다.
|
||||
farmWarDeployer.hostOnly=FarmWarDeployer는 오직 하위 엘리먼트인 호스트 클러스터 엘리먼트에서 존재해야 합니다.
|
||||
farmWarDeployer.hostParentEngine=FarmWarDeployer는, 오직 [{0}]의 부모가 엔진일 때에만, 정상 동작할 수 있습니다!
|
||||
farmWarDeployer.mbeanNameFail=엔진 [{0}]와(과) 호스트 [{1}]을(를) 위한 MBean 객체 이름을 구성할 수 없습니다.
|
||||
farmWarDeployer.modInstall=[{1}](으)로부터 웹 애플리케이션 [{0}]을(를) 설치합니다.
|
||||
farmWarDeployer.modInstallFail=WAR 파일을 설치할 수 없습니다.
|
||||
farmWarDeployer.msgIoe=farm deploy 파일 메시지를 읽을 수 없습니다.
|
||||
farmWarDeployer.msgRxDeploy=클러스터 배치 경로 [{0}]을(를) 받았음, war: [{1}]
|
||||
farmWarDeployer.msgRxUndeploy=경로 [{0}]에 대한 클러스터 배치 제거 메시지를 수신했습니다.
|
||||
farmWarDeployer.removeFailLocal=[{0}](으)로부터 로컬 삭제가 실패했습니다.
|
||||
farmWarDeployer.removeFailRemote=FarmWarDeployer가 컨텍스트 [{0}]을(를) 로컬에서 제거하지 못하였습니다. 다른 Manager가 해당 애플리케이션을 서비스 중에 있습니다!
|
||||
farmWarDeployer.removeLocal=웹 애플리케이션 [{0}]을(를) 제거합니다.
|
||||
farmWarDeployer.removeLocalFail=WAR 파일을 제거할 수 없습니다.
|
||||
farmWarDeployer.removeStart=웹 애플리케이션 [{0}]을(를) 전 클러스터에서 제거
|
||||
farmWarDeployer.removeTxMsg=전 클러스터에서 [{0}]에 대한 배치를 제거 할 것을 전송합니다.
|
||||
farmWarDeployer.renameFail=[{0}]을(를) [{1}](으)로 이름을 변경하지 못했습니다.
|
||||
farmWarDeployer.sendEnd=클러스터 war 배치 경로 [{0}]을(를) 전송합니다. war [{1}]은(는) 완료되었습니다.
|
||||
farmWarDeployer.sendFragment=클러스터 war 파일 (경로: [{0}]) [{1}]을(를) [{2}](으)로 전송합니다.
|
||||
farmWarDeployer.sendStart=클러스터 war 배치 경로 [{0}]을(를) 전송합니다, war [{1}]이(가) 시작되었습니다.
|
||||
farmWarDeployer.servicingDeploy=애플리케이션 [{0}]이(가) 서비스되고 있습니다. War 파일 [{1}]을(를) 다시 touch 하십시오!
|
||||
farmWarDeployer.servicingUndeploy=애플리케이션 [{0}]이(가) 서비스 되고 있는 중이어서, 백업 클러스터 노드로부터 제거될 수 없습니다.
|
||||
farmWarDeployer.started=클러스터 FarmWarDeployer가 시작되었습니다.
|
||||
farmWarDeployer.stopped=클러스터 FarmWarDeployer가 중지되었습니다.
|
||||
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}] 내의 파일 목록을 구할 수 없습니다. 해당 디렉토리가 존재하는지 그리고 읽기 권한이 있는지 점검하십시오.
|
||||
warWatcher.checkWarResult=WarInfo.check()가 [{1}]을(를) 위해 [{0}]을(를) 반환했습니다.
|
||||
warWatcher.checkingWar=WAR 파일 [{0}]을(를) 점검합니다.
|
||||
warWatcher.checkingWars=[{0}] 내의 WAR들을 점검합니다.
|
||||
warWatcher.listedFileDoesNotExist=[{0}]이(가) [{1}]에서 탐지되었으나, 존재하지 않습니다. [{1}]에 대한 디렉토리 접근 허가 설정을 점검해 보시겠습니까?
|
||||
@@ -0,0 +1,18 @@
|
||||
# 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.
|
||||
|
||||
farmWarDeployer.modInstall=Установка веб приложения [{0}] из [{1}]
|
||||
|
||||
warWatcher.checkingWar=Проверяем WAR файл [{}]
|
||||
@@ -0,0 +1,38 @@
|
||||
# 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.
|
||||
|
||||
farmWarDeployer.deleteFail=无法删除 [{0}]
|
||||
farmWarDeployer.hostOnly=FarmWarDeployer 只有做为 host cluster 的子元素是才生效
|
||||
farmWarDeployer.mbeanNameFail=无法为引擎[{0}]和主机[{1}]构造MBean对象名
|
||||
farmWarDeployer.modInstall=从 [{1}] 安装 webapp [{0}]
|
||||
farmWarDeployer.modInstallFail=无法安装 WAR 文件
|
||||
farmWarDeployer.msgIoe=无法读取服务器场部署文件消息。
|
||||
farmWarDeployer.msgRxDeploy=接收集群部署路径[{0}],战争[{1}]
|
||||
farmWarDeployer.msgRxUndeploy=从路径[{0}]接收未部署群集
|
||||
farmWarDeployer.removeFailLocal=从[{0}]本地移除失败
|
||||
farmWarDeployer.removeFailRemote=本地从[{0}]删除失败,其他经理有app在服务!
|
||||
farmWarDeployer.removeLocalFail=无法移除WAR文件
|
||||
farmWarDeployer.renameFail=将 [{0}] 重命名为 [{1}] 失败
|
||||
farmWarDeployer.sendFragment=将群集战争片段路径[{0}],战争[{1}]发送到[{2}]
|
||||
farmWarDeployer.servicingDeploy=应用程序[{0}]正在服务。再次触摸WAR文件[{1}]!
|
||||
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}]
|
||||
69
java/org/apache/catalina/ha/deploy/UndeployMessage.java
Normal file
69
java/org/apache/catalina/ha/deploy/UndeployMessage.java
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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.deploy;
|
||||
|
||||
import org.apache.catalina.ha.ClusterMessage;
|
||||
import org.apache.catalina.tribes.Member;
|
||||
|
||||
public class UndeployMessage implements ClusterMessage {
|
||||
private static final long serialVersionUID = 2L;
|
||||
|
||||
private Member address;
|
||||
private long timestamp;
|
||||
private String uniqueId;
|
||||
private final String contextName;
|
||||
|
||||
public UndeployMessage(Member address,
|
||||
long timestamp,
|
||||
String uniqueId,
|
||||
String contextName) {
|
||||
this.address = address;
|
||||
this.timestamp= timestamp;
|
||||
this.uniqueId = uniqueId;
|
||||
this.contextName = contextName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Member getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAddress(Member address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueId() {
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
public String getContextName() {
|
||||
return contextName;
|
||||
}
|
||||
}
|
||||
225
java/org/apache/catalina/ha/deploy/WarWatcher.java
Normal file
225
java/org/apache/catalina/ha/deploy/WarWatcher.java
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* 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.deploy;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* The <b>WarWatcher </b> watches the deployDir for changes made to the
|
||||
* directory (adding new WAR files->deploy or remove WAR files->undeploy)
|
||||
* and notifies a listener of the changes made.
|
||||
*
|
||||
* @author Peter Rossbach
|
||||
* @version 1.1
|
||||
*/
|
||||
public class WarWatcher {
|
||||
|
||||
/*--Static Variables----------------------------------------*/
|
||||
private static final Log log = LogFactory.getLog(WarWatcher.class);
|
||||
private static final StringManager sm = StringManager.getManager(WarWatcher.class);
|
||||
|
||||
/*--Instance Variables--------------------------------------*/
|
||||
/**
|
||||
* Directory to watch for war files
|
||||
*/
|
||||
protected final File watchDir;
|
||||
|
||||
/**
|
||||
* Parent to be notified of changes
|
||||
*/
|
||||
protected final FileChangeListener listener;
|
||||
|
||||
/**
|
||||
* Currently deployed files
|
||||
*/
|
||||
protected final Map<String, WarInfo> currentStatus = new HashMap<>();
|
||||
|
||||
/*--Constructor---------------------------------------------*/
|
||||
|
||||
public WarWatcher(FileChangeListener listener, File watchDir) {
|
||||
this.listener = listener;
|
||||
this.watchDir = watchDir;
|
||||
}
|
||||
|
||||
/*--Logic---------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* check for modification and send notification to listener
|
||||
*/
|
||||
public void check() {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("warWatcher.checkingWars", watchDir));
|
||||
File[] list = watchDir.listFiles(new WarFilter());
|
||||
if (list == null) {
|
||||
log.warn(sm.getString("warWatcher.cantListWatchDir",
|
||||
watchDir));
|
||||
|
||||
list = new File[0];
|
||||
}
|
||||
//first make sure all the files are listed in our current status
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
if(!list[i].exists())
|
||||
log.warn(sm.getString("warWatcher.listedFileDoesNotExist",
|
||||
list[i], watchDir));
|
||||
|
||||
addWarInfo(list[i]);
|
||||
}
|
||||
|
||||
// Check all the status codes and update the FarmDeployer
|
||||
for (Iterator<Map.Entry<String,WarInfo>> i =
|
||||
currentStatus.entrySet().iterator(); i.hasNext();) {
|
||||
Map.Entry<String,WarInfo> entry = i.next();
|
||||
WarInfo info = entry.getValue();
|
||||
if(log.isTraceEnabled())
|
||||
log.trace(sm.getString("warWatcher.checkingWar",
|
||||
info.getWar()));
|
||||
int check = info.check();
|
||||
if (check == 1) {
|
||||
listener.fileModified(info.getWar());
|
||||
} else if (check == -1) {
|
||||
listener.fileRemoved(info.getWar());
|
||||
//no need to keep in memory
|
||||
i.remove();
|
||||
}
|
||||
if(log.isTraceEnabled())
|
||||
log.trace(sm.getString("warWatcher.checkWarResult",
|
||||
Integer.valueOf(check),
|
||||
info.getWar()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* add cluster war to the watcher state
|
||||
* @param warfile The WAR to add
|
||||
*/
|
||||
protected void addWarInfo(File warfile) {
|
||||
WarInfo info = currentStatus.get(warfile.getAbsolutePath());
|
||||
if (info == null) {
|
||||
info = new WarInfo(warfile);
|
||||
info.setLastState(-1); //assume file is non existent
|
||||
currentStatus.put(warfile.getAbsolutePath(), info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clear watcher state
|
||||
*/
|
||||
public void clear() {
|
||||
currentStatus.clear();
|
||||
}
|
||||
|
||||
|
||||
/*--Inner classes-------------------------------------------*/
|
||||
|
||||
/**
|
||||
* File name filter for war files
|
||||
*/
|
||||
protected static class WarFilter implements java.io.FilenameFilter {
|
||||
@Override
|
||||
public boolean accept(File path, String name) {
|
||||
if (name == null)
|
||||
return false;
|
||||
return name.endsWith(".war");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* File information on existing WAR files
|
||||
*/
|
||||
protected static class WarInfo {
|
||||
protected final File war;
|
||||
|
||||
protected long lastChecked = 0;
|
||||
|
||||
protected long lastState = 0;
|
||||
|
||||
public WarInfo(File war) {
|
||||
this.war = war;
|
||||
this.lastChecked = war.lastModified();
|
||||
if (!war.exists())
|
||||
lastState = -1;
|
||||
}
|
||||
|
||||
public boolean modified() {
|
||||
return war.exists() && war.lastModified() > lastChecked;
|
||||
}
|
||||
|
||||
public boolean exists() {
|
||||
return war.exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns 1 if the file has been added/modified, 0 if the file is
|
||||
* unchanged and -1 if the file has been removed
|
||||
*
|
||||
* @return int 1=file added; 0=unchanged; -1=file removed
|
||||
*/
|
||||
public int check() {
|
||||
//file unchanged by default
|
||||
int result = 0;
|
||||
|
||||
if (modified()) {
|
||||
//file has changed - timestamp
|
||||
result = 1;
|
||||
lastState = result;
|
||||
} else if ((!exists()) && (!(lastState == -1))) {
|
||||
//file was removed
|
||||
result = -1;
|
||||
lastState = result;
|
||||
} else if ((lastState == -1) && exists()) {
|
||||
//file was added
|
||||
result = 1;
|
||||
lastState = result;
|
||||
}
|
||||
this.lastChecked = System.currentTimeMillis();
|
||||
return result;
|
||||
}
|
||||
|
||||
public File getWar() {
|
||||
return war;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return war.getAbsolutePath().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof WarInfo) {
|
||||
WarInfo wo = (WarInfo) other;
|
||||
return wo.getWar().equals(getWar());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected void setLastState(int lastState) {
|
||||
this.lastState = lastState;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
51
java/org/apache/catalina/ha/deploy/mbeans-descriptors.xml
Normal file
51
java/org/apache/catalina/ha/deploy/mbeans-descriptors.xml
Normal file
@@ -0,0 +1,51 @@
|
||||
<?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.
|
||||
-->
|
||||
<mbeans-descriptors>
|
||||
<mbean
|
||||
name="FarmWarDeployer"
|
||||
className="org.apache.catalina.mbeans.ClassNameMBean"
|
||||
description="Farm Deployer"
|
||||
domain="Catalina"
|
||||
group="Cluster"
|
||||
type="org.apache.catalina.ha.deploy.FarmWarDeployer">
|
||||
<attribute
|
||||
name="deployDir"
|
||||
description="Deployment directory."
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="tempDir"
|
||||
description="The temporaryDirectory to store binary data when downloading a war from the cluster"
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="watchDir"
|
||||
description="The directory where we watch for changes"
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="watchEnabled"
|
||||
description="Is watching enabled?"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="processDeployFrequency"
|
||||
description="Frequency of the Farm watchDir check."
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="maxValidTime"
|
||||
description="The maximum valid time of FileMessageFactory."
|
||||
type="int"/>
|
||||
</mbean>
|
||||
</mbeans-descriptors>
|
||||
23
java/org/apache/catalina/ha/package.html
Normal file
23
java/org/apache/catalina/ha/package.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<body>
|
||||
|
||||
<p>This package contains code for Clustering, the base class
|
||||
of a Cluster is <code>org.apache.catalina.Cluster</code> implementations
|
||||
of this class is done when implementing a new Cluster protocol</p>
|
||||
|
||||
</body>
|
||||
265
java/org/apache/catalina/ha/session/BackupManager.java
Normal file
265
java/org/apache/catalina/ha/session/BackupManager.java
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* 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.session;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.catalina.DistributedManager;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.LifecycleState;
|
||||
import org.apache.catalina.Session;
|
||||
import org.apache.catalina.ha.ClusterManager;
|
||||
import org.apache.catalina.ha.ClusterMessage;
|
||||
import org.apache.catalina.tribes.Channel;
|
||||
import org.apache.catalina.tribes.tipis.AbstractReplicatedMap.MapOwner;
|
||||
import org.apache.catalina.tribes.tipis.LazyReplicatedMap;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
*@version 1.0
|
||||
*/
|
||||
public class BackupManager extends ClusterManagerBase
|
||||
implements MapOwner, DistributedManager {
|
||||
|
||||
private final Log log = LogFactory.getLog(BackupManager.class); // must not be static
|
||||
|
||||
/**
|
||||
* The string manager for this package.
|
||||
*/
|
||||
protected static final StringManager sm = StringManager.getManager(BackupManager.class);
|
||||
|
||||
protected static final long DEFAULT_REPL_TIMEOUT = 15000;//15 seconds
|
||||
|
||||
/**
|
||||
* The name of this manager
|
||||
*/
|
||||
protected String name;
|
||||
|
||||
/**
|
||||
* Flag for how this map sends messages.
|
||||
*/
|
||||
private int mapSendOptions = Channel.SEND_OPTIONS_SYNCHRONIZED_ACK|Channel.SEND_OPTIONS_USE_ACK;
|
||||
|
||||
/**
|
||||
* Timeout for RPC messages.
|
||||
*/
|
||||
private long rpcTimeout = DEFAULT_REPL_TIMEOUT;
|
||||
|
||||
/**
|
||||
* Flag for whether to terminate this map that failed to start.
|
||||
*/
|
||||
private boolean terminateOnStartFailure = false;
|
||||
|
||||
/**
|
||||
* The timeout for a ping message in replication map.
|
||||
*/
|
||||
private long accessTimeout = 5000;
|
||||
|
||||
/**
|
||||
* Constructor, just calls super()
|
||||
*
|
||||
*/
|
||||
public BackupManager() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
//******************************************************************************/
|
||||
// ClusterManager Interface
|
||||
//******************************************************************************/
|
||||
|
||||
@Override
|
||||
public void messageDataReceived(ClusterMessage msg) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClusterMessage requestCompleted(String sessionId) {
|
||||
if (!getState().isAvailable()) return null;
|
||||
LazyReplicatedMap<String,Session> map =
|
||||
(LazyReplicatedMap<String,Session>)sessions;
|
||||
map.replicate(sessionId,false);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//=========================================================================
|
||||
// OVERRIDE THESE METHODS TO IMPLEMENT THE REPLICATION
|
||||
//=========================================================================
|
||||
@Override
|
||||
public void objectMadePrimary(Object key, Object value) {
|
||||
if (value instanceof DeltaSession) {
|
||||
DeltaSession session = (DeltaSession)value;
|
||||
synchronized (session) {
|
||||
session.access();
|
||||
session.setPrimarySession(true);
|
||||
session.endAccess();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Session createEmptySession() {
|
||||
return new DeltaSession(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start this component and implement the requirements
|
||||
* of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
|
||||
*
|
||||
* Starts the cluster communication channel, this will connect with the
|
||||
* other nodes in the cluster, and request the current session state to be
|
||||
* transferred to this node.
|
||||
*
|
||||
* @exception LifecycleException if this component detects a fatal error
|
||||
* that prevents this component from being used
|
||||
*/
|
||||
@Override
|
||||
protected synchronized void startInternal() throws LifecycleException {
|
||||
|
||||
super.startInternal();
|
||||
|
||||
try {
|
||||
if (cluster == null) throw new LifecycleException(sm.getString("backupManager.noCluster", getName()));
|
||||
LazyReplicatedMap<String,Session> map = new LazyReplicatedMap<>(
|
||||
this, cluster.getChannel(), rpcTimeout, getMapName(),
|
||||
getClassLoaders(), terminateOnStartFailure);
|
||||
map.setChannelSendOptions(mapSendOptions);
|
||||
map.setAccessTimeout(accessTimeout);
|
||||
this.sessions = map;
|
||||
} catch ( Exception x ) {
|
||||
log.error(sm.getString("backupManager.startUnable", getName()),x);
|
||||
throw new LifecycleException(sm.getString("backupManager.startFailed", getName()),x);
|
||||
}
|
||||
setState(LifecycleState.STARTING);
|
||||
}
|
||||
|
||||
public String getMapName() {
|
||||
String name = cluster.getManagerName(getName(),this)+"-"+"map";
|
||||
if ( log.isDebugEnabled() ) log.debug("Backup manager, Setting map name to:"+name);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stop this component and implement the requirements
|
||||
* of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}.
|
||||
*
|
||||
* This will disconnect the cluster communication channel and stop the
|
||||
* listener thread.
|
||||
*
|
||||
* @exception LifecycleException if this component detects a fatal error
|
||||
* that prevents this component from being used
|
||||
*/
|
||||
@Override
|
||||
protected synchronized void stopInternal() throws LifecycleException {
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("backupManager.stopped", getName()));
|
||||
|
||||
setState(LifecycleState.STOPPING);
|
||||
|
||||
if (sessions instanceof LazyReplicatedMap) {
|
||||
LazyReplicatedMap<String,Session> map =
|
||||
(LazyReplicatedMap<String,Session>)sessions;
|
||||
map.breakdown();
|
||||
}
|
||||
|
||||
super.stopInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setMapSendOptions(int mapSendOptions) {
|
||||
this.mapSendOptions = mapSendOptions;
|
||||
}
|
||||
|
||||
public int getMapSendOptions() {
|
||||
return mapSendOptions;
|
||||
}
|
||||
|
||||
public void setRpcTimeout(long rpcTimeout) {
|
||||
this.rpcTimeout = rpcTimeout;
|
||||
}
|
||||
|
||||
public long getRpcTimeout() {
|
||||
return rpcTimeout;
|
||||
}
|
||||
|
||||
public void setTerminateOnStartFailure(boolean terminateOnStartFailure) {
|
||||
this.terminateOnStartFailure = terminateOnStartFailure;
|
||||
}
|
||||
|
||||
public boolean isTerminateOnStartFailure() {
|
||||
return terminateOnStartFailure;
|
||||
}
|
||||
|
||||
public long getAccessTimeout() {
|
||||
return accessTimeout;
|
||||
}
|
||||
|
||||
public void setAccessTimeout(long accessTimeout) {
|
||||
this.accessTimeout = accessTimeout;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getInvalidatedSessions() {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClusterManager cloneFromTemplate() {
|
||||
BackupManager result = new BackupManager();
|
||||
clone(result);
|
||||
result.mapSendOptions = mapSendOptions;
|
||||
result.rpcTimeout = rpcTimeout;
|
||||
result.terminateOnStartFailure = terminateOnStartFailure;
|
||||
result.accessTimeout = accessTimeout;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getActiveSessionsFull() {
|
||||
LazyReplicatedMap<String,Session> map =
|
||||
(LazyReplicatedMap<String,Session>)sessions;
|
||||
return map.sizeFull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSessionIdsFull() {
|
||||
Set<String> sessionIds = new HashSet<>();
|
||||
LazyReplicatedMap<String,Session> map =
|
||||
(LazyReplicatedMap<String,Session>)sessions;
|
||||
for (String id : map.keySetFull()) {
|
||||
sessionIds.add(id);
|
||||
}
|
||||
return sessionIds;
|
||||
}
|
||||
|
||||
}
|
||||
220
java/org/apache/catalina/ha/session/ClusterManagerBase.java
Normal file
220
java/org/apache/catalina/ha/session/ClusterManagerBase.java
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* 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.session;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.catalina.Cluster;
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.Loader;
|
||||
import org.apache.catalina.SessionIdGenerator;
|
||||
import org.apache.catalina.Valve;
|
||||
import org.apache.catalina.ha.CatalinaCluster;
|
||||
import org.apache.catalina.ha.ClusterManager;
|
||||
import org.apache.catalina.ha.tcp.ReplicationValve;
|
||||
import org.apache.catalina.session.ManagerBase;
|
||||
import org.apache.catalina.tribes.io.ReplicationStream;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.collections.SynchronizedStack;
|
||||
|
||||
public abstract class ClusterManagerBase extends ManagerBase implements ClusterManager {
|
||||
|
||||
private final Log log = LogFactory.getLog(ClusterManagerBase.class); // must not be static
|
||||
|
||||
/**
|
||||
* A reference to the cluster
|
||||
*/
|
||||
protected CatalinaCluster cluster = null;
|
||||
|
||||
/**
|
||||
* Should listeners be notified?
|
||||
*/
|
||||
private boolean notifyListenersOnReplication = true;
|
||||
|
||||
/**
|
||||
* cached replication valve cluster container!
|
||||
*/
|
||||
private volatile ReplicationValve replicationValve = null ;
|
||||
|
||||
/**
|
||||
* send all actions of session attributes.
|
||||
*/
|
||||
private boolean recordAllActions = false;
|
||||
|
||||
private SynchronizedStack<DeltaRequest> deltaRequestPool = new SynchronizedStack<>();
|
||||
|
||||
|
||||
protected SynchronizedStack<DeltaRequest> getDeltaRequestPool() {
|
||||
return deltaRequestPool;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CatalinaCluster getCluster() {
|
||||
return cluster;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCluster(CatalinaCluster cluster) {
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNotifyListenersOnReplication() {
|
||||
return notifyListenersOnReplication;
|
||||
}
|
||||
|
||||
public void setNotifyListenersOnReplication(boolean notifyListenersOnReplication) {
|
||||
this.notifyListenersOnReplication = notifyListenersOnReplication;
|
||||
}
|
||||
|
||||
|
||||
public boolean isRecordAllActions() {
|
||||
return recordAllActions;
|
||||
}
|
||||
|
||||
public void setRecordAllActions(boolean recordAllActions) {
|
||||
this.recordAllActions = recordAllActions;
|
||||
}
|
||||
|
||||
|
||||
public static ClassLoader[] getClassLoaders(Context context) {
|
||||
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
|
||||
Loader loader = context.getLoader();
|
||||
ClassLoader classLoader = null;
|
||||
if (loader != null) {
|
||||
classLoader = loader.getClassLoader();
|
||||
}
|
||||
if (classLoader == null) {
|
||||
classLoader = tccl;
|
||||
}
|
||||
if (classLoader == tccl) {
|
||||
return new ClassLoader[] {classLoader};
|
||||
} else {
|
||||
return new ClassLoader[] {classLoader, tccl};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ClassLoader[] getClassLoaders() {
|
||||
return getClassLoaders(getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplicationStream getReplicationStream(byte[] data) throws IOException {
|
||||
return getReplicationStream(data,0,data.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReplicationStream getReplicationStream(byte[] data, int offset, int length) throws IOException {
|
||||
ByteArrayInputStream fis = new ByteArrayInputStream(data, offset, length);
|
||||
return new ReplicationStream(fis, getClassLoaders());
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------- persistence handler
|
||||
|
||||
/**
|
||||
* {@link org.apache.catalina.Manager} implementations that also implement
|
||||
* {@link ClusterManager} do not support local session persistence.
|
||||
*/
|
||||
@Override
|
||||
public void load() {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link org.apache.catalina.Manager} implementations that also implement
|
||||
* {@link ClusterManager} do not support local session persistence.
|
||||
*/
|
||||
@Override
|
||||
public void unload() {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
protected void clone(ClusterManagerBase copy) {
|
||||
copy.setName("Clone-from-" + getName());
|
||||
copy.setMaxActiveSessions(getMaxActiveSessions());
|
||||
copy.setProcessExpiresFrequency(getProcessExpiresFrequency());
|
||||
copy.setNotifyListenersOnReplication(isNotifyListenersOnReplication());
|
||||
copy.setSessionAttributeNameFilter(getSessionAttributeNameFilter());
|
||||
copy.setSessionAttributeValueClassNameFilter(getSessionAttributeValueClassNameFilter());
|
||||
copy.setWarnOnSessionAttributeFilterFailure(getWarnOnSessionAttributeFilterFailure());
|
||||
copy.setSecureRandomClass(getSecureRandomClass());
|
||||
copy.setSecureRandomProvider(getSecureRandomProvider());
|
||||
copy.setSecureRandomAlgorithm(getSecureRandomAlgorithm());
|
||||
if (getSessionIdGenerator() != null) {
|
||||
try {
|
||||
SessionIdGenerator copyIdGenerator = sessionIdGeneratorClass.getConstructor().newInstance();
|
||||
copyIdGenerator.setSessionIdLength(getSessionIdGenerator().getSessionIdLength());
|
||||
copyIdGenerator.setJvmRoute(getSessionIdGenerator().getJvmRoute());
|
||||
copy.setSessionIdGenerator(copyIdGenerator);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
copy.setRecordAllActions(isRecordAllActions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Register cross context session at replication valve thread local
|
||||
* @param session cross context session
|
||||
*/
|
||||
protected void registerSessionAtReplicationValve(DeltaSession session) {
|
||||
if(replicationValve == null) {
|
||||
CatalinaCluster cluster = getCluster() ;
|
||||
if(cluster != null) {
|
||||
Valve[] valves = cluster.getValves();
|
||||
if(valves != null && valves.length > 0) {
|
||||
for(int i=0; replicationValve == null && i < valves.length ; i++ ){
|
||||
if(valves[i] instanceof ReplicationValve) replicationValve =
|
||||
(ReplicationValve)valves[i] ;
|
||||
}//for
|
||||
|
||||
if(replicationValve == null && log.isDebugEnabled()) {
|
||||
log.debug("no ReplicationValve found for CrossContext Support");
|
||||
}//endif
|
||||
}//end if
|
||||
}//endif
|
||||
}//end if
|
||||
if(replicationValve != null) {
|
||||
replicationValve.registerReplicationSession(session);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startInternal() throws LifecycleException {
|
||||
super.startInternal();
|
||||
if (getCluster() == null) {
|
||||
Cluster cluster = getContext().getCluster();
|
||||
if (cluster instanceof CatalinaCluster) {
|
||||
setCluster((CatalinaCluster)cluster);
|
||||
}
|
||||
}
|
||||
if (cluster != null) cluster.registerManager(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stopInternal() throws LifecycleException {
|
||||
if (cluster != null) cluster.removeManager(this);
|
||||
replicationValve = null;
|
||||
super.stopInternal();
|
||||
}
|
||||
}
|
||||
109
java/org/apache/catalina/ha/session/ClusterSessionListener.java
Normal file
109
java/org/apache/catalina/ha/session/ClusterSessionListener.java
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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.session;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.catalina.ha.ClusterListener;
|
||||
import org.apache.catalina.ha.ClusterManager;
|
||||
import org.apache.catalina.ha.ClusterMessage;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* Receive replicated SessionMessage form other cluster node.
|
||||
* @author Peter Rossbach
|
||||
*/
|
||||
public class ClusterSessionListener extends ClusterListener {
|
||||
|
||||
private static final Log log =
|
||||
LogFactory.getLog(ClusterSessionListener.class);
|
||||
private static final StringManager sm = StringManager.getManager(ClusterSessionListener.class);
|
||||
|
||||
//--Constructor---------------------------------------------
|
||||
|
||||
public ClusterSessionListener() {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
//--Logic---------------------------------------------------
|
||||
|
||||
/**
|
||||
* Callback from the cluster, when a message is received, The cluster will
|
||||
* broadcast it invoking the messageReceived on the receiver.
|
||||
*
|
||||
* @param myobj
|
||||
* ClusterMessage - the message received from the cluster
|
||||
*/
|
||||
@Override
|
||||
public void messageReceived(ClusterMessage myobj) {
|
||||
if (myobj instanceof SessionMessage) {
|
||||
SessionMessage msg = (SessionMessage) myobj;
|
||||
String ctxname = msg.getContextName();
|
||||
//check if the message is a EVT_GET_ALL_SESSIONS,
|
||||
//if so, wait until we are fully started up
|
||||
Map<String,ClusterManager> managers = cluster.getManagers() ;
|
||||
if (ctxname == null) {
|
||||
for (Map.Entry<String, ClusterManager> entry :
|
||||
managers.entrySet()) {
|
||||
if (entry.getValue() != null)
|
||||
entry.getValue().messageDataReceived(msg);
|
||||
else {
|
||||
//this happens a lot before the system has started
|
||||
// up
|
||||
if (log.isDebugEnabled())
|
||||
log.debug(sm.getString("clusterSessionListener.noManager", entry.getKey()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ClusterManager mgr = managers.get(ctxname);
|
||||
if (mgr != null) {
|
||||
mgr.messageDataReceived(msg);
|
||||
} else {
|
||||
if (log.isWarnEnabled())
|
||||
log.warn(sm.getString("clusterSessionListener.noManager", ctxname));
|
||||
|
||||
// A no context manager message is replied in order to avoid
|
||||
// timeout of GET_ALL_SESSIONS sync phase.
|
||||
if (msg.getEventType() == SessionMessage.EVT_GET_ALL_SESSIONS) {
|
||||
SessionMessage replymsg = new SessionMessageImpl(ctxname,
|
||||
SessionMessage.EVT_ALL_SESSION_NOCONTEXTMANAGER,
|
||||
null, "NO-CONTEXT-MANAGER","NO-CONTEXT-MANAGER-" + ctxname);
|
||||
cluster.send(replymsg, msg.getAddress());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept only SessionMessage
|
||||
*
|
||||
* @param msg
|
||||
* ClusterMessage
|
||||
* @return boolean - returns true to indicate that messageReceived should be
|
||||
* invoked. If false is returned, the messageReceived method will
|
||||
* not be invoked.
|
||||
*/
|
||||
@Override
|
||||
public boolean accept(ClusterMessage msg) {
|
||||
return msg instanceof SessionMessage;
|
||||
}
|
||||
}
|
||||
|
||||
1467
java/org/apache/catalina/ha/session/DeltaManager.java
Normal file
1467
java/org/apache/catalina/ha/session/DeltaManager.java
Normal file
File diff suppressed because it is too large
Load Diff
413
java/org/apache/catalina/ha/session/DeltaRequest.java
Normal file
413
java/org/apache/catalina/ha/session/DeltaRequest.java
Normal file
@@ -0,0 +1,413 @@
|
||||
/*
|
||||
* 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.session;
|
||||
|
||||
/**
|
||||
* This class is used to track the series of actions that happens when
|
||||
* a request is executed. These actions will then translate into invocations of methods
|
||||
* on the actual session.
|
||||
* This class is NOT thread safe. One DeltaRequest per session
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.security.Principal;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.apache.catalina.SessionListener;
|
||||
import org.apache.catalina.realm.GenericPrincipal;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
|
||||
public class DeltaRequest implements Externalizable {
|
||||
|
||||
public static final Log log = LogFactory.getLog(DeltaRequest.class);
|
||||
|
||||
/**
|
||||
* The string manager for this package.
|
||||
*/
|
||||
protected static final StringManager sm = StringManager.getManager(DeltaRequest.class);
|
||||
|
||||
public static final int TYPE_ATTRIBUTE = 0;
|
||||
public static final int TYPE_PRINCIPAL = 1;
|
||||
public static final int TYPE_ISNEW = 2;
|
||||
public static final int TYPE_MAXINTERVAL = 3;
|
||||
public static final int TYPE_AUTHTYPE = 4;
|
||||
public static final int TYPE_LISTENER = 5;
|
||||
|
||||
public static final int ACTION_SET = 0;
|
||||
public static final int ACTION_REMOVE = 1;
|
||||
|
||||
public static final String NAME_PRINCIPAL = "__SET__PRINCIPAL__";
|
||||
public static final String NAME_MAXINTERVAL = "__SET__MAXINTERVAL__";
|
||||
public static final String NAME_ISNEW = "__SET__ISNEW__";
|
||||
public static final String NAME_AUTHTYPE = "__SET__AUTHTYPE__";
|
||||
public static final String NAME_LISTENER = "__SET__LISTENER__";
|
||||
|
||||
private String sessionId;
|
||||
private LinkedList<AttributeInfo> actions = new LinkedList<>();
|
||||
private final LinkedList<AttributeInfo> actionPool = new LinkedList<>();
|
||||
|
||||
private boolean recordAllActions = false;
|
||||
|
||||
public DeltaRequest() {
|
||||
|
||||
}
|
||||
|
||||
public DeltaRequest(String sessionId, boolean recordAllActions) {
|
||||
this.recordAllActions=recordAllActions;
|
||||
if(sessionId != null)
|
||||
setSessionId(sessionId);
|
||||
}
|
||||
|
||||
|
||||
public void setAttribute(String name, Object value) {
|
||||
int action = (value==null)?ACTION_REMOVE:ACTION_SET;
|
||||
addAction(TYPE_ATTRIBUTE,action,name,value);
|
||||
}
|
||||
|
||||
public void removeAttribute(String name) {
|
||||
addAction(TYPE_ATTRIBUTE, ACTION_REMOVE, name, null);
|
||||
}
|
||||
|
||||
public void setMaxInactiveInterval(int interval) {
|
||||
addAction(TYPE_MAXINTERVAL, ACTION_SET, NAME_MAXINTERVAL, Integer.valueOf(interval));
|
||||
}
|
||||
|
||||
/**
|
||||
* Only support principals from type {@link GenericPrincipal GenericPrincipal}
|
||||
* @param p Session principal
|
||||
* @see GenericPrincipal
|
||||
*/
|
||||
public void setPrincipal(Principal p) {
|
||||
int action = (p==null)?ACTION_REMOVE:ACTION_SET;
|
||||
GenericPrincipal gp = null;
|
||||
if (p != null) {
|
||||
if (p instanceof GenericPrincipal) {
|
||||
gp = (GenericPrincipal) p;
|
||||
if(log.isDebugEnabled())
|
||||
log.debug(sm.getString("deltaRequest.showPrincipal", p.getName() , getSessionId()));
|
||||
} else
|
||||
log.error(sm.getString("deltaRequest.wrongPrincipalClass",p.getClass().getName()));
|
||||
}
|
||||
addAction(TYPE_PRINCIPAL, action, NAME_PRINCIPAL, gp);
|
||||
}
|
||||
|
||||
public void setNew(boolean n) {
|
||||
int action = ACTION_SET;
|
||||
addAction(TYPE_ISNEW,action,NAME_ISNEW,Boolean.valueOf(n));
|
||||
}
|
||||
|
||||
public void setAuthType(String authType) {
|
||||
int action = (authType==null)?ACTION_REMOVE:ACTION_SET;
|
||||
addAction(TYPE_AUTHTYPE,action,NAME_AUTHTYPE, authType);
|
||||
}
|
||||
|
||||
public void addSessionListener(SessionListener listener) {
|
||||
addAction(TYPE_LISTENER, ACTION_SET, NAME_LISTENER ,listener);
|
||||
}
|
||||
|
||||
public void removeSessionListener(SessionListener listener) {
|
||||
addAction(TYPE_LISTENER, ACTION_REMOVE, NAME_LISTENER ,listener);
|
||||
}
|
||||
|
||||
protected void addAction(int type,
|
||||
int action,
|
||||
String name,
|
||||
Object value) {
|
||||
AttributeInfo info = null;
|
||||
if ( this.actionPool.size() > 0 ) {
|
||||
try {
|
||||
info = actionPool.removeFirst();
|
||||
}catch ( Exception x ) {
|
||||
log.error(sm.getString("deltaRequest.removeUnable"),x);
|
||||
info = new AttributeInfo(type, action, name, value);
|
||||
}
|
||||
info.init(type,action,name,value);
|
||||
} else {
|
||||
info = new AttributeInfo(type, action, name, value);
|
||||
}
|
||||
//if we have already done something to this attribute, make sure
|
||||
//we don't send multiple actions across the wire
|
||||
if ( !recordAllActions) {
|
||||
try {
|
||||
actions.remove(info);
|
||||
} catch (java.util.NoSuchElementException x) {
|
||||
//do nothing, we wanted to remove it anyway
|
||||
}
|
||||
}
|
||||
//add the action
|
||||
actions.addLast(info);
|
||||
}
|
||||
|
||||
public void execute(DeltaSession session, boolean notifyListeners) {
|
||||
if ( !this.sessionId.equals( session.getId() ) )
|
||||
throw new java.lang.IllegalArgumentException(sm.getString("deltaRequest.ssid.mismatch"));
|
||||
session.access();
|
||||
for ( int i=0; i<actions.size(); i++ ) {
|
||||
AttributeInfo info = actions.get(i);
|
||||
switch ( info.getType() ) {
|
||||
case TYPE_ATTRIBUTE:
|
||||
if ( info.getAction() == ACTION_SET ) {
|
||||
if ( log.isTraceEnabled() ) log.trace("Session.setAttribute('"+info.getName()+"', '"+info.getValue()+"')");
|
||||
session.setAttribute(info.getName(), info.getValue(),notifyListeners,false);
|
||||
} else {
|
||||
if ( log.isTraceEnabled() ) log.trace("Session.removeAttribute('"+info.getName()+"')");
|
||||
session.removeAttribute(info.getName(),notifyListeners,false);
|
||||
}
|
||||
|
||||
break;
|
||||
case TYPE_ISNEW:
|
||||
if ( log.isTraceEnabled() ) log.trace("Session.setNew('"+info.getValue()+"')");
|
||||
session.setNew(((Boolean)info.getValue()).booleanValue(),false);
|
||||
break;
|
||||
case TYPE_MAXINTERVAL:
|
||||
if ( log.isTraceEnabled() ) log.trace("Session.setMaxInactiveInterval('"+info.getValue()+"')");
|
||||
session.setMaxInactiveInterval(((Integer)info.getValue()).intValue(),false);
|
||||
break;
|
||||
case TYPE_PRINCIPAL:
|
||||
Principal p = null;
|
||||
if (info.getAction() == ACTION_SET) {
|
||||
p = (Principal) info.getValue();
|
||||
}
|
||||
session.setPrincipal(p,false);
|
||||
break;
|
||||
case TYPE_AUTHTYPE:
|
||||
String authType = null;
|
||||
if ( info.getAction() == ACTION_SET ) {
|
||||
authType = (String)info.getValue();
|
||||
}
|
||||
session.setAuthType(authType,false);
|
||||
break;
|
||||
case TYPE_LISTENER:
|
||||
SessionListener listener = (SessionListener) info.getValue();
|
||||
if (info.getAction() == ACTION_SET) {
|
||||
session.addSessionListener(listener,false);
|
||||
} else {
|
||||
session.removeSessionListener(listener,false);
|
||||
}
|
||||
break;
|
||||
default :
|
||||
throw new java.lang.IllegalArgumentException(sm.getString("deltaRequest.invalidAttributeInfoType", info));
|
||||
}//switch
|
||||
}//for
|
||||
session.endAccess();
|
||||
reset();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
while ( actions.size() > 0 ) {
|
||||
try {
|
||||
AttributeInfo info = actions.removeFirst();
|
||||
info.recycle();
|
||||
actionPool.addLast(info);
|
||||
}catch ( Exception x ) {
|
||||
log.error(sm.getString("deltaRequest.removeUnable"),x);
|
||||
}
|
||||
}
|
||||
actions.clear();
|
||||
}
|
||||
|
||||
public String getSessionId() {
|
||||
return sessionId;
|
||||
}
|
||||
public void setSessionId(String sessionId) {
|
||||
this.sessionId = sessionId;
|
||||
if ( sessionId == null ) {
|
||||
new Exception(sm.getString("deltaRequest.ssid.null")).fillInStackTrace().printStackTrace();
|
||||
}
|
||||
}
|
||||
public int getSize() {
|
||||
return actions.size();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
actions.clear();
|
||||
actionPool.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readExternal(java.io.ObjectInput in) throws IOException,ClassNotFoundException {
|
||||
//sessionId - String
|
||||
//recordAll - boolean
|
||||
//size - int
|
||||
//AttributeInfo - in an array
|
||||
reset();
|
||||
sessionId = in.readUTF();
|
||||
recordAllActions = in.readBoolean();
|
||||
int cnt = in.readInt();
|
||||
if (actions == null)
|
||||
actions = new LinkedList<>();
|
||||
else
|
||||
actions.clear();
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
AttributeInfo info = null;
|
||||
if (this.actionPool.size() > 0) {
|
||||
try {
|
||||
info = actionPool.removeFirst();
|
||||
} catch ( Exception x ) {
|
||||
log.error(sm.getString("deltaRequest.removeUnable"),x);
|
||||
info = new AttributeInfo();
|
||||
}
|
||||
}
|
||||
else {
|
||||
info = new AttributeInfo();
|
||||
}
|
||||
info.readExternal(in);
|
||||
actions.addLast(info);
|
||||
}//for
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void writeExternal(java.io.ObjectOutput out ) throws java.io.IOException {
|
||||
//sessionId - String
|
||||
//recordAll - boolean
|
||||
//size - int
|
||||
//AttributeInfo - in an array
|
||||
out.writeUTF(getSessionId());
|
||||
out.writeBoolean(recordAllActions);
|
||||
out.writeInt(getSize());
|
||||
for ( int i=0; i<getSize(); i++ ) {
|
||||
AttributeInfo info = actions.get(i);
|
||||
info.writeExternal(out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* serialize DeltaRequest
|
||||
* @see DeltaRequest#writeExternal(java.io.ObjectOutput)
|
||||
*
|
||||
* @return serialized delta request
|
||||
* @throws IOException IO error serializing
|
||||
*/
|
||||
protected byte[] serialize() throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(bos);
|
||||
writeExternal(oos);
|
||||
oos.flush();
|
||||
oos.close();
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
private static class AttributeInfo implements java.io.Externalizable {
|
||||
private String name = null;
|
||||
private Object value = null;
|
||||
private int action;
|
||||
private int type;
|
||||
|
||||
public AttributeInfo() {
|
||||
this(-1, -1, null, null);
|
||||
}
|
||||
|
||||
public AttributeInfo(int type,
|
||||
int action,
|
||||
String name,
|
||||
Object value) {
|
||||
super();
|
||||
init(type,action,name,value);
|
||||
}
|
||||
|
||||
public void init(int type,
|
||||
int action,
|
||||
String name,
|
||||
Object value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
this.action = action;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void recycle() {
|
||||
name = null;
|
||||
value = null;
|
||||
type=-1;
|
||||
action=-1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( ! (o instanceof AttributeInfo ) ) return false;
|
||||
AttributeInfo other = (AttributeInfo)o;
|
||||
return other.getName().equals(this.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readExternal(java.io.ObjectInput in ) throws IOException,ClassNotFoundException {
|
||||
//type - int
|
||||
//action - int
|
||||
//name - String
|
||||
//hasvalue - boolean
|
||||
//value - object
|
||||
type = in.readInt();
|
||||
action = in.readInt();
|
||||
name = in.readUTF();
|
||||
boolean hasValue = in.readBoolean();
|
||||
if ( hasValue ) value = in.readObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeExternal(java.io.ObjectOutput out) throws IOException {
|
||||
//type - int
|
||||
//action - int
|
||||
//name - String
|
||||
//hasvalue - boolean
|
||||
//value - object
|
||||
out.writeInt(getType());
|
||||
out.writeInt(getAction());
|
||||
out.writeUTF(getName());
|
||||
out.writeBoolean(getValue()!=null);
|
||||
if (getValue()!=null) out.writeObject(getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder("AttributeInfo[type=");
|
||||
buf.append(getType()).append(", action=").append(getAction());
|
||||
buf.append(", name=").append(getName()).append(", value=").append(getValue());
|
||||
buf.append(", addr=").append(super.toString()).append("]");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
1009
java/org/apache/catalina/ha/session/DeltaSession.java
Normal file
1009
java/org/apache/catalina/ha/session/DeltaSession.java
Normal file
File diff suppressed because it is too large
Load Diff
408
java/org/apache/catalina/ha/session/JvmRouteBinderValve.java
Normal file
408
java/org/apache/catalina/ha/session/JvmRouteBinderValve.java
Normal file
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* 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.session;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.apache.catalina.Cluster;
|
||||
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.ha.CatalinaCluster;
|
||||
import org.apache.catalina.ha.ClusterManager;
|
||||
import org.apache.catalina.ha.ClusterValve;
|
||||
import org.apache.catalina.session.ManagerBase;
|
||||
import org.apache.catalina.session.PersistentManager;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Valve to handle Tomcat jvmRoute takeover using mod_jk module after node
|
||||
* failure. After a node crashes, subsequent requests go to other cluster nodes.
|
||||
* That incurs a drop in performance. When this Valve is enabled on a backup
|
||||
* node and sees a request, which was intended for another (thus failed) node,
|
||||
* it will rewrite the cookie jsessionid information to use the route to this
|
||||
* backup cluster node, that answered the request. After the response is
|
||||
* delivered to the client, all subsequent client requests will go directly to
|
||||
* the backup node. The change of sessionid is also sent to all other cluster
|
||||
* nodes. After all that, the session stickiness will work directly to the
|
||||
* backup node and the traffic will not go back to the failed node after it is
|
||||
* restarted!
|
||||
*
|
||||
* <p>
|
||||
* Add this Valve to your cluster definition at conf/server.xml .
|
||||
*
|
||||
* <pre>
|
||||
* <Cluster>
|
||||
* <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve" />
|
||||
* </Cluster>
|
||||
* </pre>
|
||||
*
|
||||
* <em>A Trick:</em><br>
|
||||
* You can enable this mod_jk turnover mode via JMX before you drop a node to
|
||||
* all backup nodes! Set enable true on all JvmRouteBinderValve backups, disable
|
||||
* worker at mod_jk and then drop node and restart it! Then enable mod_jk worker
|
||||
* and disable JvmRouteBinderValves again. This use case means that only
|
||||
* requested sessions are migrated.
|
||||
*
|
||||
* @author Peter Rossbach
|
||||
*/
|
||||
public class JvmRouteBinderValve extends ValveBase implements ClusterValve {
|
||||
|
||||
/*--Static Variables----------------------------------------*/
|
||||
public static final Log log = LogFactory.getLog(JvmRouteBinderValve.class);
|
||||
|
||||
//------------------------------------------------------ Constructor
|
||||
public JvmRouteBinderValve() {
|
||||
super(true);
|
||||
}
|
||||
|
||||
/*--Instance Variables--------------------------------------*/
|
||||
|
||||
/**
|
||||
* the cluster
|
||||
*/
|
||||
protected CatalinaCluster cluster;
|
||||
|
||||
/**
|
||||
* The string manager for this package.
|
||||
*/
|
||||
protected static final StringManager sm = StringManager.getManager(JvmRouteBinderValve.class);
|
||||
|
||||
/**
|
||||
* enabled this component
|
||||
*/
|
||||
protected boolean enabled = true;
|
||||
|
||||
/**
|
||||
* number of session that no at this tomcat instance hosted
|
||||
*/
|
||||
protected long numberOfSessions = 0;
|
||||
|
||||
protected String sessionIdAttribute = "org.apache.catalina.ha.session.JvmRouteOrignalSessionID";
|
||||
|
||||
|
||||
/*--Logic---------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* set session id attribute to failed node for request.
|
||||
*
|
||||
* @return Returns the sessionIdAttribute.
|
||||
*/
|
||||
public String getSessionIdAttribute() {
|
||||
return sessionIdAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* get name of failed request session attribute
|
||||
*
|
||||
* @param sessionIdAttribute
|
||||
* The sessionIdAttribute to set.
|
||||
*/
|
||||
public void setSessionIdAttribute(String sessionIdAttribute) {
|
||||
this.sessionIdAttribute = sessionIdAttribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the number of migrated sessions.
|
||||
*/
|
||||
public long getNumberOfSessions() {
|
||||
return numberOfSessions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the enabled.
|
||||
*/
|
||||
public boolean getEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param enabled
|
||||
* The enabled to set.
|
||||
*/
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect possible the JVMRoute change at cluster backup node..
|
||||
*
|
||||
* @param request
|
||||
* tomcat request being processed
|
||||
* @param response
|
||||
* tomcat response being processed
|
||||
* @exception IOException
|
||||
* if an input/output error has occurred
|
||||
* @exception ServletException
|
||||
* if a servlet error has occurred
|
||||
*/
|
||||
@Override
|
||||
public void invoke(Request request, Response response) throws IOException,
|
||||
ServletException {
|
||||
|
||||
if (getEnabled() &&
|
||||
request.getContext() != null &&
|
||||
request.getContext().getDistributable() &&
|
||||
!request.isAsyncDispatching()) {
|
||||
// valve cluster can access manager - other cluster handle turnover
|
||||
// at host level - hopefully!
|
||||
Manager manager = request.getContext().getManager();
|
||||
|
||||
if (manager != null && (
|
||||
(manager instanceof ClusterManager
|
||||
&& getCluster() != null
|
||||
&& getCluster().getManager(((ClusterManager)manager).getName()) != null)
|
||||
||
|
||||
(manager instanceof PersistentManager))) {
|
||||
handlePossibleTurnover(request);
|
||||
}
|
||||
}
|
||||
// Pass this request on to the next valve in our pipeline
|
||||
getNext().invoke(request, response);
|
||||
}
|
||||
|
||||
/**
|
||||
* handle possible session turn over.
|
||||
*
|
||||
* @see JvmRouteBinderValve#handleJvmRoute(Request, String, String)
|
||||
* @param request current request
|
||||
*/
|
||||
protected void handlePossibleTurnover(Request request) {
|
||||
String sessionID = request.getRequestedSessionId() ;
|
||||
if (sessionID != null) {
|
||||
long t1 = System.currentTimeMillis();
|
||||
String jvmRoute = getLocalJvmRoute(request);
|
||||
if (jvmRoute == null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("jvmRoute.missingJvmRouteAttribute"));
|
||||
}
|
||||
return;
|
||||
}
|
||||
handleJvmRoute( request, sessionID, jvmRoute);
|
||||
if (log.isDebugEnabled()) {
|
||||
long t2 = System.currentTimeMillis();
|
||||
long time = t2 - t1;
|
||||
log.debug(sm.getString("jvmRoute.turnoverInfo", Long.valueOf(time)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get jvmroute from engine
|
||||
*
|
||||
* @param request current request
|
||||
* @return return jvmRoute from ManagerBase or null
|
||||
*/
|
||||
protected String getLocalJvmRoute(Request request) {
|
||||
Manager manager = getManager(request);
|
||||
if(manager instanceof ManagerBase) {
|
||||
return ((ManagerBase) manager).getJvmRoute();
|
||||
}
|
||||
return null ;
|
||||
}
|
||||
|
||||
/**
|
||||
* get ClusterManager
|
||||
*
|
||||
* @param request current request
|
||||
* @return manager or null
|
||||
*/
|
||||
protected Manager getManager(Request request) {
|
||||
Manager manager = request.getContext().getManager();
|
||||
if (log.isDebugEnabled()) {
|
||||
if(manager != null) {
|
||||
log.debug(sm.getString("jvmRoute.foundManager", manager, request.getContext().getName()));
|
||||
} else {
|
||||
log.debug(sm.getString("jvmRoute.notFoundManager", request.getContext().getName()));
|
||||
}
|
||||
}
|
||||
return manager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the cluster.
|
||||
*/
|
||||
@Override
|
||||
public CatalinaCluster getCluster() {
|
||||
return cluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param cluster The cluster to set.
|
||||
*/
|
||||
@Override
|
||||
public void setCluster(CatalinaCluster cluster) {
|
||||
this.cluster = cluster;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle jvmRoute stickiness after tomcat instance failed. After this
|
||||
* correction a new Cookie send to client with new jvmRoute and the
|
||||
* SessionID change propagate to the other cluster nodes.
|
||||
*
|
||||
* @param request current request
|
||||
* @param sessionId
|
||||
* request SessionID from Cookie
|
||||
* @param localJvmRoute
|
||||
* local jvmRoute
|
||||
*/
|
||||
protected void handleJvmRoute(
|
||||
Request request, String sessionId, String localJvmRoute) {
|
||||
// get requested jvmRoute.
|
||||
String requestJvmRoute = null;
|
||||
int index = sessionId.indexOf('.');
|
||||
if (index > 0) {
|
||||
requestJvmRoute = sessionId
|
||||
.substring(index + 1, sessionId.length());
|
||||
}
|
||||
if (requestJvmRoute != null && !requestJvmRoute.equals(localJvmRoute)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("jvmRoute.failover", requestJvmRoute,
|
||||
localJvmRoute, sessionId));
|
||||
}
|
||||
Session catalinaSession = null;
|
||||
try {
|
||||
catalinaSession = getManager(request).findSession(sessionId);
|
||||
} catch (IOException e) {
|
||||
// Hups!
|
||||
}
|
||||
String id = sessionId.substring(0, index);
|
||||
String newSessionID = id + "." + localJvmRoute;
|
||||
// OK - turnover the session and inform other cluster nodes
|
||||
if (catalinaSession != null) {
|
||||
changeSessionID(request, sessionId, newSessionID,
|
||||
catalinaSession);
|
||||
numberOfSessions++;
|
||||
} else {
|
||||
try {
|
||||
catalinaSession = getManager(request).findSession(newSessionID);
|
||||
} catch (IOException e) {
|
||||
// Hups!
|
||||
}
|
||||
if (catalinaSession != null) {
|
||||
// session is rewrite at other request, rewrite this also
|
||||
changeRequestSessionID(request, sessionId, newSessionID);
|
||||
} else {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("jvmRoute.cannotFindSession",sessionId));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* change session id and send to all cluster nodes
|
||||
*
|
||||
* @param request current request
|
||||
* @param sessionId
|
||||
* original session id
|
||||
* @param newSessionID
|
||||
* new session id for node migration
|
||||
* @param catalinaSession
|
||||
* current session with original session id
|
||||
*/
|
||||
protected void changeSessionID(Request request, String sessionId,
|
||||
String newSessionID, Session catalinaSession) {
|
||||
fireLifecycleEvent("Before session migration", catalinaSession);
|
||||
catalinaSession.getManager().changeSessionId(catalinaSession, newSessionID);
|
||||
changeRequestSessionID(request, sessionId, newSessionID);
|
||||
fireLifecycleEvent("After session migration", catalinaSession);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("jvmRoute.changeSession", sessionId,
|
||||
newSessionID));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change Request Session id
|
||||
* @param request current request
|
||||
* @param sessionId
|
||||
* original session id
|
||||
* @param newSessionID
|
||||
* new session id for node migration
|
||||
*/
|
||||
protected void changeRequestSessionID(Request request, String sessionId, String newSessionID) {
|
||||
request.changeSessionId(newSessionID);
|
||||
|
||||
// set original sessionid at request, to allow application detect the
|
||||
// change
|
||||
if (sessionIdAttribute != null && !"".equals(sessionIdAttribute)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("jvmRoute.set.orignalsessionid",sessionIdAttribute,sessionId));
|
||||
}
|
||||
request.setAttribute(sessionIdAttribute, sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info(sm.getString("jvmRoute.valve.started"));
|
||||
if (cluster == null) {
|
||||
log.info(sm.getString("jvmRoute.noCluster"));
|
||||
}
|
||||
}
|
||||
|
||||
super.startInternal();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stop this component 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 synchronized void stopInternal() throws LifecycleException {
|
||||
|
||||
super.stopInternal();
|
||||
|
||||
cluster = null;
|
||||
numberOfSessions = 0;
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info(sm.getString("jvmRoute.valve.stopped"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
90
java/org/apache/catalina/ha/session/LocalStrings.properties
Normal file
90
java/org/apache/catalina/ha/session/LocalStrings.properties
Normal file
@@ -0,0 +1,90 @@
|
||||
# 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.
|
||||
|
||||
backupManager.noCluster=no cluster associated with this context: [{0}]
|
||||
backupManager.startFailed=Failed to start BackupManager: [{0}]
|
||||
backupManager.startUnable=Unable to start BackupManager: [{0}]
|
||||
backupManager.stopped=Manager [{0}] is stopping
|
||||
|
||||
clusterSessionListener.noManager=Context manager doesn''t exist:[{0}]
|
||||
|
||||
deltaManager.createMessage.access=Manager [{0}]: create session access message for session [{1}]
|
||||
deltaManager.createMessage.accessChangePrimary=Manager [{0}]: create change primary node message for session [{1}]
|
||||
deltaManager.createMessage.allSessionData=Manager [{0}] sent all session data.
|
||||
deltaManager.createMessage.allSessionTransfered=Manager [{0}] sent all session data transferred
|
||||
deltaManager.createMessage.delta=Manager [{0}]: create delta request message for session [{1}]
|
||||
deltaManager.createMessage.expire=Manager [{0}]: create session expire message for session [{1}]
|
||||
deltaManager.createMessage.unableCreateDeltaRequest=Unable to serialize delta request for sessionid [{0}]
|
||||
deltaManager.createSession.newSession=Created a new DeltaSession with Id [{0}] Total count=[{1}]
|
||||
deltaManager.dropMessage=Manager [{0}]: Drop message [{1}] inside GET_ALL_SESSIONS sync phase start date [{2}] message date [{3}]
|
||||
deltaManager.expireSessions=Manager [{0}] expiring sessions upon shutdown
|
||||
deltaManager.foundMasterMember=Found for context [{0}] the replication master member [{1}]
|
||||
deltaManager.loading.cnfe=ClassNotFoundException while loading persisted sessions: [{0}]
|
||||
deltaManager.loading.existing.session=overload existing session [{0}]
|
||||
deltaManager.loading.ioe=IOException while loading persisted sessions: [{0}]
|
||||
deltaManager.managerLoad=Exception loading sessions from persistent storage
|
||||
deltaManager.noCluster=Starting... no cluster associated with this context: [{0}]
|
||||
deltaManager.noContextManager=Manager [{0}]: In reply to the ''Get all session data'' message sent at [{1}], a ''No matching context manager'' message was received after [{2}] ms.
|
||||
deltaManager.noMasterMember=Starting... with no other member for context [{0}] at domain [{1}]
|
||||
deltaManager.noMembers=Manager [{0}]: skipping state transfer. No members active in cluster group.
|
||||
deltaManager.noSessionState=Manager [{0}]: No session state sent at [{1}] received, timing out after [{2}] ms.
|
||||
deltaManager.receiveMessage.accessed=Manager [{0}]: received session accessed message for session [{1}]
|
||||
deltaManager.receiveMessage.allSessionDataAfter=Manager [{0}]: all session state deserialized
|
||||
deltaManager.receiveMessage.allSessionDataBegin=Manager [{0}]: received all session state data
|
||||
deltaManager.receiveMessage.createNewSession=Manager [{0}]: received session created message for session [{1}]
|
||||
deltaManager.receiveMessage.delta=Manager [{0}]: received session delta message for session [{1}]
|
||||
deltaManager.receiveMessage.delta.unknown=Manager [{0}]: received session delta for unknown session [{1}]
|
||||
deltaManager.receiveMessage.error=Manager [{0}]: Unable to receive message through TCP channel
|
||||
deltaManager.receiveMessage.eventType=Manager [{0}]: Received SessionMessage of type=[{1}] from [{2}]
|
||||
deltaManager.receiveMessage.expired=Manager [{0}]: received session expired message for session [{1}]
|
||||
deltaManager.receiveMessage.noContextManager=Manager [{0}] received from node [{1}:{2}] no context manager.
|
||||
deltaManager.receiveMessage.transfercomplete=Manager [{0}] received from node [{1}:{2}] session state transfered.
|
||||
deltaManager.receiveMessage.unloadingAfter=Manager [{0}]: unloading sessions complete
|
||||
deltaManager.receiveMessage.unloadingBegin=Manager [{0}]: start unloading sessions
|
||||
deltaManager.registerCluster=Register manager [{0}] to cluster element [{1}] with name [{2}]
|
||||
deltaManager.sendMessage.newSession=Manager [{0}] send new session [{1}]
|
||||
deltaManager.sessionReceived=Manager [{0}]; session state sent at [{1}] received in [{2}] ms.
|
||||
deltaManager.startClustering=Starting clustering manager at [{0}]
|
||||
deltaManager.stopped=Manager [{0}] is stopping
|
||||
deltaManager.unableSerializeSessionID=Unable to serialize sessionID [{0}]
|
||||
deltaManager.unloading.ioe=IOException while saving persisted sessions: [{0}]
|
||||
deltaManager.waitForSessionState=Manager [{0}], requesting session state from [{1}]. This operation will timeout if no session state has been received within [{2}] seconds.
|
||||
|
||||
deltaRequest.invalidAttributeInfoType=Invalid attribute info type=[{0}]
|
||||
deltaRequest.removeUnable=Unable to remove element:
|
||||
deltaRequest.showPrincipal=Principal [{0}] is set to session [{1}]
|
||||
deltaRequest.ssid.mismatch=Session id mismatch, not executing the delta request
|
||||
deltaRequest.ssid.null=Session Id is null for setSessionId
|
||||
deltaRequest.wrongPrincipalClass=ClusterManager only support GenericPrincipal. Your realm used principal class [{0}].
|
||||
|
||||
deltaSession.notifying=Notifying cluster of session expiration: primary=[{0}], sessionId [{1}]
|
||||
deltaSession.readSession=readObject() loading session [{0}]
|
||||
deltaSession.writeSession=writeObject() storing session [{0}]
|
||||
|
||||
jvmRoute.cannotFindSession=Cannot find session [{0}]
|
||||
jvmRoute.changeSession=Changed session from [{0}] to [{1}]
|
||||
jvmRoute.failover=Detected a failover with different jvmRoute - orginal route: [{0}] new one: [{1}] at session id [{2}]
|
||||
jvmRoute.foundManager=Found Cluster Manager [{0}] at [{1}]
|
||||
jvmRoute.missingJvmRouteAttribute=No engine jvmRoute attribute configured!
|
||||
jvmRoute.noCluster=The JvmRouterBinderValve is configured, but clustering is not being used. Fail over will still work, providing a PersistentManager is used.
|
||||
jvmRoute.notFoundManager=Not found Cluster Manager at [{0}]
|
||||
jvmRoute.set.orignalsessionid=Set Orginal Session id at request attribute [{0}] value: [{1}]
|
||||
jvmRoute.turnoverInfo=Turnover Check time [{0}] msec
|
||||
jvmRoute.valve.started=JvmRouteBinderValve started
|
||||
jvmRoute.valve.stopped=JvmRouteBinderValve stopped
|
||||
|
||||
standardSession.notSerializable=Cannot serialize session attribute [{0}] for session [{1}]
|
||||
standardSession.removeAttribute.ise=removeAttribute: Session already invalidated
|
||||
standardSession.setAttribute.namenull=setAttribute: name parameter cannot be null
|
||||
@@ -0,0 +1,26 @@
|
||||
# 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.
|
||||
|
||||
deltaManager.foundMasterMember=Für den Kontext [{0}] wurde der Replikationsmaster [{1}] gefunden
|
||||
deltaManager.noContextManager=Manager [{0}]: Als Antwort auf eine um [{1}] gesendete "Hole alle Sitzungsdaten"-Nachricht, wurde nach [{2}] ms eine "Kein passender Context-Manager"-Nachricht empfangen.
|
||||
deltaManager.receiveMessage.allSessionDataBegin=Manager [{0}]: alle Sitzungsdaten empfangen
|
||||
deltaManager.receiveMessage.delta.unknown=Manager [{0}]: Habe Session-Delta für unbekannte Session [{1}] empfangen
|
||||
deltaManager.receiveMessage.unloadingBegin=Manager [{0}]: Beginne die Sessions zu entladen
|
||||
deltaManager.unloading.ioe=IOExceptio während des Speichers der Persisted Sessions: [{0}]
|
||||
|
||||
deltaRequest.removeUnable=Kann Element nicht entfernen:
|
||||
deltaRequest.wrongPrincipalClass=Der ClusterManager unterstützt nur GenericPrincipal. Ihr Realm benutzt die Principal Klasse [{0}].
|
||||
|
||||
jvmRoute.valve.started=JvmRouteBinderValve gestartet
|
||||
@@ -0,0 +1,81 @@
|
||||
# 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.
|
||||
|
||||
backupManager.startUnable=Imposible de iniciar BackupManager: [{0}]\n
|
||||
|
||||
deltaManager.createMessage.access=Gestor [{0}]: creado mensaje de sesión [{1}] acceso.
|
||||
deltaManager.createMessage.accessChangePrimary=Gestor [{0}]: creado mensaje de sesión [{1}] acceso para cambiar el primario.
|
||||
deltaManager.createMessage.allSessionData=Gestor [{0}] envía todos los datos de sesión.
|
||||
deltaManager.createMessage.allSessionTransfered=Gestor [{0}] envía todos los datos de sesión transferidos
|
||||
deltaManager.createMessage.delta=Gestor [{0}]: crea mensaje de sesión [{1}] de requerimiento delta.
|
||||
deltaManager.createMessage.expire=Gestor [{0}]: crea mensaje de sesión [{1}] de expiración.
|
||||
deltaManager.createMessage.unableCreateDeltaRequest=No puedo serializar requerimiento delta para la id de sesión [{0}]
|
||||
deltaManager.createSession.newSession=Creada una DeltaSession con Id [{0}] Total contador=[{1}]
|
||||
deltaManager.dropMessage=Gestor [{0}]: Quita mensaje [{1}] dentro de fase sincronizada GET_ALL_SESSIONS fecha inicio [{2}] fecha mensaje [{3}]
|
||||
deltaManager.expireSessions=Gestor [{0}] expirando sesiones al apagar
|
||||
deltaManager.foundMasterMember=Hallado para contexto [{0}] el miembro maestro de réplica [{1}]
|
||||
deltaManager.loading.cnfe=ClassNotFoundException al cargar sesiones persistentes: [{0}]
|
||||
deltaManager.loading.existing.session=sobrecarga en sesión existente [{0}]
|
||||
deltaManager.loading.ioe=IOException al cargar sesiones persistentes: [{0}]
|
||||
deltaManager.managerLoad=Excepción cargando sesiones desde almacenaje persistente
|
||||
deltaManager.noCluster=Arrancando... no hay clúster asociado con este contexto: [{0}]
|
||||
deltaManager.noContextManager=Manejador [{0}]: En respuesta al mensaje ''Tomar todos los datos de sesión (Get all session data)'' enviado a [{1}], recibión el mensaje ''El manejador no machea con ningún contexto (No matching context manager)'' luego de [{2}] ms.\n
|
||||
deltaManager.noMasterMember=Arrancando... sin otro miembro para el contexto [{0}] en dominio [{1}]
|
||||
deltaManager.noMembers=Gestor [{0}]: saltando estado de transferencia. No hay miembros activos en grupo de clúster.
|
||||
deltaManager.noSessionState=Gestor [{0}]: No se ha recibido estado de sesión a las [{1}], agotando tiempo tras [{2}] ms.
|
||||
deltaManager.receiveMessage.accessed=Gestor [{0}]: accedida sesión [{1}] recibida.
|
||||
deltaManager.receiveMessage.allSessionDataAfter=Gestor [{0}]: estado de sesión deserializado
|
||||
deltaManager.receiveMessage.allSessionDataBegin=Gestor [{0}]: recibidos datos de estado de sesión
|
||||
deltaManager.receiveMessage.createNewSession=Gestor [{0}]: creada sesión [{1}] recibida.
|
||||
deltaManager.receiveMessage.delta=Gestor [{0}]: delta sesión [{1}] recibida.
|
||||
deltaManager.receiveMessage.delta.unknown=Manejador [{0}]: recibió una diferencia de sesión para una sesión desconocida [{1}]
|
||||
deltaManager.receiveMessage.error=Gestor [{0}]: No puedo recibir mensaje a través del canal TCP
|
||||
deltaManager.receiveMessage.eventType=Gestor [{0}]: recibido SessionMessage de tipo=[{1}] desde [{2}]
|
||||
deltaManager.receiveMessage.expired=Gestor [{0}]: expirada sesión [{1}] recibida.
|
||||
deltaManager.receiveMessage.transfercomplete=Gestor [{0}] recibido desde nodo [{1}:{2}] estado de sesión transferido.
|
||||
deltaManager.receiveMessage.unloadingAfter=Gestor [{0}]: completada la descarga de sesiones
|
||||
deltaManager.receiveMessage.unloadingBegin=Gestor [{0}]: iniciada descarga de sesiones
|
||||
deltaManager.registerCluster=Registrar gestor [{0}] a elemento de clúster [{1}] con nombre [{2}]
|
||||
deltaManager.sendMessage.newSession=El gestor [{0}] envía nueva sesión [{1}]
|
||||
deltaManager.sessionReceived=Gestor [{0}]; estado de sesión enviado a las [{1}] recibido en [{2}] ms.
|
||||
deltaManager.startClustering=Iniciando gestor de clúster a las [{0}]
|
||||
deltaManager.stopped=El gestor [{0}] se está parando
|
||||
deltaManager.unableSerializeSessionID=No puedo seriallizar la ID de sesión [{0}]
|
||||
deltaManager.unloading.ioe=IOException al grabar sesiones persistentes: [{0}]
|
||||
deltaManager.waitForSessionState=Gestor [{0}], requiriendo estado de sesión desde [{1}]. Esta operación se agotará si no se recibe estado de sesión dentro de [{2}] segundos.
|
||||
|
||||
deltaRequest.removeUnable=Imposible eliminar elemento:
|
||||
deltaRequest.showPrincipal=El Principal [{0}] está puesto a sesión [{1}]
|
||||
deltaRequest.wrongPrincipalClass=DeltaManager sólo soporta GenericPrincipal. Tu reino utilizó clase principal [{0}].
|
||||
|
||||
deltaSession.notifying=Notificando clúster de expiración primaria=[{0}] sessionId [{1}]
|
||||
deltaSession.readSession=readObject() cargando sesión [{0}]
|
||||
deltaSession.writeSession=writeObject() guardando sesión [{0}]
|
||||
|
||||
jvmRoute.cannotFindSession=No puedo hallar sesión [{0}]
|
||||
jvmRoute.changeSession=Cambiada sesión desde [{0}] a [{1}]
|
||||
jvmRoute.failover=Detectada una caída con diferente jvmRoute - ruta original: [{0}] nueva: [{1}] en id de sesión [{2}]
|
||||
jvmRoute.foundManager=Hallado Clúster DeltaManager [{0}] en [{1}]
|
||||
jvmRoute.missingJvmRouteAttribute=¡No se ha configurado atributo de motor jvmRoute!
|
||||
jvmRoute.noCluster=La válvula JvmRouterBinderValve se encuentra configurada, pero no se usa el clúster. Aún funcionará la tolerancia a fallos, siempre que se esté usando PersistentManager.
|
||||
jvmRoute.notFoundManager=No hallado Clúster DeltaManager [{0}] en [{1}]
|
||||
jvmRoute.set.orignalsessionid=Puesta id Orginal de Sesión en atributo de requerimiento [{0}] valor: [{1}]
|
||||
jvmRoute.turnoverInfo=Ajustado tiempo de Chequeo a [{0}] mseg
|
||||
jvmRoute.valve.started=JvmRouteBinderValve arrancada
|
||||
jvmRoute.valve.stopped=JvmRouteBinderValve parada
|
||||
|
||||
standardSession.notSerializable=No puedo serializar atributo de sesión [{0}] para sesión [{1}]
|
||||
standardSession.removeAttribute.ise=removeAttribute: Sesión ya invalidada
|
||||
standardSession.setAttribute.namenull=setAttribute: parámetro de nombre no puede ser nulo
|
||||
@@ -0,0 +1,90 @@
|
||||
# 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.
|
||||
|
||||
backupManager.noCluster=pas de groupe (cluster) associé à ce contexte: [{0}]
|
||||
backupManager.startFailed=Impossible de démarrer le BackupManager: [{0}]
|
||||
backupManager.startUnable=Impossible de démarrer le BackupManager: [{0}]
|
||||
backupManager.stopped=Le gestionnaire de session [{0}] s''est arrêté
|
||||
|
||||
clusterSessionListener.noManager=Le gestionnaire de session du contexte n''existe pas: [{0}]
|
||||
|
||||
deltaManager.createMessage.access=Gestionnaire de session [{0}]: création du message de session [{1}] d''accès
|
||||
deltaManager.createMessage.accessChangePrimary=Gestionnaire de session [{0}] : création du message de session [{1}] accès pour changer le primaire
|
||||
deltaManager.createMessage.allSessionData=Gestionnaire de session [{0}] envoyé toutes les données de session
|
||||
deltaManager.createMessage.allSessionTransfered=Gestionnaire de session [{0}] envoi du message signalant le transfert de toutes les données de session
|
||||
deltaManager.createMessage.delta=Gestionnaire de session [{0}]: création du message [{0}] de requête delta
|
||||
deltaManager.createMessage.expire=Gestionnaire de session [{0}]: création du message [{1}] d''expiration de session
|
||||
deltaManager.createMessage.unableCreateDeltaRequest=Impossible de sérialiser la requête delta pour l''id de session [{0}]
|
||||
deltaManager.createSession.newSession=Crée une DeltaSession avec Id [{0}] Nombre total=[{1}]
|
||||
deltaManager.dropMessage=Gestionnaire de session [{0}] : Abandon du message [{1}] dans GET_ALL_SESSIONS début de la phase de sync [{2}] date du message [{3}]
|
||||
deltaManager.expireSessions=Gestionnaire de session [{0}] expiration des sessions lors de l''arrêt
|
||||
deltaManager.foundMasterMember=Le membre maître [{1}] a été trouvé pour la réplication du contexte [{0}]
|
||||
deltaManager.loading.cnfe=Exception ClassNotFoundException lors du chargement des sessions persistantes : [{0}]
|
||||
deltaManager.loading.existing.session=la session existante [{0}] est surchargée
|
||||
deltaManager.loading.ioe=IOException lors du chargement des session persistées: [{0}]
|
||||
deltaManager.managerLoad=Exception lors du chargement des sessions depuis le stockage persistant
|
||||
deltaManager.noCluster=Démarrage, pas de cluster associé à ce contexte [{0}]
|
||||
deltaManager.noContextManager=Gestionnaire de session [{0}]: En réponse à l''envoi d''un message demandant toutes les données des sessions à [{0}], un message indiquant l''absence d''un gestionnaire de sessions correspondant à été reçu au bout de [{2}] ms
|
||||
deltaManager.noMasterMember=Démarrage sans autre membre pour le contexte [{0}] du domaine [{1}]
|
||||
deltaManager.noMembers=Gestionnaire de session [{0}] : pas de transfert d''état, il n''y a pas de membres actifs dans le cluster
|
||||
deltaManager.noSessionState=Gestionnaire de session [{0}] : pas de statut de session envoyé à [{1}] reçu, délai d''attente maximum de [{2}] ms.
|
||||
deltaManager.receiveMessage.accessed=Gestionnaire de session [{0}] : reçu un accès à la session [{1}]
|
||||
deltaManager.receiveMessage.allSessionDataAfter=Gestionnaire de session [{0}] : l''état de la session a été désérialisé
|
||||
deltaManager.receiveMessage.allSessionDataBegin=Gestionnaire de session [{0}] : : reçu les données d''état des sessions
|
||||
deltaManager.receiveMessage.createNewSession=Gestionnaire de session [{0}] : reçu la création de la session [{1}]
|
||||
deltaManager.receiveMessage.delta=Gestionnaire de session [{0}] : reçu le delta de session [{1}]
|
||||
deltaManager.receiveMessage.delta.unknown=Gestionnaire de session [{0}] : reçu un delta pour une session inconnue [{1}]
|
||||
deltaManager.receiveMessage.error=Gestionnaire de session [{0}] : impossible de recevoir un message par le canal TCP
|
||||
deltaManager.receiveMessage.eventType=Gestionnaire de session [{0}] : recu un SessionMessage de type=[{1}] de [{2}]
|
||||
deltaManager.receiveMessage.expired=Gestionnaire de session [{0}] : reçu l''expiration de la session [{1}]
|
||||
deltaManager.receiveMessage.noContextManager=Gestionnaire de session [{0}] a reçu d''un nœud [{1}:{2}] sans gestionnaire de contexte
|
||||
deltaManager.receiveMessage.transfercomplete=Gestionnaire de session [{0}] reçu du nœud [{1}:{2}] l''état de la session a été transféré
|
||||
deltaManager.receiveMessage.unloadingAfter=Gestionnaire de session [{0}] : fin du déchargement des sessions
|
||||
deltaManager.receiveMessage.unloadingBegin=Gestionnaire de session [{0}] : début du déchargement des sessions
|
||||
deltaManager.registerCluster=Enregistrement du gestionnaire [{0}] dans l''élément du cluster [{1}] avec le nom [{2}]
|
||||
deltaManager.sendMessage.newSession=Gestionnaire de session [{0}] : envoi de la nouvelle session [{1}]
|
||||
deltaManager.sessionReceived=Gestionnaire de session [{0}]: l''état de session envoyé à [{0}] a été reçu en [{2}] ms
|
||||
deltaManager.startClustering=Démarrage du gestionnaire du cluster à [{0}]
|
||||
deltaManager.stopped=Le gestionnaire de session [{0}] s''arrête
|
||||
deltaManager.unableSerializeSessionID=Impossible de sérialiser le sessionID [{0}]
|
||||
deltaManager.unloading.ioe=IOException lors de la sauvegarde des sessions persistantes: [{0}]
|
||||
deltaManager.waitForSessionState=Gestionnaire de session [{0}], demande de l''état de session depuis [{1}], cette opération fera un timeout si l''état de la session n''a pas été reçu en moins de [{2}] secondes
|
||||
|
||||
deltaRequest.invalidAttributeInfoType=Info d''attribut invalide = [{0}]
|
||||
deltaRequest.removeUnable=N'a pas pu enlever l'élément:
|
||||
deltaRequest.showPrincipal=Le principal [{0}] est associé à la session [{1}]
|
||||
deltaRequest.ssid.mismatch=L'id de session ne correspond pas, la requête delta ne sera pas exécutée
|
||||
deltaRequest.ssid.null=L'id de session est null pour setSessionId
|
||||
deltaRequest.wrongPrincipalClass=Un ClusterManager n''accepte que des GenericPrincipal. Votre realm a utilisé la classe de "principal" [{0}]
|
||||
|
||||
deltaSession.notifying=Notification du cluster de l''expiration de la session: primaire=[{0}] sessionId [{1}]
|
||||
deltaSession.readSession=readObject() charge la session [{0}]
|
||||
deltaSession.writeSession=writeObject() stocke la session [{0}]
|
||||
|
||||
jvmRoute.cannotFindSession=Impossible de trouver la session [{0}]
|
||||
jvmRoute.changeSession=Changé la session de [{0}] vers [{1}]
|
||||
jvmRoute.failover=Un changement de serveur a été détecté avec une jvmRoute différente, route originale: [{0}] nouvelle: [{1}] pour l''id de session [{2}]
|
||||
jvmRoute.foundManager=Trouvé le gestionnaire de session du cluster [{0}] à [{1}]
|
||||
jvmRoute.missingJvmRouteAttribute=Pas d'attribut jvmRoute configuré sur le moteur
|
||||
jvmRoute.noCluster=La JvmRouterBinderValve est configurée mais le cluster n'est pas activé, la bascule vers un autre serveur fonctionnera tout de même à condition qu'un PersistentManager soit utilisé
|
||||
jvmRoute.notFoundManager=Gestionnaire de cluster ("Cluster Manager") non trouvé à [{0}]
|
||||
jvmRoute.set.orignalsessionid=Fixe l''id de session d''origine dans l''attribut de requête [{0}] valeur: [{1}]
|
||||
jvmRoute.turnoverInfo=Temps de vérification de turnover [{0}] ms
|
||||
jvmRoute.valve.started=La JvmRouteBinderValve a démarrée
|
||||
jvmRoute.valve.stopped=JvmRouteBinderValve s'est arrêté
|
||||
|
||||
standardSession.notSerializable=Impossible de sérialiser l''attribut de session [{0}] pour la session [{1}]
|
||||
standardSession.removeAttribute.ise=removeAttribute : session déjà invalidée
|
||||
standardSession.setAttribute.namenull=setAttribute: le paramètre nom ne peut pas être null
|
||||
@@ -0,0 +1,90 @@
|
||||
# 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.
|
||||
|
||||
backupManager.noCluster=コンテキスト: [{0}]にクラスターが関連付けられていません。
|
||||
backupManager.startFailed=BackupManager: [{0}]の起動に失敗しました。
|
||||
backupManager.startUnable=BackupManager を開始できません。: [{0}]
|
||||
backupManager.stopped=Manager [{0}] を停止します。
|
||||
|
||||
clusterSessionListener.noManager=Context Managerが存在しません。
|
||||
|
||||
deltaManager.createMessage.access=Manager [{0}]: セッション [{1}] へのアクセスメッセージを作成します。
|
||||
deltaManager.createMessage.accessChangePrimary=Manager[{0}]: セッション [{1}] でプライマリノード変更メッセージを作成しました。
|
||||
deltaManager.createMessage.allSessionData=Manager [{0}] はすべてのセッションデータを送信しました。
|
||||
deltaManager.createMessage.allSessionTransfered=Manager [{0}]はすべてのセッションデータ転送を送信しました。
|
||||
deltaManager.createMessage.delta=Manager [{0}]:セッション[{1}]のデルタリクエストメッセージを作成します
|
||||
deltaManager.createMessage.expire=Manager [{0}]:セッション[{1}]のセッションの期限切れメッセージを作成します。
|
||||
deltaManager.createMessage.unableCreateDeltaRequest=セッションID [{0}]のDeltaRequestシリアライズできません。
|
||||
deltaManager.createSession.newSession=DeltaSession (ID は [{0}]) を作成しました。総数は [{1}] です。
|
||||
deltaManager.dropMessage=Manager [{0}]:GET_ALL_SESSIONS同期フェーズの開始日[{2}] メッセージの日付[{3}]内のメッセージ[{1}]をドロップします。
|
||||
deltaManager.expireSessions=シャットダウン時にManager[{0}]はセッションを満了します。
|
||||
deltaManager.foundMasterMember=コンテキスト [{0}] のレプリケーションマスターメンバー [{1}] を発見しました。
|
||||
deltaManager.loading.cnfe=永続セッションのロード中にClassNotFoundExceptionが発生しました:[{0}]
|
||||
deltaManager.loading.existing.session=既存セッション[{0}]のオーバーロード
|
||||
deltaManager.loading.ioe=永続化セッションの読み込み中に IOException が発生しました: [{0}]
|
||||
deltaManager.managerLoad=永続化ストレージからセッションの読み込み中に例外が発生しました。
|
||||
deltaManager.noCluster=Starting ...このコンテキスト[{0}]に関連付けられたクラスタはありません。
|
||||
deltaManager.noContextManager=マネージャ[{0}]:[{2}] msで[{1}]でNo Context Managerの送信が受信されました
|
||||
deltaManager.noMasterMember=ドメイン[{1}]のコンテキスト[{0}]に他のメンバーがいない状態で開始しています。
|
||||
deltaManager.noMembers=Manager [{0}]:状態転送をスキップします。 クラスタグループ内でアクティブなメンバーはいません。
|
||||
deltaManager.noSessionState=Manager [{0}]:[{1}]で送信されたセッション状態はありませんでした。[{2}] ms後にタイムアウトしました。
|
||||
deltaManager.receiveMessage.accessed=Manager [{0}]:セッション[{1}]のセッションアクセスメッセージを受信しました。
|
||||
deltaManager.receiveMessage.allSessionDataAfter=Manager[{0}]: 全てのセッション状態をデシリアライズしました。
|
||||
deltaManager.receiveMessage.allSessionDataBegin=Manager[{0}]:すべてのセッション状態データを受信しました。
|
||||
deltaManager.receiveMessage.createNewSession=Manager [{0}]:セッション[{1}]のセッション作成メッセージを受信しました。
|
||||
deltaManager.receiveMessage.delta=Manager [{0}]:セッション[{1}]のセッションデルタメッセージを受信しました。
|
||||
deltaManager.receiveMessage.delta.unknown=マネージャ[{0}]:未知のセッション[{1}]デルタを受信しました。
|
||||
deltaManager.receiveMessage.error=Manager [{0}]: TCP チャンネルからメッセージを受信できません。
|
||||
deltaManager.receiveMessage.eventType=Manager[{0}]: [{2}] からセッションメッセージ [{1}] を受信しました。
|
||||
deltaManager.receiveMessage.expired=Manager[{0}]:セッション[{1}]のセッションの期限切れメッセージを受信しました。
|
||||
deltaManager.receiveMessage.noContextManager=Manager [{0}]はノード[{1}:{2}]からコンテキストマネージャ無しメッセージを受信しました。
|
||||
deltaManager.receiveMessage.transfercomplete=Manager [{0}]はノード[{1}:{2}]からセッション状態が転送を受信しました。
|
||||
deltaManager.receiveMessage.unloadingAfter=Manager[{0}]:セッションのアンロードが完了しました。
|
||||
deltaManager.receiveMessage.unloadingBegin=Manager [{0}]:セッションのアンロードを開始します
|
||||
deltaManager.registerCluster=マネージャー [{0}] をクラスターの構成要素 [{1}] に名前 [{2}] で登録しました。
|
||||
deltaManager.sendMessage.newSession=Manager[{0}]が新しいセッションを送信します。[{1}]
|
||||
deltaManager.sessionReceived=Manager [{0}]; [{2}] msで受信した[{1}]で送信されたセッション状態。
|
||||
deltaManager.startClustering=[{0}]でクラスタリングマネージャを開始しています。
|
||||
deltaManager.stopped=マネージャ[{0}]が停止しています
|
||||
deltaManager.unableSerializeSessionID=セッション ID [{0}] をシリアライズできません。
|
||||
deltaManager.unloading.ioe=永続セッションを保存中のIOException:[{0}]
|
||||
deltaManager.waitForSessionState=Manager[{0}]、[{1}]からのセッション状態を要求しています。 [{2}]秒以内にセッション状態が受信されなかった場合、この操作はタイムアウトになります。
|
||||
|
||||
deltaRequest.invalidAttributeInfoType=無効な属性情報タイプ= [{0}]
|
||||
deltaRequest.removeUnable=要素を削除できません。
|
||||
deltaRequest.showPrincipal=プリンシパル [{0}]はセッション [{1}]に設定されています
|
||||
deltaRequest.ssid.mismatch=セッションIDが一致しません。デルタリクエストが実行されていません。
|
||||
deltaRequest.ssid.null=setSessionId に指定したセッション ID が null です。
|
||||
deltaRequest.wrongPrincipalClass=ClusterManagerはGenericPrincipalのみをサポートします。 あなたのRealmはプリンシパルクラス[{0}]を使用しました。
|
||||
|
||||
deltaSession.notifying=クラスタにセッションの有効期限を通知する:primary = [{0}]、sessionId [{1}]
|
||||
deltaSession.readSession=readObject() はセッション [{0}] を読み込みました。
|
||||
deltaSession.writeSession=writeObject() によりセッション [{0}] を格納しました。
|
||||
|
||||
jvmRoute.cannotFindSession=セッション [{0}] がありません。
|
||||
jvmRoute.changeSession=セッションを [{0}] から [{1}] へ変更しました。
|
||||
jvmRoute.failover=他の jvmRoute へのフェールオーバーを検出しました。元のルートは [{0}]、新しいルートは [{1}]、セッション ID は [{2}] です。
|
||||
jvmRoute.foundManager=コンテキスト [{1}] のCluster Manager [{0}] を発見しました。
|
||||
jvmRoute.missingJvmRouteAttribute=jvmRoute 属性にエンジンが指定されていません。
|
||||
jvmRoute.noCluster=JvmRouterBinderValveは設定されていますが、クラスタリングは使用されていません。 PersistentManagerが使用されている場合、フェールオーバーは引き続き機能します。
|
||||
jvmRoute.notFoundManager=[{0}]でCluster Managerが見つかりません。
|
||||
jvmRoute.set.orignalsessionid=オリジナルSession idをリクエスト属性[{0}]の値:[{1}]で設定します。
|
||||
jvmRoute.turnoverInfo=折り返しの所要時間は [{0}] ミリ秒でした。
|
||||
jvmRoute.valve.started=JvmRouteBinderValve が起動しました。
|
||||
jvmRoute.valve.stopped=JvmRouteBinderValve が停止しました。
|
||||
|
||||
standardSession.notSerializable=セッション[{1}]のセッション属性[{0}]をシリアライズできません。
|
||||
standardSession.removeAttribute.ise=removeAttribute: Session already invalidated
|
||||
standardSession.setAttribute.namenull=setAttribute:nameパラメータをnullにすることはできません。
|
||||
@@ -0,0 +1,90 @@
|
||||
# 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.
|
||||
|
||||
backupManager.noCluster=이 컨텍스트 [{0}]와(과) 연관된 클러스터가 없습니다.
|
||||
backupManager.startFailed=백업매니저 [{0}]을(를) 시작하지 못했습니다.
|
||||
backupManager.startUnable=BackupManager를 시작할 수 없습니다: [{0}]
|
||||
backupManager.stopped=매니저 [{0}]이(가) 중지되고 있습니다.
|
||||
|
||||
clusterSessionListener.noManager=컨텍스트 매니저가 존재하지 않습니다: [{0}]
|
||||
|
||||
deltaManager.createMessage.access=매니저 [{0}]: 세션(ID: [{1}])을 위한 세션 접근 메시지를 생성합니다.
|
||||
deltaManager.createMessage.accessChangePrimary=매니저 [{0}]: 세션(ID: [{1}])을 위해 Primary 노드 변경 메시지를 생성합니다.
|
||||
deltaManager.createMessage.allSessionData=매니저 [{0}]이(가) 모든 세션 데이터를 전송했습니다.
|
||||
deltaManager.createMessage.allSessionTransfered=매니저 [{0}]이(가), 모든 세션 데이터 전송 완료 메시지를 보냈습니다.
|
||||
deltaManager.createMessage.delta=매니저 [{0}]: 세션(ID: [{1}])을 위한 델타 요청 메시지를 생성합니다.
|
||||
deltaManager.createMessage.expire=매니저 [{0}]: 세션(ID: [{1}])을 위한 세션 만료 메시지를 생성합니다.
|
||||
deltaManager.createMessage.unableCreateDeltaRequest=세션 ID [{0}]을(를) 위한 델타 요청을 직렬화할 수 없습니다.
|
||||
deltaManager.createSession.newSession=ID가 [{0}]인 DeltaSession을 생성했습니다. 총 개수=[{1}]
|
||||
deltaManager.dropMessage=매니저 [{0}]: GET_ALL_SESSIONS 동기화 국면 내에서, 메시지 [{1}]을(를) 무시합니다. 시작 시간: [{2}], 메시지의 타임스탬프: [{3}]
|
||||
deltaManager.expireSessions=매니저 [{0}]이(가) 셧다운 시에 세션들을 만료시킵니다.
|
||||
deltaManager.foundMasterMember=컨텍스트 [{0}]을(를) 위한 복제 마스터 멤버 [{1}]을(를) 찾았습니다.
|
||||
deltaManager.loading.cnfe=저장된 세션들을 로드하는 중 ClassNotFoundException 발생: [{0}]
|
||||
deltaManager.loading.existing.session=기존 세션 [{0}]을(를) 오버로드합니다.
|
||||
deltaManager.loading.ioe=저장된 세션들을 로드하는 중 IOException 발생: [{0}]
|
||||
deltaManager.managerLoad=저장소로부터 세션들을 로드하는 중 예외 발생
|
||||
deltaManager.noCluster=시작 중... 이 컨텍스트와 연관된 클러스터가 없습니다: [{0}]
|
||||
deltaManager.noContextManager=매니저 [{0}]: [{1}]에서 전송되었던 ''Get all session data'' 메시지에 응답하여, ''No matching context manager'' 메시지를 [{2}] 밀리초 후에 받았습니다.
|
||||
deltaManager.noMasterMember=시작 중... 도메인 [{1}]에 컨텍스트 [{0}]을(를) 위한 다른 멤버들은 없는 상태입니다.
|
||||
deltaManager.noMembers=매니저 [{0}]: 상태 이전 작업을 건너뜁니다. 클러스터 그룹 내에 활성화된 멤버가 없습니다.
|
||||
deltaManager.noSessionState=매니저 [{0}]: [{1}]에서 보낸 세션 상태 메시지를 받지 못했습니다. [{2}] 밀리초 이후 제한 시간 초과되었습니다.
|
||||
deltaManager.receiveMessage.accessed=매니저 [{0}]: 세션(ID: [{1}])을 위한 세션 접근 메시지를 받았습니다.
|
||||
deltaManager.receiveMessage.allSessionDataAfter=매니저 [{0}]: 모든 세션 상태가 역직렬화되었습니다.
|
||||
deltaManager.receiveMessage.allSessionDataBegin=매니저 [{0}]: 모든 세션 상태 데이터를 받았습니다.
|
||||
deltaManager.receiveMessage.createNewSession=매니저 [{0}]: 세션 [{1}]을(를) 위한 세션 생성됨 메시지를 수신했습니다.
|
||||
deltaManager.receiveMessage.delta=매니저 [{0}]: 세션(ID: [{1}])을 위한 세션 델타 메시지를 받았습니다.
|
||||
deltaManager.receiveMessage.delta.unknown=매니저 [{0}]: 알 수 없는 세션 [{1}]을(를) 위한 세션 델타를 받았습니다.
|
||||
deltaManager.receiveMessage.error=매니저 [{0}]: TCP 채널을 통해 메시지를 받을 수 없습니다.
|
||||
deltaManager.receiveMessage.eventType=매니저 [{0}]: 타입이 [{1}]인 SessionMessage를 [{2}](으)로부터 받았습니다.
|
||||
deltaManager.receiveMessage.expired=매니저 [{0}]: 세션 [{1}]을(를) 위한 세션 만료 메시지를 받았습니다.
|
||||
deltaManager.receiveMessage.noContextManager=매니저 [{0}]이(가) 노드 [{1}:{2}](으)로부터 no context manager 메시지를 받았습니다.
|
||||
deltaManager.receiveMessage.transfercomplete=매니저 [{0}]이(가) 노드 [{1}:{2}](으)로부터, 세션 상태 이전 완료 메시지를 받았습니다.
|
||||
deltaManager.receiveMessage.unloadingAfter=매니저 [{0}]: 세션들을 언로드하는 작업이 완료되었습니다.
|
||||
deltaManager.receiveMessage.unloadingBegin=매니저 [{0}]: 세션들에 대해 언로드를 시작합니다.
|
||||
deltaManager.registerCluster=매니저 [{0}]을(를), [{2}](이)라는 이름의 클러스터 엘리먼트 [{1}](으)로 등록합니다.
|
||||
deltaManager.sendMessage.newSession=매니저 [{0}]이(가) 새로운 세션 [{1}]을(를) 전송합니다.
|
||||
deltaManager.sessionReceived=매니저 [{0}]; [{1}]에서 전송된 세션 상태를 [{2}] 밀리초 이내에 받음
|
||||
deltaManager.startClustering=[{0}]에서 클러스터 매니저를 시작합니다.
|
||||
deltaManager.stopped=매니저 [{0}]이(가) 중지됩니다.
|
||||
deltaManager.unableSerializeSessionID=세션 ID [{0}]을(를) 직렬화할 수 없습니다.
|
||||
deltaManager.unloading.ioe=세션들을 저장하는 중 IOException 발생: [{0}]
|
||||
deltaManager.waitForSessionState=매니저 [{0}]: [{1}](으)로부터 세션 상태를 요청합니다. 만일 [{2}]초 이내에 세션 상태를 받지 못하면, 이 오퍼레이션은 제한 시간 초과 처리될 것입니다.
|
||||
|
||||
deltaRequest.invalidAttributeInfoType=유효하지 않은 AttributeInfo 타입=[{0}]
|
||||
deltaRequest.removeUnable=클러스터 엘리먼트를 제거할 수 없습니다:
|
||||
deltaRequest.showPrincipal=Principal [{0}]이(가) 세션 [{1}]에 설정되었습니다.
|
||||
deltaRequest.ssid.mismatch=세션 ID가 일치하지 않아, 델타 요청을 실행하지 않습니다.
|
||||
deltaRequest.ssid.null=setSessionId를 위한 세션 ID가 널입니다.
|
||||
deltaRequest.wrongPrincipalClass=ClusterManager는 오직 GenericPrincipal만을 지원합니다. 사용된 realm은 principal 클래스 [{0}]을(를) 사용했습니다.
|
||||
|
||||
deltaSession.notifying=클러스터에 세션 만료를 통지합니다: primary여부: [{0}], 세션ID: [{1}]
|
||||
deltaSession.readSession=readObject()가 세션 [{0}]을(를) 로드합니다.
|
||||
deltaSession.writeSession=writeObject()가 세션 [{0}]을(를) 저장합니다.
|
||||
|
||||
jvmRoute.cannotFindSession=세션 [{0}]을(를) 찾을 수 없습니다.
|
||||
jvmRoute.changeSession=세션을 [{0}]에서 [{1}](으)로 변경했습니다.
|
||||
jvmRoute.failover=다른 jvmRoute로 Failover를 탐지했습니다. 원래의 라우트: [{0}], 새로운 라우트: [{1}]. 세션 ID: [{2}]
|
||||
jvmRoute.foundManager=[{1}]에서 클러스터 매니저 [{0}]을(를) 찾았습니다.
|
||||
jvmRoute.missingJvmRouteAttribute=엔진의 jvmRoute 속성이 설정되지 않았습니다!
|
||||
jvmRoute.noCluster=JvmRouterBinderValve가 설정되었지만, 클러스터링이 사용되고 있지 않습니다. PersistentManager가 사용되는 경우, Fail over는 여전히 정상 동작할 것입니다.
|
||||
jvmRoute.notFoundManager=[{0}]에서 클러스터 매니저를 찾을 수 없습니다.
|
||||
jvmRoute.set.orignalsessionid=요청의 속성 [{0}]에 원래의 세션 ID를 설정합니다: [{1}]
|
||||
jvmRoute.turnoverInfo=Failover를 위한 jvmRoute 교체 수행 시간: [{0}] 밀리초
|
||||
jvmRoute.valve.started=JvmRouteBinderValve가 시작됐습니다.
|
||||
jvmRoute.valve.stopped=JvmRouteBinderValve가 중지되었습니다.
|
||||
|
||||
standardSession.notSerializable=세션 [{1}]을 위한 세션 속성 [{0}]을(를) 직렬화할 수 없습니다.
|
||||
standardSession.removeAttribute.ise=removeAttribute: 세션이 이미 무효화되었습니다.
|
||||
standardSession.setAttribute.namenull=setAttribute: name 파라미터는 널일 수 없습니다.
|
||||
@@ -0,0 +1,55 @@
|
||||
# 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.
|
||||
|
||||
backupManager.noCluster=没有与此上下文关联的集群:[{0}]
|
||||
backupManager.startFailed=启动BackupManager: [{0}]失败
|
||||
backupManager.startUnable=无法启动BackupManager: [{0}]
|
||||
backupManager.stopped=管理者[{0}]正在停止。
|
||||
|
||||
deltaManager.createMessage.access=管理器[{0}]:创建会话为会话[{1}]存取消息
|
||||
deltaManager.createMessage.delta=管理器[{0}] ):为会话[{1}]创建增量请求消息
|
||||
deltaManager.createMessage.expire=管理器[{0}] (:为会话[{1}]创建会话过期消息
|
||||
deltaManager.createSession.newSession=用id[{0}]创建一个扩展会话(DeltaSession),总数为 [{1}]
|
||||
deltaManager.foundMasterMember=复制主master 成员在上下文中被发现.\n
|
||||
deltaManager.loading.cnfe=加载持久化会话 [{0}] 时出现ClassNotFoundException
|
||||
deltaManager.loading.ioe=加载持久 session 时出现 IOException:[{0}]
|
||||
deltaManager.managerLoad=从永久存储加载会话时发生异常
|
||||
deltaManager.noContextManager=管理器[{0}]:回复[{1}]发送的“获取所有会话数据”消息,在[{2}] ms后收到“无匹配的上下文管理器”消息
|
||||
deltaManager.noSessionState=管理者[{0}]:没有收到[{1}]发送的会话状态,在[{2}]毫秒之后超时。
|
||||
deltaManager.receiveMessage.accessed=管理器[{0}]:接收会话为会话[{1}]存取消息
|
||||
deltaManager.receiveMessage.allSessionDataAfter=Manager [{0}]: session 状态反序列化
|
||||
deltaManager.receiveMessage.allSessionDataBegin=管理者[{0}]:接收到所有会话数据状态
|
||||
deltaManager.receiveMessage.delta.unknown=管理器[{0}]:未知会话的接收会话增量[{1}]
|
||||
deltaManager.receiveMessage.expired=管理器[{0}]: 接收到的会话 [{1}] 已过期。
|
||||
deltaManager.receiveMessage.unloadingBegin=管理器[{0}]: 开始卸载会话
|
||||
deltaManager.registerCluster=将管理器[{0}]注册到名为[{2}]的集群元素[{1}]
|
||||
deltaManager.sendMessage.newSession=\ 管理器 [{0}] 发送新的会话 [{1}]
|
||||
deltaManager.sessionReceived=管理器[{0}];在[{1}]发送的会话状态在[{2}]毫秒内收到。
|
||||
deltaManager.unableSerializeSessionID=无法序列化会话ID [{0}]
|
||||
deltaManager.unloading.ioe=当保存永久回话:[{0}] 时,抛出 IOException
|
||||
|
||||
deltaRequest.removeUnable=不能移除元素
|
||||
deltaRequest.showPrincipal=Principal [{0}] 和session [{1}]产生关联。
|
||||
deltaRequest.wrongPrincipalClass=ClusterManager仅支持GenericPrincipal。 你的Realm使用的Principal类为[{0}]。
|
||||
|
||||
deltaSession.writeSession=writeObject()存储会话[{0}]
|
||||
|
||||
jvmRoute.changeSession=会话从[{0}]切换到[{1}]
|
||||
jvmRoute.missingJvmRouteAttribute=没有配置引擎jvmRoute属性!
|
||||
jvmRoute.notFoundManager=没有在 [{0}] 找到Cluster Manager
|
||||
jvmRoute.set.orignalsessionid=在请求属性[{0}]值:[{1}]处设置原始会话ID
|
||||
jvmRoute.valve.started=JvmRouteBinderValve 启动
|
||||
|
||||
standardSession.setAttribute.namenull=setAttribute:名称属性不能为空
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.session;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.apache.catalina.SessionListener;
|
||||
|
||||
/**
|
||||
* This is a marker interface used to indicate an implementation of
|
||||
* {@link SessionListener} that should be replicated with the session across the
|
||||
* cluster.
|
||||
*/
|
||||
public interface ReplicatedSessionListener extends SessionListener, Serializable {
|
||||
}
|
||||
110
java/org/apache/catalina/ha/session/SessionMessage.java
Normal file
110
java/org/apache/catalina/ha/session/SessionMessage.java
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.session;
|
||||
import org.apache.catalina.ha.ClusterMessage;
|
||||
|
||||
/**
|
||||
*
|
||||
* <B>Class Description:</B><BR>
|
||||
* The SessionMessage class is a class that is used when a session has been
|
||||
* created, modified, expired in a Tomcat cluster node.<BR>
|
||||
*
|
||||
* The following events are currently available:
|
||||
* <ul>
|
||||
* <li><pre>public static final int EVT_SESSION_CREATED</pre><li>
|
||||
* <li><pre>public static final int EVT_SESSION_EXPIRED</pre><li>
|
||||
* <li><pre>public static final int EVT_SESSION_ACCESSED</pre><li>
|
||||
* <li><pre>public static final int EVT_GET_ALL_SESSIONS</pre><li>
|
||||
* <li><pre>public static final int EVT_SESSION_DELTA</pre><li>
|
||||
* <li><pre>public static final int EVT_ALL_SESSION_DATA</pre><li>
|
||||
* <li><pre>public static final int EVT_ALL_SESSION_TRANSFERCOMPLETE</pre><li>
|
||||
* <li><pre>public static final int EVT_CHANGE_SESSION_ID</pre><li>
|
||||
* <li><pre>public static final int EVT_ALL_SESSION_NOCONTEXTMANAGER</pre><li>
|
||||
* </ul>
|
||||
*
|
||||
*/
|
||||
|
||||
public interface SessionMessage extends ClusterMessage {
|
||||
|
||||
/**
|
||||
* Event type used when a session has been created on a node
|
||||
*/
|
||||
public static final int EVT_SESSION_CREATED = 1;
|
||||
/**
|
||||
* Event type used when a session has expired
|
||||
*/
|
||||
public static final int EVT_SESSION_EXPIRED = 2;
|
||||
|
||||
/**
|
||||
* Event type used when a session has been accessed (ie, last access time
|
||||
* has been updated. This is used so that the replicated sessions will not expire
|
||||
* on the network
|
||||
*/
|
||||
public static final int EVT_SESSION_ACCESSED = 3;
|
||||
/**
|
||||
* Event type used when a server comes online for the first time.
|
||||
* The first thing the newly started server wants to do is to grab the
|
||||
* all the sessions from one of the nodes and keep the same state in there
|
||||
*/
|
||||
public static final int EVT_GET_ALL_SESSIONS = 4;
|
||||
/**
|
||||
* Event type used when an attribute has been added to a session,
|
||||
* the attribute will be sent to all the other nodes in the cluster
|
||||
*/
|
||||
public static final int EVT_SESSION_DELTA = 13;
|
||||
|
||||
/**
|
||||
* When a session state is transferred, this is the event.
|
||||
*/
|
||||
public static final int EVT_ALL_SESSION_DATA = 12;
|
||||
|
||||
/**
|
||||
* When a session state is complete transferred, this is the event.
|
||||
*/
|
||||
public static final int EVT_ALL_SESSION_TRANSFERCOMPLETE = 14;
|
||||
|
||||
/**
|
||||
* Event type used when a sessionID has been changed.
|
||||
*/
|
||||
public static final int EVT_CHANGE_SESSION_ID = 15;
|
||||
|
||||
/**
|
||||
* Event type used when context manager doesn't exist.
|
||||
* This is used when the manager which send a session state does not exist.
|
||||
*/
|
||||
public static final int EVT_ALL_SESSION_NOCONTEXTMANAGER = 16;
|
||||
|
||||
public String getContextName();
|
||||
|
||||
public String getEventTypeString();
|
||||
|
||||
/**
|
||||
* returns the event type
|
||||
* @return one of the event types EVT_XXXX
|
||||
*/
|
||||
public int getEventType();
|
||||
/**
|
||||
* @return the serialized data for the session
|
||||
*/
|
||||
public byte[] getSession();
|
||||
/**
|
||||
* @return the session ID for the session
|
||||
*/
|
||||
public String getSessionID();
|
||||
|
||||
|
||||
}//SessionMessage
|
||||
168
java/org/apache/catalina/ha/session/SessionMessageImpl.java
Normal file
168
java/org/apache/catalina/ha/session/SessionMessageImpl.java
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* 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.session;
|
||||
|
||||
|
||||
import org.apache.catalina.ha.ClusterMessageBase;
|
||||
|
||||
/**
|
||||
* Session cluster message
|
||||
*
|
||||
* @author Peter Rossbach
|
||||
*/
|
||||
public class SessionMessageImpl extends ClusterMessageBase implements SessionMessage {
|
||||
|
||||
private static final long serialVersionUID = 2L;
|
||||
|
||||
|
||||
/*
|
||||
* Private serializable variables to keep the messages state
|
||||
*/
|
||||
private final int mEvtType;
|
||||
private final byte[] mSession;
|
||||
private final String mSessionID;
|
||||
|
||||
private final String mContextName;
|
||||
private long serializationTimestamp;
|
||||
private boolean timestampSet = false ;
|
||||
private String uniqueId;
|
||||
|
||||
|
||||
private SessionMessageImpl( String contextName,
|
||||
int eventtype,
|
||||
byte[] session,
|
||||
String sessionID)
|
||||
{
|
||||
mEvtType = eventtype;
|
||||
mSession = session;
|
||||
mSessionID = sessionID;
|
||||
mContextName = contextName;
|
||||
uniqueId = sessionID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a session message. Depending on what event type you want this
|
||||
* message to represent, you populate the different parameters in the constructor<BR>
|
||||
* The following rules apply dependent on what event type argument you use:<BR>
|
||||
* <B>EVT_SESSION_CREATED</B><BR>
|
||||
* The parameters: session, sessionID must be set.<BR>
|
||||
* <B>EVT_SESSION_EXPIRED</B><BR>
|
||||
* The parameters: sessionID must be set.<BR>
|
||||
* <B>EVT_SESSION_ACCESSED</B><BR>
|
||||
* The parameters: sessionID must be set.<BR>
|
||||
* <B>EVT_GET_ALL_SESSIONS</B><BR>
|
||||
* get all sessions from from one of the nodes.<BR>
|
||||
* <B>EVT_SESSION_DELTA</B><BR>
|
||||
* Send attribute delta (add,update,remove attribute or principal, ...).<BR>
|
||||
* <B>EVT_ALL_SESSION_DATA</B><BR>
|
||||
* Send complete serializes session list<BR>
|
||||
* <B>EVT_ALL_SESSION_TRANSFERCOMPLETE</B><BR>
|
||||
* send that all session state information are transferred
|
||||
* after GET_ALL_SESSION received from this sender.<BR>
|
||||
* <B>EVT_CHANGE_SESSION_ID</B><BR>
|
||||
* send original sessionID and new sessionID.<BR>
|
||||
* <B>EVT_ALL_SESSION_NOCONTEXTMANAGER</B><BR>
|
||||
* send that context manager does not exist
|
||||
* after GET_ALL_SESSION received from this sender.<BR>
|
||||
* @param contextName - the name of the context (application
|
||||
* @param eventtype - one of the 8 event type defined in this class
|
||||
* @param session - the serialized byte array of the session itself
|
||||
* @param sessionID - the id that identifies this session
|
||||
* @param uniqueID - the id that identifies this message
|
||||
*/
|
||||
public SessionMessageImpl( String contextName,
|
||||
int eventtype,
|
||||
byte[] session,
|
||||
String sessionID,
|
||||
String uniqueID)
|
||||
{
|
||||
this(contextName,eventtype,session,sessionID);
|
||||
uniqueId = uniqueID;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the event type
|
||||
* @return one of the event types EVT_XXXX
|
||||
*/
|
||||
@Override
|
||||
public int getEventType() { return mEvtType; }
|
||||
|
||||
/**
|
||||
* @return the serialized data for the session
|
||||
*/
|
||||
@Override
|
||||
public byte[] getSession() { return mSession;}
|
||||
|
||||
/**
|
||||
* @return the session ID for the session
|
||||
*/
|
||||
@Override
|
||||
public String getSessionID(){ return mSessionID; }
|
||||
|
||||
/**
|
||||
* set message send time but only the first setting works (one shot)
|
||||
*/
|
||||
@Override
|
||||
public void setTimestamp(long time) {
|
||||
synchronized(this) {
|
||||
if(!timestampSet) {
|
||||
serializationTimestamp=time;
|
||||
timestampSet = true ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimestamp() { return serializationTimestamp;}
|
||||
|
||||
/**
|
||||
* clear text event type name (for logging purpose only)
|
||||
* @return the event type in a string representation, useful for debugging
|
||||
*/
|
||||
@Override
|
||||
public String getEventTypeString()
|
||||
{
|
||||
switch (mEvtType)
|
||||
{
|
||||
case EVT_SESSION_CREATED : return "SESSION-MODIFIED";
|
||||
case EVT_SESSION_EXPIRED : return "SESSION-EXPIRED";
|
||||
case EVT_SESSION_ACCESSED : return "SESSION-ACCESSED";
|
||||
case EVT_GET_ALL_SESSIONS : return "SESSION-GET-ALL";
|
||||
case EVT_SESSION_DELTA : return "SESSION-DELTA";
|
||||
case EVT_ALL_SESSION_DATA : return "ALL-SESSION-DATA";
|
||||
case EVT_ALL_SESSION_TRANSFERCOMPLETE : return "SESSION-STATE-TRANSFERRED";
|
||||
case EVT_CHANGE_SESSION_ID : return "SESSION-ID-CHANGED";
|
||||
case EVT_ALL_SESSION_NOCONTEXTMANAGER : return "NO-CONTEXT-MANAGER";
|
||||
default : return "UNKNOWN-EVENT-TYPE";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContextName() {
|
||||
return mContextName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueId() {
|
||||
return uniqueId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getEventTypeString() + "#" + getContextName() + "#" + getSessionID() ;
|
||||
}
|
||||
}
|
||||
629
java/org/apache/catalina/ha/session/mbeans-descriptors.xml
Normal file
629
java/org/apache/catalina/ha/session/mbeans-descriptors.xml
Normal file
@@ -0,0 +1,629 @@
|
||||
<?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="JvmRouteBinderValve"
|
||||
description="mod_jk jvmRoute jsessionid cookie backup correction"
|
||||
domain="Catalina"
|
||||
group="Valve"
|
||||
type="org.apache.catalina.ha.session.JvmRouteBinderValve">
|
||||
<attribute
|
||||
name="asyncSupported"
|
||||
description="Does this valve support async reporting? "
|
||||
is="true"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="className"
|
||||
description="Fully qualified class name of the managed object"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="enabled"
|
||||
description="enable a jvm Route check"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="numberOfSessions"
|
||||
description="number of jvmRoute session corrections"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="sessionIdAttribute"
|
||||
description="Name of attribute with sessionid value before turnover a session"
|
||||
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"/>
|
||||
<operation
|
||||
name="start"
|
||||
description="Stops the Cluster JvmRouteBinderValve"
|
||||
impact="ACTION"
|
||||
returnType="void"/>
|
||||
<operation
|
||||
name="stop"
|
||||
description="Stops the Cluster JvmRouteBinderValve"
|
||||
impact="ACTION"
|
||||
returnType="void"/>
|
||||
</mbean>
|
||||
<mbean
|
||||
name="DeltaManager"
|
||||
description="Cluster Manager implementation of the Manager interface"
|
||||
domain="Catalina"
|
||||
group="Manager"
|
||||
type="org.apache.catalina.ha.session.DeltaManager">
|
||||
<attribute
|
||||
name="activeSessions"
|
||||
description="Number of active sessions at this moment"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="className"
|
||||
description="Fully qualified class name of the managed object"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterNoStateTransfered"
|
||||
description="Count the failed session transfers noStateTransfered"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterReceive_EVT_GET_ALL_SESSIONS"
|
||||
description="Count receive EVT_GET_ALL_SESSIONS messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterReceive_EVT_ALL_SESSION_DATA"
|
||||
description="Count receive EVT_ALL_SESSION_DATA messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterReceive_EVT_SESSION_CREATED"
|
||||
description="Count receive EVT_SESSION_CREATED messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterReceive_EVT_SESSION_DELTA"
|
||||
description="Count receive EVT_SESSION_DELTA messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterReceive_EVT_SESSION_ACCESSED"
|
||||
description="Count receive EVT_SESSION_ACCESSED messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterReceive_EVT_SESSION_EXPIRED"
|
||||
description="Count receive EVT_SESSION_EXPIRED messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterReceive_EVT_ALL_SESSION_TRANSFERCOMPLETE"
|
||||
description="Count receive EVT_ALL_SESSION_TRANSFERCOMPLETE messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterReceive_EVT_CHANGE_SESSION_ID"
|
||||
description="Count receive EVT_CHANGE_SESSION_ID messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterReceive_EVT_ALL_SESSION_NOCONTEXTMANAGER"
|
||||
description="Count receive EVT_ALL_SESSION_NOCONTEXTMANAGER messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterSend_EVT_GET_ALL_SESSIONS"
|
||||
description="Count send EVT_GET_ALL_SESSIONS messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterSend_EVT_ALL_SESSION_DATA"
|
||||
description="Count send EVT_ALL_SESSION_DATA messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterSend_EVT_SESSION_CREATED"
|
||||
description="Count send EVT_SESSION_CREATED messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterSend_EVT_SESSION_DELTA"
|
||||
description="Count send EVT_SESSION_DELTA messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterSend_EVT_SESSION_ACCESSED"
|
||||
description="Count send EVT_SESSION_ACCESSED messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterSend_EVT_SESSION_EXPIRED"
|
||||
description="Count send EVT_SESSION_EXPIRED messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterSend_EVT_ALL_SESSION_TRANSFERCOMPLETE"
|
||||
description="Count send EVT_ALL_SESSION_TRANSFERCOMPLETE messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="counterSend_EVT_CHANGE_SESSION_ID"
|
||||
description="Count send EVT_CHANGE_SESSION_ID messages"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="duplicates"
|
||||
description="Number of duplicated session ids generated"
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="expiredSessions"
|
||||
description="Number of sessions that expired ( doesn't include explicit invalidations )"
|
||||
type="long"/>
|
||||
<attribute
|
||||
name="expireSessionsOnShutdown"
|
||||
is="true"
|
||||
description="expire all sessions cluster wide as one node goes down"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="invalidatedSessions"
|
||||
description="describe version"
|
||||
type="[Ljava.lang.String;"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="maxActive"
|
||||
description="Maximum number of active sessions so far"
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="maxActiveSessions"
|
||||
description="The maximum number of active Sessions allowed, or -1 for no limit"
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="name"
|
||||
description="The descriptive name of this Manager implementation (for logging)"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="notifyListenersOnReplication"
|
||||
is="true"
|
||||
description="Send session attribute change events on backup nodes"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="notifySessionListenersOnReplication"
|
||||
is="true"
|
||||
description="Send session start/stop events on backup nodes"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="notifyContainerListenersOnReplication"
|
||||
is="true"
|
||||
description="Send container events on backup nodes"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="processExpiresFrequency"
|
||||
description="The frequency of the manager checks (expiration and passivation)"
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="processingTime"
|
||||
description="Time spent doing housekeeping and expiration"
|
||||
type="long"/>
|
||||
<attribute
|
||||
name="sendAllSessions"
|
||||
is="true"
|
||||
description="Send all sessions at one big block"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="sendAllSessionsSize"
|
||||
description="session block size when sendAllSessions=false (default=1000)"
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="sendAllSessionsWaitTime"
|
||||
description="wait time between send session block (default 2 sec)"
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="sessionAverageAliveTime"
|
||||
description="Average time an expired session had been alive"
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="sessionCounter"
|
||||
description="Total number of sessions created by this manager"
|
||||
type="long"/>
|
||||
<attribute
|
||||
name="sessionMaxAliveTime"
|
||||
description="Longest time an expired session had been alive"
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="sessionReplaceCounter"
|
||||
description="Total number of replaced sessions that load from external nodes"
|
||||
type="long"
|
||||
writeable="false"/>
|
||||
<attribute name="stateName"
|
||||
description="The name of the LifecycleState that this component is currently in"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="stateTransfered"
|
||||
description="Is session state transferred complete? "
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="stateTransferTimeout"
|
||||
description="state transfer timeout in sec"
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="receivedQueueSize"
|
||||
description="length of receive queue size when session received from other node"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="rejectedSessions"
|
||||
description="Number of sessions we rejected due to maxActive being reached"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="noContextManagerReceived"
|
||||
is="true"
|
||||
description="Is no context manager message received? "
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="secureRandomAlgorithm"
|
||||
description="The secure random number generator algorithm name"
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="secureRandomClass"
|
||||
description="The secure random number generator class name"
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="secureRandomProvider"
|
||||
description="The secure random number generator provider name"
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="stateTimestampDrop"
|
||||
is="true"
|
||||
description="All session messages before state transfer message creation are dropped."
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="recordAllActions"
|
||||
is="true"
|
||||
description="Flag whether send all actions for session across Tomcat cluster nodes."
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="sessionAttributeNameFilter"
|
||||
description="The string pattern used for including session attributes in replication. Null means all attributes are included."
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="sessionAttributeValueClassNameFilter"
|
||||
description="The regular expression used to filter session attributes based on the implementation class of the value. The regular expression is anchored and must match the fully qualified class name."
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="warnOnSessionAttributeFilterFailure"
|
||||
description="Should a WARN level log message be generated if a session attribute fails to match sessionAttributeNameFilter or sessionAttributeClassNameFilter?"
|
||||
type="boolean"/>
|
||||
<operation
|
||||
name="expireSession"
|
||||
description="Expired the given session"
|
||||
impact="ACTION"
|
||||
returnType="void">
|
||||
<parameter
|
||||
name="sessionId"
|
||||
description="The session id for the session to be expired"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
<operation
|
||||
name="expireAllLocalSessions"
|
||||
description="expire all active local sessions and replicate the invalid sessions"
|
||||
impact="ACTION"
|
||||
returnType="void"/>
|
||||
<operation
|
||||
name="findSession"
|
||||
description="Return the active Session, associated with this Manager, with the specified session id (if any)"
|
||||
impact="ACTION"
|
||||
returnType="org.apache.catalina.Session">
|
||||
<parameter
|
||||
name="id"
|
||||
description="The session id for the session to be returned"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
<operation
|
||||
name="findSessions"
|
||||
description="Return the set of active Sessions associated with this Manager."
|
||||
impact="ACTION"
|
||||
returnType="[Lorg.apache.catalina.Session;">
|
||||
</operation>
|
||||
<operation
|
||||
name="getAllClusterSessions"
|
||||
description="send to oldest cluster member that this node need all cluster sessions (resync member)"
|
||||
impact="ACTION"
|
||||
returnType="void"/>
|
||||
<operation
|
||||
name="getCreationTime"
|
||||
description="Return the creation time for this session"
|
||||
impact="ACTION"
|
||||
returnType="java.lang.String">
|
||||
<parameter
|
||||
name="sessionId"
|
||||
description="The session id for the session "
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
<operation
|
||||
name="getLastAccessedTime"
|
||||
description="Get the last access time. This one gets updated whenever a request finishes. "
|
||||
impact="ACTION"
|
||||
returnType="java.lang.String">
|
||||
<parameter
|
||||
name="sessionId"
|
||||
description="Id of the session"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
<operation
|
||||
name="getSessionAttribute"
|
||||
description="Return a session attribute"
|
||||
impact="ACTION"
|
||||
returnType="java.lang.String">
|
||||
<parameter
|
||||
name="sessionId"
|
||||
description="Id of the session"
|
||||
type="java.lang.String"/>
|
||||
<parameter
|
||||
name="key"
|
||||
description="key of the attribute"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
<operation
|
||||
name="getThisAccessedTime"
|
||||
description="Get the last access time. This one gets updated whenever a request starts. "
|
||||
impact="ACTION"
|
||||
returnType="java.lang.String">
|
||||
<parameter
|
||||
name="sessionId"
|
||||
description="Id of the session"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
<operation
|
||||
name="listSessionIds"
|
||||
description="Return the list of active primary session ids"
|
||||
impact="ACTION"
|
||||
returnType="java.lang.String"/>
|
||||
<operation
|
||||
name="processExpires"
|
||||
description="Invalidate all sessions that have expired.s"
|
||||
impact="ACTION"
|
||||
returnType="void"/>
|
||||
<operation
|
||||
name="resetStatistics"
|
||||
description="Reset all statistics"
|
||||
impact="ACTION"
|
||||
returnType="void"/>
|
||||
</mbean>
|
||||
<mbean
|
||||
name="BackupManager"
|
||||
description="Cluster Manager implementation of the Manager interface"
|
||||
domain="Catalina"
|
||||
group="Manager"
|
||||
type="org.apache.catalina.ha.session.BackupManager">
|
||||
<attribute
|
||||
name="activeSessions"
|
||||
description="Number of active primary sessions at this moment"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="activeSessionsFull"
|
||||
description="Number of active sessions at this moment"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="className"
|
||||
description="Fully qualified class name of the managed object"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="duplicates"
|
||||
description="Number of duplicated session ids generated"
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="expiredSessions"
|
||||
description="Number of sessions that expired ( doesn't include explicit invalidations )"
|
||||
type="long"/>
|
||||
<attribute
|
||||
name="invalidatedSessions"
|
||||
description="Get the list of invalidated session."
|
||||
type="[Ljava.lang.String;"/>
|
||||
<attribute
|
||||
name="mapName"
|
||||
description="mapName"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="mapSendOptions"
|
||||
description="mapSendOptions"
|
||||
type="int"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="maxActive"
|
||||
description="Maximum number of active sessions so far"
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="maxActiveSessions"
|
||||
description="The maximum number of active Sessions allowed, or -1 for no limit"
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="name"
|
||||
description="The name of component. "
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="notifyListenersOnReplication"
|
||||
is="true"
|
||||
description="Send session attribute change events on backup nodes"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="processExpiresFrequency"
|
||||
description="The frequency of the manager checks (expiration and passivation)"
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="processingTime"
|
||||
description="Time spent doing housekeeping and expiration"
|
||||
type="long"/>
|
||||
<attribute
|
||||
name="sessionAverageAliveTime"
|
||||
description="Average time an expired session had been alive"
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="sessionCounter"
|
||||
description="Total number of sessions created by this manager"
|
||||
type="long"/>
|
||||
<attribute
|
||||
name="sessionMaxAliveTime"
|
||||
description="Longest time an expired session had been alive"
|
||||
type="int"/>
|
||||
<attribute name="stateName"
|
||||
description="The name of the LifecycleState that this component is currently in"
|
||||
type="java.lang.String"
|
||||
writeable="false"/>
|
||||
<attribute
|
||||
name="rejectedSessions"
|
||||
description="Number of sessions we rejected due to maxActive being reached"
|
||||
type="int"/>
|
||||
<attribute
|
||||
name="rpcTimeout"
|
||||
description="Timeout for RPC messages, how long we will wait for a reply"
|
||||
type="long"/>
|
||||
<attribute
|
||||
name="terminateOnStartFailure"
|
||||
description="Flag for whether to terminate this map that failed to start."
|
||||
is="true"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="secureRandomAlgorithm"
|
||||
description="The secure random number generator algorithm name"
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="secureRandomClass"
|
||||
description="The secure random number generator class name"
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="secureRandomProvider"
|
||||
description="The secure random number generator provider name"
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="recordAllActions"
|
||||
is="true"
|
||||
description="Flag whether send all actions for session across Tomcat cluster nodes."
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="sessionAttributeNameFilter"
|
||||
description="The string pattern used for including session attributes in replication. Null means all attributes are included."
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="sessionAttributeValueClassNameFilter"
|
||||
description="The regular expression used to filter session attributes based on the implementation class of the value. The regular expression is anchored and must match the fully qualified class name."
|
||||
type="java.lang.String"/>
|
||||
<attribute
|
||||
name="warnOnSessionAttributeFilterFailure"
|
||||
description="Should a WARN level log message be generated if a session attribute fails to match sessionAttributeNameFilter or sessionAttributeClassNameFilter?"
|
||||
type="boolean"/>
|
||||
<attribute
|
||||
name="accessTimeout"
|
||||
description="The timeout for a ping message in replication map."
|
||||
type="long"/>
|
||||
<operation
|
||||
name="expireSession"
|
||||
description="Expired the given session"
|
||||
impact="ACTION"
|
||||
returnType="void">
|
||||
<parameter
|
||||
name="sessionId"
|
||||
description="The session id for the session to be expired"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
<operation
|
||||
name="findSession"
|
||||
description="Return the active Session, associated with this Manager, with the specified session id (if any)"
|
||||
impact="ACTION"
|
||||
returnType="org.apache.catalina.Session">
|
||||
<parameter
|
||||
name="id"
|
||||
description="The session id for the session to be returned"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
<operation
|
||||
name="findSessions"
|
||||
description="Return the set of active Sessions associated with this Manager."
|
||||
impact="ACTION"
|
||||
returnType="[Lorg.apache.catalina.Session;">
|
||||
</operation>
|
||||
<operation
|
||||
name="getCreationTime"
|
||||
description="Return the creation time for this session"
|
||||
impact="ACTION"
|
||||
returnType="java.lang.String">
|
||||
<parameter
|
||||
name="sessionId"
|
||||
description="The session id for the session "
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
<operation
|
||||
name="getLastAccessedTime"
|
||||
description="Get the last access time. This one gets updated whenever a request finishes. "
|
||||
impact="ACTION"
|
||||
returnType="java.lang.String">
|
||||
<parameter
|
||||
name="sessionId"
|
||||
description="Id of the session"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
<operation
|
||||
name="getSessionAttribute"
|
||||
description="Return a session attribute"
|
||||
impact="ACTION"
|
||||
returnType="java.lang.String">
|
||||
<parameter
|
||||
name="sessionId"
|
||||
description="Id of the session"
|
||||
type="java.lang.String"/>
|
||||
<parameter
|
||||
name="key"
|
||||
description="key of the attribute"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
<operation
|
||||
name="getThisAccessedTime"
|
||||
description="Get the last access time. This one gets updated whenever a request starts. "
|
||||
impact="ACTION"
|
||||
returnType="java.lang.String">
|
||||
<parameter
|
||||
name="sessionId"
|
||||
description="Id of the session"
|
||||
type="java.lang.String"/>
|
||||
</operation>
|
||||
<operation
|
||||
name="listSessionIds"
|
||||
description="Return the list of active primary session ids"
|
||||
impact="ACTION"
|
||||
returnType="java.lang.String"/>
|
||||
<operation
|
||||
name="getSessionIdsFull"
|
||||
description="Returns the list of all sessions IDS (primary, backup and proxy)."
|
||||
impact="ACTION"
|
||||
returnType="java.util.Set"/>
|
||||
<operation
|
||||
name="processExpires"
|
||||
description="Invalidate all sessions that have expired.s"
|
||||
impact="ACTION"
|
||||
returnType="void"/>
|
||||
</mbean>
|
||||
</mbeans-descriptors>
|
||||
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