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

org.jgroups.JChannel Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote Jakarta Enterprise Beans and Jakarta Messaging, including all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and Jakarta Messaging BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 35.0.0.Beta1
Show newest version
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"); } } 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 - 2025 Weber Informatics LLC | Privacy Policy