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

org.jgroups.stack.Protocol Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS 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: 34.0.0.Final
Show newest version


package org.jgroups.stack;


import org.jgroups.*;
import org.jgroups.annotations.ManagedAttribute;
import org.jgroups.annotations.ManagedOperation;
import org.jgroups.annotations.Property;
import org.jgroups.conf.ClassConfigurator;
import org.jgroups.conf.XmlNode;
import org.jgroups.logging.Log;
import org.jgroups.logging.LogFactory;
import org.jgroups.protocols.TP;
import org.jgroups.util.MessageBatch;
import org.jgroups.util.SocketFactory;
import org.jgroups.util.ThreadFactory;
import org.jgroups.util.Util;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;


/**
 * The Protocol class provides a set of common services for protocol layers. Each layer has to
 * be a subclass of Protocol and override a number of methods (typically just {@code up()},
 * {@code down()} and {@code getName()}. Layers are stacked in a certain order to form
 * a protocol stack. Events are passed from lower
 * layers to upper ones and vice versa. E.g. a Message received by the UDP layer at the bottom
 * will be passed to its higher layer as an Event. That layer will in turn pass the Event to
 * its layer and so on, until a layer handles the Message and sends a response or discards it,
 * the former resulting in another Event being passed down the stack.
 * 

* The important thing to bear in mind is that Events have to * be passed on between layers in FIFO order which is guaranteed by the Protocol implementation * and must be guaranteed by subclasses implementing their on Event queuing.

* Note that each class implementing interface Protocol MUST provide an empty, public * constructor ! * * @author Bela Ban */ public abstract class Protocol implements Lifecycle { protected Protocol up_prot, down_prot; protected ProtocolStack stack; @Property(description="Determines whether to collect statistics (and expose them via JMX). Default is true") protected boolean stats=true; @Property(description="Enables ergonomics: dynamically find the best values for properties at runtime") protected boolean ergonomics=true; @Property(description="Fully qualified name of a class implementing ProtocolHook, will be called after creation of " + "the protocol (before init())",writable=false) protected String after_creation_hook; @Property(description="Give the protocol a different ID if needed so we can have multiple " + "instances of it in the same stack",writable=false) protected short id=ClassConfigurator.getProtocolId(getClass()); @ManagedAttribute(description="The local address of this member") protected Address local_addr; protected final Log log=LogFactory.getLog(this.getClass()); /** * Sets the level of a logger. This method is used to dynamically change the logging level of a running system, * e.g. via JMX. The appender of a level needs to exist. * @param level The new level. Valid values are "fatal", "error", "warn", "info", "debug", "trace" * (capitalization not relevant) */ @Property(name="level", description="Sets the level") public T setLevel(String level) {log.setLevel(level); return (T)this;} @Property(name="level", description="logger level (see javadocs)") public String getLevel() {return log.getLevel();} public T level(String level) {return setLevel(level);} public Address getAddress() {return local_addr;} public Address addr() {return local_addr;} public T addr(Address addr) {this.local_addr=addr; return (T)this;} public T setAddress(Address addr) {this.local_addr=addr; return (T)this;} public boolean isErgonomics() {return ergonomics;} public T setErgonomics(boolean ergonomics) {this.ergonomics=ergonomics; return (T)this;} public ProtocolStack getProtocolStack() {return stack;} public boolean statsEnabled() {return stats;} public void enableStats(boolean flag) {stats=flag;} public String getName() {return getClass().getSimpleName();} public short getId() {return id;} public T setId(short id) {this.id=id; return (T)this;} public T getUpProtocol() {return (T)up_prot;} public T getDownProtocol() {return (T)down_prot;} public T setUpProtocol(Protocol prot) {this.up_prot=prot; return (T)this;} public T setDownProtocol(Protocol prot) {this.down_prot=prot; return (T)this;} public T setProtocolStack(ProtocolStack s) {this.stack=s; return (T)this;} public String afterCreationHook() {return after_creation_hook;} public Log getLog() {return log;} public Object getValue(String name) { if(name == null) return null; Field field=Util.getField(getClass(), name); if(field == null) throw new IllegalArgumentException("field \"" + name + "\n not found"); return Util.getField(field, this); } public T setValue(String name, Object value) { if(name == null || value == null) return (T)this; Field field=Util.getField(getClass(), name); if(field == null) throw new IllegalArgumentException("field " + name + " not found"); Property prop=field.getAnnotation(Property.class); if(prop != null) { String deprecated_msg=prop.deprecatedMessage(); if(deprecated_msg != null && !deprecated_msg.isEmpty()) log.warn("Field " + getName() + "." + name + " is deprecated: " + deprecated_msg); } Util.setField(field, this, value); return (T)this; } /** * After configuring the protocol itself from the properties defined in the XML config, a protocol might have * additional component objects which need to be configured. This callback allows a protocol developer to configure those * other objects. This call is guaranteed to be invoked after the protocol itself has been configured.
* See AUTH for an example. */ public List getComponents() { return Util.getComponents(this); } /** Called by the XML parser when subelements are found in the configuration of a protocol. This allows * a protocol to define protocol-specific information and to parse it */ public void parse(XmlNode node) throws Exception {;} /** Returns the protocol IDs of all protocols above this one (excluding the current protocol) */ public short[] getIdsAbove() { short[] retval; List ids=new ArrayList<>(); Protocol current=up_prot; while(current != null) { ids.add(current.getId()); current=current.up_prot; } retval=new short[ids.size()]; for(int i=0; i < ids.size(); i++) retval[i]=ids.get(i); return retval; } public TP getTransport() { Protocol retval=this; while(retval != null && retval.down_prot != null) { retval=retval.down_prot; } return retval instanceof TP? (TP)retval : null; } /** Supposed to be overwritten by subclasses. Usually the transport returns a valid non-null thread factory, but * thread factories can also be created by individual protocols * @return */ public ThreadFactory getThreadFactory() { return down_prot != null? down_prot.getThreadFactory(): null; } /** * Returns the SocketFactory associated with this protocol, if overridden in a subclass, or passes the call down * @return SocketFactory */ public SocketFactory getSocketFactory() { return down_prot != null? down_prot.getSocketFactory() : null; } /** * Sets a SocketFactory. Socket factories are typically provided by the transport ({@link org.jgroups.protocols.TP}) * @param factory */ public void setSocketFactory(SocketFactory factory) { if(down_prot != null) down_prot.setSocketFactory(factory); } @ManagedOperation(description="Resets all stats") public void resetStatistics() {resetStats();} public void resetStats() { ; } /** * Called after a protocol has been created and before the protocol is started. * Attributes are already set. Other protocols are not yet connected and events cannot yet be sent. * @exception Exception Thrown if protocol cannot be initialized successfully. This will cause the * ProtocolStack to fail, so the the channel constructor will throw an exception */ @Override public void init() throws Exception { } /** * This method is called on a {@link JChannel#connect(String)}; starts work. Protocols are connected ready to * receive events. Will be called from bottom to top. * @exception Exception Thrown if protocol cannot be started successfully. This will cause the ProtocolStack * to fail, so {@link JChannel#connect(String)} will throw an exception */ @Override public void start() throws Exception { } /** * Called on a {@link JChannel#disconnect()}; stops work (e.g. by closing multicast socket). Will be called * from top to bottom. */ @Override public void stop() { } /** * This method is called on a {@link JChannel#close()}. Does some cleanup; after the call, the VM will terminate */ @Override public void destroy() { } /** List of events that are required to be answered by some layer above */ public List requiredUpServices() {return null;} /** List of events that are required to be answered by some layer below */ public List requiredDownServices() {return null;} /** List of events that are provided to layers above (they will be handled when sent down from above) */ public List providedUpServices() {return null;} /** List of events that are provided to layers below (they will be handled when sent from down below) */ public List providedDownServices() {return null;} /** Returns all services provided by protocols below the current protocol */ public final List getDownServices() { List retval=new ArrayList<>(); Protocol prot=down_prot; while(prot != null) { List tmp=prot.providedUpServices(); if(tmp != null && !tmp.isEmpty()) retval.addAll(tmp); prot=prot.down_prot; } return retval; } /** Returns all services provided by the protocols above the current protocol */ public final List getUpServices() { List retval=new ArrayList<>(); Protocol prot=up_prot; while(prot != null) { List tmp=prot.providedDownServices(); if(tmp != null && !tmp.isEmpty()) retval.addAll(tmp); prot=prot.up_prot; } return retval; } /** * An event is to be sent down the stack. A protocol may want to examine its type and perform some action on it, * depending on the event's type. If the event is a message MSG, then the protocol may need to add a header to it * (or do nothing at all) before sending it down the stack using {@code down_prot.down()}. */ public Object down(Event evt) { return down_prot.down(evt); } /** * A message is sent down the stack. Protocols may examine the message and do something (e.g. add a header) with it * before passing it down. * @since 4.0 */ public Object down(Message msg) { return down_prot.down(msg); } /** * An event was received from the protocol below. Usually the current protocol will want to examine the event type * and - depending on its type - perform some computation (e.g. removing headers from a MSG event type, or updating * the internal membership list when receiving a VIEW_CHANGE event). * Finally the event is either a) discarded, or b) an event is sent down the stack using {@code down_prot.down()} * or c) the event (or another event) is sent up the stack using {@code up_prot.up()}. */ public Object up(Event evt) { return up_prot.up(evt); } /** * A single message was received. Protocols may examine the message and do something (e.g. add a header) with it * before passing it up. * @since 4.0 */ public Object up(Message msg) { return up_prot.up(msg); } /** * Sends up a multiple messages in a {@link MessageBatch}. The sender of the batch is always the same, and so is the * destination (null == multicast messages). Messages in a batch can be OOB messages, regular messages, or mixed * messages, although the transport itself will create initial MessageBatches that contain only either OOB or * regular messages.

* The default processing below sends messages up the stack individually, based on a matching criteria * (calling {@link #accept(Message)}), and - if true - calls {@link #up(org.jgroups.Event)} * for that message and removes the message. If the batch is not empty, it is passed up, or else it is dropped.

* Subclasses should check if there are any messages destined for them (e.g. using * {@link MessageBatch#getMatchingMessages(short,boolean)}), then possibly remove and process them and finally pass * the batch up to the next protocol. Protocols can also modify messages in place, e.g. ENCRYPT could decrypt all * encrypted messages in the batch, not remove them, and pass the batch up when done. * @param batch The message batch */ public void up(MessageBatch batch) { for(Iterator it=batch.iterator(); it.hasNext();) { Message msg=it.next(); if(msg != null && accept(msg)) { it.remove(); try { up(msg); } catch(Throwable t) { log.error(Util.getMessage("PassUpFailure"), t); } } } if(!batch.isEmpty()) up_prot.up(batch); } /** * Called by the default implementation of {@link #up(org.jgroups.util.MessageBatch)} for each message to determine * if the message should be removed from the message batch (and handled by the current protocol) or not. * @param msg The message. Guaranteed to be non-null * @return True if the message should be handled by this protocol (will be removed from the batch), false if the * message should remain in the batch and be passed up.

* The default implementation tries to find a header matching the current protocol's ID and returns true if there * is a match, or false otherwise */ protected boolean accept(Message msg) { short tmp_id=getId(); return tmp_id > 0 && msg.getHeader(tmp_id) != null; } }