mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Jean-Noel Rouvignac
06.33.2014 79aa099229a8d7dcd15798b4857d12f0649afa4e
OPENDJ-1307 Migrate server ASN1 classes to SDK


Code review: Matthew Swift


ByteStringBuilder.java:
Renamed clear(int capacity) to clearAndTruncate(int thresholdCapacity, int newCapacity).
Minor code cleanups.

ASN1OutputStreamWriter.java
In writeEndSequence(), moved some code to ByteStringBuilder.clearAndTruncate() + called the latter.

ByteStringBuilderTestCase.java:
Added tests for ByteStringBuilder.clearAndTruncate().
Added method "_" to ease bytes readability.
3 files modified
293 ■■■■ changed files
opendj-core/src/main/java/org/forgerock/opendj/io/ASN1OutputStreamWriter.java 7 ●●●● patch | view | raw | blame | history
opendj-core/src/main/java/org/forgerock/opendj/ldap/ByteStringBuilder.java 179 ●●●●● patch | view | raw | blame | history
opendj-core/src/test/java/org/forgerock/opendj/ldap/ByteStringBuilderTestCase.java 107 ●●●●● patch | view | raw | blame | history
opendj-core/src/main/java/org/forgerock/opendj/io/ASN1OutputStreamWriter.java
@@ -128,12 +128,7 @@
        logger.trace("WRITE ASN.1 END SEQUENCE(length=%d)", childStream.length());
        if (childStream.capacity() > maxBufferSize) {
            // garbage collect excessively large buffers
            childStream.clear(maxBufferSize);
        } else {
            childStream.clear();
        }
        childStream.clearAndTruncate(maxBufferSize, maxBufferSize);
        return this;
    }
opendj-core/src/main/java/org/forgerock/opendj/ldap/ByteStringBuilder.java
@@ -22,7 +22,7 @@
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 *      Portions copyright 2011-2013 ForgeRock AS
 *      Portions copyright 2011-2014 ForgeRock AS
 */
package org.forgerock.opendj.ldap;
@@ -60,7 +60,7 @@
        @Override
        public void write(final int i) {
            append(((byte) (i & 0xFF)));
            append((byte) (i & 0xFF));
        }
    }
@@ -71,10 +71,10 @@
     */
    private final class SubSequence implements ByteSequence {
        // The length of the sub-sequence.
        /** The length of the sub-sequence. */
        private final int subLength;
        // The offset of the sub-sequence.
        /** The offset of the sub-sequence. */
        private final int subOffset;
        /**
@@ -90,16 +90,14 @@
            this.subLength = length;
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public ByteSequenceReader asReader() {
            return new ByteSequenceReader(this);
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public byte byteAt(final int index) {
            if (index >= subLength || index < 0) {
                throw new IndexOutOfBoundsException();
@@ -109,9 +107,8 @@
            return buffer[subOffset + index];
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public int compareTo(final byte[] b, final int offset, final int length) {
            ByteString.checkArrayBounds(b, offset, length);
@@ -119,9 +116,8 @@
            return ByteString.compareTo(buffer, subOffset, subLength, b, offset, length);
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public int compareTo(final ByteSequence o) {
            if (this == o) {
                return 0;
@@ -131,17 +127,15 @@
            return -o.compareTo(buffer, subOffset, subLength);
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public byte[] copyTo(final byte[] b) {
            copyTo(b, 0);
            return b;
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public byte[] copyTo(final byte[] b, final int offset) {
            if (offset < 0) {
                throw new IndexOutOfBoundsException();
@@ -152,26 +146,23 @@
            return b;
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public ByteStringBuilder copyTo(final ByteStringBuilder builder) {
            // Protect against reallocation: use builder's buffer.
            return builder.append(buffer, subOffset, subLength);
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public OutputStream copyTo(final OutputStream stream) throws IOException {
            // Protect against reallocation: use builder's buffer.
            stream.write(buffer, subOffset, subLength);
            return stream;
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public boolean equals(final byte[] b, final int offset, final int length) {
            ByteString.checkArrayBounds(b, offset, length);
@@ -179,9 +170,7 @@
            return ByteString.equals(buffer, subOffset, subLength, b, offset, length);
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public boolean equals(final Object o) {
            if (this == o) {
@@ -196,9 +185,7 @@
            }
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public int hashCode() {
            // Protect against reallocation: use builder's buffer.
@@ -210,16 +197,14 @@
            return length == 0;
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public int length() {
            return subLength;
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public ByteSequence subSequence(final int start, final int end) {
            if (start < 0 || start > end || end > subLength) {
                throw new IndexOutOfBoundsException();
@@ -229,24 +214,20 @@
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public String toBase64String() {
            return Base64.encode(this);
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public byte[] toByteArray() {
            return copyTo(new byte[subLength]);
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public ByteString toByteString() {
            // Protect against reallocation: use builder's buffer.
            final byte[] b = new byte[subLength];
@@ -254,9 +235,7 @@
            return ByteString.wrap(b);
        }
        /**
         * {@inheritDoc}
         */
        /** {@inheritDoc} */
        @Override
        public String toString() {
            // Protect against reallocation: use builder's buffer.
@@ -267,10 +246,10 @@
    // These are package private so that compression and crypto
    // functionality may directly access the fields.
    // The buffer where data is stored.
    /** The buffer where data is stored. */
    byte[] buffer;
    // The number of bytes to expose from the buffer.
    /** The number of bytes to expose from the buffer. */
    int length;
    /**
@@ -706,13 +685,13 @@
     *         read and decode data from this byte string builder.
     * @see #clear()
     */
    @Override
    public ByteSequenceReader asReader() {
        return new ByteSequenceReader(this);
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public byte byteAt(final int index) {
        if (index >= length || index < 0) {
            throw new IndexOutOfBoundsException();
@@ -747,41 +726,47 @@
    /**
     * Sets the length of this byte string builder to zero, and resets the
     * capacity to the specified size.
     * capacity to the specified size if above provided threshold.
     * <p>
     * <b>NOTE:</b> if this method is called, then
     * {@code ByteSequenceReader.rewind()} must also be called on any associated
     * byte sequence readers in order for them to remain valid.
     *
     * @param capacity
     * @param thresholdCapacity
     *             The threshold capacity triggering a truncate
     * @param newCapacity
     *            The new capacity.
     * @return This byte string builder.
     * @throws IllegalArgumentException
     *             If the {@code capacity} is negative.
     *             If the {@code newCapacity} is negative or the {@code newCapacity}
     *             is bigger than the {@code thresholdCapacity}.
     * @see #asReader()
     */
    public ByteStringBuilder clear(int capacity) {
        if (capacity < 0) {
            throw new IllegalArgumentException();
    public ByteStringBuilder clearAndTruncate(int thresholdCapacity, int newCapacity) {
        if (newCapacity > thresholdCapacity) {
            throw new IllegalArgumentException("new capacity '" + newCapacity
                    + "' cannot be bigger than threshold capacity '" + thresholdCapacity + "'");
        }
        if (capacity != buffer.length) {
            buffer = new byte[capacity];
        if (newCapacity < 0) {
            throw new IllegalArgumentException("new capacity '" + newCapacity + "' cannot be negative.");
        }
        if (buffer.length > thresholdCapacity) {
            // garbage collect excessively large buffers
            buffer = new byte[newCapacity];
        }
        length = 0;
        return this;
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public int compareTo(final byte[] bytes, final int offset, final int length) {
        ByteString.checkArrayBounds(bytes, offset, length);
        return ByteString.compareTo(this.buffer, 0, this.length, bytes, offset, length);
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public int compareTo(final ByteSequence o) {
        if (this == o) {
            return 0;
@@ -789,17 +774,15 @@
        return -o.compareTo(buffer, 0, length);
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public byte[] copyTo(final byte[] bytes) {
        copyTo(bytes, 0);
        return bytes;
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public byte[] copyTo(final byte[] bytes, final int offset) {
        if (offset < 0) {
            throw new IndexOutOfBoundsException();
@@ -808,17 +791,15 @@
        return bytes;
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public ByteStringBuilder copyTo(final ByteStringBuilder builder) {
        builder.append(buffer, 0, length);
        return builder;
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public OutputStream copyTo(final OutputStream stream) throws IOException {
        stream.write(buffer, 0, length);
        return stream;
@@ -857,9 +838,8 @@
        return this;
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public boolean equals(final byte[] bytes, final int offset, final int length) {
        ByteString.checkArrayBounds(bytes, offset, length);
        return ByteString.equals(this.buffer, 0, this.length, bytes, offset, length);
@@ -921,14 +901,14 @@
        return ByteString.hashCode(buffer, 0, length);
    }
    /** {@inheritDoc} */
    @Override
    public boolean isEmpty() {
        return length == 0;
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public int length() {
        return length;
    }
@@ -991,6 +971,7 @@
     *            The end index, exclusive.
     * @return The newly created byte subsequence.
     */
    @Override
    public ByteSequence subSequence(final int start, final int end) {
        if (start < 0 || start > end || end > length) {
            throw new IndexOutOfBoundsException();
@@ -999,17 +980,14 @@
        return new SubSequence(start, end - start);
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public String toBase64String() {
        return Base64.encode(this);
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public byte[] toByteArray() {
        return copyTo(new byte[length]);
    }
@@ -1021,15 +999,14 @@
     *
     * @return The {@link ByteString} representation of this byte sequence.
     */
    @Override
    public ByteString toByteString() {
        final byte[] b = new byte[length];
        System.arraycopy(buffer, 0, b, 0, length);
        return ByteString.wrap(b);
    }
    /**
     * {@inheritDoc}
     */
    /** {@inheritDoc} */
    @Override
    public String toString() {
        return ByteString.toString(buffer, 0, length);
opendj-core/src/test/java/org/forgerock/opendj/ldap/ByteStringBuilderTestCase.java
@@ -22,9 +22,8 @@
 *
 *
 *      Copyright 2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 *      Portions copyright 2011-2014 ForgeRock AS
 */
package org.forgerock.opendj.ldap;
import java.io.ByteArrayInputStream;
@@ -35,6 +34,7 @@
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterOutputStream;
import org.fest.assertions.Assertions;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
@@ -44,8 +44,15 @@
 */
@SuppressWarnings("javadoc")
public class ByteStringBuilderTestCase extends ByteSequenceTestCase {
    private static final byte[] EIGHT_BYTES = new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03,
        (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08 };
    //@Checkstyle:off
    private static byte _(int i) {
        return (byte) i;
    }
    //@Checkstyle:on
    private static final byte[] EIGHT_BYTES = new byte[] { _(0x01), _(0x02), _(0x03),
        _(0x04), _(0x05), _(0x06), _(0x07), _(0x08) };
    /**
     * ByteSequence data provider.
@@ -59,7 +66,7 @@
        System.arraycopy(builders, 0, addlSequences, 0, builders.length);
        addlSequences[builders.length] =
                new Object[] { new ByteStringBuilder().append(EIGHT_BYTES).subSequence(2, 6),
                    new byte[] { (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06 } };
                    new byte[] { _(0x03), _(0x04), _(0x05), _(0x06) } };
        return addlSequences;
    }
@@ -124,12 +131,39 @@
        bs.byteAt(0);
    }
    @Test(dataProvider = "builderProvider", expectedExceptions = IndexOutOfBoundsException.class)
    public void testClearWithNewCapacity(ByteStringBuilder bs, byte[] ba) {
        bs.clear(123);
        Assert.assertEquals(bs.length(), 0);
        Assert.assertEquals(bs.capacity(), 123);
        bs.byteAt(0);
    @DataProvider
    public Object[][] clearAndTruncateProvider() throws Exception {
        return new Object[][] {
            { builder(0), 42, 42 },
            { builder(42), 42, 42 },
            { builder(43), 42, 42 },
        };
    }
    private ByteStringBuilder builder(int length) {
        final ByteStringBuilder builder = new ByteStringBuilder();
        for (int i = 0; i < length; i++) {
            builder.append(42);
        }
        return builder;
    }
    @Test(dataProvider = "clearAndTruncateProvider")
    public void testClearAndTruncate(ByteStringBuilder bs, int thresholdCapacity, int newCapacity) {
        bs.clearAndTruncate(thresholdCapacity, newCapacity);
        Assertions.assertThat(bs.length()).isEqualTo(0);
        Assertions.assertThat(bs.capacity()).isLessThanOrEqualTo(thresholdCapacity);
        Assertions.assertThat(bs.capacity()).isLessThanOrEqualTo(newCapacity);
    }
    @Test(expectedExceptions = { IllegalArgumentException.class })
    public void clearAndTruncateThrowsWithNegativeNewCapacity() {
        new ByteStringBuilder().clearAndTruncate(42, -1);
    }
    @Test(expectedExceptions = { IllegalArgumentException.class })
    public void clearAndTruncateThrowsWithNewCapacityAboveThreshold() {
        new ByteStringBuilder().clearAndTruncate(42, 42 + 1);
    }
    @Test
@@ -166,7 +200,7 @@
    public void testAsOutputStream() throws Exception {
        final ByteStringBuilder bsb = new ByteStringBuilder();
        final OutputStream os = bsb.asOutputStream();
        os.write((byte) 0x01);
        os.write(_(0x01));
        os.write(2);
        os.write(new byte[] { 2, 3, 4, 5 }, 1, 2);
        os.close();
@@ -200,12 +234,11 @@
        testBuilderFromStream.append(testStream, 8);
        return new Object[][] {
            { new ByteStringBuilder().append((byte) 0x00).append((byte) 0x01),
                new byte[] { (byte) 0x00, (byte) 0x01 } },
            {
                new ByteStringBuilder(5).append(
                        new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04 }).append(
                        new byte[] { (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08 }),
            { new ByteStringBuilder().append(_(0x00)).append(_(0x01)),
                new byte[] { _(0x00), _(0x01) } },
            { new ByteStringBuilder(5)
                      .append(new byte[] { _(0x01), _(0x02), _(0x03), _(0x04) })
                      .append(new byte[] { _(0x05), _(0x06), _(0x07), _(0x08) }),
                EIGHT_BYTES },
            { new ByteStringBuilder(3).append(EIGHT_BYTES, 0, 3).append(EIGHT_BYTES, 3, 5),
                EIGHT_BYTES },
@@ -215,16 +248,16 @@
                EIGHT_BYTES },
            { testBuilderFromStream, EIGHT_BYTES },
            { new ByteStringBuilder().append(Short.MIN_VALUE).append(Short.MAX_VALUE),
                new byte[] { (byte) 0x80, (byte) 0x00, (byte) 0x7F, (byte) 0xFF } },
                new byte[] { _(0x80), _(0x00), _(0x7F), _(0xFF) } },
            {
                new ByteStringBuilder(5).append(Integer.MIN_VALUE).append(Integer.MAX_VALUE),
                new byte[] { (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x7F,
                    (byte) 0xFF, (byte) 0xFF, (byte) 0xFF } },
                new byte[] { _(0x80), _(0x00), _(0x00), _(0x00), _(0x7F),
                    _(0xFF), _(0xFF), _(0xFF) } },
            {
                new ByteStringBuilder().append(Long.MIN_VALUE).append(Long.MAX_VALUE),
                new byte[] { (byte) 0x80, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
                    (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x7F, (byte) 0xFF, (byte) 0xFF,
                    (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF } },
                new byte[] { _(0x80), _(0x00), _(0x00), _(0x00), _(0x00),
                    _(0x00), _(0x00), _(0x00), _(0x7F), _(0xFF), _(0xFF),
                    _(0xFF), _(0xFF), _(0xFF), _(0xFF), _(0xFF) } },
            { new ByteStringBuilder(11).append("this is a").append(" test"),
                "this is a test".getBytes("UTF-8") },
            { new ByteStringBuilder().append((Object) "this is a").append((Object) " test"),
@@ -237,9 +270,9 @@
                        (Object) " test".toCharArray()), "this is a test".getBytes("UTF-8") },
            {
                new ByteStringBuilder().append((Object) EIGHT_BYTES).append((Object) EIGHT_BYTES),
                new byte[] { (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05,
                    (byte) 0x06, (byte) 0x07, (byte) 0x08, (byte) 0x01, (byte) 0x02, (byte) 0x03,
                    (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08 } },
                new byte[] { _(0x01), _(0x02), _(0x03), _(0x04), _(0x05),
                    _(0x06), _(0x07), _(0x08), _(0x01), _(0x02), _(0x03),
                    _(0x04), _(0x05), _(0x06), _(0x07), _(0x08) } },
            {
                new ByteStringBuilder().appendBERLength(0x00000000).appendBERLength(0x00000001)
                        .appendBERLength(0x0000000F).appendBERLength(0x00000010).appendBERLength(
@@ -249,15 +282,15 @@
                        .appendBERLength(0x00100000).appendBERLength(0x00FFFFFF).appendBERLength(
                                0x01000000).appendBERLength(0x0FFFFFFF).appendBERLength(0x10000000)
                        .appendBERLength(0xFFFFFFFF),
                new byte[] { (byte) 0x00, (byte) 0x01, (byte) 0x0F, (byte) 0x10, (byte) 0x7F,
                    (byte) 0x81, (byte) 0xFF, (byte) 0x82, (byte) 0x01, (byte) 0x00, (byte) 0x82,
                    (byte) 0x0F, (byte) 0xFF, (byte) 0x82, (byte) 0x10, (byte) 0x00, (byte) 0x82,
                    (byte) 0xFF, (byte) 0xFF, (byte) 0x83, (byte) 0x01, (byte) 0x00, (byte) 0x00,
                    (byte) 0x83, (byte) 0x0F, (byte) 0xFF, (byte) 0xFF, (byte) 0x83, (byte) 0x10,
                    (byte) 0x00, (byte) 0x00, (byte) 0x83, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF,
                    (byte) 0x84, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x84,
                    (byte) 0x0F, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0x84, (byte) 0x10,
                    (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x84, (byte) 0xFF, (byte) 0xFF,
                    (byte) 0xFF, (byte) 0xFF } }, };
                new byte[] { _(0x00), _(0x01), _(0x0F), _(0x10), _(0x7F),
                    _(0x81), _(0xFF), _(0x82), _(0x01), _(0x00), _(0x82),
                    _(0x0F), _(0xFF), _(0x82), _(0x10), _(0x00), _(0x82),
                    _(0xFF), _(0xFF), _(0x83), _(0x01), _(0x00), _(0x00),
                    _(0x83), _(0x0F), _(0xFF), _(0xFF), _(0x83), _(0x10),
                    _(0x00), _(0x00), _(0x83), _(0xFF), _(0xFF), _(0xFF),
                    _(0x84), _(0x01), _(0x00), _(0x00), _(0x00), _(0x84),
                    _(0x0F), _(0xFF), _(0xFF), _(0xFF), _(0x84), _(0x10),
                    _(0x00), _(0x00), _(0x00), _(0x84), _(0xFF), _(0xFF),
                    _(0xFF), _(0xFF) } }, };
    }
}