From 88cfe5045d77d433ce02b0ef10ee84c9d4fb15e2 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Fri, 23 May 2014 15:17:15 +0000
Subject: [PATCH] (CR-3599) Convert all protocols message to use ByteArrayBuilder + ByteArrayScanner

---
 opends/src/server/org/opends/server/replication/protocol/ByteArrayScanner.java |  151 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 146 insertions(+), 5 deletions(-)

diff --git a/opends/src/server/org/opends/server/replication/protocol/ByteArrayScanner.java b/opends/src/server/org/opends/server/replication/protocol/ByteArrayScanner.java
index 374bf0b..f0a13ec 100644
--- a/opends/src/server/org/opends/server/replication/protocol/ByteArrayScanner.java
+++ b/opends/src/server/org/opends/server/replication/protocol/ByteArrayScanner.java
@@ -27,9 +27,14 @@
 import java.util.Collection;
 import java.util.zip.DataFormatException;
 
+import org.opends.server.protocols.asn1.ASN1;
+import org.opends.server.protocols.asn1.ASN1Reader;
 import org.opends.server.replication.common.CSN;
+import org.opends.server.replication.common.ServerState;
 import org.opends.server.types.ByteSequenceReader;
 import org.opends.server.types.ByteString;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
 
 /**
  * Byte array scanner class helps decode data from byte arrays received via
@@ -44,6 +49,7 @@
 {
 
   private final ByteSequenceReader bytes;
+  private final byte[] byteArray;
 
   /**
    * Builds a ByteArrayScanner object that will read from the supplied byte
@@ -55,6 +61,7 @@
   public ByteArrayScanner(byte[] bytes)
   {
     this.bytes = ByteString.wrap(bytes).asReader();
+    this.byteArray = bytes;
   }
 
   /**
@@ -172,7 +179,7 @@
   /**
    * Reads the next UTF8-encoded string.
    *
-   * @return the next UTF8-encoded string.
+   * @return the next UTF8-encoded string or null if the string length is zero
    * @throws DataFormatException
    *           if no more data can be read from the input
    */
@@ -180,9 +187,15 @@
   {
     try
     {
-      final String s = bytes.getString(findZeroSeparator());
-      bytes.skip(1); // skip the zero separator
-      return s;
+      final int offset = findZeroSeparator();
+      if (offset > 0)
+      {
+        final String s = bytes.getString(offset);
+        skipZeroSeparator();
+        return s;
+      }
+      skipZeroSeparator();
+      return null;
     }
     catch (IndexOutOfBoundsException e)
     {
@@ -220,7 +233,8 @@
   public <TCol extends Collection<String>> TCol nextStrings(TCol output)
       throws DataFormatException
   {
-    final int colSize = nextInt();
+    // nextInt() would have been safer, but byte is compatible with legacy code.
+    final int colSize = nextByte();
     for (int i = 0; i < colSize; i++)
     {
       output.add(nextString());
@@ -269,6 +283,127 @@
   }
 
   /**
+   * Reads the next DN.
+   *
+   * @return the next DN.
+   * @throws DataFormatException
+   *           if DN was incorrectly encoded or no more data can be read from
+   *           the input
+   */
+  public DN nextDN() throws DataFormatException
+  {
+    try
+    {
+      return DN.decode(nextString());
+    }
+    catch (DirectoryException e)
+    {
+      throw new DataFormatException(e.getLocalizedMessage());
+    }
+  }
+
+  /**
+   * Return a new byte array containing all remaining bytes in this
+   * ByteArrayScanner.
+   *
+   * @return new byte array containing all remaining bytes
+   */
+  public byte[] remainingBytes()
+  {
+    final int length = byteArray.length - bytes.position();
+    return nextByteArray(length);
+  }
+
+  /**
+   * Return a new byte array containing all remaining bytes in this
+   * ByteArrayScanner bar the last one which is a zero terminated byte
+   * (compatible with legacy code).
+   *
+   * @return new byte array containing all remaining bytes bar the last one
+   */
+  public byte[] remainingBytesZeroTerminated()
+  {
+    /* do not copy stupid legacy zero separator */
+    final int length = byteArray.length - (bytes.position() + 1);
+    final byte[] result = nextByteArray(length);
+    bytes.skip(1); // ignore last (supposedly) zero byte
+    return result;
+  }
+
+  /**
+   * Return a new byte array containing the requested number of bytes.
+   *
+   * @param length
+   *          the number of bytes to be read and copied to the new byte array.
+   * @return new byte array containing the requested number of bytes.
+   */
+  public byte[] nextByteArray(final int length)
+  {
+    final byte[] result = new byte[length];
+    System.arraycopy(byteArray, bytes.position(), result, 0, length);
+    bytes.skip(length);
+    return result;
+  }
+
+  /**
+   * Reads the next ServerState.
+   * <p>
+   * Caution: ServerState MUST be the last field (see
+   * {@link ByteArrayBuilder#append(ServerState)} javadoc).
+   *
+   * @return the next ServerState.
+   * @throws DataFormatException
+   *           if ServerState was incorrectly encoded or no more data can be
+   *           read from the input
+   * @see ByteArrayBuilder#append(ServerState)
+   */
+  public ServerState nextServerState() throws DataFormatException
+  {
+    final ServerState result = new ServerState();
+
+    final int maxPos = byteArray.length - 1 /* stupid legacy zero separator */;
+    while (bytes.position() < maxPos)
+    {
+      final int serverId = nextIntUTF8();
+      final CSN csn = nextCSNUTF8();
+      if (serverId != csn.getServerId())
+      {
+        throw new DataFormatException("Expected serverId=" + serverId
+            + " to be the same as serverId for CSN=" + csn);
+      }
+      result.update(csn);
+    }
+    skipZeroSeparator();
+    return result;
+  }
+
+  /**
+   * Skips the next byte and verifies it is effectively the zero separator.
+   *
+   * @throws DataFormatException
+   *           if the next byte is not the zero separator.
+   */
+  public void skipZeroSeparator() throws DataFormatException
+  {
+    if (bytes.peek() != (byte) 0)
+    {
+      throw new DataFormatException("Expected a zero separator at position "
+          + bytes.position() + " but found byte " + bytes.peek());
+    }
+    bytes.skip(1);
+  }
+
+  /**
+   * Returns a new ASN1Reader that will read bytes from this ByteArrayScanner.
+   *
+   * @return a new ASN1Reader that will read bytes from this ByteArrayScanner.
+   */
+  public ASN1Reader getASN1Reader()
+  {
+    return ASN1.getReader(bytes);
+  }
+
+  /**
    * Returns whether the scanner has more bytes to consume.
    *
    * @return true if the scanner has more bytes to consume, false otherwise.
@@ -278,4 +413,10 @@
     return bytes.remaining() == 0;
   }
 
+  /** {@inheritDoc} */
+  @Override
+  public String toString()
+  {
+    return bytes.toString();
+  }
 }

--
Gitblit v1.10.0