cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jo...@apache.org
Subject svn commit: r665972 - in /cocoon/trunk/core: cocoon-pipeline/cocoon-pipeline-impl/src/changes/ cocoon-pipeline/cocoon-pipeline-impl/src/main/java/org/apache/cocoon/environment/ cocoon-sitemap/cocoon-sitemap-impl/src/main/java/org/apache/cocoon/environm...
Date Tue, 10 Jun 2008 04:18:57 GMT
Author: joerg
Date: Mon Jun  9 21:18:56 2008
New Revision: 665972

URL: http://svn.apache.org/viewvc?rev=665972&view=rev
Log:
as a follow-up of COCOON-2168 (http://marc.info/?t=120899868500003&r=1&w=4):
Cocoon's pipeline buffer increases from an initial buffer size of 8192 bytes to the configurable
flush buffer size rather than allocating the complete buffer beforehand.

Added:
    cocoon/trunk/core/cocoon-util/src/test/java/org/apache/cocoon/util/BufferedOutputStreamTestCase.java
Modified:
    cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-impl/src/changes/changes.xml
    cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-impl/src/main/java/org/apache/cocoon/environment/AbstractEnvironment.java
    cocoon/trunk/core/cocoon-sitemap/cocoon-sitemap-impl/src/main/java/org/apache/cocoon/environment/wrapper/EnvironmentWrapper.java
    cocoon/trunk/core/cocoon-util/src/changes/changes.xml
    cocoon/trunk/core/cocoon-util/src/main/java/org/apache/cocoon/util/BufferedOutputStream.java

Modified: cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-impl/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-impl/src/changes/changes.xml?rev=665972&r1=665971&r2=665972&view=diff
==============================================================================
--- cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-impl/src/changes/changes.xml (original)
+++ cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-impl/src/changes/changes.xml Mon Jun
 9 21:18:56 2008
@@ -25,6 +25,10 @@
 <document>
   <body>
     <release version="1.0.1" date="TBD" description="unreleased">
+      <action dev="joerg" type="update">
+        Cocoon's pipeline buffer increases from an initial buffer size of 8192 bytes to the
configurable flush
+        buffer size rather than allocating the complete buffer beforehand.
+      </action>
       <action dev="joerg" type="fix" fixes-bug="COCOON-2192" due-to="Steven Dolg" due-to-email="steven.dolg@indoqa.com">
         Fix CachingOutputStream not caching all content or leading to ArrayIndexOutOfBoundsException
when using
         write(byte[], int, int).

Modified: cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-impl/src/main/java/org/apache/cocoon/environment/AbstractEnvironment.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-impl/src/main/java/org/apache/cocoon/environment/AbstractEnvironment.java?rev=665972&r1=665971&r2=665972&view=diff
==============================================================================
--- cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-impl/src/main/java/org/apache/cocoon/environment/AbstractEnvironment.java
(original)
+++ cocoon/trunk/core/cocoon-pipeline/cocoon-pipeline-impl/src/main/java/org/apache/cocoon/environment/AbstractEnvironment.java
Mon Jun  9 21:18:56 2008
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -33,7 +33,7 @@
  *
  * @version $Id$
  */
-public abstract class AbstractEnvironment extends AbstractLogEnabled 
+public abstract class AbstractEnvironment extends AbstractLogEnabled
                                           implements Environment {
 
     /** The current uri in progress */
@@ -41,7 +41,7 @@
 
     /** The prefix */
     protected String prefix = "";
-    
+
     /** The View requested */
     protected String view;
 
@@ -221,38 +221,36 @@
     /* (non-Javadoc)
      * @see org.apache.cocoon.environment.Environment#getOutputStream(int)
      */
-    public OutputStream getOutputStream(int bufferSize)
-    throws IOException {
-
+    public OutputStream getOutputStream(int bufferSize) throws IOException {
         // This method could be called several times during request processing
         // with differing values of bufferSize and should handle this situation
         // correctly.
-
-        if (bufferSize == -1) {
-            if (this.secureOutputStream == null) {
-                this.secureOutputStream = new BufferedOutputStream(this.outputStream);
-            }
-            return this.secureOutputStream;
-        } else if (bufferSize == 0) {
+        // FIXME (JH): Question is what "correctly" means. The current behavior
+        // seems to be inconsistent: On a second call with bufferSize == 0 we
+        // discard whatever the first called set up. With a bufferSize != 0 the
+        // first call's setup is preserved. Why not always creating new
+        // BufferedOutputStream in the else block replacing a potentially
+        // existing one?
+        if (bufferSize == 0) {
             // Discard secure output stream if it was created before.
             if (this.secureOutputStream != null) {
                 this.secureOutputStream = null;
             }
             return this.outputStream;
         } else {
-            // FIXME Triple buffering, anyone?
-            this.outputStream = new java.io.BufferedOutputStream(this.outputStream, bufferSize);
-            return this.outputStream;
+            if (this.secureOutputStream == null) {
+                this.secureOutputStream = new BufferedOutputStream(this.outputStream, bufferSize);
+            }
+            return this.secureOutputStream;
         }
     }
 
     /* (non-Javadoc)
      * @see org.apache.cocoon.environment.Environment#tryResetResponse()
      */
-    public boolean tryResetResponse()
-    throws IOException {
-        if (this.secureOutputStream != null) {
-            this.secureOutputStream.clearBuffer();
+    public boolean tryResetResponse() throws IOException {
+        if (this.secureOutputStream != null && this.secureOutputStream.isResettable())
{
+            this.secureOutputStream.reset();
             return true;
         }
         return false;
@@ -261,11 +259,12 @@
     /* (non-Javadoc)
      * @see org.apache.cocoon.environment.Environment#commitResponse()
      */
-    public void commitResponse()
-    throws IOException {
+    public void commitResponse() throws IOException {
         if (this.secureOutputStream != null) {
-            this.setContentLength(this.secureOutputStream.getCount());
-            this.secureOutputStream.realFlush();
+            if (this.secureOutputStream.isResettable()) {
+                this.setContentLength(this.secureOutputStream.getCount());
+            }
+            this.secureOutputStream.flush();
         } else if ( this.outputStream != null ){
             this.outputStream.flush();
         }
@@ -284,7 +283,7 @@
     public void finishingProcessing() {
         // do nothing here
     }
-    
+
     /* (non-Javadoc)
      * @see org.apache.cocoon.environment.Environment#isInternRedirect()
      */

Modified: cocoon/trunk/core/cocoon-sitemap/cocoon-sitemap-impl/src/main/java/org/apache/cocoon/environment/wrapper/EnvironmentWrapper.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-sitemap/cocoon-sitemap-impl/src/main/java/org/apache/cocoon/environment/wrapper/EnvironmentWrapper.java?rev=665972&r1=665971&r2=665972&view=diff
==============================================================================
--- cocoon/trunk/core/cocoon-sitemap/cocoon-sitemap-impl/src/main/java/org/apache/cocoon/environment/wrapper/EnvironmentWrapper.java
(original)
+++ cocoon/trunk/core/cocoon-sitemap/cocoon-sitemap-impl/src/main/java/org/apache/cocoon/environment/wrapper/EnvironmentWrapper.java
Mon Jun  9 21:18:56 2008
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -19,7 +19,6 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
 
 import org.apache.cocoon.components.source.impl.SitemapSourceInfo;
@@ -55,7 +54,7 @@
 
     /**
      * Construct a new environment.
-     * 
+     *
      * @param env    The origial Environment
      * @param info   A description of the uri for the new environment
      */
@@ -66,7 +65,7 @@
 
     /**
      * Construct a new environment.
-     * 
+     *
      * @param env    The origial Environment
      * @param info   A description of the uri for the new environment
      * @param wrapResponse  Whether or not to wrap the Response object
@@ -94,9 +93,9 @@
             this.objectModel.put(ObjectModelHelper.RESPONSE_OBJECT, response);
         }
 
-        setURI(info.prefix, info.uri);        
+        setURI(info.prefix, info.uri);
     }
-    
+
     /**
      * @see org.apache.cocoon.environment.Environment#redirect(String, boolean, boolean)
      */
@@ -130,26 +129,25 @@
     /**
      * @see org.apache.cocoon.environment.Environment#tryResetResponse()
      */
-    public boolean tryResetResponse()
-    throws IOException {
+    public boolean tryResetResponse() throws IOException {
         final OutputStream os = getOutputStream(-1);
-        if (os instanceof BufferedOutputStream) {
-            ((BufferedOutputStream) os).clearBuffer();
+        if (os instanceof BufferedOutputStream && ((BufferedOutputStream) os).isResettable())
{
+            ((BufferedOutputStream) os).reset();
             return true;
         }
-
+        // return false
         return super.tryResetResponse();
     }
 
     /**
      * @see org.apache.cocoon.environment.Environment#commitResponse()
      */
-    public void commitResponse() 
-    throws IOException {
+    public void commitResponse() throws IOException {
         final OutputStream os = getOutputStream(-1);
-        if (os instanceof BufferedOutputStream) {
-            ((BufferedOutputStream) os).realFlush();
+        if (os != null) {
+            os.flush();
         } else {
+            // no action
             super.commitResponse();
         }
     }
@@ -161,7 +159,7 @@
     public String getRedirectURL() {
         return this.redirectURL;
     }
-    
+
     public void reset() {
         this.redirectURL = null;
     }

Modified: cocoon/trunk/core/cocoon-util/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-util/src/changes/changes.xml?rev=665972&r1=665971&r2=665972&view=diff
==============================================================================
--- cocoon/trunk/core/cocoon-util/src/changes/changes.xml (original)
+++ cocoon/trunk/core/cocoon-util/src/changes/changes.xml Mon Jun  9 21:18:56 2008
@@ -23,6 +23,13 @@
  -->
 <document>
   <body>
+    <release version="1.0.1" date="TBD" description="unreleased">
+      <action dev="joerg" type="update">
+        Cocoon's BufferedOutputStream extends functionality of the java.io implementation
by providing an increasing
+        buffer, the ability to reset the stream and counting written bytes.
+      </action>
+    </release>
+
     <release version="1.0.0" date="TBA" description="released">
     </release>
 

Modified: cocoon/trunk/core/cocoon-util/src/main/java/org/apache/cocoon/util/BufferedOutputStream.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-util/src/main/java/org/apache/cocoon/util/BufferedOutputStream.java?rev=665972&r1=665971&r2=665972&view=diff
==============================================================================
--- cocoon/trunk/core/cocoon-util/src/main/java/org/apache/cocoon/util/BufferedOutputStream.java
(original)
+++ cocoon/trunk/core/cocoon-util/src/main/java/org/apache/cocoon/util/BufferedOutputStream.java
Mon Jun  9 21:18:56 2008
@@ -5,9 +5,9 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -21,62 +21,92 @@
 import java.io.OutputStream;
 
 /**
- * This class is like the {@link java.io.BufferedOutputStream} but it
- * extends it with a logic to count the number of bytes written to
- * the output stream.
- * 
+ * This class is similar to the {@link java.io.BufferedOutputStream}. In
+ * addition it provides an increasing buffer, the possibility to reset the
+ * buffer and it counts the number of bytes written to the output stream.
+ *
  * @version $Id$
  * @since   2.1
  */
-public final class BufferedOutputStream extends FilterOutputStream {
-    
-    protected byte buf[];
-
-    protected int count;
-    
-    /**
-     * Creates a new buffered output stream to write data to the 
-     * specified underlying output stream with a default 8192-byte
-     * buffer size.
+public class BufferedOutputStream extends FilterOutputStream {
+
+    private byte buffer[];
+
+    private int count;
+    private int totalCount;
+
+    private final int flushBufferSize;
+
+    /**
+     * Creates a new buffered output stream to write data to the specified
+     * underlying output stream with a default flush buffer size of 32768 bytes
+     * and a default initial buffer size of 8192 bytes.
+     *
+     * @param   out   the underlying output stream.
+     */
+    public BufferedOutputStream(final OutputStream out) {
+        this(out, 32768);
+    }
+
+    /**
+     * Creates a new buffered output stream to write data to the specified
+     * underlying output stream with the specified flush buffer size and a
+     * default initial buffer size of 8192 bytes.
      *
      * @param   out   the underlying output stream.
      */
-    public BufferedOutputStream(OutputStream out) {
-        this(out, 8192);
+    public BufferedOutputStream(final OutputStream out, final int flushBufferSize) {
+        this(out, flushBufferSize, 8192);
     }
 
     /**
-     * Creates a new buffered output stream to write data to the 
-     * specified underlying output stream with the specified buffer 
-     * size. 
+     * Creates a new buffered output stream to write data to the specified
+     * underlying output stream with the specified buffer sizes.
      *
-     * @param   out    the underlying output stream.
-     * @param   size   the buffer size.
-     * @exception IllegalArgumentException if size <= 0.
+     * @param out    the underlying output stream.
+     * @param flushBufferSize  the buffer size when the stream is flushed. Must
+     *                         be greater than 0 or -1 meaning the stream never
+     *                         flushes itself.
+     * @param initialBufferSize  the initial buffer size. Must be greater than 0.
+     *                           Will be limited to the flush buffer size.
      */
-    public BufferedOutputStream(OutputStream out, int size) {
+    public BufferedOutputStream(final OutputStream out,
+                                final int flushBufferSize,
+                                final int initialBufferSize) {
         super(out);
-        if (size <= 0) {
-            throw new IllegalArgumentException("Buffer size <= 0");
+        if (flushBufferSize <= 0 && flushBufferSize != -1) {
+            throw new IllegalArgumentException("Flush buffer size <= 0 && != -1");
         }
-        this.buf = new byte[size];
+        if (initialBufferSize <= 0) {
+            throw new IllegalArgumentException("Initial buffer size <= 0");
+        }
+        int actualInitialBufferSize =
+            flushBufferSize > 0 && initialBufferSize > flushBufferSize ? flushBufferSize
+                                                                       : initialBufferSize;
+        this.buffer = new byte[actualInitialBufferSize];
+        this.flushBufferSize = flushBufferSize;
     }
 
     /**
-     * Writes the specified byte to this buffered output stream. 
+     * Writes the specified byte to this buffered output stream.
      *
      * @param      b   the byte to be written.
      * @exception  IOException  if an I/O error occurs.
      */
-    public void write(int b) throws IOException {
-        if (this.count >= this.buf.length) {
-            this.incBuffer();
+    public void write(final int b) throws IOException {
+        if (this.count == this.buffer.length) {
+            // No need to check return value, can NEVER be 0.
+            this.increaseBuffer(1);
         }
-        this.buf[count++] = (byte)b;
+
+        this.buffer[this.count++] = (byte)b;
+        this.totalCount++;
+
+        checkForFlush();
     }
 
     /**
-     * Writes <code>len</code> bytes from the specified byte array 
+     * Writes <code>len</code> bytes from the specified byte array
      * starting at offset <code>off</code> to this buffered output stream.
      *
      * <p> Ordinarily this method stores bytes from the given array into this
@@ -91,22 +121,54 @@
      * @param      len   the number of bytes to write.
      * @exception  IOException  if an I/O error occurs.
      */
-    public void write(byte b[], int off, int len) throws IOException {
-        while (len > buf.length - count) {
-            this.incBuffer();
+    public void write(final byte[] b, final int off, final int len) throws IOException {
+        int free = this.buffer.length - this.count;
+        int necessaryIncrease = len - free;
+        if (necessaryIncrease > 0) {
+            int actualIncrease = this.increaseBuffer(necessaryIncrease);
+            if (actualIncrease < necessaryIncrease) {
+                free += actualIncrease;
+                // Needs to be written in chunks by recursive calls to this method.
+                writeToBuffer(b, off, free);
+                int newOff = off + free;
+                int newLen = len - free;
+                while (newLen > 0) {
+                    writeToBuffer(b, newOff, Math.min(newLen, this.flushBufferSize));
+                    newOff += this.flushBufferSize;
+                    newLen -= this.flushBufferSize;
+                }
+                return;
+            }
+        }
+
+        writeToBuffer(b, off, len);
+    }
+
+    private void writeToBuffer(final byte[] b, final int off, final int len) throws IOException
{
+        System.arraycopy(b, off, this.buffer, this.count, len);
+        this.count += len;
+        this.totalCount += len;
+
+        checkForFlush();
+    }
+
+    private void checkForFlush() throws IOException {
+        if (this.count == this.flushBufferSize) {
+            flush();
         }
-        System.arraycopy(b, off, buf, count, len);
-        count += len;
     }
 
     /**
-     * Flushes this buffered output stream. 
-     * We don't flush here, flushing is done during closing.
+     * Flushes this buffered output stream.
      *
      * @exception  IOException  if an I/O error occurs.
      */
     public void flush() throws IOException {
-        // nothing
+        if (this.count > 0) {
+            this.out.write(this.buffer, 0, this.count);
+            this.count = 0;
+        }
+        this.out.flush();
     }
 
     /**
@@ -116,52 +178,73 @@
      * @exception  IOException  if an I/O error occurs.
      */
     public void close() throws IOException {
-        realFlush();
-        super.close ();
+        flush();
+        super.close();
     }
 
     /**
-     * Flushes this buffered output stream. 
+     * Increase the buffer by at least as many bytes as specified via the
+     * parameter, but not exceeding the flushBufferSize. The actual increase is
+     * returned.
+     *
+     * @return  increase in buffer size.
      */
-    public void realFlush() throws IOException {
-        this.writeBuffer();
-        this.out.flush();
+    private int increaseBuffer(final int increase) {
+        int oldLength = this.buffer.length;
+        if (oldLength == this.flushBufferSize) {
+            // fast way out
+            return 0;
+        }
+
+        int newLength = oldLength;
+        int actualIncrease;
+        do {
+            newLength = newLength * 2;
+            if (this.flushBufferSize > 0 && newLength >= this.flushBufferSize)
{
+                newLength = this.flushBufferSize;
+                actualIncrease = newLength - oldLength;
+                break;
+            }
+            actualIncrease = newLength - oldLength;
+        } while (actualIncrease < increase);
+
+        // Because of the "fast way out" above at this point there should always be an increase.
+        byte[] newBuffer = new byte[newLength];
+        if (this.count > 0) {
+            System.arraycopy(this.buffer, 0, newBuffer, 0, this.count);
+        }
+        this.buffer = newBuffer;
+        return actualIncrease;
     }
-    
+
     /**
-     * Write the buffer
+     * Clear the buffer.
+     * @deprecated Public access is deprecated. Use {@link #reset()} instead.
      */
-    private void writeBuffer() 
-    throws IOException {
-        if (this.count > 0) {
-            this.out.write(this.buf, 0, this.count);
-            this.clearBuffer();
-        }
+    public void clearBuffer() {
+        this.totalCount -= this.count;
+        this.count = 0;
     }
 
     /**
-     * Increment the buffer
+     * Reset the BufferedOutputStream to the last {@link #flush()}.
      */
-    private void incBuffer() {
-        // currently we double the buffer size
-        // this is not so fast but is a very simple logic
-        byte[] newBuf = new byte[this.buf.length * 2];
-        System.arraycopy(this.buf, 0, newBuf, 0, this.buf.length);
-        this.buf = newBuf;
+    public void reset() {
+        clearBuffer();
     }
-    
+
     /**
-     * Clear/reset the buffer
+     * @return if it is possible to reset the buffer completely, i.e. nothing has been flushed
yet.
      */
-    public void clearBuffer() {
-        this.count = 0;
+    public boolean isResettable() {
+        return this.count == this.totalCount;
     }
 
     /**
      * Return the size of the current buffer
      */
     public int getCount() {
-        return this.count;
+        return this.totalCount;
     }
-}
 
+}

Added: cocoon/trunk/core/cocoon-util/src/test/java/org/apache/cocoon/util/BufferedOutputStreamTestCase.java
URL: http://svn.apache.org/viewvc/cocoon/trunk/core/cocoon-util/src/test/java/org/apache/cocoon/util/BufferedOutputStreamTestCase.java?rev=665972&view=auto
==============================================================================
--- cocoon/trunk/core/cocoon-util/src/test/java/org/apache/cocoon/util/BufferedOutputStreamTestCase.java
(added)
+++ cocoon/trunk/core/cocoon-util/src/test/java/org/apache/cocoon/util/BufferedOutputStreamTestCase.java
Mon Jun  9 21:18:56 2008
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.util;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+public class BufferedOutputStreamTestCase extends TestCase {
+
+    public void testUnlimitedBuffering() throws Exception
+    {
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream,
-1, 32);
+
+        byte[] bytes = new byte[1024];
+        for (int i = 0; i < bytes.length; i++) {
+            bytes[i] = (byte) i;
+        }
+
+        assertEquals("Count of buffered and flushed bytes is wrong", 0, bufferedOutputStream.getCount());
+        assertEquals("Streamed bytes is not empty", 0, byteArrayOutputStream.size());
+
+        // write bytes into buffer
+        bufferedOutputStream.write(bytes);
+
+        assertEquals("Count of buffered and flushed bytes is wrong", bytes.length, bufferedOutputStream.getCount());
+        assertEquals("Streamed bytes is not empty", 0, byteArrayOutputStream.size());
+
+        // reset, all back to beginning
+        bufferedOutputStream.reset();
+
+        assertEquals("Count of buffered and flushed bytes is wrong", 0, bufferedOutputStream.getCount());
+        assertEquals("Streamed bytes is not empty", 0, byteArrayOutputStream.size());
+
+        // write bytes into buffer
+        bufferedOutputStream.write(bytes);
+
+        assertEquals("Count of buffered and flushed bytes is wrong", bytes.length, bufferedOutputStream.getCount());
+        assertEquals("Streamed bytes is not empty", 0, byteArrayOutputStream.size());
+
+        // eventually flush
+        bufferedOutputStream.flush();
+        byte[] streamedBytes = byteArrayOutputStream.toByteArray();
+
+        assertEquals("Count of buffered and flushed bytes is wrong", bytes.length, bufferedOutputStream.getCount());
+        assertEquals("Count of streamed bytes is wrong", bytes.length, byteArrayOutputStream.size());
+        assertTrue("Streamed bytes are wrong", Arrays.equals(bytes, streamedBytes));
+    }
+
+    public void testCompleteBuffering() throws Exception
+    {
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream,
1024, 32);
+
+        byte[] bytes = new byte[1000];
+        for (int i = 0; i < bytes.length; i++) {
+            bytes[i] = (byte) i;
+        }
+
+        assertEquals("Count of buffered and flushed bytes is wrong", 0, bufferedOutputStream.getCount());
+        assertEquals("Streamed bytes is not empty", 0, byteArrayOutputStream.size());
+
+        // write bytes into buffer
+        bufferedOutputStream.write(bytes);
+
+        assertEquals("Count of buffered and flushed bytes is wrong", bytes.length, bufferedOutputStream.getCount());
+        assertEquals("Streamed bytes is not empty", 0, byteArrayOutputStream.size());
+
+        // reset, all back to beginning
+        bufferedOutputStream.reset();
+
+        assertEquals("Count of buffered and flushed bytes is wrong", 0, bufferedOutputStream.getCount());
+        assertEquals("Streamed bytes is not empty", 0, byteArrayOutputStream.size());
+
+        // write bytes into buffer
+        bufferedOutputStream.write(bytes);
+
+        assertEquals("Count of buffered and flushed bytes is wrong", bytes.length, bufferedOutputStream.getCount());
+        assertEquals("Streamed bytes is not empty", 0, byteArrayOutputStream.size());
+
+        // eventually flush
+        bufferedOutputStream.flush();
+        byte[] streamedBytes = byteArrayOutputStream.toByteArray();
+
+        assertEquals("Count of buffered and flushed bytes is wrong", bytes.length, bufferedOutputStream.getCount());
+        assertEquals("Count of streamed bytes is wrong", bytes.length, byteArrayOutputStream.size());
+        assertTrue("Streamed bytes are wrong", Arrays.equals(bytes, streamedBytes));
+    }
+
+    public void testCompleteBufferingHittingFlushSize() throws Exception
+    {
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream,
1024, 32);
+
+        byte[] bytes = new byte[1024];
+        for (int i = 0; i < bytes.length; i++) {
+            bytes[i] = (byte) i;
+        }
+
+        assertEquals("Count of buffered and flushed bytes is wrong", 0, bufferedOutputStream.getCount());
+        assertEquals("Streamed bytes is not empty", 0, byteArrayOutputStream.size());
+
+        // write bytes into buffer, buffer will be flushed automatically
+        bufferedOutputStream.write(bytes);
+        byte[] streamedBytes = byteArrayOutputStream.toByteArray();
+
+        assertEquals("Count of buffered and flushed bytes is wrong", bytes.length, bufferedOutputStream.getCount());
+        assertEquals("Count of streamed bytes is wrong", bytes.length, byteArrayOutputStream.size());
+        assertTrue("Streamed bytes are wrong", Arrays.equals(bytes, streamedBytes));
+
+        // reset should not change anything
+        bufferedOutputStream.reset();
+        streamedBytes = byteArrayOutputStream.toByteArray();
+
+        assertEquals("Count of buffered and flushed bytes is wrong", bytes.length, bufferedOutputStream.getCount());
+        assertEquals("Count of streamed bytes is wrong", bytes.length, byteArrayOutputStream.size());
+        assertTrue("Streamed bytes are wrong", Arrays.equals(bytes, streamedBytes));
+    }
+
+    public void testBufferingExceedingFlushSize() throws Exception
+    {
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        int flushSize = 512;
+        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream,
flushSize, 32);
+
+        byte[] bytes = new byte[2000];
+        for (int i = 0; i < bytes.length; i++) {
+            bytes[i] = (byte) i;
+        }
+
+        assertEquals("Count of buffered and flushed bytes is wrong", 0, bufferedOutputStream.getCount());
+        assertEquals("Streamed bytes is not empty", 0, byteArrayOutputStream.size());
+
+        // write bytes into buffer
+        bufferedOutputStream.write(bytes);
+        int flushed = ((int)bytes.length / flushSize) * flushSize;
+
+        assertEquals("Count of buffered and flushed bytes is wrong", bytes.length, bufferedOutputStream.getCount());
+        assertEquals("Count of streamed bytes is wrong", flushed, byteArrayOutputStream.size());
+
+        // reset, back to last flush
+        bufferedOutputStream.reset();
+
+        assertEquals("Count of buffered and flushed bytes is wrong", flushed, bufferedOutputStream.getCount());
+        assertEquals("Count of streamed bytes is wrong", flushed, byteArrayOutputStream.size());
+
+        // write bytes into buffer
+        bufferedOutputStream.write(bytes, flushed, bytes.length - flushed);
+
+        assertEquals("Count of buffered and flushed bytes is wrong", bytes.length, bufferedOutputStream.getCount());
+        assertEquals("Count of streamed bytes is wrong", flushed, byteArrayOutputStream.size());
+
+        // eventually flush
+        bufferedOutputStream.flush();
+        byte[] streamedBytes = byteArrayOutputStream.toByteArray();
+
+        assertEquals("Count of buffered and flushed bytes is wrong", bytes.length, bufferedOutputStream.getCount());
+        assertEquals("Count of streamed bytes is wrong", bytes.length, byteArrayOutputStream.size());
+        assertTrue("Streamed bytes are wrong", Arrays.equals(bytes, streamedBytes));
+    }
+
+    public void testBufferingExceedingFlushSizeWithInitialContent() throws Exception
+    {
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        int flushSize = 512;
+        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream,
flushSize, 32);
+
+        byte[] bytes = new byte[2000];
+        for (int i = 0; i < bytes.length; i++) {
+            bytes[i] = (byte) i;
+        }
+
+        int initialContentSize = 50;
+        bufferedOutputStream.write(bytes, 0, initialContentSize);
+
+        assertEquals("Count of buffered and flushed bytes is wrong", initialContentSize,
bufferedOutputStream.getCount());
+        assertEquals("Streamed bytes is not empty", 0, byteArrayOutputStream.size());
+
+        // write bytes into buffer
+        bufferedOutputStream.write(bytes);
+        int flushed = ((int)((initialContentSize + bytes.length) / flushSize)) * flushSize;
+
+        assertEquals("Count of buffered and flushed bytes is wrong", initialContentSize +
bytes.length, bufferedOutputStream.getCount());
+        assertEquals("Count of streamed bytes is wrong", flushed, byteArrayOutputStream.size());
+
+        // reset, back to last flush
+        bufferedOutputStream.reset();
+
+        assertEquals("Count of buffered and flushed bytes is wrong", flushed, bufferedOutputStream.getCount());
+        assertEquals("Count of streamed bytes is wrong", flushed, byteArrayOutputStream.size());
+
+        // write bytes into buffer
+        bufferedOutputStream.write(bytes, flushed - initialContentSize, bytes.length - flushed
+ initialContentSize);
+
+        assertEquals("Count of buffered and flushed bytes is wrong", initialContentSize +
bytes.length, bufferedOutputStream.getCount());
+        assertEquals("Count of streamed bytes is wrong", flushed, byteArrayOutputStream.size());
+
+        // eventually flush
+        bufferedOutputStream.flush();
+        byte[] streamedBytes = byteArrayOutputStream.toByteArray();
+
+        assertEquals("Count of buffered and flushed bytes is wrong", initialContentSize +
bytes.length, bufferedOutputStream.getCount());
+        assertEquals("Count of streamed bytes is wrong", initialContentSize + bytes.length,
byteArrayOutputStream.size());
+        byte[] expectedBytes = new byte[2050];
+        System.arraycopy(bytes, 0, expectedBytes, 0, initialContentSize);
+        System.arraycopy(bytes, 0, expectedBytes, initialContentSize, bytes.length);
+        assertTrue("Streamed bytes are wrong", Arrays.equals(expectedBytes, streamedBytes));
+    }
+
+}



Mime
View raw message