FileDocCategorySizeDatePackage
SimpleTcpCluster.javaAPI DocApache Tomcat 6.0.1434338Fri Jul 20 04:20:32 BST 2007org.apache.catalina.ha.tcp

SimpleTcpCluster

public class SimpleTcpCluster extends Object implements org.apache.catalina.tribes.ChannelListener, org.apache.catalina.ha.CatalinaCluster, org.apache.catalina.ha.util.IDynamicProperty, org.apache.catalina.Lifecycle, org.apache.catalina.LifecycleListener, org.apache.catalina.tribes.MembershipListener
A Cluster implementation using simple multicast. Responsible for setting up a cluster and provides callers with a valid multicast receiver/sender. FIXME remove install/remove/start/stop context dummys FIXME wrote testcases
author
Filip Hanik
author
Remy Maucherat
author
Peter Rossbach
version
$Revision: 532865 $, $Date: 2007-04-26 23:09:41 +0200 (jeu., 26 avr. 2007) $

Fields Summary
public static org.apache.juli.logging.Log
log
protected static final String
info
Descriptive information about this component implementation.
public static final String
BEFORE_MEMBERREGISTER_EVENT
public static final String
AFTER_MEMBERREGISTER_EVENT
public static final String
BEFORE_MANAGERREGISTER_EVENT
public static final String
AFTER_MANAGERREGISTER_EVENT
public static final String
BEFORE_MANAGERUNREGISTER_EVENT
public static final String
AFTER_MANAGERUNREGISTER_EVENT
public static final String
BEFORE_MEMBERUNREGISTER_EVENT
public static final String
AFTER_MEMBERUNREGISTER_EVENT
public static final String
SEND_MESSAGE_FAILURE_EVENT
public static final String
RECEIVE_MESSAGE_FAILURE_EVENT
protected org.apache.catalina.tribes.Channel
channel
Group channel.
protected String
clusterImpName
Name for logging purpose
protected org.apache.catalina.util.StringManager
sm
The string manager for this package.
protected String
clusterName
The cluster name to join
protected boolean
heartbeatBackgroundEnabled
call Channel.heartbeat() at container background thread
protected org.apache.catalina.Container
container
The Container associated with this Cluster.
protected org.apache.catalina.util.LifecycleSupport
lifecycle
The lifecycle event support for this component.
protected boolean
started
Has this component been started?
protected PropertyChangeSupport
support
The property change support for this component.
protected Map
managers
The context name <->manager association for distributed contexts.
protected org.apache.catalina.ha.ClusterManager
managerTemplate
private List
valves
private org.apache.catalina.ha.ClusterDeployer
clusterDeployer
protected List
clusterListeners
Listeners of messages
private boolean
notifyLifecycleListenerOnFailure
Comment for notifyLifecycleListenerOnFailure
private Map
properties
dynamic sender properties
private int
channelSendOptions
protected boolean
hasMembers
has members
Constructors Summary
public SimpleTcpCluster()


    // ------------------------------------------------------------- Properties

      
    
Methods Summary
public booleanaccept(java.io.Serializable msg, org.apache.catalina.tribes.Member sender)
notify all listeners from receiving a new message is not ClusterMessage emitt Failure Event to LifecylceListener

param
message receveived Message

        return (msg instanceof ClusterMessage);
    
public voidaddClusterListener(org.apache.catalina.ha.ClusterListener listener)
add cluster message listener and register cluster to this listener

see
org.apache.catalina.ha.CatalinaCluster#addClusterListener(org.apache.catalina.ha.MessageListener)

        if (listener != null && !clusterListeners.contains(listener)) {
            clusterListeners.add(listener);
            listener.setCluster(this);
        }
    
public voidaddLifecycleListener(org.apache.catalina.LifecycleListener listener)
Add a lifecycle event listener to this component.

param
listener The listener to add

        lifecycle.addLifecycleListener(listener);
    
public voidaddValve(org.apache.catalina.Valve valve)
Add cluster valve Cluster Valves are only add to container when cluster is started!

param
valve The new cluster Valve.

        if (valve instanceof ClusterValve && (!valves.contains(valve)))
            valves.add(valve);
    
public voidbackgroundProcess()
Execute a periodic task, such as reloading, etc. This method will be invoked inside the classloading context of this container. Unexpected throwables will be caught and logged.

see
org.apache.catalina.ha.deploy.FarmWarDeployer#backgroundProcess()
see
org.apache.catalina.tribes.group.GroupChannel#heartbeat()
see
org.apache.catalina.tribes.group.GroupChannel.HeartbeatThread#run()

        if (clusterDeployer != null) clusterDeployer.backgroundProcess();
       
        //send a heartbeat through the channel        
        if ( isHeartbeatBackgroundEnabled() && channel !=null ) channel.heartbeat();
    
protected voidcheckDefaults()

        if ( clusterListeners.size() == 0 ) {
            addClusterListener(new JvmRouteSessionIDBinderListener()); 
            addClusterListener(new ClusterSessionListener());
        }
        if ( valves.size() == 0 ) {
            addValve(new JvmRouteBinderValve());
            addValve(new ReplicationValve());
        }
        if ( clusterDeployer != null ) clusterDeployer.setCluster(this);
        if ( channel == null ) channel = new GroupChannel();
        if ( channel instanceof GroupChannel && !((GroupChannel)channel).getInterceptors().hasNext()) {
            channel.addInterceptor(new MessageDispatch15Interceptor());
            channel.addInterceptor(new TcpFailureDetector());
        }
    
public synchronized org.apache.catalina.ManagercreateManager(java.lang.String name)
Create new Manager without add to cluster (comes with start the manager)

param
name Context Name of this manager
see
org.apache.catalina.Cluster#createManager(java.lang.String)
see
#addManager(String, Manager)
see
DeltaManager#start()

        if (log.isDebugEnabled()) log.debug("Creating ClusterManager for context " + name + " using class " + getManagerClassName());
        Manager manager = null;
        try {
            manager = managerTemplate.cloneFromTemplate();
            ((ClusterManager)manager).setName(name);
        } catch (Exception x) {
            log.error("Unable to clone cluster manager, defaulting to org.apache.catalina.ha.session.DeltaManager", x);
            manager = new org.apache.catalina.ha.session.DeltaManager();
        } finally {
            if ( manager != null && (manager instanceof ClusterManager)) ((ClusterManager)manager).setCluster(this);
        }
        return manager;
    
public org.apache.catalina.ha.ClusterListener[]findClusterListeners()
Get the cluster listeners associated with this cluster. If this Array has no listeners registered, a zero-length array is returned.

        if (clusterListeners.size() > 0) {
            ClusterListener[] listener = new ClusterListener[clusterListeners.size()];
            clusterListeners.toArray(listener);
            return listener;
        } else
            return new ClusterListener[0];

    
public org.apache.catalina.LifecycleListener[]findLifecycleListeners()
Get the lifecycle listeners associated with this lifecycle. If this Lifecycle has no listeners registered, a zero-length array is returned.


        return lifecycle.findLifecycleListeners();

    
public org.apache.catalina.tribes.ChannelgetChannel()

        return channel;
    
public intgetChannelSendOptions()

        return channelSendOptions;
    
public org.apache.catalina.ha.ClusterDeployergetClusterDeployer()
get current Deployer

        return clusterDeployer;
    
public java.lang.StringgetClusterName()
Return the name of the cluster that this Server is currently configured to operate within.

return
The name of the cluster associated with this server

        if(clusterName == null && container != null)
            return container.getName() ;
        return clusterName;
    
public org.apache.catalina.ContainergetContainer()
Get the Container associated with our Cluster

return
The Container associated with our Cluster

        return (this.container);
    
public java.lang.StringgetInfo()
Return descriptive information about this Cluster implementation and the corresponding version number, in the format <description>/<version>.

        return (info);
    
public org.apache.catalina.tribes.MembergetLocalMember()
Return the member that represents this node.

return
Member

        return channel.getLocalMember(true);
    
public org.apache.juli.logging.LoggetLogger()

        return log;
    
public org.apache.catalina.ManagergetManager(java.lang.String name)

        return (Manager) managers.get(name);
    
public java.lang.StringgetManagerClassName()

deprecated
use getManagerTemplate().getClass().getName() instead.
return
String

        return managerTemplate.getClass().getName();
    
public java.lang.StringgetManagerName(java.lang.String name, org.apache.catalina.Manager manager)

param
name
param
manager
return

        String clusterName = name ;
        if ( clusterName == null ) clusterName = manager.getContainer().getName();
        if(getContainer() instanceof Engine) {
            Container context = manager.getContainer() ;
            if(context != null && context instanceof Context) {
                Container host = ((Context)context).getParent();
                if(host != null && host instanceof Host && clusterName!=null && !(clusterName.indexOf("#")>=0))
                    clusterName = host.getName() +"#" + clusterName ;
            }
        }
        return clusterName;
    
public org.apache.catalina.ha.ClusterManagergetManagerTemplate()

        return managerTemplate;
    
public java.util.MapgetManagers()

return
Returns the managers.

        return managers;
    
public org.apache.catalina.tribes.Member[]getMembers()
Get all current cluster members

return
all members or empty array

        return channel.getMembers();
    
public java.lang.ObjectgetProperty(java.lang.String key)
get current config

param
key
return
The property

        if (log.isTraceEnabled())
            log.trace(sm.getString("SimpleTcpCluster.getProperty", key));
        return properties.get(key);
    
public java.util.IteratorgetPropertyNames()
Get all properties keys

return
An iterator over the property names.

        return properties.keySet().iterator();
    
public java.lang.StringgetProtocol()

see
org.apache.catalina.Cluster#getProtocol()

        return null;
    
public org.apache.catalina.Valve[]getValves()
get all cluster valves

return
current cluster valves

        return (Valve[]) valves.toArray(new Valve[valves.size()]);
    
public booleanhasMembers()

       
        return hasMembers;
    
public booleanisHeartbeatBackgroundEnabled()
Return heartbeat enable flag (default false)

return
the heartbeatBackgroundEnabled

        return heartbeatBackgroundEnabled;
    
public booleanisNotifyLifecycleListenerOnFailure()

return
Returns the notifyLifecycleListenerOnFailure.

        return notifyLifecycleListenerOnFailure;
    
public voidlifecycleEvent(org.apache.catalina.LifecycleEvent lifecycleEvent)
Use as base to handle start/stop/periodic Events from host. Currently only log the messages as trace level.

see
org.apache.catalina.LifecycleListener#lifecycleEvent(org.apache.catalina.LifecycleEvent)

        if (log.isTraceEnabled())
            log.trace(sm.getString("SimpleTcpCluster.event.log", lifecycleEvent.getType(), lifecycleEvent.getData()));
    
public voidmemberAdded(org.apache.catalina.tribes.Member member)
New cluster member is registered

see
org.apache.catalina.ha.MembershipListener#memberAdded(org.apache.catalina.ha.Member)

        try {
            hasMembers = channel.hasMembers();
            if (log.isInfoEnabled()) log.info("Replication member added:" + member);
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(BEFORE_MEMBERREGISTER_EVENT, member);
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(AFTER_MEMBERREGISTER_EVENT, member);
        } catch (Exception x) {
            log.error("Unable to connect to replication system.", x);
        }

    
public voidmemberDisappeared(org.apache.catalina.tribes.Member member)
Cluster member is gone

see
org.apache.catalina.ha.MembershipListener#memberDisappeared(org.apache.catalina.ha.Member)

        try {
            hasMembers = channel.hasMembers();            
            if (log.isInfoEnabled()) log.info("Received member disappeared:" + member);
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(BEFORE_MEMBERUNREGISTER_EVENT, member);
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(AFTER_MEMBERUNREGISTER_EVENT, member);
        } catch (Exception x) {
            log.error("Unable remove cluster node from replication system.", x);
        }
    
public voidmessageReceived(java.io.Serializable message, org.apache.catalina.tribes.Member sender)

        ClusterMessage fwd = (ClusterMessage)message;
        fwd.setAddress(sender);
        messageReceived(fwd);
    
public voidmessageReceived(org.apache.catalina.ha.ClusterMessage message)


        long start = 0;
        if (log.isDebugEnabled() && message != null)
            log.debug("Assuming clocks are synched: Replication for "
                    + message.getUniqueId() + " took="
                    + (System.currentTimeMillis() - (message).getTimestamp())
                    + " ms.");

        //invoke all the listeners
        boolean accepted = false;
        if (message != null) {
            for (Iterator iter = clusterListeners.iterator(); iter.hasNext();) {
                ClusterListener listener = (ClusterListener) iter.next();
                if (listener.accept(message)) {
                    accepted = true;
                    listener.messageReceived(message);
                }
            }
        }
        if (!accepted && log.isDebugEnabled()) {
            if (notifyLifecycleListenerOnFailure) {
                Member dest = message.getAddress();
                // Notify our interested LifecycleListeners
                lifecycle.fireLifecycleEvent(RECEIVE_MESSAGE_FAILURE_EVENT,
                        new SendMessageData(message, dest, null));
            }
            log.debug("Message " + message.toString() + " from type "
                    + message.getClass().getName()
                    + " transfered but no listener registered");
        }
        return;
    
protected voidregisterClusterValve()
register all cluster valve to host or engine

throws
Exception
throws
ClassNotFoundException

        if(container != null ) {
            for (Iterator iter = valves.iterator(); iter.hasNext();) {
                ClusterValve valve = (ClusterValve) iter.next();
                if (log.isDebugEnabled())
                    log.debug("Invoking addValve on " + getContainer()
                            + " with class=" + valve.getClass().getName());
                if (valve != null) {
                    IntrospectionUtils.callMethodN(getContainer(), "addValve",
                            new Object[] { valve },
                            new Class[] { org.apache.catalina.Valve.class });

                }
                valve.setCluster(this);
            }
        }
    
public voidregisterManager(org.apache.catalina.Manager manager)

    
        if (! (manager instanceof ClusterManager)) {
            log.warn("Manager [ " + manager + "] does not implement ClusterManager, addition to cluster has been aborted.");
            return;
        }
        ClusterManager cmanager = (ClusterManager) manager ;
        cmanager.setDistributable(true);
        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_MANAGERREGISTER_EVENT, manager);
        String clusterName = getManagerName(cmanager.getName(), manager);
        cmanager.setName(clusterName);
        cmanager.setCluster(this);
        cmanager.setDefaultMode(false);
    
        managers.put(clusterName, manager);
        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_MANAGERREGISTER_EVENT, manager);    
    
public voidremoveClusterListener(org.apache.catalina.ha.ClusterListener listener)
remove message listener and deregister Cluster from listener

see
org.apache.catalina.ha.CatalinaCluster#removeClusterListener(org.apache.catalina.ha.MessageListener)

        if (listener != null) {
            clusterListeners.remove(listener);
            listener.setCluster(null);
        }
    
public voidremoveLifecycleListener(org.apache.catalina.LifecycleListener listener)
Remove a lifecycle event listener from this component.

param
listener The listener to remove

        lifecycle.removeLifecycleListener(listener);
    
public voidremoveManager(org.apache.catalina.Manager manager)
remove an application form cluster replication bus

see
org.apache.catalina.ha.CatalinaCluster#removeManager(java.lang.String,Manager)

        if (manager != null && manager instanceof ClusterManager ) {
            ClusterManager cmgr = (ClusterManager) manager;
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(BEFORE_MANAGERUNREGISTER_EVENT,manager);
            managers.remove(getManagerName(cmgr.getName(),manager));
            cmgr.setCluster(null);
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(AFTER_MANAGERUNREGISTER_EVENT, manager);
        }
    
public voidremoveProperty(java.lang.String key)
remove a configured property.

param
key

        properties.remove(key);
    
public voidsend(org.apache.catalina.ha.ClusterMessage msg)
send message to all cluster members

param
msg message to transfer
see
org.apache.catalina.ha.CatalinaCluster#send(org.apache.catalina.ha.ClusterMessage)

        send(msg, null);
    
public voidsend(org.apache.catalina.ha.ClusterMessage msg, org.apache.catalina.tribes.Member dest)
send a cluster message to one member

param
msg message to transfer
param
dest Receiver member
see
org.apache.catalina.ha.CatalinaCluster#send(org.apache.catalina.ha.ClusterMessage, org.apache.catalina.ha.Member)

        try {
            msg.setAddress(getLocalMember());
            if (dest != null) {
                if (!getLocalMember().equals(dest)) {
                    channel.send(new Member[] {dest}, msg,channelSendOptions);
                } else
                    log.error("Unable to send message to local member " + msg);
            } else {
                channel.send(channel.getMembers(),msg,channelSendOptions);
            }
        } catch (Exception x) {
            log.error("Unable to send message through cluster sender.", x);
        }
    
public voidsendClusterDomain(org.apache.catalina.ha.ClusterMessage msg)
send message to all cluster members same cluster domain

see
org.apache.catalina.ha.CatalinaCluster#send(org.apache.catalina.ha.ClusterMessage)

        send(msg,null);
    
public voidsetChannel(org.apache.catalina.tribes.Channel channel)

        this.channel = channel;
    
public voidsetChannelSendOptions(int channelSendOptions)

        this.channelSendOptions = channelSendOptions;
    
public voidsetClusterDeployer(org.apache.catalina.ha.ClusterDeployer clusterDeployer)
set a new Deployer, must be set before cluster started!

        this.clusterDeployer = clusterDeployer;
    
public voidsetClusterName(java.lang.String clusterName)
Set the name of the cluster to join, if no cluster with this name is present create one.

param
clusterName The clustername to join

        this.clusterName = clusterName;
    
public voidsetContainer(org.apache.catalina.Container container)
Set the Container associated with our Cluster

param
container The Container to use

        Container oldContainer = this.container;
        this.container = container;
        support.firePropertyChange("container", oldContainer, this.container);
    
public voidsetHeartbeatBackgroundEnabled(boolean heartbeatBackgroundEnabled)
enabled that container backgroundThread call heartbeat at channel

param
heartbeatBackgroundEnabled the heartbeatBackgroundEnabled to set

        this.heartbeatBackgroundEnabled = heartbeatBackgroundEnabled;
    
public voidsetManagerClassName(java.lang.String managerClassName)

deprecated
use nested <Manager> element inside the cluster config instead.
param
managerClassName String

        log.warn("setManagerClassName is deprecated, use nested <Manager> element inside the <Cluster> element instead, this request will be ignored.");
    
public voidsetManagerTemplate(org.apache.catalina.ha.ClusterManager managerTemplate)

        this.managerTemplate = managerTemplate;
    
public voidsetNotifyLifecycleListenerOnFailure(boolean notifyListenerOnFailure)

param
notifyListenerOnFailure The notifyLifecycleListenerOnFailure to set.

        boolean oldNotifyListenerOnFailure = this.notifyLifecycleListenerOnFailure;
        this.notifyLifecycleListenerOnFailure = notifyListenerOnFailure;
        support.firePropertyChange("notifyLifecycleListenerOnFailure",
                oldNotifyListenerOnFailure,
                this.notifyLifecycleListenerOnFailure);
    
public voidsetProperty(java.lang.String name, java.lang.String value)
JMX hack to direct use at jconsole

param
name
param
value

        setProperty(name, (Object) value);
    
public voidsetProperty(java.lang.String name, java.lang.Object value)
set config attributes with reflect and propagate to all managers

param
name
param
value

        if (log.isTraceEnabled())
            log.trace(sm.getString("SimpleTcpCluster.setProperty", name, value,properties.get(name)));
        properties.put(name, value);
        //using a dynamic way of setting properties is nice, but a security risk
        //if exposed through JMX. This way you can sit and try to guess property names,
        //we will only allow explicit property names
        log.warn("Dynamic setProperty("+name+",value) has been disabled, please use explicit properties for the element you are trying to identify");
        if(started) {
            // FIXME Hmm, is that correct when some DeltaManagers are direct configured inside Context?
            // Why we not support it for other elements, like sender, receiver or membership?
            // Must we restart element after change?
//            if (name.startsWith("manager")) {
//                String key = name.substring("manager".length() + 1);
//                String pvalue = value.toString();
//                for (Iterator iter = managers.values().iterator(); iter.hasNext();) {
//                    Manager manager = (Manager) iter.next();
//                    if(manager instanceof DeltaManager && ((ClusterManager) manager).isDefaultMode()) {
//                        IntrospectionUtils.setProperty(manager, key, pvalue );
//                    }
//                }
//            } 
        }
    
public voidsetProtocol(java.lang.String protocol)

see
org.apache.catalina.Cluster#setProtocol(java.lang.String)

    
public voidstart()
Prepare for the beginning of active use of the public methods of this component. This method should be called after configure(), and before any of the public methods of the component are utilized.
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
IllegalStateException if this component has already been started
exception
LifecycleException if this component detects a fatal error that prevents this component from being used

        if (started)
            throw new LifecycleException(sm.getString("cluster.alreadyStarted"));
        if (log.isInfoEnabled()) log.info("Cluster is about to start");

        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, this);
        try {
            checkDefaults();
            registerClusterValve();
            channel.addMembershipListener(this);
            channel.addChannelListener(this);
            channel.start(channel.DEFAULT);
            if (clusterDeployer != null) clusterDeployer.start();
            this.started = true;
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(AFTER_START_EVENT, this);
        } catch (Exception x) {
            log.error("Unable to start cluster.", x);
            throw new LifecycleException(x);
        }
    
public voidstop()
Gracefully terminate the active cluster component.
This will disconnect the cluster communication channel, stop the listener and deregister the valves from host or engine.

Note:
The sub elements receiver, sender, membership, listener or valves are not removed. You can easily start the cluster again.

exception
IllegalStateException if this component has not been started
exception
LifecycleException if this component detects a fatal error that needs to be reported


        if (!started)
            throw new IllegalStateException(sm.getString("cluster.notStarted"));
        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, this);

        if (clusterDeployer != null) clusterDeployer.stop();
        this.managers.clear();
        try {
            if ( clusterDeployer != null ) clusterDeployer.setCluster(null);
            channel.stop(Channel.DEFAULT);
            channel.removeChannelListener(this);
            channel.removeMembershipListener(this);
            this.unregisterClusterValve();
        } catch (Exception x) {
            log.error("Unable to stop cluster valve.", x);
        }
        started = false;
        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, this);
   
protected voidtransferProperty(java.lang.String prefix, java.lang.Object bean)
transfer properties from cluster configuration to subelement bean.

param
prefix
param
bean

        if (prefix != null) {
            for (Iterator iter = getPropertyNames(); iter.hasNext();) {
                String pkey = (String) iter.next();
                if (pkey.startsWith(prefix)) {
                    String key = pkey.substring(prefix.length() + 1);
                    Object value = getProperty(pkey);
                    IntrospectionUtils.setProperty(bean, key, value.toString());
                }
            }
        }
    
protected voidunregisterClusterValve()
unregister all cluster valve to host or engine

throws
Exception
throws
ClassNotFoundException

        for (Iterator iter = valves.iterator(); iter.hasNext();) {
            ClusterValve valve = (ClusterValve) iter.next();
            if (log.isDebugEnabled())
                log.debug("Invoking removeValve on " + getContainer()
                        + " with class=" + valve.getClass().getName());
            if (valve != null) {
                    IntrospectionUtils.callMethodN(getContainer(), "removeValve",
                        new Object[] { valve }, new Class[] { org.apache.catalina.Valve.class });
            }
            valve.setCluster(this);
        }