org.jgroups.stack.Protocol Maven / Gradle / Ivy
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.PropertyConverters;
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;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* 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());
protected List policies;
/**
* 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 List extends Policy> getPolicies() {return policies;}
@ManagedAttribute(description="The list of policies")
public String policies() {return policies == null? "n/a" :
policies.stream().map(p -> p.getClass().getSimpleName()).collect(Collectors.joining(", "));}
@Property(name="policies",converter= PropertyConverters.PolicyConverter.class)
public T setPolicies(List l) {
this.policies=l;
return (T)this;
}
public T addPolicy(Policy p) {
if(policies == null)
policies=new ArrayList<>();
policies.add(Objects.requireNonNull(p));
return (T)this;
}
public T removePolicy(Policy p) {
if(policies != null && p != null)
policies.remove(p);
return (T)this;
}
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