All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgroups.JChannel Maven / Gradle / Ivy

package org.jgroups;

import org.jgroups.annotations.MBean;
import org.jgroups.annotations.ManagedAttribute;
import org.jgroups.annotations.ManagedOperation;
import org.jgroups.blocks.MethodCall;
import org.jgroups.conf.ConfiguratorFactory;
import org.jgroups.conf.ProtocolConfiguration;
import org.jgroups.conf.ProtocolStackConfigurator;
import org.jgroups.jmx.ResourceDMBean;
import org.jgroups.protocols.TP;
import org.jgroups.stack.*;
import org.jgroups.util.*;
import org.jgroups.util.UUID;
import org.w3c.dom.Element;

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;

/**
 * JChannel is a default implementation of a Channel abstraction.
 * 

* * JChannel is instantiated using an appropriate form of a protocol stack description. Protocol * stack can be described using a file, URL or a stream containing XML stack description. * * @author Bela Ban * @since 2.0 */ @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"; /*the address of this JChannel instance*/ protected Address local_addr; protected List address_generators; protected String name; /* the channel (also know as group) name */ protected String cluster_name; /* the latest view of the group membership */ protected View my_view; /*the protocol stack, used to send and receive messages from the protocol stack*/ protected ProtocolStack prot_stack; protected final Promise state_promise=new Promise<>(); /** True if a state transfer protocol is available, false otherwise (set by CONFIG event from STATE_TRANSFER protocol) */ protected boolean state_transfer_supported=false; /** True if a flush protocol is available, false otherwise (set by CONFIG event from FLUSH protocol) */ protected volatile boolean flush_supported=false; protected final ConcurrentMap config=Util.createConcurrentMap(16); /** 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; protected final DiagnosticsHandler.ProbeHandler probe_handler=new MyProbeHandler(); /** * Creates a JChannel without a protocol stack; used for programmatic creation of channel and protocol stack * @param create_protocol_stack If true, the default configuration will be used. If false, no protocol stack * will be created * @param create_protocol_stack Creates the default stack if true, or no stack if false */ public JChannel(boolean create_protocol_stack) { if(create_protocol_stack) { try { init(ConfiguratorFactory.getStackConfigurator(DEFAULT_PROTOCOL_STACK)); } catch(Exception e) { throw new RuntimeException(e); } } } /** * Constructs a JChannel instance with the protocol stack * specified by the DEFAULT_PROTOCOL_STACK member. * @throws Exception If problems occur during the initialization of the protocol stack. */ public JChannel() throws Exception { this(DEFAULT_PROTOCOL_STACK); } /** * Constructs a JChannel instance with the protocol stack configuration contained by the specified file. * @param properties A file containing a JGroups XML protocol stack configuration. * @throws Exception If problems occur during the configuration or initialization of the protocol stack. */ public JChannel(File properties) throws Exception { this(ConfiguratorFactory.getStackConfigurator(properties)); } /** * Constructs a JChannel instance with the protocol stack configuration contained by the specified XML element. * @param properties An XML element containing a JGroups XML protocol stack configuration. * @throws Exception If problems occur during the configuration or initialization of the protocol stack. */ public JChannel(Element properties) throws Exception { this(ConfiguratorFactory.getStackConfigurator(properties)); } /** * Constructs a JChannel instance with the protocol stack configuration indicated by the specified URL. * @param properties A URL pointing to a JGroups XML protocol stack configuration. * @throws Exception If problems occur during the configuration or initialization of the protocol stack. */ public JChannel(URL properties) throws Exception { this(ConfiguratorFactory.getStackConfigurator(properties)); } /** * Constructs a JChannel instance with the protocol stack configuration based upon the specified properties parameter. * @param props A file containing a JGroups XML configuration, a URL pointing to an XML configuration, or an old * style plain configuration string. * @throws Exception If problems occur during the configuration or initialization of the protocol stack. */ public JChannel(String props) throws Exception { this(ConfiguratorFactory.getStackConfigurator(props)); } /** * Creates a channel with a configuration based on an input stream. * @param input An input stream, pointing to a streamed configuration * @throws Exception */ public JChannel(InputStream input) throws Exception { this(ConfiguratorFactory.getStackConfigurator(input)); } /** * Constructs a JChannel 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 Exception If problems occur during the initialization of the protocol stack. */ public JChannel(ProtocolStackConfigurator configurator) throws Exception { init(configurator); } /** * Creates a channel from an array of protocols. Note that after a {@link org.jgroups.JChannel#close()}, the protocol * list should not be reused, ie. new JChannel(protocols) would reuse the same protocol list, and this * might lead to problems ! * @param protocols The list of protocols, from bottom to top, ie. the first protocol in the list is the transport, * the last the top protocol * @throws Exception */ public JChannel(Protocol ... protocols) throws Exception { this(Arrays.asList(protocols)); } /** * Creates a channel from an array of protocols. Note that after a {@link org.jgroups.JChannel#close()}, the protocol * list should not be reused, ie. new JChannel(protocols) would reuse the same protocol list, and this * might lead to problems ! * @param protocols The list of protocols, from bottom to top, ie. the first protocol in the list is the transport, * the last the top protocol * @throws Exception */ public JChannel(Collection protocols) throws Exception { prot_stack=new ProtocolStack(); setProtocolStack(prot_stack); for(Protocol prot: protocols) { prot_stack.addProtocol(prot); prot.setProtocolStack(prot_stack); } prot_stack.init(); // Substitute vars with defined system props (if any) List prots=prot_stack.getProtocols(); Map map=new HashMap<>(); for(Protocol prot: prots) Configurator.resolveAndAssignFields(prot, map); } /** * 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 clients ! * @param ch * @throws Exception */ public JChannel(JChannel ch) throws Exception { init(ch); discard_own_messages=ch.discard_own_messages; } /** * Returns the protocol stack */ public ProtocolStack getProtocolStack() { return prot_stack; } public void setProtocolStack(ProtocolStack stack) { this.prot_stack=stack; if(prot_stack != null) prot_stack.setChannel(this); } /** * 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() {return prot_stack != null? prot_stack.printProtocolSpec(true) : null;} 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.getMinThreads() : -1; } @ManagedOperation public String dumpTimerQueue() { TimeScheduler timer=getTimer(); return timer != null? timer.dumpTimerTasks() : " * This method invokes connect() and then getState.

* If the FLUSH protocol is in the channel's stack definition, only one flush round is executed for both connecting and * fetching the state rather than two flushes if we invoke connect and getState in succession. *

* 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, the state will be fetched from the coordinator, unless this channel * is the coordinator. * @param timeout The timeout for the state transfer. * * @exception Exception The protocol stack cannot be started, or the JOIN failed * @exception IllegalStateException The channel is closed or disconnected * @exception StateTransferException State transfer was not successful * */ public synchronized void connect(String cluster_name, Address target, long timeout, boolean useFlushIfPresent) throws Exception { if(!_preConnect(cluster_name)) return; if(cluster_name == null) { // only connect if we are not a unicast channel state=State.CONNECTED; return; } boolean canFetchState=false; try { Event connect_event=useFlushIfPresent? new Event(Event.CONNECT_WITH_STATE_TRANSFER_USE_FLUSH, cluster_name) : new Event(Event.CONNECT_WITH_STATE_TRANSFER, cluster_name); _connect(connect_event); state=State.CONNECTED; notifyChannelConnected(this); canFetchState=getView() != null && getView().size() > 1; // if I am not the only member in cluster then if(canFetchState) getState(target, timeout, false); // fetch state from target } finally { if(flushSupported() && useFlushIfPresent) { if(canFetchState || state != State.CONNECTED) // stopFlush if we fetched the state or failed to connect... stopFlush(); } } } @ManagedOperation(description="Disconnects the channel if connected") public synchronized void disconnect() { switch(state) { case OPEN: case CLOSED: return; case CONNECTING: case CONNECTED: if(cluster_name != null) { // Send down a DISCONNECT event, which travels down to the GMS, where a response is returned try { down(new Event(Event.DISCONNECT, local_addr)); // DISCONNECT is handled by each layer } catch(Throwable t) { log.error(Util.getMessage("DisconnectFailure"), local_addr, t); } } state=State.OPEN; stopStack(true, false); notifyChannelDisconnected(this); init(); // sets local_addr=null; changed March 18 2003 (bela) -- prevented successful rejoining break; default: throw new IllegalStateException("state " + state + " unknown"); } } @ManagedOperation(description="Disconnects and destroys the channel") public synchronized void close() { _close(true); // by default disconnect before closing channel and close mq } @ManagedOperation public Map dumpStats() { Map retval=prot_stack.dumpStats(); if(retval != null) { Map tmp=dumpChannelStats(); if(tmp != null) retval.put("channel", tmp); } return retval; } public Map dumpStats(String protocol_name, List attrs) { return prot_stack.dumpStats(protocol_name, attrs); } @ManagedOperation public Map dumpStats(String protocol_name) { return prot_stack.dumpStats(protocol_name, null); } 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; } public void send(Message msg) throws Exception { checkClosedOrNotConnected(); if(msg == null) throw new NullPointerException("msg is null"); down(new Event(Event.MSG, msg)); } public void send(Address dst, Object obj) throws Exception { send(new Message(dst, obj)); } public void send(Address dst, byte[] buf) throws Exception { send(new Message(dst, buf)); } public void send(Address dst, byte[] buf, int offset, int length) throws Exception { send(new Message(dst, buf, offset, length)); } public View getView() { return state == State.CONNECTED ? my_view : null; } @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 getAddress() {return state == State.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 instanceof UUID? ((UUID)local_addr).toStringLong() : null;} public String getName() {return name;} public String getName(Address member) {return member != null? UUID.get(member) : null;} @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) { if(isConnected()) throw new IllegalStateException("name cannot be set if channel is connected (should be done before)"); this.name=name; if(local_addr != null) UUID.add(local_addr, this.name); } } public JChannel name(String name) {setName(name); return this;} public JChannel receiver(Receiver r) {setReceiver(r); return this;} @ManagedAttribute(description="Returns cluster name this channel is connected to") public String getClusterName() {return state == State.CONNECTED? cluster_name : null;} /** * Returns the first {@link AddressGenerator} in the list, or null if none is set * @return * @since 2.12 * @deprecated Doesn't make any sense as there's list of address generators, will be removed in 4.0 */ @Deprecated public AddressGenerator getAddressGenerator() { return (address_generators == null || address_generators.isEmpty())? null : address_generators.get(0); } /** * @deprecated Use {@link #addAddressGenerator(org.jgroups.stack.AddressGenerator)} instead */ @Deprecated public void setAddressGenerator(AddressGenerator address_generator) { addAddressGenerator(address_generator); } /** * Sets the new {@link AddressGenerator}. New addresses will be generated using the new generator. This * should not be done while a channel is connected, but before connecting. * @param address_generator * @since 2.12 */ public void addAddressGenerator(AddressGenerator address_generator) { if(address_generator == null) return; if(address_generators == null) address_generators=new ArrayList<>(3); address_generators.add(address_generator); } public boolean removeAddressGenerator(AddressGenerator address_generator) { return address_generator != null && address_generators != null && address_generators.remove(address_generator); } public void getState(Address target, long timeout) throws Exception { getState(target, timeout, true); } /** * Retrieves state from the target member. See {@link #getState(Address,long)} for details. */ public void getState(Address target, long timeout, boolean useFlushIfPresent) throws Exception { Callable flusher = new Callable() { public Boolean call() throws Exception { return Util.startFlush(JChannel.this); } }; getState(target, timeout, useFlushIfPresent?flusher:null); } protected boolean _preConnect(String cluster_name) throws Exception { if(state == State.CONNECTED) { if(log.isTraceEnabled()) log.trace("already connected to " + this.cluster_name); return false; } checkClosed(); setAddress(); State old_state=state; state=State.CONNECTING; try { startStack(cluster_name); } catch(Exception ex) { state=old_state; throw ex; } return true; } protected void _connect(Event connect_event) throws Exception { try { down(connect_event); } catch(Throwable t) { stopStack(true, false); state=State.OPEN; init(); throw new Exception("connecting to channel \"" + connect_event.getArg() + "\" failed", t); } } protected void getState(Address target, long timeout, Callable flushInvoker) throws Exception { 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 configuration"); if(target == null) target=determineCoordinator(); if(target != null && local_addr != null && target.equals(local_addr)) { log.trace(local_addr + ": cannot get state from myself (" + target + "): probably the first member"); return; } boolean initiateFlush=flushSupported() && flushInvoker != null; if(initiateFlush) { boolean successfulFlush=false; try { successfulFlush=flushInvoker.call(); } catch(Throwable e) { successfulFlush=false; // http://jira.jboss.com/jira/browse/JGRP-759 } 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, timeout); long start=System.currentTimeMillis(); down(new Event(Event.GET_STATE, state_info)); StateTransferResult result=state_promise.getResult(state_info.timeout); if(initiateFlush) stopFlush(); if(result == null) throw new StateTransferException("timeout during state transfer (" + (System.currentTimeMillis() - start) + "ms)"); if(result.hasException()) throw new StateTransferException("state transfer failed", result.getException()); } /** * Callback method
* Called by the ProtocolStack when a message is received. * @param evt the event carrying the message from the protocol stack */ public Object up(Event evt) { switch(evt.getType()) { case Event.MSG: Message msg=(Message)evt.getArg(); if(stats) { received_msgs++; received_bytes+=msg.getLength(); } // discard local messages (sent by myself to me) if(discard_own_messages && local_addr != null && msg.getSrc() != null && 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.getViewId(), tmp.getMembers()); else my_view=tmp; // Bela&Vladimir Oct 27th,2006 (JGroups 2.4): we need to set connected=true because a client can // call 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 // Changed: when a channel gets a view of which it is a member then it should be // connected even if connect() hasn't returned yet ! (bela Noc 2010) if(state != State.CONNECTED) state=State.CONNECTED; break; case Event.CONFIG: Map cfg=(Map)evt.getArg(); if(cfg != null) { if(cfg.containsKey("state_transfer")) { state_transfer_supported=(Boolean)cfg.get("state_transfer"); } if(cfg.containsKey("flush_supported")) { flush_supported=(Boolean)cfg.get("flush_supported"); } cfg.putAll(cfg); } break; case Event.GET_STATE_OK: StateTransferResult result=(StateTransferResult)evt.getArg(); if(up_handler != null) { try { Object retval=up_handler.up(evt); state_promise.setResult(new StateTransferResult()); return retval; } catch(Throwable t) { state_promise.setResult(new StateTransferResult(t)); } } if(receiver != null) { try { if(result.hasBuffer()) { byte[] tmp_state=result.getBuffer(); ByteArrayInputStream input=new ByteArrayInputStream(tmp_state); receiver.setState(input); } state_promise.setResult(result); } catch(Throwable t) { state_promise.setResult(new StateTransferResult(t)); } } break; case Event.STATE_TRANSFER_INPUTSTREAM_CLOSED: state_promise.setResult((StateTransferResult)evt.getArg()); break; case Event.STATE_TRANSFER_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); InputStream is=(InputStream)evt.getArg(); if(is != null && receiver != null) { try { receiver.setState(is); } catch(Throwable t) { throw new RuntimeException("failed calling setState() in state requester", t); } } break; case Event.STATE_TRANSFER_OUTPUTSTREAM: if(receiver != null && evt.getArg() != null) { try { receiver.getState((OutputStream)evt.getArg()); } catch(Exception e) { throw new RuntimeException("failed calling getState() in state provider", 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); if(receiver != null) return invokeCallback(evt.getType(), evt.getArg()); return null; } /** Callback invoked by the protocol stack to deliver a message batch */ public void up(MessageBatch batch) { if(stats) { received_msgs+=batch.size(); received_bytes+=batch.length(); } // discard local messages (sent by myself to me) if(discard_own_messages && local_addr != null && batch.sender() != null && local_addr.equals(batch.sender())) return; for(Message msg: batch) { if(up_handler != null) { try { up_handler.up(new Event(Event.MSG, msg)); } catch(Throwable t) { log.error(Util.getMessage("UpHandlerFailure"), t); } } else if(receiver != null) { try { receiver.receive(msg); } catch(Throwable t) { log.error(Util.getMessage("ReceiverFailure"), t); } } } } /** * Sends an event down the protocol stack. Note that - contrary to {@link #send(Message)}, if the event is a message, * no checks are performed whether the channel is closed or disconnected. * @param evt the message to send down, encapsulated in an event */ public Object down(Event evt) { if(evt == null) return null; if(stats && evt.getType() == Event.MSG) { sent_msgs++; sent_bytes+=((Message)evt.getArg()).getLength(); } 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("state=").append(state).append('\n'); if(details) { sb.append("discard_own_messages=").append(discard_own_messages).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 Object invokeCallback(int type, Object arg) { switch(type) { case Event.MSG: receiver.receive((Message)arg); break; case Event.VIEW_CHANGE: receiver.viewAccepted((View)arg); break; case Event.SUSPECT: receiver.suspect((Address)arg); break; case Event.GET_APPLSTATE: byte[] tmp_state=null; if(receiver != null) { ByteArrayOutputStream output=new ByteArrayOutputStream(1024); try { receiver.getState(output); tmp_state=output.toByteArray(); } catch(Exception e) { throw new RuntimeException(local_addr + ": failed getting state from application", e); } } return new StateTransferInfo(null, 0L, tmp_state); case Event.BLOCK: receiver.block(); return true; case Event.UNBLOCK: receiver.unblock(); } return null; } protected final void init(ProtocolStackConfigurator configurator) throws Exception { List configs=configurator.getProtocolStack(); for(ProtocolConfiguration config: configs) config.substituteVariables(); // replace vars with system props prot_stack=new ProtocolStack(this); prot_stack.setup(configs); // Setup protocol stack (creates protocol, calls init() on them) } protected final void init(JChannel ch) throws Exception { if(ch == null) throw new IllegalArgumentException("channel is null"); prot_stack=new ProtocolStack(this); prot_stack.setup(ch.getProtocolStack()); // Setup protocol stack (creates protocol, calls init() on them) } /** * Initializes all variables. Used after close() or disconnect(), * to be ready for new connect() */ protected void init() { if(local_addr != null) down(new Event(Event.REMOVE_ADDRESS, local_addr)); local_addr=null; cluster_name=null; my_view=null; } protected void startStack(String cluster_name) throws Exception { /*make sure the channel is not closed*/ checkClosed(); /*make sure we have a valid channel name*/ if(cluster_name == null) log.debug("cluster_name is null, assuming unicast channel"); else this.cluster_name=cluster_name; if(socket_factory != null) prot_stack.getTopProtocol().setSocketFactory(socket_factory); prot_stack.startStack(cluster_name, local_addr); // calls start() in all protocols, from top to bottom /*create a temporary view, assume this channel is the only member and is the coordinator*/ List

t=new ArrayList<>(1); t.add(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() { Address old_addr=local_addr; local_addr=generateAddress(); if(old_addr != null) down(new Event(Event.REMOVE_ADDRESS, old_addr)); if(name == null || name.isEmpty()) // generate a logical name if not set name=Util.generateLocalName(); if(name != null && !name.isEmpty()) 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); } protected Address generateAddress() { if(address_generators == null || address_generators.isEmpty()) return UUID.randomUUID(); if(address_generators.size() == 1) return address_generators.get(0).generateAddress(); // at this point we have multiple AddressGenerators installed Address[] addrs=new Address[address_generators.size()]; for(int i=0; i < addrs.length; i++) addrs[i]=address_generators.get(i).generateAddress(); for(int i=0; i < addrs.length; i++) { if(!(addrs[i] instanceof ExtendedUUID)) { log.error("address generator %s does not subclass %s which is required if multiple address generators " + "are installed, removing it", addrs[i].getClass().getSimpleName(), ExtendedUUID.class.getSimpleName()); addrs[i]=null; } } ExtendedUUID uuid=null; for(int i=0; i < addrs.length; i++) { // we only have ExtendedUUIDs in addrs if(addrs[i] != null) { if(uuid == null) uuid=(ExtendedUUID)addrs[i]; else uuid.addContents((ExtendedUUID)addrs[i]); } } return uuid != null? uuid : UUID.randomUUID(); } /** * health check
* throws a ChannelClosed exception if the channel is closed */ protected void checkClosed() { if(state == State.CLOSED) throw new IllegalStateException("channel is closed"); } protected void checkClosedOrNotConnected() { if(state == State.CLOSED) throw new IllegalStateException("channel is closed"); if(!(state == State.CONNECTING || state == State.CONNECTED)) throw new IllegalStateException("channel is disconnected"); } /** * Disconnects and closes the channel. This method does the following things *
    *
  1. Calls this.disconnect if the disconnect parameter is true *
  2. Calls ProtocolStack.stop on the protocol stack *
  3. Calls ProtocolStack.destroy on the protocol stack *
  4. Sets the channel closed and channel connected flags to true and false *
  5. Notifies any channel listener of the channel close operation *
*/ protected void _close(boolean disconnect) { Address old_addr=local_addr; if(state == State.CLOSED) return; if(disconnect) disconnect(); // leave group if connected stopStack(true, true); state=State.CLOSED; 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) { log.error(Util.getMessage("StackDestroyFailure"), e); } TP transport=prot_stack.getTransport(); if(transport != null) transport.unregisterProbeHandler(probe_handler); } } public boolean flushSupported() { return flush_supported; } public void startFlush(boolean automatic_resume) throws Exception { if(!flushSupported()) throw new IllegalStateException("Flush is not supported, add pbcast.FLUSH protocol to your configuration"); try { down(new Event(Event.SUSPEND)); } catch (Exception e) { throw new Exception("Flush failed", e.getCause()); } finally { if (automatic_resume) stopFlush(); } } public void startFlush(List
flushParticipants, boolean automatic_resume) throws Exception { if (!flushSupported()) throw new IllegalStateException("Flush is not supported, add pbcast.FLUSH protocol to your configuration"); View v = getView(); boolean validParticipants = v != null && v.getMembers().containsAll(flushParticipants); if (!validParticipants) throw new IllegalArgumentException("Current view " + v + " does not contain all flush participants " + flushParticipants); try { down(new Event(Event.SUSPEND, flushParticipants)); } catch (Exception e) { throw new Exception("Flush failed", e.getCause()); } finally { if (automatic_resume) stopFlush(flushParticipants); } } 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)); } Address determineCoordinator() { List
mbrs=my_view != null? my_view.getMembers() : null; if(mbrs == null) return null; if(!mbrs.isEmpty()) return mbrs.iterator().next(); return null; } protected 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 DiagnosticsHandler.ProbeHandler { public Map handleProbe(String... keys) { Map map=new HashMap<>(2); for(String key: keys) { if(key.startsWith("jmx")) { handleJmx(map, key); continue; } if(key.startsWith("reset-stats")) { resetAllStats(); continue; } 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(Util.getMessage("OperationInvocationFailure"), key.substring(index+1), throwable); } } } } map.put("version", Version.description); if(my_view != null && !map.containsKey("view")) map.put("view", my_view.toString()); map.put("local_addr", getAddressAsString() + " [" + getAddressAsUUID() + "]"); PhysicalAddress physical_addr=(PhysicalAddress)down(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[]{"reset-stats", "jmx", "invoke=[]", "\nop=[]"}; } protected void resetAllStats() { List prots=getProtocolStack().getProtocols(); for(Protocol prot: prots) prot.resetStatistics(); resetStats(); } protected void handleJmx(Map map, String input) { Map tmp_stats; int index=input.indexOf("="); if(index > -1) { List list=null; String protocol_name=input.substring(index +1); index=protocol_name.indexOf("."); if(index > -1) { String rest=protocol_name; protocol_name=protocol_name.substring(0, index); String attrs=rest.substring(index +1); // e.g. "num_sent,msgs,num_received_msgs" list=Util.parseStringList(attrs, ","); // check if there are any attribute-sets in the list for(Iterator it=list.iterator(); it.hasNext();) { String tmp=it.next(); index=tmp.indexOf("="); if(index != -1) { String attrname=tmp.substring(0, index); String attrvalue=tmp.substring(index+1); Protocol prot=prot_stack.findProtocol(protocol_name); Field field=prot != null? Util.getField(prot.getClass(), attrname) : null; if(field != null) { Object value=MethodCall.convert(attrvalue,field.getType()); if(value != null) prot.setValue(attrname, value); } else { // try to find a setter for X, e.g. x(type-of-x) or setX(type-of-x) ResourceDMBean.Accessor setter=ResourceDMBean.findSetter(prot, attrname); // Util.getSetter(prot.getClass(), attrname); if(setter != null) { try { Class type=setter instanceof ResourceDMBean.FieldAccessor? ((ResourceDMBean.FieldAccessor)setter).getField().getType() : setter instanceof ResourceDMBean.MethodAccessor? ((ResourceDMBean.MethodAccessor)setter).getMethod().getParameterTypes()[0].getClass() : null; Object converted_value=MethodCall.convert(attrvalue, type); setter.invoke(converted_value); } catch(Exception e) { log.error("unable to invoke %s() on %s: %s", setter, protocol_name, e); } } else log.warn(Util.getMessage("FieldNotFound"), attrname, protocol_name); } it.remove(); } } } tmp_stats=dumpStats(protocol_name, list); if(tmp_stats != null) { for(Map.Entry entry : tmp_stats.entrySet()) { Map tmp_map=(Map)entry.getValue(); String key=entry.getKey(); map.put(key, tmp_map != null? tmp_map.toString() : null); } } } else { tmp_stats=dumpStats(); if(tmp_stats != null) { for(Map.Entry entry : tmp_stats.entrySet()) { Map tmp_map=(Map)entry.getValue(); String key=entry.getKey(); map.put(key, tmp_map != null? tmp_map.toString() : null); } } } } /** * Invokes an operation and puts the return value into map * @param map * @param operation Protocol.OperationName[args], e.g. STABLE.foo[arg1 arg2 arg3] */ protected void handleOperation(Map map, String operation) throws Exception { int index=operation.indexOf("."); if(index == -1) throw new IllegalArgumentException("operation " + operation + " is missing the protocol name"); String prot_name=operation.substring(0, index); Protocol prot=prot_stack.findProtocol(prot_name); if(prot == null) return; // less drastic than throwing an exception... int args_index=operation.indexOf("["); String method_name; if(args_index != -1) method_name=operation.substring(index +1, args_index).trim(); else method_name=operation.substring(index+1).trim(); String[] args=null; if(args_index != -1) { int end_index=operation.indexOf("]"); if(end_index == -1) throw new IllegalArgumentException("] not found"); List str_args=Util.parseCommaDelimitedStrings(operation.substring(args_index + 1, end_index)); Object[] strings=str_args.toArray(); args=new String[strings.length]; for(int i=0; i < strings.length; i++) args[i]=(String)strings[i]; } Method method=MethodCall.findMethod(prot.getClass(), method_name, args); if(method == null) { log.warn(Util.getMessage("MethodNotFound"), local_addr, prot.getClass().getSimpleName(), method_name); return; } MethodCall call=new MethodCall(method); Object[] converted_args=null; if(args != null) { converted_args=new Object[args.length]; Class[] types=method.getParameterTypes(); for(int i=0; i < args.length; i++) converted_args[i]=MethodCall.convert(args[i], types[i]); } Object retval=call.invoke(prot, converted_args); if(retval != null) map.put(prot_name + "." + method_name, retval.toString()); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy