This commit is contained in:
2024-11-30 19:03:49 +08:00
commit 1e6763c160
3806 changed files with 737676 additions and 0 deletions

View 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();
}

View 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);
}

View 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) ;
}

View 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();
}

View 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);
}

View 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;
}
}

View 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
}
}

View 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);
}

View 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);
}

View File

@@ -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();
}
}
}

View 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.
*/
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);
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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に関連するクラスタがありません。

View File

@@ -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을 위한 클러스터가 없습니다.

View File

@@ -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=在集群加载时, 集群单点登录异常

View File

@@ -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>

View 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();
}
}

View 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);
}
}
}
}

View 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;
}
}

View 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;
}

View 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;
}

View 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;
}
}

View 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}]

View 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=Le nom ne peut être null
replicatedContext.startFailed=Echec de démarrage du ReplicatedContext: [{0}]
replicatedContext.startUnable=Impossible de démarrer le ReplicatedContext: [{0}]

View 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=名前はnullにできません
replicatedContext.startFailed=ReplicatedContext: [{0}]の起動に失敗しました。
replicatedContext.startUnable=ReplicatedContext[{0}]を開始できません。

View 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=이름이 널일 수 없습니다.
replicatedContext.startFailed=ReplicatedContext를 시작하지 못했습니다: [{0}]
replicatedContext.startUnable=ReplicatedContext [{0}]을(를) 시작할 수 없습니다.

View 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
}
}

File diff suppressed because it is too large Load Diff

View 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);
}

View 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;
}
}

View 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;
}
}

View 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}]?

View File

@@ -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.

View 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.
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}]

View File

@@ -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

View File

@@ -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}] のディレクトリ権限を確認してください。

View File

@@ -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}]에 대한 디렉토리 접근 허가 설정을 점검해 보시겠습니까?

View File

@@ -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 файл [{}]

View 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.
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}]

View 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;
}
}

View 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-&gt;deploy or remove WAR files-&gt;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;
}
}
}

View 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>

View 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>

View 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;
}
}

View 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();
}
}

View 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;
}
}

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More