bboss.org.jgroups.JChannel Maven / Gradle / Ivy
package bboss.org.jgroups; import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.io.Serializable; import java.lang.reflect.Method; import java.net.DatagramSocket; import java.net.ServerSocket; import java.net.URL; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Vector; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Exchanger; import bboss.org.jgroups.annotations.MBean; import bboss.org.jgroups.annotations.ManagedAttribute; import bboss.org.jgroups.annotations.ManagedOperation; import bboss.org.jgroups.blocks.MethodCall; import bboss.org.jgroups.conf.ConfiguratorFactory; import bboss.org.jgroups.conf.ProtocolStackConfigurator; import bboss.org.jgroups.logging.Log; import bboss.org.jgroups.logging.LogFactory; import bboss.org.jgroups.protocols.TP; import bboss.org.jgroups.stack.Configurator; import bboss.org.jgroups.stack.IpAddress; import bboss.org.jgroups.stack.Protocol; import bboss.org.jgroups.stack.ProtocolStack; import bboss.org.jgroups.stack.StateTransferInfo; import bboss.org.jgroups.util.Promise; import bboss.org.jgroups.util.Queue; import bboss.org.jgroups.util.QueueClosedException; import bboss.org.jgroups.util.TimeScheduler; import bboss.org.jgroups.util.UUID; import bboss.org.jgroups.util.Util; import org.w3c.dom.Element; /** * JChannel is a pure Java implementation of Channel. * When a JChannel object is instantiated it automatically sets up the * protocol stack. *
denoting the group name. Cannot be null. * @exception ChannelException The protocol stack cannot be started * @exception ChannelClosedException The channel is closed and therefore cannot be used any longer. * A new channel has to be created first. */ @ManagedOperation(description="Connects the channel to a group") public synchronized void connect(String cluster_name) throws ChannelException { connect(cluster_name,true); } /** * Connects the channel to a group. * If the channel is already connected, an error message will be printed to the error log. * If the channel is closed a ChannelClosed exception will be thrown. * This method starts the protocol stack by calling ProtocolStack.start, * then it sends an Event.CONNECT event down the stack and waits for the return value. * Once the call returns, the channel listeners are notified and the channel is considered connected. * * @param cluster_name A* Properties *
* Properties are used to configure a channel, and are accepted in * several forms; the String form is described here. * A property string consists of a number of properties separated by * colons. For example: *
*
"<prop1>(arg1=val1):<prop2>(arg1=val1;arg2=val2):<prop3>:<propn>"** Each property relates directly to a protocol layer, which is * implemented as a Java class. When a protocol stack is to be created * based on the above property string, the first property becomes the * bottom-most layer, the second one will be placed on the first, etc.: * the stack is created from the bottom to the top, as the string is * parsed from left to right. Each property has to be the name of a * Java class that resides in the * {@link bboss.org.jgroups.protocols} package. *
* Note that only the base name has to be given, not the fully specified * class name (e.g., UDP instead of bboss.org.jgroups.protocols.UDP). *
* Each layer may have 0 or more arguments, which are specified as a * list of name/value pairs in parentheses directly after the property. * In the example above, the first protocol layer has 1 argument, * the second 2, the third none. When a layer is created, these * properties (if there are any) will be set in a layer by invoking * the layer's setProperties() method *
* As an example the property string below instructs JGroups to create * a JChannel with protocols UDP, PING, FD and GMS:
*
"UDP(mcast_addr=228.10.9.8;mcast_port=5678):PING:FD:GMS"** The UDP protocol layer is at the bottom of the stack, and it * should use mcast address 228.10.9.8. and port 5678 rather than * the default IP multicast address and port. The only other argument * instructs FD to output debug information while executing. * Property UDP refers to a class {@link bboss.org.jgroups.protocols.UDP}, * which is subsequently loaded and an instance of which is created as protocol layer. * If any of these classes are not found, an exception will be thrown and * the construction of the stack will be aborted. * * @author Bela Ban * @version $Id: JChannel.java,v 1.240 2010/06/15 10:10:42 belaban Exp $ */ @MBean(description="JGroups channel") public class JChannel extends Channel { /** The default protocol stack used by the default constructor */ public static final String DEFAULT_PROTOCOL_STACK="udp.xml"; protected String properties=null; /*the address of this JChannel instance*/ protected UUID local_addr=null; protected String name=null; /*the channel (also know as group) name*/ private String cluster_name=null; // group name /*the latest view of the group membership*/ private View my_view=null; /*the queue that is used to receive messages (events) from the protocol stack*/ private final Queue mq=new Queue(); /*the protocol stack, used to send and receive messages from the protocol stack*/ private ProtocolStack prot_stack=null; private final Promise
state_promise=new Promise (); private final Exchanger applstate_exchanger=new Exchanger (); /*flag to indicate whether to receive blocks, if this is set to true, receive_views is set to true*/ @ManagedAttribute(description="Flag indicating whether to receive blocks",writable=true) private boolean receive_blocks=false; /*flag to indicate whether to receive local messages *if this is set to false, the JChannel will not receive messages sent by itself*/ @ManagedAttribute(description="Flag indicating whether to receive this channel's own messages",writable=true) private boolean receive_local_msgs=true; /*channel connected flag*/ protected volatile boolean connected=false; /*channel closed flag*/ protected volatile boolean closed=false; // close() has been called, channel is unusable /** True if a state transfer protocol is available, false otherwise */ private boolean state_transfer_supported=false; // set by CONFIG event from STATE_TRANSFER protocol /** True if a flush protocol is available, false otherwise */ private volatile boolean flush_supported=false; // set by CONFIG event from FLUSH protocol /** Provides storage for arbitrary objects. Protocols can send up CONFIG events, and all key-value pairs of * a CONFIG event will be added to additional_data. On reconnect, a CONFIG event will be sent down by the channel, * containing all key-value pairs of additional_data */ protected final Map additional_data=new HashMap (); protected final ConcurrentMap config=new ConcurrentHashMap (); protected final Log log=LogFactory.getLog(JChannel.class); /** Collect statistics */ @ManagedAttribute(description="Collect channel statistics",writable=true) protected boolean stats=true; protected long sent_msgs=0, received_msgs=0, sent_bytes=0, received_bytes=0; private final TP.ProbeHandler probe_handler=new MyProbeHandler(); /** * Used by subclass to create a JChannel without a protocol stack, don't use as application programmer * @deprecated Remove in 3.0 */ protected JChannel(boolean no_op) { ; } /** * Constructs a JChannel
instance with the protocol stack * specified by theDEFAULT_PROTOCOL_STACK
member. * * @throws ChannelException if problems occur during the initialization of * the protocol stack. */ public JChannel() throws ChannelException { this(DEFAULT_PROTOCOL_STACK); } /** * Constructs aJChannel
instance with the protocol stack * configuration contained by the specified file. * * @param properties a file containing a JGroups XML protocol stack * configuration. * * @throws ChannelException if problems occur during the configuration or * initialization of the protocol stack. */ public JChannel(File properties) throws ChannelException { this(ConfiguratorFactory.getStackConfigurator(properties)); } /** * Constructs aJChannel
instance with the protocol stack * configuration contained by the specified XML element. * * @param properties a XML element containing a JGroups XML protocol stack * configuration. * * @throws ChannelException if problems occur during the configuration or * initialization of the protocol stack. */ public JChannel(Element properties) throws ChannelException { this(ConfiguratorFactory.getStackConfigurator(properties)); } /** * Constructs aJChannel
instance with the protocol stack * configuration indicated by the specified URL. * * @param properties a URL pointing to a JGroups XML protocol stack * configuration. * * @throws ChannelException if problems occur during the configuration or * initialization of the protocol stack. */ public JChannel(URL properties) throws ChannelException { this(ConfiguratorFactory.getStackConfigurator(properties)); } /** * Constructs aJChannel
instance with the protocol stack * configuration based upon the specified properties parameter. * * @param properties an old style property string, a string representing a * system resource containing a JGroups XML configuration, * a string representing a URL pointing to a JGroups XML * XML configuration, or a string representing a file name * that contains a JGroups XML configuration. * * @throws ChannelException if problems occur during the configuration and * initialization of the protocol stack. */ public JChannel(String properties) throws ChannelException { this(ConfiguratorFactory.getStackConfigurator(properties)); } /** * Constructs aJChannel
instance with the protocol stack * configuration contained by the protocol stack configurator parameter. ** All of the public constructors of this class eventually delegate to this * method. * * @param configurator a protocol stack configurator containing a JGroups * protocol stack configuration. * * @throws ChannelException if problems occur during the initialization of * the protocol stack. */ public JChannel(ProtocolStackConfigurator configurator) throws ChannelException { init(configurator); } /** * Creates a new JChannel with the protocol stack as defined in the properties * parameter. an example of this parameter is
* "UDP:PING:FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:VIEW_ENFORCER:STATE_TRANSFER:QUEUE"
* Other examples can be found in the ./conf directory
* @param properties the protocol stack setup; if null, the default protocol stack will be used. * The properties can also be a java.net.URL object or a string that is a URL spec. * The JChannel will validate any URL object and String object to see if they are a URL. * In case of the parameter being a url, the JChannel will try to load the xml from there. * In case properties is a org.w3c.dom.Element, the ConfiguratorFactory will parse the * DOM tree with the element as its root element. * @deprecated Use the constructors with specific parameter types instead. */ public JChannel(Object properties) throws ChannelException { if (properties == null) properties = DEFAULT_PROTOCOL_STACK; ProtocolStackConfigurator c; try { c=ConfiguratorFactory.getStackConfigurator(properties); } catch(Exception x) { throw new ChannelException("unable to load protocol stack", x); } init(c); } /** * Creates a channel with the same configuration as the channel passed to this constructor. This is used by * testing code, and should not be used by any other code ! * @param ch * @throws ChannelException */ public JChannel(JChannel ch) throws ChannelException { init(ch); receive_blocks=ch.receive_blocks; receive_local_msgs=ch.receive_local_msgs; } /** * Returns the protocol stack. * Currently used by Debugger. * Specific to JChannel, therefore * not visible in Channel */ public ProtocolStack getProtocolStack() { return prot_stack; } protected Log getLog() { return log; } /** * Returns the protocol stack configuration in string format. An example of this property is
* "UDP:PING:FD:STABLE:NAKACK:UNICAST:FRAG:FLUSH:GMS:VIEW_ENFORCER:STATE_TRANSFER:QUEUE" */ public String getProperties() { String retval=prot_stack != null? prot_stack.printProtocolSpec(true) : null; if(retval != null) properties=retval; return properties; } public boolean statsEnabled() { return stats; } public void enableStats(boolean stats) { this.stats=stats; } @ManagedOperation public void resetStats() { sent_msgs=received_msgs=sent_bytes=received_bytes=0; } @ManagedAttribute public long getSentMessages() {return sent_msgs;} @ManagedAttribute public long getSentBytes() {return sent_bytes;} @ManagedAttribute public long getReceivedMessages() {return received_msgs;} @ManagedAttribute public long getReceivedBytes() {return received_bytes;} @ManagedAttribute public int getNumberOfTasksInTimer() { TimeScheduler timer=getTimer(); return timer != null? timer.size() : -1; } @ManagedAttribute public int getTimerThreads() { TimeScheduler timer=getTimer(); return timer != null? timer.getCorePoolSize() : -1; } public String dumpTimerQueue() { TimeScheduler timer=getTimer(); return timer != null? timer.dumpTaskQueue() : "String String
denoting the group name. Cannot be null. * @exception ChannelException The protocol stack cannot be started * @exception ChannelClosedException The channel is closed and therefore cannot be used any longer. * A new channel has to be created first. */ @ManagedOperation(description="Connects the channel to a group") public synchronized void connect(String cluster_name, boolean useFlushIfPresent) throws ChannelException { if (connected) { if (log.isTraceEnabled()) log.trace("already connected to " + cluster_name); return; } setAddress(); startStack(cluster_name); if (cluster_name != null) { // only connect if we are not a unicast channel Event connect_event; if (useFlushIfPresent) { connect_event = new Event(Event.CONNECT_USE_FLUSH, cluster_name); } else { connect_event = new Event(Event.CONNECT, cluster_name); } // waits forever until connected (or channel is closed) Object res = downcall(connect_event); if (res != null && res instanceof Exception) { // the JOIN was rejected by the coordinator stopStack(true, false); init(); throw new ChannelException("connect() failed", (Throwable) res); } } connected = true; notifyChannelConnected(this); } /** * Connects this channel to a group and gets a state from a specified state * provider. ** * This method essentially invokes *
connect
and
getState
methods successively. * If FLUSH protocol is in channel's stack definition only one flush is executed for both connecting and * fetching state rather than two flushes if we invoke
connect
and
getState
in succesion. * * If the channel is already connected, an error message will be printed to the error log. * If the channel is closed a ChannelClosed exception will be thrown. * * * @param cluster_name the cluster name to connect to. Cannot be null. * @param target the state provider. If null state will be fetched from coordinator, unless this channel is coordinator. * @param state_id the substate id for partial state transfer. If null entire state will be transferred. * @param timeout the timeout for state transfer. * * @exception ChannelException The protocol stack cannot be started * @exception ChannelException Connecting to cluster was not successful * @exception ChannelClosedException The channel is closed and therefore cannot be used any longer. * A new channel has to be created first. * @exception StateTransferException State transfer was not successful * */ public synchronized void connect(String cluster_name, Address target, String state_id, long timeout) throws ChannelException { connect(cluster_name, target, state_id, timeout,true); } /** * Connects this channel to a group and gets a state from a specified state * provider. *
* * This method essentially invokes *
connect
and
getState
methods successively. * If FLUSH protocol is in channel's stack definition only one flush is executed for both connecting and * fetching state rather than two flushes if we invoke
connect
and
getState
in succesion. * * If the channel is already connected, an error message will be printed to the error log. * If the channel is closed a ChannelClosed exception will be thrown. * * * @param cluster_name the cluster name to connect to. Cannot be null. * @param target the state provider. If null state will be fetched from coordinator, unless this channel is coordinator. * @param state_id the substate id for partial state transfer. If null entire state will be transferred. * @param timeout the timeout for state transfer. * * @exception ChannelException The protocol stack cannot be started * @exception ChannelException Connecting to cluster was not successful * @exception ChannelClosedException The channel is closed and therefore cannot be used any longer. * A new channel has to be created first. * @exception StateTransferException State transfer was not successful * */ public synchronized void connect(String cluster_name, Address target, String state_id, long timeout, boolean useFlushIfPresent) throws ChannelException { if(connected) { if(log.isTraceEnabled()) log.trace("already connected to " + cluster_name); return; } setAddress(); startStack(cluster_name); boolean stateTransferOk; boolean joinSuccessful; boolean canFetchState=false; // only connect if we are not a unicast channel if(cluster_name == null) return; try { Event connect_event; if(useFlushIfPresent) connect_event=new Event(Event.CONNECT_WITH_STATE_TRANSFER_USE_FLUSH, cluster_name); else connect_event=new Event(Event.CONNECT_WITH_STATE_TRANSFER, cluster_name); Object res=downcall(connect_event); // waits forever until connected (or channel is closed) joinSuccessful=!(res != null && res instanceof Exception); if(!joinSuccessful) { stopStack(true, false); init(); throw new ChannelException("connect() failed", (Throwable)res); } connected=true; notifyChannelConnected(this); canFetchState=getView() != null && getView().size() > 1; // if I am not the only member in cluster then if(canFetchState) { try { // fetch state from target stateTransferOk=getState(target, state_id, timeout, false); if(!stateTransferOk) { throw new StateTransferException(getAddress() + " could not fetch state " + (state_id == null ? "(full)" : state_id) + " from " + (target == null ? "(all)" : target)); } } catch(Exception e) { throw new StateTransferException(getAddress() + " could not fetch state " + (state_id == null ? "(full)" : state_id) + " from " + (target == null ? "(all)" : target), e); } } } finally { if (flushSupported() && useFlushIfPresent){ //stopFlush if we fetched the state or failed to connect... if(canFetchState || !connected) stopFlush(); } } } /** * Disconnects the channel if it is connected. If the channel is closed, * this operation is ignored
* Otherwise the following actions happen in the listed order
**
*/ @ManagedOperation(description="Disconnects the channel if connected") public synchronized void disconnect() { if(closed) return; if(connected) { if(cluster_name != null) { // Send down a DISCONNECT event, which travels down to the GMS, where a response is returned Event disconnect_event=new Event(Event.DISCONNECT, local_addr); down(disconnect_event); // DISCONNECT is handled by each layer } connected=false; stopStack(true, false); notifyChannelDisconnected(this); init(); // sets local_addr=null; changed March 18 2003 (bela) -- prevented successful rejoining } } /** * Destroys the channel. * After this method has been called, the channel us unusable.- The JChannel sends a DISCONNECT event down the protocol stack
*- Blocks until the event has returned
*- Sends a STOP_QUEING event down the stack
*- Stops the protocol stack by calling ProtocolStack.stop()
*- Notifies the listener, if the listener is available
*
* This operation will disconnect the channel and close the channel receive queue immediately
*/ @ManagedOperation(description="Disconnects and destroys the channel") public synchronized void close() { _close(true, true); // by default disconnect before closing channel and close mq } /** * Shuts down a channel without disconnecting. To be used by tests only, don't use for application purposes * @deprecated Use {@link Util#shutdown(Channel)} instead. This method will be removed in 3.0 */ @ManagedOperation(description="Shuts down the channel without disconnecting") @Deprecated public synchronized void shutdown() { try { Util.shutdown(this); } catch(Exception e) { log.error("failed shutting down channel " + getAddress(), e); } } /** * Opens the channel. Note that the channel is only open, but not connected. * This does the following actions: **
* @deprecated With the removal of shunning, this method should not be used anymore */ @Deprecated public synchronized void open() throws ChannelException { if(!closed) throw new ChannelException("channel is already open"); try { mq.reset(); String props=getProperties(); // new stack is created on open() - bela June 12 2003 prot_stack=new ProtocolStack(this, props); prot_stack.setup(); closed=false; } catch(Exception e) { throw new ChannelException("failed to open channel" , e); } } /** * returns true if the Open operation has been called successfully */ @ManagedAttribute public boolean isOpen() { return !closed; } /** * returns true if the Connect operation has been called successfully */ @ManagedAttribute public boolean isConnected() { return connected; } @ManagedAttribute public int getNumMessages() { return mq.size(); } @ManagedOperation public String dumpQueue() { return Util.dumpQueue(mq); } /** * Returns a map of statistics of the various protocols and of the channel itself. * @return Map- Resets the receiver queue by calling Queue.reset *
- Sets up the protocol stack by calling ProtocolStack.setup *
- Sets the closed flag to false *
. A map where the keys are the protocols ("channel" pseudo key is * used for the channel itself") and the values are property maps. */ @ManagedOperation public Map dumpStats() { Map retval=prot_stack.dumpStats(); if(retval != null) { Map tmp=dumpChannelStats(); if(tmp != null) retval.put("channel", tmp); } return retval; } @ManagedOperation public Map dumpStats(String protocol_name) { return prot_stack.dumpStats(protocol_name); } protected Map dumpChannelStats() { Map retval=new HashMap (); retval.put("sent_msgs", sent_msgs); retval.put("sent_bytes", sent_bytes); retval.put("received_msgs", received_msgs); retval.put("received_bytes", received_bytes); return retval; } /** * Sends a message through the protocol stack. * Implements the Transport interface. * * @param msg the message to be sent through the protocol stack, * the destination of the message is specified inside the message itself * @exception ChannelNotConnectedException * @exception ChannelClosedException */ @ManagedOperation public void send(Message msg) throws ChannelNotConnectedException, ChannelClosedException { checkClosedOrNotConnected(); if(msg == null) throw new NullPointerException("msg is null"); if(stats) { sent_msgs++; sent_bytes+=msg.getLength(); } down(new Event(Event.MSG, msg)); } /** * creates a new message with the destination address, and the source address * and the object as the message value * @param dst - the destination address of the message, null for all members * @param src - the source address of the message * @param obj - the value of the message * @exception ChannelNotConnectedException * @exception ChannelClosedException * @see JChannel#send */ @ManagedOperation public void send(Address dst, Address src, Serializable obj) throws ChannelNotConnectedException, ChannelClosedException { send(new Message(dst, src, obj)); } public void send(Address dst, Address src, byte[] buf) throws ChannelNotConnectedException, ChannelClosedException { send(new Message(dst, src, buf)); } public void send(Address dst, Address src, byte[] buf, int offset, int length) throws ChannelNotConnectedException, ChannelClosedException { send(new Message(dst, src, buf, offset, length)); } /** * Blocking receive method. * This method returns the object that was first received by this JChannel and that has not been * received before. After the object is received, it is removed from the receive queue.
* If you only want to inspect the object received without removing it from the queue call * JChannel.peek
* If no messages are in the receive queue, this method blocks until a message is added or the operation times out
* By specifying a timeout of 0, the operation blocks forever, or until a message has been received. * @param timeout the number of milliseconds to wait if the receive queue is empty. 0 means wait forever * @exception TimeoutException if a timeout occured prior to a new message was received * @exception ChannelNotConnectedException * @exception ChannelClosedException * @see JChannel#peek * @deprecated Use a {@link Receiver} instead */ public Object receive(long timeout) throws ChannelNotConnectedException, ChannelClosedException, TimeoutException { checkClosedOrNotConnected(); try { Event evt=(timeout <= 0)? (Event)mq.remove() : (Event)mq.remove(timeout); Object retval=getEvent(evt); evt=null; return retval; } catch(QueueClosedException queue_closed) { throw new ChannelClosedException(); } catch(TimeoutException t) { throw t; } catch(Exception e) { if(log.isErrorEnabled()) log.error("exception: " + e); return null; } } /** * Just peeks at the next message, view or block. Does not install * new view if view is received
* Does the same thing as JChannel.receive but doesn't remove the object from the * receiver queue * * @deprecated Use a {@link Receiver} instead */ public Object peek(long timeout) throws ChannelNotConnectedException, ChannelClosedException, TimeoutException { checkClosedOrNotConnected(); try { Event evt=(timeout <= 0)? (Event)mq.peek() : (Event)mq.peek(timeout); Object retval=getEvent(evt); evt=null; return retval; } catch(QueueClosedException queue_closed) { if(log.isErrorEnabled()) log.error("exception: " + queue_closed); return null; } catch(TimeoutException t) { return null; } catch(Exception e) { if(log.isErrorEnabled()) log.error("exception: " + e); return null; } } /** * Returns the current view. *
* If the channel is not connected or if it is closed it will return null. *
* @return returns the current group view, or null if the channel is closed or disconnected */ public View getView() { return closed || !connected ? null : my_view; } @ManagedAttribute(name="View") public String getViewAsString() { View v=getView(); return v != null ? v.toString() : "n/a"; } @ManagedAttribute public static String getVersion() { return Version.printDescription(); } public Address getLocalAddress() { return getAddress(); } /** * Returns the local address of the channel (null if the channel is closed) */ public Address getAddress() { return closed ? null : local_addr; } @ManagedAttribute(name="Address") public String getAddressAsString() { return local_addr != null? local_addr.toString() : "n/a"; } @ManagedAttribute(name="Address (UUID)") public String getAddressAsUUID() { return local_addr != null? local_addr.toStringLong() : null; } public String getName() { return name; } public String getName(Address member) { return member != null? UUID.get(member) : null; } /** * Sets the logical name for the channel. The name will stay associated with this channel for the channel's * lifetime (until close() is called). This method should be called before calling connect().
* @param name */ @ManagedAttribute(writable=true, description="The logical name of this channel. Stays with the channel until " + "the channel is closed") public void setName(String name) { if(name != null) { this.name=name; if(local_addr != null) { UUID.add(local_addr, this.name); } } } /** * returns the name of the channel * if the channel is not connected or if it is closed it will return null * @deprecated Use {@link #getClusterName()} instead */ public String getChannelName() { return closed ? null : !connected ? null : cluster_name; } @ManagedAttribute(description="Returns cluster name this channel is connected to") public String getClusterName() { return closed ? null : !connected ? null : cluster_name; } /** * Sets a channel option. The options can be one of the following: **
*- Channel.BLOCK *
- Channel.LOCAL *
- Channel.AUTO_RECONNECT *
- Channel.AUTO_GETSTATE *
* There are certain dependencies between the options that you can set, * I will try to describe them here. *
* Option: Channel.BLOCK
* Value: java.lang.Boolean
* Result: set to true will set setOpt(VIEW, true) and the JChannel will receive BLOCKS and VIEW events
*
* Option: LOCAL
* Value: java.lang.Boolean
* Result: set to true the JChannel will receive messages that it self sent out.
*
* Option: AUTO_RECONNECT
* Value: java.lang.Boolean
* Result: set to true and the JChannel will try to reconnect when it is being closed
*
* Option: AUTO_GETSTATE
* Value: java.lang.Boolean
* Result: set to true, the AUTO_RECONNECT will be set to true and the JChannel will try to get the state after a close and reconnect happens
*
* * @param option the parameter option Channel.VIEW, Channel.SUSPECT, etc * @param value the value to set for this option * */ public void setOpt(int option, Object value) { if(closed) { if(log.isWarnEnabled()) log.warn("channel is closed; option not set !"); return; } switch(option) { case VIEW: case SUSPECT: case GET_STATE_EVENTS: case AUTO_RECONNECT: case AUTO_GETSTATE: break; case BLOCK: if(value instanceof Boolean) receive_blocks=((Boolean)value).booleanValue(); else if(log.isErrorEnabled()) log.error("option " + Channel.option2String(option) + " (" + value + "): value has to be Boolean"); break; case LOCAL: if(value instanceof Boolean) receive_local_msgs=((Boolean)value).booleanValue(); else if(log.isErrorEnabled()) log.error("option " + Channel.option2String(option) + " (" + value + "): value has to be Boolean"); break; default: if(log.isErrorEnabled()) log.error("option " + Channel.option2String(option) + " not known"); break; } } /** * returns the value of an option. * @param option the option you want to see the value for * @return the object value, in most cases java.lang.Boolean * @see JChannel#setOpt */ public Object getOpt(int option) { switch(option) { case VIEW: return Boolean.TRUE; case BLOCK: return receive_blocks; case SUSPECT: return Boolean.TRUE; case AUTO_RECONNECT: return false; case AUTO_GETSTATE: return false; case GET_STATE_EVENTS: return Boolean.TRUE; case LOCAL: return receive_local_msgs ? Boolean.TRUE : Boolean.FALSE; default: if(log.isErrorEnabled()) log.error("option " + Channel.option2String(option) + " not known"); return null; } } /** * Called to acknowledge a block() (callback inMembershipListener
or *BlockEvent
received from call toreceive()
). * After sending blockOk(), no messages should be sent until a new view has been received. * Calling this method on a closed channel has no effect. */ public void blockOk() { } /** * Retrieves a full state from the target member. ** * State transfer is initiated by invoking getState on this channel, state * receiver, and sending a GET_STATE message to a target member - state * provider. State provider passes GET_STATE message to application that is * using the state provider channel which in turn provides an application * state to a state receiver. Upon successful installation of a state at * state receiver this method returns true. * * * @param target * State provider. If null, coordinator is used * @param timeout * the number of milliseconds to wait for the operation to * complete successfully. 0 waits until the state has been * received * * @see ExtendedMessageListener#getState(OutputStream) * @see ExtendedMessageListener#setState(InputStream) * @see MessageListener#getState() * @see MessageListener#setState(byte[]) * * * @return true if state transfer was successful, false otherwise * @throws ChannelNotConnectedException * if channel was not connected at the time state retrieval * was initiated * @throws ChannelClosedException * if channel was closed at the time state retrieval was * initiated * @throws IllegalStateException * if one of state transfer protocols is not present in this * channel * @throws IllegalStateException * if flush is used in this channel and cluster could not be * flushed */ public boolean getState(Address target, long timeout) throws ChannelNotConnectedException, ChannelClosedException { return getState(target,null,timeout); } /** * Retrieves a substate (or partial state) indicated by state_id from the target member. *
* * State transfer is initiated by invoking getState on this channel, state * receiver, and sending a GET_STATE message to a target member - state * provider. State provider passes GET_STATE message to application that is * using the state provider channel which in turn provides an application * state to a state receiver. Upon successful installation of a state at * state receiver this method returns true. * * * @param target * State provider. If null, coordinator is used * @param state_id * The ID of the substate. If null, the entire state will be * transferred * @param timeout * the number of milliseconds to wait for the operation to * complete successfully. 0 waits until the state has been * received * * @see ExtendedMessageListener#getState(OutputStream) * @see ExtendedMessageListener#setState(InputStream) * @see MessageListener#getState() * @see MessageListener#setState(byte[]) * * * @return true if state transfer was successful, false otherwise * @throws ChannelNotConnectedException * if channel was not connected at the time state retrieval * was initiated * @throws ChannelClosedException * if channel was closed at the time state retrieval was * initiated * @throws IllegalStateException * if one of state transfer protocols is not present in this * channel * @throws IllegalStateException * if flush is used in this channel and cluster could not be * flushed */ public boolean getState(Address target, String state_id, long timeout) throws ChannelNotConnectedException, ChannelClosedException { return getState(target, state_id, timeout, true); } /** * Retrieves a substate (or partial state) indicated by state_id from the target member. *
* * State transfer is initiated by invoking getState on this channel, state * receiver, and sending a GET_STATE message to a target member - state * provider. State provider passes GET_STATE message to application that is * using the state provider channel which in turn provides an application * state to a state receiver. Upon successful installation of a state at * state receiver this method returns true. * * * @param target * State provider. If null, coordinator is used * @param state_id * The ID of the substate. If null, the entire state will be * transferred * @param timeout * the number of milliseconds to wait for the operation to * complete successfully. 0 waits until the state has been * received * @param useFlushIfPresent * whether channel should be flushed prior to state retrieval * * @see ExtendedMessageListener#getState(OutputStream) * @see ExtendedMessageListener#setState(InputStream) * @see MessageListener#getState() * @see MessageListener#setState(byte[]) * * * @return true if state transfer was successful, false otherwise * @throws ChannelNotConnectedException * if channel was not connected at the time state retrieval * was initiated * @throws ChannelClosedException * if channel was closed at the time state retrieval was * initiated * @throws IllegalStateException * if one of state transfer protocols is not present in this * channel * @throws IllegalStateException * if flush is used in this channel and cluster could not be * flushed */ public boolean getState(Address target, String state_id, long timeout, boolean useFlushIfPresent) throws ChannelNotConnectedException, ChannelClosedException { Callable
flusher = new Callable () { public Boolean call() throws Exception { return Util.startFlush(JChannel.this); } }; return getState(target, state_id, timeout, useFlushIfPresent?flusher:null); } /** * Retrieves a substate (or partial state) indicated by state_id from the target member. * * * State transfer is initiated by invoking getState on this channel, state * receiver, and sending a GET_STATE message to a target member - state * provider. State provider passes GET_STATE message to application that is * using the state provider channel which in turn provides an application * state to a state receiver. Upon successful installation of a state at * state receiver this method returns true. * * * @param target * State provider. If null, coordinator is used * @param state_id * The ID of the substate. If null, the entire state will be * transferred * @param timeout * the number of milliseconds to wait for the operation to * complete successfully. 0 waits until the state has been * received * @param flushInvoker * algorithm invoking flush * * @see ExtendedMessageListener#getState(OutputStream) * @see ExtendedMessageListener#setState(InputStream) * @see MessageListener#getState() * @see MessageListener#setState(byte[]) * * * @return true if state transfer was successful, false otherwise * @throws ChannelNotConnectedException * if channel was not connected at the time state retrieval * was initiated * @throws ChannelClosedException * if channel was closed at the time state retrieval was * initiated * @throws IllegalStateException * if one of state transfer protocols is not present in this * channel * @throws IllegalStateException * if flush is used in this channel and cluster could not be * flushed */ protected boolean getState(Address target, String state_id, long timeout,Callable
flushInvoker) throws ChannelNotConnectedException, ChannelClosedException { checkClosedOrNotConnected(); if(!state_transfer_supported) { throw new IllegalStateException("fetching state will fail as state transfer is not supported. " + "Add one of the STATE_TRANSFER protocols to your protocol configuration"); } if(target == null) target=determineCoordinator(); if(target != null && local_addr != null && target.equals(local_addr)) { if(log.isTraceEnabled()) log.trace("cannot get state from myself (" + target + "): probably the first member"); return false; } boolean initiateFlush = flushSupported() && flushInvoker!=null; if (initiateFlush) { boolean successfulFlush = false; try { successfulFlush = flushInvoker.call(); } catch (Exception e) { successfulFlush = false; // http://jira.jboss.com/jira/browse/JGRP-759 } finally { if (!successfulFlush) { throw new IllegalStateException("Node "+ local_addr+ " could not flush the cluster for state retrieval"); } } } state_promise.reset(); StateTransferInfo state_info=new StateTransferInfo(target, state_id, timeout); down(new Event(Event.GET_STATE, state_info)); Boolean b=state_promise.getResult(state_info.timeout); if(initiateFlush) stopFlush(); boolean state_transfer_successfull = b != null && b.booleanValue(); if(!state_transfer_successfull) down(new Event(Event.RESUME_STABLE)); return state_transfer_successfull; } /** * Retrieves the current group state. Sends GET_STATE event down to STATE_TRANSFER layer. * Blocks until STATE_TRANSFER sends up a GET_STATE_OK event or until timeout
* milliseconds have elapsed. The argument of GET_STATE_OK should be a vector of objects. * @param targets - the target members to receive the state from ( an Address list ) * @param timeout - the number of milliseconds to wait for the operation to complete successfully * @return true of the state was received, false if the operation timed out * @deprecated Not really needed - we always want to get the state from a single member, * use {@link #getState(bboss.org.jgroups.Address, long)} instead */ public boolean getAllStates(Vector targets, long timeout) throws ChannelNotConnectedException, ChannelClosedException { throw new UnsupportedOperationException("use getState() instead"); } /** * Called by the application is response to receiving agetState()
object when * callingreceive()
. * When the application receives a getState() message on the receive() method, * it should call returnState() to reply with the state of the application * @param state The state of the application as a byte buffer * (to send over the network). */ public void returnState(byte[] state) { try { StateTransferInfo state_info=new StateTransferInfo(null, null, 0L, state); applstate_exchanger.exchange(state_info); } catch(InterruptedException e) { Thread.currentThread().interrupt(); } } /** * Returns a substate as indicated by state_id * @param state * @param state_id */ public void returnState(byte[] state, String state_id) { try { StateTransferInfo state_info=new StateTransferInfo(null, state_id, 0L, state); applstate_exchanger.exchange(state_info); } catch(InterruptedException e) { Thread.currentThread().interrupt(); } } /** * Callback method
* Called by the ProtocolStack when a message is received. * It will be added to the message queue from which subsequent *Receive
s will dequeue it. * @param evt the event carrying the message from the protocol stack */ public Object up(Event evt) { int type=evt.getType(); Message msg; switch(type) { case Event.MSG: msg=(Message)evt.getArg(); if(stats) { received_msgs++; received_bytes+=msg.getLength(); } if(!receive_local_msgs) { // discard local messages (sent by myself to me) if(local_addr != null && msg.getSrc() != null) if(local_addr.equals(msg.getSrc())) return null; } break; case Event.VIEW_CHANGE: View tmp=(View)evt.getArg(); if(tmp instanceof MergeView) my_view=new View(tmp.getVid(), tmp.getMembers()); else my_view=tmp; /* * Bela&Vladimir Oct 27th,2006 (JGroups 2.4)- we need to switch to * connected=true because client can invoke channel.getView() in * viewAccepted() callback invoked on this thread * (see Event.VIEW_CHANGE handling below) */ // not good: we are only connected when we returned from connect() - bela June 22 2007 // if(connected == false) { // connected=true; // } break; case Event.CONFIG: Mapcfg=(Map )evt.getArg(); if(cfg != null) { if(cfg.containsKey("state_transfer")) { state_transfer_supported=((Boolean)cfg.get("state_transfer")).booleanValue(); } if(cfg.containsKey("flush_supported")) { flush_supported=((Boolean)cfg.get("flush_supported")).booleanValue(); } cfg.putAll(cfg); } break; case Event.GET_STATE_OK: StateTransferInfo state_info=(StateTransferInfo)evt.getArg(); byte[] state=state_info.state; try { if(up_handler != null) { return up_handler.up(evt); } if(state != null) { String state_id=state_info.state_id; if(receiver != null) { try { if(receiver instanceof ExtendedReceiver && state_id != null) ((ExtendedReceiver)receiver).setState(state_id, state); else receiver.setState(state); } catch(Throwable t) { if(log.isWarnEnabled()) log.warn("failed calling setState() in receiver", t); } } else { try { mq.add(new Event(Event.STATE_RECEIVED, state_info)); } catch(Exception e) { } } } } finally { state_promise.setResult(state != null? Boolean.TRUE : Boolean.FALSE); } break; case Event.STATE_TRANSFER_INPUTSTREAM_CLOSED: state_promise.setResult(Boolean.TRUE); break; case Event.STATE_TRANSFER_INPUTSTREAM: StateTransferInfo sti=(StateTransferInfo)evt.getArg(); InputStream is=sti.inputStream; //Oct 13,2006 moved to down() when Event.STATE_TRANSFER_INPUTSTREAM_CLOSED is received //state_promise.setResult(is != null? Boolean.TRUE : Boolean.FALSE); if(up_handler != null) { return up_handler.up(evt); } if(is != null) { if(receiver instanceof ExtendedReceiver) { try { if(sti.state_id == null) ((ExtendedReceiver)receiver).setState(is); else ((ExtendedReceiver)receiver).setState(sti.state_id, is); } catch(Throwable t) { if(log.isWarnEnabled()) log.warn("failed calling setState() in receiver", t); } } else if(receiver instanceof Receiver){ if(log.isWarnEnabled()){ log.warn("Channel has STREAMING_STATE_TRANSFER, however," + " application does not implement ExtendedMessageListener. State is not transfered"); Util.close(is); } } else { try { mq.add(new Event(Event.STATE_TRANSFER_INPUTSTREAM, sti)); } catch(Exception e) { } } } break; case Event.GET_LOCAL_ADDRESS: return local_addr; default: break; } // If UpHandler is installed, pass all events to it and return (UpHandler is e.g. a building block) if(up_handler != null) return up_handler.up(evt); switch(type) { case Event.MSG: if(receiver != null) { try { receiver.receive((Message)evt.getArg()); } catch(Throwable t) { if(log.isWarnEnabled()) log.warn("failed calling receive() in receiver", t); } return null; } break; case Event.VIEW_CHANGE: if(receiver != null) { try { receiver.viewAccepted((View)evt.getArg()); } catch(Throwable t) { if(log.isWarnEnabled()) log.warn("failed calling viewAccepted() in receiver", t); } return null; } break; case Event.SUSPECT: if(receiver != null) { try { receiver.suspect((Address)evt.getArg()); } catch(Throwable t) { if(log.isWarnEnabled()) log.warn("failed calling suspect() in receiver", t); } return null; } break; case Event.GET_APPLSTATE: if(receiver != null) { StateTransferInfo state_info=(StateTransferInfo)evt.getArg(); byte[] tmp_state=null; String state_id=state_info.state_id; try { if(receiver instanceof ExtendedReceiver && state_id!=null) { tmp_state=((ExtendedReceiver)receiver).getState(state_id); } else { tmp_state=receiver.getState(); } } catch(Throwable t) { if(log.isWarnEnabled()) log.warn("failed calling getState() in receiver", t); } return new StateTransferInfo(null, state_id, 0L, tmp_state); } break; case Event.STATE_TRANSFER_OUTPUTSTREAM: StateTransferInfo sti=(StateTransferInfo)evt.getArg(); OutputStream os=sti.outputStream; if(receiver instanceof ExtendedReceiver) { if(os != null) { try { if(sti.state_id == null) ((ExtendedReceiver)receiver).getState(os); else ((ExtendedReceiver)receiver).getState(sti.state_id, os); } catch(Throwable t) { if(log.isWarnEnabled()) log.warn("failed calling getState() in receiver", t); } } } else if(receiver instanceof Receiver){ if(log.isWarnEnabled()){ log.warn("Channel has STREAMING_STATE_TRANSFER, however," + " application does not implement ExtendedMessageListener. State is not transfered"); Util.close(os); } } break; case Event.BLOCK: if(!receive_blocks) { // discard if client has not set 'receiving blocks' to 'on' return true; } if(receiver != null) { try { receiver.block(); } catch(Throwable t) { if(log.isErrorEnabled()) log.error("failed calling block() in receiver", t); } return true; } break; case Event.UNBLOCK: //invoke receiver if block receiving is on if(receive_blocks && receiver instanceof ExtendedReceiver) { try { ((ExtendedReceiver)receiver).unblock(); } catch(Throwable t) { if(log.isErrorEnabled()) log.error("failed calling unblock() in receiver", t); } } return null; default: break; } if(type == Event.MSG || type == Event.VIEW_CHANGE || type == Event.SUSPECT || type == Event.GET_APPLSTATE || type== Event.STATE_TRANSFER_OUTPUTSTREAM || type == Event.BLOCK || type == Event.UNBLOCK) { try { mq.add(evt); } catch(QueueClosedException queue_closed) { ; // ignore } catch(Exception e) { if(log.isWarnEnabled()) log.warn("exception adding event " + evt + " to message queue", e); } } if(type == Event.GET_APPLSTATE) { try { return applstate_exchanger.exchange(null); } catch(InterruptedException e) { Thread.currentThread().interrupt(); return null; } } return null; } /** * Sends a message through the protocol stack if the stack is available * @param evt the message to send down, encapsulated in an event */ public void down(Event evt) { if(evt == null) return; switch(evt.getType()) { case Event.CONFIG: try { Map m=(Map )evt.getArg(); if(m != null) { additional_data.putAll(m); if(m.containsKey("additional_data")) { byte[] tmp=(byte[])m.get("additional_data"); if(local_addr != null) local_addr.setAdditionalData(tmp); } } } catch(Throwable t) { if(log.isErrorEnabled()) log.error("CONFIG event did not contain a hashmap: " + t); } break; } prot_stack.down(evt); } public Object downcall(Event evt) { if(evt == null) return null; switch(evt.getType()) { case Event.CONFIG: try { Map m=(Map )evt.getArg(); if(m != null) { additional_data.putAll(m); if(m.containsKey("additional_data")) { byte[] tmp=(byte[])m.get("additional_data"); if(local_addr != null) local_addr.setAdditionalData(tmp); } } } catch(Throwable t) { if(log.isErrorEnabled()) log.error("CONFIG event did not contain a hashmap: " + t); } break; } return prot_stack.down(evt); } @ManagedOperation public String toString(boolean details) { StringBuilder sb=new StringBuilder(); sb.append("local_addr=").append(local_addr).append('\n'); sb.append("cluster_name=").append(cluster_name).append('\n'); sb.append("my_view=").append(my_view).append('\n'); sb.append("connected=").append(connected).append('\n'); sb.append("closed=").append(closed).append('\n'); sb.append("incoming queue size=").append(mq.size()).append('\n'); if(details) { sb.append("receive_blocks=").append(receive_blocks).append('\n'); sb.append("receive_local_msgs=").append(receive_local_msgs).append('\n'); sb.append("state_transfer_supported=").append(state_transfer_supported).append('\n'); sb.append("props=").append(getProperties()).append('\n'); } return sb.toString(); } /* ----------------------------------- Private Methods ------------------------------------- */ protected final void init(ProtocolStackConfigurator configurator) throws ChannelException { if(log.isInfoEnabled()) log.info("JGroups version: " + Version.description); // ConfiguratorFactory.substituteVariables(configurator); // replace vars with system props String tmp=configurator.getProtocolStackString(); // replace vars with system props try { Collection configs=Configurator.parseConfigurations(tmp); for(Configurator.ProtocolConfiguration config: configs) config.substituteVariables(); tmp=Configurator.printConfigurations(configs); } catch(Exception e) { throw new ChannelException("unable to parse the protocol configuration", e); } synchronized(Channel.class) { prot_stack=new ProtocolStack(this, tmp); try { prot_stack.setup(); // Setup protocol stack (creates protocol, calls init() on them) properties=tmp; } catch(Throwable e) { throw new ChannelException("unable to setup the protocol stack", e); } } } protected final void init(JChannel ch) throws ChannelException { if(ch == null) throw new IllegalArgumentException("channel is null"); if(log.isInfoEnabled()) log.info("JGroups version: " + Version.description); synchronized(JChannel.class) { prot_stack=new ProtocolStack(this, null); try { prot_stack.setup(ch.getProtocolStack()); // Setup protocol stack (creates protocol, calls init() on them) getProperties(); } catch(Throwable e) { throw new ChannelException("unable to setup the protocol stack: " + e.getMessage(), e); } } } /** * Initializes all variables. Used after close() or disconnect(), * to be ready for new connect() */ private void init() { if(local_addr != null) down(new Event(Event.REMOVE_ADDRESS, local_addr)); local_addr=null; cluster_name=null; my_view=null; // changed by Bela Sept 25 2003 //if(mq != null && mq.closed()) // mq.reset(); connected=false; } private void startStack(String cluster_name) throws ChannelException { /*make sure the channel is not closed*/ checkClosed(); /*make sure we have a valid channel name*/ if(cluster_name == null) { if(log.isDebugEnabled()) log.debug("cluster_name is null, assuming unicast channel"); } else this.cluster_name=cluster_name; try { prot_stack.startStack(cluster_name, local_addr); // calls start() in all protocols, from top to bottom } catch(Throwable e) { throw new ChannelException("failed to start protocol stack", e); } if(socket_factory != null) { prot_stack.getTopProtocol().setSocketFactory(socket_factory); } /*create a temporary view, assume this channel is the only member and is the coordinator*/ Vector t=new Vector(1); t.addElement(local_addr); my_view=new View(local_addr, 0, t); // create a dummy view TP transport=prot_stack.getTransport(); transport.registerProbeHandler(probe_handler); } /** * Generates new UUID and sets local address. Sends down a REMOVE_ADDRESS (if existing address was present) and * a SET_LOCAL_ADDRESS */ protected void setAddress() { UUID old_addr=local_addr; local_addr=UUID.randomUUID(); byte[] buf=(byte[])additional_data.get("additional_data"); if(buf != null) local_addr.setAdditionalData(buf); if(old_addr != null) down(new Event(Event.REMOVE_ADDRESS, old_addr)); if(name == null || name.length() == 0) // generate a logical name if not set name=Util.generateLocalName(); if(name != null && name.length() > 0) UUID.add(local_addr, name); Event evt=new Event(Event.SET_LOCAL_ADDRESS, local_addr); down(evt); if(up_handler != null) up_handler.up(evt); } /** * health check
* throws a ChannelClosed exception if the channel is closed */ protected void checkClosed() throws ChannelClosedException { if(closed) throw new ChannelClosedException(); } protected void checkClosedOrNotConnected() throws ChannelNotConnectedException, ChannelClosedException { if(closed) throw new ChannelClosedException(); if(!connected) throw new ChannelNotConnectedException(); } /** * returns the value of the event
* These objects will be returned
** Event Type - Return Type * Event.MSG - returns a Message object * Event.VIEW_CHANGE - returns a View object * Event.SUSPECT - returns a SuspectEvent object * Event.BLOCK - returns a new BlockEvent object * Event.GET_APPLSTATE - returns a GetStateEvent object * Event.STATE_RECEIVED- returns a SetStateEvent object * Event.Exit - returns an ExitEvent object * All other - return the actual Event object ** @param evt - the event of which you want to extract the value * @return the event value if it matches the select list, * returns null if the event is null * returns the event itself if a match (See above) can not be made of the event type */ static Object getEvent(Event evt) { if(evt == null) return null; // correct ? switch(evt.getType()) { case Event.MSG: return evt.getArg(); case Event.VIEW_CHANGE: return evt.getArg(); case Event.SUSPECT: return new SuspectEvent(evt.getArg()); case Event.BLOCK: return new BlockEvent(); case Event.UNBLOCK: return new UnblockEvent(); case Event.GET_APPLSTATE: StateTransferInfo info=(StateTransferInfo)evt.getArg(); return new GetStateEvent(info.target, info.state_id); case Event.STATE_RECEIVED: info=(StateTransferInfo)evt.getArg(); return new SetStateEvent(info.state, info.state_id); case Event.STATE_TRANSFER_OUTPUTSTREAM: info = (StateTransferInfo)evt.getArg(); return new StreamingGetStateEvent(info.outputStream,info.state_id); case Event.STATE_TRANSFER_INPUTSTREAM: info = (StateTransferInfo)evt.getArg(); return new StreamingSetStateEvent(info.inputStream,info.state_id); default: return evt; } } /** * Disconnects and closes the channel. * This method does the following things **
*/ protected void _close(boolean disconnect, boolean close_mq) { UUID old_addr=local_addr; if(closed) return; if(disconnect) disconnect(); // leave group if connected if(close_mq) closeMessageQueue(false); stopStack(true, true); closed=true; connected=false; notifyChannelClosed(this); init(); // sets local_addr=null; changed March 18 2003 (bela) -- prevented successful rejoining if(old_addr != null) UUID.remove(old_addr); } protected void stopStack(boolean stop, boolean destroy) { if(prot_stack != null) { try { if(stop) prot_stack.stopStack(cluster_name); if(destroy) prot_stack.destroy(); } catch(Exception e) { if(log.isErrorEnabled()) log.error("failed destroying the protocol stack", e); } TP transport=prot_stack.getTransport(); if(transport != null) transport.unregisterProbeHandler(probe_handler); } } public final void closeMessageQueue(boolean flush_entries) { mq.close(flush_entries); } public boolean flushSupported() { return flush_supported; } /** * Will perform a flush of the system, ie. all pending messages are flushed out of the * system and all members ack their reception. After this call returns, no member will * be sending any messages until {@link #stopFlush()} is called. *- Calls
this.disconnect
if the disconnect parameter is true *- Calls
Queue.close
on mq if the close_mq parameter is true *- Calls
ProtocolStack.stop
on the protocol stack *- Calls
ProtocolStack.destroy
on the protocol stack *- Sets the channel closed and channel connected flags to true and false *
- Notifies any channel listener of the channel close operation *
* In case of flush collisions, random sleep time backoff algorithm is employed and * flush is reattempted for numberOfAttempts. Therefore this method is guaranteed * to return after timeout x numberOfAttempts miliseconds. * * @param automatic_resume Call {@link #stopFlush()} after the flush * @return true if FLUSH completed within the timeout */ public boolean startFlush(boolean automatic_resume) { if(!flushSupported()) { throw new IllegalStateException("Flush is not supported, add pbcast.FLUSH protocol to your configuration"); } boolean successfulFlush = (Boolean) downcall(new Event(Event.SUSPEND)); if(automatic_resume) stopFlush(); return successfulFlush; } /** * Performs a partial flush in a cluster for flush participants. *
* All pending messages are flushed out only for flush participants. * Remaining members in a cluster are not included in flush. * Flush participants should be a proper subset of a current view. * *
* In case of flush collisions, random sleep time backoff algorithm is employed and * flush is reattempted for numberOfAttempts. Therefore this method is guaranteed * to return after timeout x numberOfAttempts miliseconds. * * @param automatic_resume Call {@link #stopFlush()} after the flush * @return true if FLUSH completed within the timeout */ public boolean startFlush(List
flushParticipants,boolean automatic_resume) { boolean successfulFlush; if(!flushSupported()){ throw new IllegalStateException("Flush is not supported, add pbcast.FLUSH protocol to your configuration"); } View v = getView(); if(v != null && v.getMembers().containsAll(flushParticipants)){ successfulFlush = (Boolean) downcall(new Event(Event.SUSPEND, flushParticipants)); }else{ throw new IllegalArgumentException("Current view " + v + " does not contain all flush participants " + flushParticipants); } if(automatic_resume) stopFlush(flushParticipants); return successfulFlush; } /** * Will perform a flush of the system, ie. all pending messages are flushed out of the * system and all members ack their reception. After this call returns, no member will * be sending any messages until {@link #stopFlush()} is called. ** In case of flush collisions, random sleep time backoff algorithm is employed and * flush is reattempted for numberOfAttempts. Therefore this method is guaranteed * to return after timeout x numberOfAttempts miliseconds. * @param timeout * @param automatic_resume Call {@link #stopFlush()} after the flush * @return true if FLUSH completed within the timeout */ public boolean startFlush(long timeout, boolean automatic_resume) { return startFlush(automatic_resume); } public void stopFlush() { if(!flushSupported()) { throw new IllegalStateException("Flush is not supported, add pbcast.FLUSH protocol to your configuration"); } down(new Event(Event.RESUME)); } public void stopFlush(List
flushParticipants) { if(!flushSupported()) { throw new IllegalStateException("Flush is not supported, add pbcast.FLUSH protocol to your configuration"); } down(new Event(Event.RESUME, flushParticipants)); } @Override public MapgetInfo(){ return new HashMap (config); } public void setInfo(String key, Object value) { if(key != null) config.put(key, value); } Address determineCoordinator() { Vector mbrs=my_view != null? my_view.getMembers() : null; if(mbrs == null) return null; if(!mbrs.isEmpty()) return mbrs.firstElement(); return null; } private TimeScheduler getTimer() { if(prot_stack != null) { TP transport=prot_stack.getTransport(); if(transport != null) { return transport.getTimer(); } } return null; } /* ------------------------------- End of Private Methods ---------------------------------- */ class MyProbeHandler implements TP.ProbeHandler { public Map handleProbe(String... keys) { Map map=new HashMap (2); for(String key: keys) { if(key.startsWith("jmx")) { Map tmp_stats; int index=key.indexOf("="); if(index > -1) { String value=key.substring(index +1); tmp_stats=dumpStats(value); } else tmp_stats=dumpStats(); map.put("jmx", tmp_stats != null? Util.mapToString(tmp_stats) : "null"); continue; } if(key.equals("info")) { Map tmp_info=getInfo(); map.put("info", tmp_info != null? Util.mapToString(tmp_info) : "null"); } if(key.equals("socks")) { map.put("socks", getOpenSockets()); } if(key.startsWith("invoke") || key.startsWith("op")) { int index=key.indexOf("="); if(index != -1) { try { handleOperation(map, key.substring(index+1)); } catch(Throwable throwable) { log.error("failed invoking operation " + key.substring(index+1), throwable); } } } } map.put("version", Version.description + ", cvs=\"" + Version.cvs + "\""); if(my_view != null && !map.containsKey("view")) map.put("view", my_view.toString()); map.put("local_addr", getAddressAsString() + " [" + getAddressAsUUID() + "]"); PhysicalAddress physical_addr=(PhysicalAddress)downcall(new Event(Event.GET_PHYSICAL_ADDRESS, local_addr)); if(physical_addr != null) map.put("physical_addr", physical_addr.toString()); map.put("cluster", getClusterName()); return map; } public String[] supportedKeys() { return new String[]{"jmx", "info", "invoke", "op", "socks"}; } String getOpenSockets() { Map