From f21d49179409cc1f7089e08d6ad1596bfd4de47f Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Wed, 08 Jan 2014 18:37:25 +0000
Subject: [PATCH] Facilitate compression and cryptographic operations to/from byte strings:

---
 /dev/null                                                                          |  113 ----------------------------
 opendj-core/src/main/java/org/forgerock/opendj/io/ASN1.java                        |    7 -
 opendj-core/src/test/java/org/forgerock/opendj/ldap/ByteStringBuilderTestCase.java |   31 +++++++
 opendj-core/src/main/java/org/forgerock/opendj/ldap/ByteStringBuilder.java         |   38 +++++++++
 opendj-core/src/main/java/org/forgerock/opendj/io/ASN1OutputStreamWriter.java      |   25 ++---
 5 files changed, 82 insertions(+), 132 deletions(-)

diff --git a/opendj-core/src/main/java/com/forgerock/opendj/util/ByteSequenceOutputStream.java b/opendj-core/src/main/java/com/forgerock/opendj/util/ByteSequenceOutputStream.java
deleted file mode 100644
index b7fb85c..0000000
--- a/opendj-core/src/main/java/com/forgerock/opendj/util/ByteSequenceOutputStream.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
- * or http://forgerock.org/license/CDDLv1.0.html.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at legal-notices/CDDLv1_0.txt.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information:
- *      Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
- */
-package com.forgerock.opendj.util;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-import org.forgerock.opendj.ldap.ByteStringBuilder;
-
-/**
- * An adapter class that allows writing to an byte string builder with the
- * outputstream interface.
- */
-public final class ByteSequenceOutputStream extends OutputStream {
-
-    private final ByteStringBuilder buffer;
-
-    /**
-     * Creates a new byte string builder output stream.
-     *
-     * @param buffer
-     *            The underlying byte string builder.
-     */
-    public ByteSequenceOutputStream(final ByteStringBuilder buffer) {
-        this.buffer = buffer;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void close() throws IOException {
-        buffer.clear();
-    }
-
-    /**
-     * Gets the length of the underlying byte string builder.
-     *
-     * @return The length of the underlying byte string builder.
-     */
-    public int length() {
-        return buffer.length();
-    }
-
-    /**
-     * Resets this output stream such that the underlying byte string builder is
-     * empty.
-     */
-    public void reset() {
-        buffer.clear();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void write(final byte[] bytes) throws IOException {
-        buffer.append(bytes);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void write(final byte[] bytes, final int i, final int i1) throws IOException {
-        buffer.append(bytes, i, i1);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void write(final int i) throws IOException {
-        buffer.append(((byte) (i & 0xFF)));
-    }
-
-    /**
-     * Writes the content of the underlying byte string builder to the provided
-     * output stream.
-     *
-     * @param stream
-     *            The output stream.
-     * @throws IOException
-     *             If an I/O error occurs. In particular, an {@code IOException}
-     *             is thrown if the output stream is closed.
-     */
-    public void writeTo(final OutputStream stream) throws IOException {
-        buffer.copyTo(stream);
-    }
-}
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/io/ASN1.java b/opendj-core/src/main/java/org/forgerock/opendj/io/ASN1.java
index db4b585..9ab3ea8 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/io/ASN1.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/io/ASN1.java
@@ -22,7 +22,7 @@
  *
  *
  *      Copyright 2006-2008 Sun Microsystems, Inc.
- *      Portions copyright 2012-2013 ForgeRock AS.
+ *      Portions copyright 2012-2014 ForgeRock AS.
  */
 
 package org.forgerock.opendj.io;
@@ -35,8 +35,6 @@
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.ByteStringBuilder;
 
-import com.forgerock.opendj.util.ByteSequenceOutputStream;
-
 /**
  * This class contains various static factory methods for creating ASN.1 readers
  * and writers.
@@ -280,8 +278,7 @@
      * @return The new ASN.1 writer.
      */
     public static ASN1Writer getWriter(final ByteStringBuilder builder) {
-        final ByteSequenceOutputStream outputStream = new ByteSequenceOutputStream(builder);
-        return getWriter(outputStream);
+        return getWriter(builder.asOutputStream());
     }
 
     /**
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/io/ASN1OutputStreamWriter.java b/opendj-core/src/main/java/org/forgerock/opendj/io/ASN1OutputStreamWriter.java
index 35943c5..c09f906 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/io/ASN1OutputStreamWriter.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/io/ASN1OutputStreamWriter.java
@@ -22,7 +22,7 @@
  *
  *
  *      Copyright 2006-2009 Sun Microsystems, Inc.
- *      Portions copyright 2012-2013 ForgeRock AS.
+ *      Portions copyright 2012-2014 ForgeRock AS.
  */
 package org.forgerock.opendj.io;
 
@@ -37,7 +37,6 @@
 import org.forgerock.opendj.ldap.ByteSequence;
 import org.forgerock.opendj.ldap.ByteStringBuilder;
 
-import com.forgerock.opendj.util.ByteSequenceOutputStream;
 import com.forgerock.opendj.util.StaticUtils;
 
 /**
@@ -46,7 +45,7 @@
 final class ASN1OutputStreamWriter extends AbstractASN1Writer implements ASN1Writer {
     private final OutputStream rootStream;
     private OutputStream out;
-    private final ArrayList<ByteSequenceOutputStream> streamStack;
+    private final ArrayList<ByteStringBuilder> streamStack;
     private int stackDepth;
 
     /**
@@ -58,7 +57,7 @@
     ASN1OutputStreamWriter(final OutputStream stream) {
         this.out = stream;
         this.rootStream = stream;
-        this.streamStack = new ArrayList<ByteSequenceOutputStream>();
+        this.streamStack = new ArrayList<ByteStringBuilder>();
         this.stackDepth = -1;
     }
 
@@ -70,7 +69,6 @@
             writeEndSequence();
         }
         rootStream.flush();
-
         streamStack.clear();
         rootStream.close();
     }
@@ -104,23 +102,23 @@
             throw new IllegalStateException(message.toString());
         }
 
-        final ByteSequenceOutputStream childStream = streamStack.get(stackDepth);
+        final ByteStringBuilder childStream = streamStack.get(stackDepth);
 
         // Decrement the stack depth and get the parent stream
         --stackDepth;
-
-        final OutputStream parentStream = stackDepth < 0 ? rootStream : streamStack.get(stackDepth);
+        final OutputStream parentStream =
+                stackDepth < 0 ? rootStream : streamStack.get(stackDepth).asOutputStream();
 
         // Switch to parent stream and reset the sub-stream
         out = parentStream;
 
         // Write the length and contents of the sub-stream
         writeLength(childStream.length());
-        childStream.writeTo(parentStream);
+        childStream.copyTo(parentStream);
 
         IO_LOG.trace("WRITE ASN.1 END SEQUENCE(length={})", childStream.length());
 
-        childStream.reset();
+        childStream.clear();
         return this;
     }
 
@@ -318,12 +316,11 @@
 
         // Make sure we have a cached sub-stream at this depth
         if (stackDepth >= streamStack.size()) {
-            final ByteSequenceOutputStream subStream =
-                    new ByteSequenceOutputStream(new ByteStringBuilder());
+            final ByteStringBuilder subStream = new ByteStringBuilder();
             streamStack.add(subStream);
-            out = subStream;
+            out = subStream.asOutputStream();
         } else {
-            out = streamStack.get(stackDepth);
+            out = streamStack.get(stackDepth).asOutputStream();
         }
 
         IO_LOG.trace("WRITE ASN.1 START SEQUENCE(type=0x{})", byteToHex(type));
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/ByteStringBuilder.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/ByteStringBuilder.java
index d99f241..4c9a05f 100755
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/ByteStringBuilder.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/ByteStringBuilder.java
@@ -38,6 +38,30 @@
  * A mutable sequence of bytes backed by a byte array.
  */
 public final class ByteStringBuilder implements ByteSequence {
+    /**
+     *  Output stream implementation.
+     */
+    private final class OutputStreamImpl extends OutputStream {
+        @Override
+        public void close() {
+            // Do nothing.
+        }
+
+        @Override
+        public void write(final byte[] bytes) {
+            append(bytes);
+        }
+
+        @Override
+        public void write(final byte[] bytes, final int i, final int i1) {
+            append(bytes, i, i1);
+        }
+
+        @Override
+        public void write(final int i) {
+            append(((byte) (i & 0xFF)));
+        }
+    }
 
     /**
      * A sub-sequence of the parent byte string builder. The sub-sequence will
@@ -655,6 +679,20 @@
     }
 
     /**
+     * Returns an {@link OutputStream} whose write operations append data to
+     * this byte string builder. The returned output stream will never throw an
+     * {@link IOException} and its {@link OutputStream#close() close} method
+     * does not do anything.
+     *
+     * @return An {@link OutputStream} whose write operations append data to
+     *         this byte string builder.
+     */
+    public OutputStream asOutputStream() {
+        // Is it worth caching this?
+        return new OutputStreamImpl();
+    }
+
+    /**
      * Returns a {@link ByteSequenceReader} which can be used to incrementally
      * read and decode data from this byte string builder.
      * <p>
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldap/ByteStringBuilderTestCase.java b/opendj-core/src/test/java/org/forgerock/opendj/ldap/ByteStringBuilderTestCase.java
index 3f66d61..bb30eeb 100644
--- a/opendj-core/src/test/java/org/forgerock/opendj/ldap/ByteStringBuilderTestCase.java
+++ b/opendj-core/src/test/java/org/forgerock/opendj/ldap/ByteStringBuilderTestCase.java
@@ -29,8 +29,11 @@
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
+import java.util.zip.DeflaterOutputStream;
+import java.util.zip.InflaterOutputStream;
 
 import org.testng.Assert;
 import org.testng.annotations.DataProvider;
@@ -151,6 +154,34 @@
         Assert.assertEquals(bsb.getBackingArray().length, 8);
     }
 
+    @Test
+    public void testAsOutputStream() throws Exception {
+        final ByteStringBuilder bsb = new ByteStringBuilder();
+        final OutputStream os = bsb.asOutputStream();
+        os.write((byte) 0x01);
+        os.write(2);
+        os.write(new byte[] { 2, 3, 4, 5 }, 1, 2);
+        os.close();
+        Assert.assertEquals(bsb.length(), 4);
+        Assert.assertEquals(bsb.toByteArray(), new byte[] { 1, 2, 3, 4 });
+    }
+
+    @Test
+    public void testAsOutputStreamCompress() throws Exception {
+        final ByteString data = ByteString.wrap(new byte[4000]);
+        final ByteStringBuilder compressedData = new ByteStringBuilder();
+        final OutputStream compressor = new DeflaterOutputStream(compressedData.asOutputStream());
+        data.copyTo(compressor);
+        compressor.close();
+        Assert.assertTrue(compressedData.length() > 0 && compressedData.length() < 4000);
+
+        final ByteStringBuilder decompressedData = new ByteStringBuilder();
+        final OutputStream decompressor = new InflaterOutputStream(decompressedData.asOutputStream());
+        compressedData.copyTo(decompressor);
+        decompressor.close();
+        Assert.assertEquals(decompressedData.toByteString(), data);
+    }
+
     @DataProvider(name = "builderProvider")
     private Object[][] byteStringBuilderProvider() throws Exception {
         final ByteBuffer testBuffer = ByteBuffer.wrap(EIGHT_BYTES);

--
Gitblit v1.10.0