Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*-
    * See the file LICENSE for redistribution information.
    *
    * Copyright (c) 2002, 2013 Oracle and/or its affiliates.  All rights reserved.
    *
    */
   
   package com.sleepycat.je.rep.utilint;
   
  import static com.sleepycat.je.rep.utilint.BinaryProtocolStatDefinition.N_BYTES_READ;
  import static com.sleepycat.je.rep.utilint.BinaryProtocolStatDefinition.N_BYTES_WRITTEN;
  import static com.sleepycat.je.rep.utilint.BinaryProtocolStatDefinition.N_MESSAGES_READ;
  import static com.sleepycat.je.rep.utilint.BinaryProtocolStatDefinition.N_MESSAGES_WRITTEN;
  import static com.sleepycat.je.rep.utilint.BinaryProtocolStatDefinition.N_READ_NANOS;
  import static com.sleepycat.je.rep.utilint.BinaryProtocolStatDefinition.N_WRITE_NANOS;
  
  import java.util.Arrays;
  import java.util.HashMap;
  import java.util.Map;
  
Supplies the basic infrastructure for BinaryProtocols used to exchange messages by the replications stream and during network based restore operations. Note that this class and its subclasses are not synchronized. There must be one instance of this class per thread of control. IMPORTANT: Please avoid all uses of ByteBuffer.get/put when serializing message fields of types: long, int and short to avoid byte order issues. Use LogUtils.read/write methods instead, since they use a single canonical byte-independent representation.
  
  public abstract class BinaryProtocol {
  
      protected static final int MESSAGE_HEADER_SIZE =
          2 /* Message op id (short) */ +
          4 /* message size (int) */;
  
      /* Buffer reused to process the header of every message. */
      protected final ByteBuffer header =
          ByteBuffer.allocate(());
  
      /* The version as implemented by the actual code. */
      protected final int codeVersion;
  
      /* The version that this instance is actually configured to use. */
      /* It's not final to facilitate testing */
      protected int configuredVersion;
  
      /* Identifies the node using this protocol. */
      protected final NameIdPair nameIdPair;
  
      /* Maps the message op id to its canonical descriptor instance. */
      private final Map<ShortMessageOpops = new HashMap<ShortMessageOp>();
      private final int predefinedMessageCount;
  
      /* The max message size which will be accepted. */
      private final long maxMessageSize;
  
      /* Whether to use UTF8 or default encoding for Strings. */
      private final boolean useStringDefaultEncoding;
  
      /*
       * The predefined messages. IMPORTANT: Note that predefined message ops
       * start at 1000. to stay out of the way of subtype ops.
       */
      public final MessageOp CLIENT_VERSION =
          new MessageOp((short) 1001, ClientVersion.class);
  
      public final MessageOp SERVER_VERSION =
          new MessageOp((short) 1002, ServerVersion.class);
  
     public final MessageOp INCOMPATIBLE_VERSION =
         new MessageOp((short) 1003, IncompatibleVersion.class);
 
     public final MessageOp PROTOCOL_ERROR =
         new MessageOp((short) 1004, ProtocolError.class);
 
     /* Statistics definition. */
     protected final StatGroup stats;
     protected final LongStat nReadNanos;
     protected final LongStat nWriteNanos;
     protected final LongStat nBytesRead;
     protected final LongStat nMessagesRead;
     protected final LongStat nBytesWritten;
     protected final LongStat nMessagesWritten;
 
     protected final Logger logger;
     protected final Formatter formatter;
     protected final EnvironmentImpl envImpl;

    
Returns a Protocol object configured that implements the specified (supported) version.

Parameters:
codeVersion the version actually implemented by the protocol.
configuredVersion the version of the protocol that must be implemented/simulated by this protocol when communicating with the recipient.
 
     protected BinaryProtocol(NameIdPair nameIdPair,
                              int codeVersion,
                              int configuredVersion,
                              EnvironmentImpl envImpl) {
         this. = nameIdPair;
         this. = codeVersion;
         this. = configuredVersion;
         this. = envImpl;
 
         if (envImpl != null) {
             this. = LoggerUtils.getLogger(getClass());
         } else {
             this. = LoggerUtils.getLoggerFormatterNeeded(getClass());
         }
         this. = new ReplicationFormatter(nameIdPair);
 
                               .);
          = new LongStat();
          = new LongStat();
          = new LongStat();
          = new LongStat();
          = new LongStat();
          = new LongStat();
 
         /* Initialize with the pre-defined protocol messages. */
         for (MessageOp op :
             new MessageOp[] { ,
                               ,
                               ,
                                }) {
 
             if (.put(op.opIdop) != null) {
                 throw EnvironmentFailureException.unexpectedState
                     ("Duplicate op: " + op.opId);
             }
         }
          = .size();
         if (envImpl != null) {
             DbConfigManager configManager = envImpl.getConfigManager();
             long mMSz =
                 configManager.getLong(.);
              = (mMSz == 0) ?
                 (envImpl.getMemoryBudget().getMaxMemory() >> 1) :
                 mMSz;
              = configManager.getBoolean
                 (.);
         } else {
             /* Some unit tests pass in null EnvImpl. */
              = 1 << 20;
              = true;
         }
     }
 
     /*
      * Must be invoked after the constructor has completed, to get around
      * base/subclass initialization dependences; MessageOps are instances of
      * nested classes declared in the subclass.
      */
     protected void initializeMessageOps(MessageOp[] protocolOps) {
 
         for (MessageOp op : protocolOps) {
             if (.put(op.opIdop) != null) {
                 throw EnvironmentFailureException.unexpectedState
                     ("Duplicate op: " + op.opId);
             }
         }
     }
 
     /*
      * The total number of messages defined by the protocol. Includes messages
      * defined by the subclass.
      */
     public int messageCount() {
         return .size();
     }
 
     /* The messages defined in this class. */
     final public int getPredefinedMessageCount() {
         return ;
     }

    
Returns the version associated with this protocol instance. Request message generated by this instance conform to this version and responses are expected to conform to this version as well.

Returns:
the version that is actually being used.
 
     public int getVersion() {
         return ;
     }
 
     public StatGroup getStats(StatsConfig config) {
         StatGroup ret = .cloneGroup(config.getClear());
 
         return ret;
     }
 
     public void resetStats() {
         .clear();
     }
 
     /* Messages <= this size will use the shared buffer. */
     private static int CACHED_BUFFER_SIZE = 0x4000;
 
     /*
      * The shared read and write buffers that are reused. There are
      * two buffers, so that reading and writing can proceed in parallel.
      */
     private final ByteBuffer cachedReadBuffer =
         ByteBuffer.allocate();
 
     private final ByteBuffer cachedWriteBuffer =
             ByteBuffer.allocate();

    
Returns a read buffer of the requested size.

Parameters:
size the size of the requested buffer in bytes
Returns:
the requested
 
     private ByteBuffer allocateReadBuffer(int size) {
         if (size <=  ) {
             .rewind();
             .limit(size);
             return ;
         }
         return ByteBuffer.allocate(size);
     }

    
Returns a write buffer of the requested size.

Parameters:
size the size of the requested buffer in bytes
Returns:
the requested
 
     private ByteBuffer allocateWriteBuffer(int size) {
         if(size <=  ) {
             .rewind();
             .limit(size);
             return ;
         }
         return ByteBuffer.allocate(size);
     }
 
     /* Returns byte size of serialized string. */
     public int stringSize(String s) {
         return stringToBytes(s).length + 4;
     }
 
     /* Serialize the string into the buffer. */
     public void putString(String sByteBuffer buffer) {
         byte[] b = stringToBytes(s);
         LogUtils.writeInt(bufferb.length);
         buffer.put(b);
     }

    
Reconstitutes the string serialized by the above method.

Parameters:
buffer the buffer containing the string
Returns:
the de-serialized string
 
     public String getString(ByteBuffer buffer) {
         int length = LogUtils.readInt(buffer);
         byte b[] = new byte[length];
         buffer.get(b);
         return bytesToString(b);
     }

    
Responsible for converting a String to an encoded value for all protocols.

In JE 5.0.36 and earlier, only the default encoding was supported. In later releases, a config param was added to force UTF-8 to be used. In JE 5.1 and later, the default will be to use UTF-8. [#20967]

 
     private byte[] stringToBytes(String s) {
         if () {
             return s.getBytes();
         }
         return StringUtils.toUTF8(s);
     }

    
Responsible for converting an encoded value to a String for all protocols.

 
     private String bytesToString(byte[] b) {
         if () {
             return new String(b);
         }
         return StringUtils.fromUTF8(b);
     }

    
The Operations that are part of the protocol.
 
     public static class MessageOp {
 
         /* The string denoting the operation for the request message. */
         private final short opId;
 
         /* The class used to represent the message. */
         private final Class<? extends MessagemessageClass;
         /* The constructor used to create message instances. */
         private Constructor<? extends Messageconstructor;
 
         /* The label is used for debugging purposes. */
         private final String label;
 
         public MessageOp(short opIdClass<? extends MessagemessageClass) {
             this. = opId;
             this. = messageClass;
             this. = messageClass.getSimpleName();
             try {
                  = messageClass.getConstructor
                     (messageClass.getEnclosingClass(), ByteBuffer.class);
             } catch (SecurityException e) {
                 throw EnvironmentFailureException.unexpectedException(e);
             } catch (NoSuchMethodException e) {
                 throw EnvironmentFailureException.unexpectedException(e);
             }
         }
 
         public short getOpId() {
             return ;
         }
 
         Class<? extends MessagegetMessageClass() {
             return ;
         }
 
         public Constructor<? extends MessagegetConstructor() {
             return ;
         }
 
         @Override
         public String toString() {
             return ;
         }
     }

    
Returns the Op from a message buffer. It's always the first item in the buffer. Leaves the message buffer positioned after the Op.

Parameters:
messageBuffer a message buffer the the protocol
Returns:
the OpId
 
     private MessageOp getOp(ByteBuffer messageBuffer) {
         short opId = LogUtils.readShort(messageBuffer);
         final MessageOp messageOp = .get(opId);
 
         if (messageOp == null) {
             throw EnvironmentFailureException.unexpectedState
                 (,
                  "Unknown message op id:" + opId +
                  " Known op ids:" + Arrays.toString(.keySet().toArray()));
         }
         return messageOp;
     }
 
     /*
      * Used to indicate that an entity is formatable and can be serialized and
      * de-serialized.
      */
     interface WireFormatable {
 
         /*
          * Returns a ByteBuffer holding the message in a representation
          * suitable for use in a network transmission. The buffer is flipped
          * and ready for relative reads.
          */
         abstract ByteBuffer wireFormat();
     }

    
Fills a dedicated empty buffer with bytes read from the channel. It flips the buffer after it has been filled, so it's ready for reading.

Parameters:
channel the channel to be read
buffer the buffer to be filled
Throws:
java.io.IOException if the errors were encountered while reading from the channel or the buffer could not be filled with the expected number of bytes
 
     private void fillBuffer(ReadableByteChannel channel,
                             ByteBuffer buffer)
         throws IOException {
 
         final long start = System.nanoTime();
         assert(buffer.position() == 0);
         while (buffer.position() < buffer.limit()) {
             int numRead = channel.read(buffer);
             if (numRead <= 0) {
                 throw new IOException("Expected bytes: " + buffer.limit() +
                                       " read bytes: " + buffer.position());
             }
         }
         .add(System.nanoTime() - start);
         buffer.flip();
     }

    
Read and parse an incoming message, specifying the incoming version.

Parameters:
channel the channel to read from. Declared as a ReadableByteChannel rather than the more obvious SocketChannel to facilitate unit testing.
Throws:
java.io.IOException
 
     public Message read(ReadableByteChannel channel)
         throws IOException {
 
         /* Get the message header. */
         fillBuffer(channel);
 
         /* Use the type value to determine the message type. */
         MessageOp op = getOp();
         try {
             Constructor<? extends Messagecons = op.getConstructor();
 
             /* Read the size to determine the body of the message. */
             int messageBodySize = LogUtils.readInt();
             .add( + messageBodySize);
             .increment();
             if (messageBodySize > 0) {
                 if (messageBodySize > ) {
                     throw EnvironmentFailureException.unexpectedState
                         ("Message op: " + op + " Body size: " +
                          messageBodySize + " is too large.  maxSizeAllowed: " +
                           +
                          "\nIf a larger value is needed, set the " +
                          "'je.rep.maxMessageSize' parameter.");
                 }
 
                 ByteBuffer body = allocateReadBuffer(messageBodySize);
                 fillBuffer(channelbody);
                 return cons.newInstance(thisbody);
             }
 
             if (messageBodySize < 0) {
                 throw EnvironmentFailureException.unexpectedState
                     ("Message op: " + op + " Body size: " + messageBodySize);
             }
             /* No body */
             return cons.newInstance(thisnull);
         } catch (InstantiationException e) {
             throw EnvironmentFailureException.unexpectedException(e);
         } catch (IllegalAccessException e) {
             throw EnvironmentFailureException.unexpectedException(e);
         } catch (SecurityException e) {
             throw EnvironmentFailureException.unexpectedException(e);
         } catch (InvocationTargetException e) {
             throw EnvironmentFailureException.unexpectedException(e);
         } finally {
             /* The header buffer will be reused, so clear it. */
             .clear();
         }
     }
 
     @SuppressWarnings("unchecked")
     public <T extends Message> T read(ReadableByteChannel channelClass<T> cl)
         throws IOExceptionProtocolException {
 
         Message message = read(channel);
 
         /*
          * Note: the subclassing check instead of an equality check makes it
          * convenient to deal with responses when there can be multiple
          * possible but related responses.
          */
         if (cl.isAssignableFrom(message.getClass())) {
             return (T)message;
         }
         throw new ProtocolException(messagecl);
     }

    
Write a message out to a channel.

 
     public void write(Message messageNamedChannel namedChannel)
         throws IOException {
 
         write(messagenamedChannelnamedChannel.getNameIdPair());
     }

    
Write a message out to a channel.

 
     public void write(Message messageWritableByteChannel channel)
         throws IOException {
 
         write(messagechannel.);
     }

    
Write a message out to a channel.

 
     private void write(Message message,
                        WritableByteChannel channel,
                        NameIdPair destinationNameIdPair)
         throws IOException {
 
         ByteBuffer messageBuffer = message.wireFormat();
                                      messageBuffer.limit() -
                                      messageBuffer.position());
         .increment();
 
         final long start = System.nanoTime();
         while (messageBuffer.remaining() > 0) {
             int bytes = channel.write(messageBuffer);
             if (bytes == 0) {
 
                 /*
                  * This should not happen since it's a blocking channel, but
                  * the java doc is vague on this subject, so yield control if
                  * we are not making progress.
                  */
                 Thread.yield();
             }
         }
         .add(System.nanoTime() -start);
 
         if (.isLoggable(.)) {
             if (destinationNameIdPair == .) {
                 /* No nameIdPair was supplied, so use the channel. */
                 LoggerUtils.logMsg(.,
                                    "Sent " + message + " to " + channel);
             } else {
                 LoggerUtils.logMsg(.,
                                    "Sent to " +
                                    destinationNameIdPair.getName() +
                                    ": "+  message);
             }
         }
 
         /* Rewind the message buffer in case it's a reusable wire format */
         messageBuffer.rewind();
     }

    
Base message class for all messages exchanged in the protocol. Serialized layout of a message: - opType (short) - size of the body of the message (int) - body of the message - message specific fields

All non-abstract subclasses must implement a constructor with a ByteBuffer argument. This constructor is used during serialization to recreate the Message instance. It's considered good practice to declare all attributes of a message as final. It's a simple way to ensure that the above constructor has initialized all the attributes of the message.

 
     public abstract class Message implements WireFormatable {
 
         public abstract MessageOp getOp();

        
The default message consists of the operation enum and just a 0 length size.
 
         public ByteBuffer wireFormat() {
             ByteBuffer messageBuffer = allocateInitializedBuffer(0);
             messageBuffer.flip();
             return messageBuffer;
         }
 
         @Override
         public String toString() {
             return getOp().toString();
         }
 
         /*
          * For unit test support, so we can compare a message created for
          * sending against a message received. Some message types need to
          * override.
          */
         public boolean match(Message other) {
             return Arrays.equals(wireFormat().array().clone(),
                                  other.wireFormat().array().clone());
         }

        
Allocate a buffer for the message with the header initialized.

Parameters:
size size of the message contents following the buffer
Returns:
the initialized buffer
 
         public ByteBuffer allocateInitializedBuffer(int size) {
             ByteBuffer messageBuffer =
                 allocateWriteBuffer( + size);
             LogUtils.writeShort(messageBuffergetOp().getOpId());
             LogUtils.writeInt(messageBuffersize);
             return messageBuffer;
         }
     }

    
Base class for simple messages. Ones where performance is not of the utmost importance and reflection can be used to simplify message serialization and de-serialization.
 
     protected abstract class SimpleMessage extends Message {

        
Assembles a sequence of arguments into its byte based wire format. The method does the serialization in two steps. In step 1, it calculates the length of the buffer. In step 2, it assembles the bytes into the allocated buffer. The interpretive approach used here is suitable for the low performance requirements of the handshake protocol, but not for the core data stream itself. It's for this reason that the method is associated with the Handshake message class and not the Message class.

Parameters:
opId the operation indicated by the message
arguments the arguments to be passed in the message
Returns:
a byte buffer containing the serialized form of the message
 
         protected ByteBuffer wireFormat(Object... arguments) {
             int size = getMessageSize(arguments);
 
             /* Allocate the buffer and fill it up */
             ByteBuffer buffer = allocateInitializedBuffer(size);
 
             for (Object obj : arguments) {
                 Class<?> cl = obj.getClass();
                 if (cl == Long.class) {
                     LogUtils.writeLong(buffer, ((Long)obj).longValue());
                 } else if (cl == Integer.class) {
                     LogUtils.writeInt(buffer, ((Integer)obj).intValue());
                 } else if (cl == Short.class) {
                     LogUtils.writeShort(buffer, ((Short)obj).shortValue());
                 } else if (cl == Byte.class) {
                     buffer.put(((Byte)obj).byteValue());
                 }  else if (cl == Boolean.class) {
                     buffer.put(((Boolean)obj).booleanValue() ?
                                 (byte)1 :
                                 (byte)0);
                 } else if (cl == VLSN.class) {
                     LogUtils.writeLong(buffer, ((VLSN)obj).getSequence());
                 } else if (Enum.class.isAssignableFrom(cl)) {
                     /* An enum is stored as it's identifier string. */
                     Enum<?> e = (Enum<?>)obj;
                     putString(e.name(), buffer);
                 } else if (cl == String.class) {
 
                     /*
                      * A string is stored with its length followed by its
                      * contents.
                      */
                     putString((String)objbuffer);
                 } else if (cl == Double.class) {
                     /* Treat a Double as a String. */
                     putString(((Doubleobj).toString(), buffer);
                 } else if (cl == String[].class) {
                     String sa[] = (String[])obj;
                     LogUtils.writeInt(buffersa.length);
                     for (String element : sa) {
                         putString(elementbuffer);
                     }
                 } else if (cl == byte[].class) {
                     putByteArray(buffer, (byte[])obj);
                 } else if (cl == RepNodeImpl[].class) {
                     putRepNodeImplArray(buffer, (RepNodeImpl[])obj);
                 } else if (obj instanceof NameIdPair) {
                     /* instanceof used to accomodate ReadOnlyNameIdPair. */
                     ((NameIdPairobj).serialize(bufferBinaryProtocol.this);
                 } else {
                     throw EnvironmentFailureException.unexpectedState
                         ("Unknow type: " + cl);
                 }
             }
             buffer.flip();
             return buffer;
         }
 
         private void putByteArray(ByteBuffer bufferbyte[] ba) {
             LogUtils.writeInt(bufferba.length);
             buffer.put(ba);
         }
 
         private void putRepNodeImplArray(ByteBuffer buffer,
                                          RepNodeImpl[] ra) {
             LogUtils.writeInt(bufferra.length);
             for (RepNodeImpl node : ra) {
                 putByteArray(buffer, RepGroupImpl.serializeBytes(node));
             }
         }
 
         protected RepNodeImpl[] getRepNodeImplArray(ByteBuffer buffer) {
             RepNodeImpl[] ra = new RepNodeImpl[LogUtils.readInt(buffer)];
             for (int i=0; i < ra.lengthi++) {
                 ra[i] = RepGroupImpl.deserializeNode(getByteArray(buffer));
             }
             return ra;
         }
 
         private int getSize(RepNodeImpl[] ra) {
             int size = 4; /* array length */
             for (RepNodeImpl node : ra) {
                 size += (4 /* Node size */ +
                          RepGroupImpl.serializeBytes(node).length);
             }
             return size;
         }

        
Computes the size of a message with the supplied arguments. It must match the actual serialization done in the wireFormat method above.
 
         private int getMessageSize(Object... arguments) {
             int size = 0;
             /* Calculate the size */
             for (Object obj : arguments) {
                 Class<?> cl = obj.getClass();
                 if (cl == Long.class) {
                     size += 8;
                 } else if (cl == Integer.class) {
                     size +=4;
                 } else if (cl == Short.class) {
                     size +=2;
                 } else if (cl == Byte.class) {
                     size +=1;
                 } else if (cl == Boolean.class) {
                     size +=1;
                 } else if (cl == VLSN.class) {
                     size += 8;
                 } else if (Enum.class.isAssignableFrom(cl)) {
                     size += stringSize(((Enum<?>)obj).name());
                 } else if (cl == String.class) {
                    size += stringSize((String)obj);
                 } else if (cl == Double.class) {
                    size += stringSize(((Doubleobj).toString());
                 } else if (cl == String[].class) {
                     size += 4; /* array length */
                     String sa[] = (String[])obj;
                     for (String element : sa) {
                         size += stringSize(element);
                     }
                 } else if (cl == byte[].class) {
                     size += 4 + ((byte[])obj).length;
                 } else if (cl == RepNodeImpl[].class) {
                     size += getSize((RepNodeImpl[])obj);
                 } else if (obj instanceof NameIdPair) {
                     /* instanceof used to accomodate ReadOnlyNameIdPair. */
                     size +=
                         ((NameIdPairobj).serializedSize(BinaryProtocol.this);
                 } else {
                     throw EnvironmentFailureException.unexpectedState
                         ("Unknown type: " + cl);
                 }
             }
             return size;
         }

        
Reconstitutes an array of strings.

Parameters:
buffer
Returns:
 
         protected String[] getStringArray(ByteBuffer buffer) {
             String sa[] = new String[LogUtils.readInt(buffer)];
             for (int i=0; i < sa.lengthi++) {
                 sa[i] = getString(buffer);
             }
             return sa;
         }
 
         protected byte[] getByteArray(ByteBuffer buffer) {
             byte ba[] = new byte[LogUtils.readInt(buffer)];
             buffer.get(ba);
             return ba;
         }
 
         protected boolean getBoolean(ByteBuffer buffer) {
             byte b = buffer.get();
             if (b == 0) {
                 return false;
             } else if (b == 1) {
                 return true;
             } else {
                 throw EnvironmentFailureException.unexpectedState
                     ("Unknown boolean value: " + b);
             }
         }
 
         protected VLSN getVLSN(ByteBuffer buffer) {
             long vlsn = LogUtils.readLong(buffer);
             return (vlsn == ..getSequence()) ?
                  . :
                  new VLSN(vlsn);
         }
 
         protected <T extends Enum<T>> T getEnum(Class<T> enumType,
                                                 ByteBuffer buffer) {
             String enumName = getString(buffer);
             return Enum.valueOf(enumTypeenumName);
         }
 
         protected Double getDouble(ByteBuffer buffer) {
             return new Double(getString(buffer));
         }
 
         protected NameIdPair getNameIdPair(ByteBuffer buffer) {
             return NameIdPair.deserialize(bufferBinaryProtocol.this);
         }
     }

    
The base class for reject responses to requests
 
     public abstract class RejectMessage extends SimpleMessage {
         protected String errorMessage;
 
         protected RejectMessage(String errorMessage) {
             super();
             this. = errorMessage;
         }
 
         @Override
         public ByteBuffer wireFormat() {
             return wireFormat();
 
         }
 
         public RejectMessage(ByteBuffer buffer) {
              = getString(buffer);
         }
 
         public String getErrorMessage() {
             return ;
         }
 
         @Override
         public String toString() {
             return ;
         }
     }
 
     public class ProtocolError extends RejectMessage {
 
         public ProtocolError(String errorMessage) {
             super(errorMessage);
         }
 
         public ProtocolError(ByteBuffer buffer) {
             super(buffer);
         }
 
         @Override
         public MessageOp getOp() {
             return ;
         }
     }

    
Version broadcasts the sending node's protocol version.
 
     abstract class ProtocolVersion extends SimpleMessage {
 
         private final int version;
 
         private final int nodeId;
 
         public ProtocolVersion(int version) {
             super();
             this. = version;
             this. = BinaryProtocol.this..getId();
         }
 
         @Override
         public ByteBuffer wireFormat() {
             return wireFormat();
         }
 
         public ProtocolVersion(ByteBuffer buffer) {
              = LogUtils.readInt(buffer);
              = LogUtils.readInt(buffer);
         }

        

Returns:
the version
 
         public int getVersion() {
             return ;
         }

        
The nodeId of the sender

Returns:
nodeId
 
         public int getNodeId() {
             return ;
         }
     }
 
     public class ClientVersion extends ProtocolVersion {
 
         public ClientVersion() {
             super();
         }
 
         public ClientVersion(ByteBuffer buffer) {
             super(buffer);
         }
 
         @Override
         public MessageOp getOp() {
             return ;
         }
     }
 
     public class ServerVersion extends ProtocolVersion {
 
         public ServerVersion() {
             super();
         }
 
         public ServerVersion(ByteBuffer buffer) {
             super(buffer);
         }
 
         @Override
         public MessageOp getOp() {
             return ;
         }
     }
 
     public class IncompatibleVersion extends RejectMessage {
         public IncompatibleVersion(String message) {
             super(message);
         }
 
         public IncompatibleVersion(ByteBuffer buffer) {
             super(buffer);
         }
 
         @Override
         public MessageOp getOp() {
             return ;
         }
     }

    
Thrown in response to an unexpected response to a request.
 
     @SuppressWarnings("serial")
     static public class ProtocolException extends InternalException {
         private final Message unexpectedMessage;
 
         private final Class<? extends Messagecl;

        
Constructor used for message sequencing errors.
 
         public ProtocolException(Message unexpectedMessage,
                                 Class<? extends Messagecl) {
            super();
            this. = unexpectedMessage;
            this. = cl;
        }
        public ProtocolException(String message) {
            super(message);
            this. = null;
            this. = null;
        }
        @Override
        public String getMessage() {
            return ( != null) ?
                    ("Expected message type: " +  + " but found: " +
                     .getClass()) :
                    super.getMessage();
        }
        public Message getUnexpectedMessage() {
            return ;
        }
    }