Author: rdonkin
Date: Sun Nov 30 14:43:10 2008
New Revision: 721917

URL: http://svn.apache.org/viewvc?rev=721917&view=rev
Log:
https://issues.apache.org/jira/browse/MIME4J-88  Make message bodies sharable. 
Contributed by Markus Wiederkehr MIME4J-88.

Added:
    
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/SingleBody.java
    
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/storage/MultiReferenceStorage.java
    
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/SingleBodyCopyTest.java
    
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/storage/MultiReferenceStorageTest.java
Modified:
    
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/AbstractBody.java
    
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/BodyFactory.java
    
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageBinaryBody.java
    
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageTextBody.java
    
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StringTextBody.java
    
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageTest.java

Modified: 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/AbstractBody.java
URL: 
http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/AbstractBody.java?rev=721917&r1=721916&r2=721917&view=diff
==============================================================================
--- 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/AbstractBody.java
 (original)
+++ 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/AbstractBody.java
 Sun Nov 30 14:43:10 2008
@@ -26,7 +26,9 @@
  *
  * 
  * @version $Id: AbstractBody.java,v 1.2 2004/10/02 12:41:11 ntherning Exp $
+ * @deprecated extend [EMAIL PROTECTED] SingleBody} instead
  */
[EMAIL PROTECTED]
 public abstract class AbstractBody implements Body {
     private Entity parent = null;
     

Modified: 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/BodyFactory.java
URL: 
http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/BodyFactory.java?rev=721917&r1=721916&r2=721917&view=diff
==============================================================================
--- 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/BodyFactory.java
 (original)
+++ 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/BodyFactory.java
 Sun Nov 30 14:43:10 2008
@@ -26,6 +26,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.james.mime4j.message.storage.DefaultStorageProvider;
+import org.apache.james.mime4j.message.storage.MultiReferenceStorage;
 import org.apache.james.mime4j.message.storage.Storage;
 import org.apache.james.mime4j.message.storage.StorageProvider;
 import org.apache.james.mime4j.util.CharsetUtil;
@@ -58,7 +59,7 @@
             throw new IllegalArgumentException();
 
         Storage storage = storageProvider.store(is);
-        return new StorageBinaryBody(storage);
+        return new StorageBinaryBody(new MultiReferenceStorage(storage));
     }
 
     public TextBody textBody(InputStream is) throws IOException {
@@ -66,7 +67,8 @@
             throw new IllegalArgumentException();
 
         Storage storage = storageProvider.store(is);
-        return new StorageTextBody(storage, MessageUtils.DEFAULT_CHARSET);
+        return new StorageTextBody(new MultiReferenceStorage(storage),
+                MessageUtils.DEFAULT_CHARSET);
     }
 
     public TextBody textBody(InputStream is, String mimeCharset)
@@ -78,7 +80,7 @@
 
         Storage storage = storageProvider.store(is);
         Charset charset = toJavaCharset(mimeCharset, false);
-        return new StorageTextBody(storage, charset);
+        return new StorageTextBody(new MultiReferenceStorage(storage), 
charset);
     }
 
     public TextBody textBody(String text) {

Added: 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/SingleBody.java
URL: 
http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/SingleBody.java?rev=721917&view=auto
==============================================================================
--- 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/SingleBody.java
 (added)
+++ 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/SingleBody.java
 Sun Nov 30 14:43:10 2008
@@ -0,0 +1,85 @@
+/****************************************************************
+ * 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.james.mime4j.message;
+
+/**
+ * Abstract implementation of a single message body; that is, a body that does
+ * not contain (directly or indirectly) any other child bodies. It also 
provides
+ * the parent functionality required by bodies.
+ */
+public abstract class SingleBody implements Body {
+
+    private Entity parent = null;
+
+    /**
+     * @see org.apache.james.mime4j.message.Body#getParent()
+     */
+    public Entity getParent() {
+        return parent;
+    }
+
+    /**
+     * @see 
org.apache.james.mime4j.message.Body#setParent(org.apache.james.mime4j.message.Entity)
+     */
+    public void setParent(Entity parent) {
+        this.parent = parent;
+    }
+
+    /**
+     * Returns a copy of this <code>SingleBody</code> (optional operation).
+     * <p>
+     * The general contract of this method is as follows:
+     * <ul>
+     * <li>Invoking [EMAIL PROTECTED] #getParent()} on the copy returns 
<code>null</code>.
+     * That means that the copy is detached from the parent entity of this
+     * <code>SingleBody</code>. The copy may get attached to a different
+     * entity later on.</li>
+     * <li>The underlying content does not have to be copied. Instead it may be
+     * shared between multiple copies of a <code>SingleBody</code>.</li>
+     * <li>If the underlying content is shared by multiple copies the
+     * implementation has to make sure that the content gets deleted when the
+     * last copy gets disposed (and not before that).</li>
+     * </ul>
+     * <p>
+     * This implementation always throws an
+     * <code>UnsupportedOperationException</code>.
+     * 
+     * @return a copy of this <code>SingleBody</code>.
+     * @throws UnsupportedOperationException
+     *             if the <code>copy</code> operation is not supported by this
+     *             single body.
+     */
+    public SingleBody copy() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Subclasses should override this method if they have allocated resources
+     * that need to be freed explicitly (e.g. cannot be simply reclaimed by the
+     * garbage collector).
+     * 
+     * The default implementation of this method does nothing.
+     * 
+     * @see org.apache.james.mime4j.message.Disposable#dispose()
+     */
+    public void dispose() {
+    }
+
+}

Modified: 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageBinaryBody.java
URL: 
http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageBinaryBody.java?rev=721917&r1=721916&r2=721917&view=diff
==============================================================================
--- 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageBinaryBody.java
 (original)
+++ 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageBinaryBody.java
 Sun Nov 30 14:43:10 2008
@@ -24,17 +24,17 @@
 import java.io.OutputStream;
 
 import org.apache.james.mime4j.decoder.CodecUtil;
-import org.apache.james.mime4j.message.storage.Storage;
+import org.apache.james.mime4j.message.storage.MultiReferenceStorage;
 
 /**
  * Binary body backed by a
  * [EMAIL PROTECTED] org.apache.james.mime4j.message.storage.Storage}
  */
-class StorageBinaryBody extends AbstractBody implements BinaryBody {
+class StorageBinaryBody extends SingleBody implements BinaryBody {
 
-    private Storage storage = null;
+    private MultiReferenceStorage storage = null;
 
-    public StorageBinaryBody(final Storage storage) {
+    public StorageBinaryBody(final MultiReferenceStorage storage) {
         this.storage = storage;
     }
 
@@ -58,6 +58,12 @@
         in.close();
     }
 
+    @Override
+    public StorageBinaryBody copy() {
+        storage.addReference();
+        return new StorageBinaryBody(storage);
+    }
+
     /**
      * Deletes the Storage that holds the content of this binary body.
      * 

Modified: 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageTextBody.java
URL: 
http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageTextBody.java?rev=721917&r1=721916&r2=721917&view=diff
==============================================================================
--- 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageTextBody.java
 (original)
+++ 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StorageTextBody.java
 Sun Nov 30 14:43:10 2008
@@ -27,17 +27,17 @@
 import java.nio.charset.Charset;
 
 import org.apache.james.mime4j.decoder.CodecUtil;
-import org.apache.james.mime4j.message.storage.Storage;
+import org.apache.james.mime4j.message.storage.MultiReferenceStorage;
 
 /**
  * Text body backed by a [EMAIL PROTECTED] 
org.apache.james.mime4j.message.storage.Storage}.
  */
-class StorageTextBody extends AbstractBody implements TextBody {
+class StorageTextBody extends SingleBody implements TextBody {
 
-    private Storage storage;
+    private MultiReferenceStorage storage;
     private Charset charset;
 
-    public StorageTextBody(Storage storage, Charset charset) {
+    public StorageTextBody(MultiReferenceStorage storage, Charset charset) {
         this.storage = storage;
         this.charset = charset;
     }
@@ -62,6 +62,12 @@
         in.close();
     }
 
+    @Override
+    public StorageTextBody copy() {
+        storage.addReference();
+        return new StorageTextBody(storage, charset);
+    }
+    
     /**
      * Deletes the Storage that holds the content of this text body.
      * 

Modified: 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StringTextBody.java
URL: 
http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StringTextBody.java?rev=721917&r1=721916&r2=721917&view=diff
==============================================================================
--- 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StringTextBody.java
 (original)
+++ 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/StringTextBody.java
 Sun Nov 30 14:43:10 2008
@@ -30,7 +30,7 @@
 /**
  * Text body backed by a <code>String</code>.
  */
-class StringTextBody extends AbstractBody implements TextBody {
+class StringTextBody extends SingleBody implements TextBody {
 
     private final String text;
     private final Charset charset;
@@ -71,4 +71,9 @@
         writer.flush();
     }
 
+    @Override
+    public StringTextBody copy() {
+        return new StringTextBody(text, charset);
+    }
+
 }

Added: 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/storage/MultiReferenceStorage.java
URL: 
http://svn.apache.org/viewvc/james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/storage/MultiReferenceStorage.java?rev=721917&view=auto
==============================================================================
--- 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/storage/MultiReferenceStorage.java
 (added)
+++ 
james/mime4j/trunk/src/main/java/org/apache/james/mime4j/message/storage/MultiReferenceStorage.java
 Sun Nov 30 14:43:10 2008
@@ -0,0 +1,103 @@
+/****************************************************************
+ * 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.james.mime4j.message.storage;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * <p>A wrapper around another [EMAIL PROTECTED] Storage} that also maintains 
a reference
+ * counter. The inner storage gets deleted only if the reference counter 
reaches
+ * zero.</p>
+ * <p>Reference counting is used to delete the storage when it is no longer 
needed.
+ * So, any users of this class should note:
+ * </p>
+ * <ul>
+ * <li>The reference count is set up one on construction. In all other cases,
+ * [EMAIL PROTECTED] #addReference()} should be called when the storage is 
shared.</li>
+ * <li>The caller of [EMAIL PROTECTED] #addReference()} should ensure that {@
+ * link #delete()} is called once and only once.</li>
+ * <li>Sharing the [EMAIL PROTECTED] Storage} instance passed into [EMAIL 
PROTECTED] #MultiReferenceStorage(Storage)}
+ * may lead to miscounting and premature deletion</li>
+ * </ul>
+ */
+public class MultiReferenceStorage implements Storage {
+
+    private final Storage storage;
+    private int referenceCounter;
+
+    /**
+     * Creates a new <code>MultiReferenceStorage</code> instance for the given
+     * back-end. The reference counter is initially set to one so the caller
+     * does not have to call [EMAIL PROTECTED] #addReference()} after this 
constructor.
+     * 
+     * @param storage
+     *            storage back-end that should be reference counted.
+     */
+    public MultiReferenceStorage(Storage storage) {
+        if (storage == null)
+            throw new IllegalArgumentException();
+
+        this.storage = storage;
+        this.referenceCounter = 1; // caller holds first reference
+    }
+
+    /**
+     * Increments the reference counter.
+     * 
+     * @throws IllegalStateException
+     *             if the reference counter is zero which implies that the
+     *             backing storage has already been deleted.
+     */
+    public synchronized void addReference() {
+        if (referenceCounter == 0)
+            throw new IllegalStateException("storage has been deleted");
+
+        referenceCounter++;
+    }
+
+    /**
+     * Decrements the reference counter and deletes the inner
+     * <code>Storage</code> object if the reference counter reaches zero.
+     * <p>
+     * A client that holds a reference to this object must make sure not to
+     * invoke this method a second time.
+     */
+    public synchronized void delete() {
+        if (referenceCounter == 0)
+            return;
+
+        referenceCounter--;
+
+        if (referenceCounter == 0) {
+            storage.delete();
+        }
+    }
+
+    /**
+     * Returns the input stream of the inner <code>Storage</code> object.
+     * 
+     * @return an input stream.
+     */
+    public InputStream getInputStream() throws IOException {
+        return storage.getInputStream();
+    }
+
+}

Modified: 
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageTest.java
URL: 
http://svn.apache.org/viewvc/james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageTest.java?rev=721917&r1=721916&r2=721917&view=diff
==============================================================================
--- 
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageTest.java
 (original)
+++ 
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/MessageTest.java
 Sun Nov 30 14:43:10 2008
@@ -212,7 +212,7 @@
         return complete.toString().getBytes();
     }
 
-    private static final class DummyBody extends AbstractBody {
+    private static final class DummyBody extends SingleBody {
 
         public boolean disposed = false;
 

Added: 
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/SingleBodyCopyTest.java
URL: 
http://svn.apache.org/viewvc/james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/SingleBodyCopyTest.java?rev=721917&view=auto
==============================================================================
--- 
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/SingleBodyCopyTest.java
 (added)
+++ 
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/SingleBodyCopyTest.java
 Sun Nov 30 14:43:10 2008
@@ -0,0 +1,129 @@
+/****************************************************************
+ * 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.james.mime4j.message;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import junit.framework.TestCase;
+
+import org.apache.james.mime4j.message.storage.MemoryStorageProvider;
+import org.apache.james.mime4j.message.storage.MultiReferenceStorage;
+import org.apache.james.mime4j.message.storage.Storage;
+import org.apache.james.mime4j.util.MessageUtils;
+
+public class SingleBodyCopyTest extends TestCase {
+
+    public void testCopyStorageBinaryBody() throws Exception {
+        Storage storage = new MemoryStorageProvider()
+                .store(new ByteArrayInputStream("test".getBytes()));
+        MultiReferenceStorage multiReferenceStorage = new 
MultiReferenceStorage(
+                storage);
+        SingleBody body = new StorageBinaryBody(multiReferenceStorage);
+        copyTest(body);
+    }
+
+    public void testCopyStorageTextBody() throws Exception {
+        Storage storage = new MemoryStorageProvider()
+                .store(new ByteArrayInputStream("test".getBytes()));
+        MultiReferenceStorage multiReferenceStorage = new 
MultiReferenceStorage(
+                storage);
+        SingleBody body = new StorageTextBody(multiReferenceStorage,
+                MessageUtils.ASCII);
+        copyTest(body);
+    }
+
+    public void testCopyStringTextBody() throws Exception {
+        SingleBody body = new StringTextBody("test", MessageUtils.ASCII);
+        copyTest(body);
+    }
+
+    public void testDisposeStorageBinaryBody() throws Exception {
+        Storage storage = new MemoryStorageProvider()
+                .store(new ByteArrayInputStream("test".getBytes()));
+        MultiReferenceStorage multiReferenceStorage = new 
MultiReferenceStorage(
+                storage);
+        SingleBody body = new StorageBinaryBody(multiReferenceStorage);
+        disposeTest(body, storage);
+    }
+
+    public void testDisposeStorageTextBody() throws Exception {
+        Storage storage = new MemoryStorageProvider()
+                .store(new ByteArrayInputStream("test".getBytes()));
+        MultiReferenceStorage multiReferenceStorage = new 
MultiReferenceStorage(
+                storage);
+        SingleBody body = new StorageTextBody(multiReferenceStorage,
+                MessageUtils.ASCII);
+        disposeTest(body, storage);
+    }
+
+    private void copyTest(SingleBody body) throws Exception {
+        Message parent = new Message();
+        parent.setBody(body);
+
+        SingleBody copy = body.copy();
+        assertNotNull(copy);
+        assertNotSame(body, copy);
+
+        assertSame(parent, body.getParent());
+        assertNull(copy.getParent());
+
+        sameContentTest(body, copy);
+    }
+
+    private void sameContentTest(SingleBody expectedBody, SingleBody 
actualBody)
+            throws Exception {
+        ByteArrayOutputStream expBaos = new ByteArrayOutputStream();
+        expectedBody.writeTo(expBaos, Mode.STRICT_ERROR);
+        byte[] expected = expBaos.toByteArray();
+
+        ByteArrayOutputStream actBaos = new ByteArrayOutputStream();
+        actualBody.writeTo(actBaos, Mode.STRICT_ERROR);
+        byte[] actual = actBaos.toByteArray();
+
+        assertEquals(expected.length, actual.length);
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals(expected[i], actual[i]);
+        }
+    }
+
+    private void disposeTest(SingleBody body, Storage storage) throws 
Exception {
+        assertTrue(storageIsReadable(storage));
+
+        SingleBody copy = body.copy();
+        assertTrue(storageIsReadable(storage));
+
+        body.dispose();
+        assertTrue(storageIsReadable(storage));
+
+        copy.dispose();
+        assertFalse(storageIsReadable(storage));
+    }
+
+    private boolean storageIsReadable(Storage storage) throws Exception {
+        try {
+            storage.getInputStream().close();
+            return true;
+        } catch (IllegalStateException e) {
+            return false;
+        }
+    }
+
+}

Added: 
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/storage/MultiReferenceStorageTest.java
URL: 
http://svn.apache.org/viewvc/james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/storage/MultiReferenceStorageTest.java?rev=721917&view=auto
==============================================================================
--- 
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/storage/MultiReferenceStorageTest.java
 (added)
+++ 
james/mime4j/trunk/src/test/java/org/apache/james/mime4j/message/storage/MultiReferenceStorageTest.java
 Sun Nov 30 14:43:10 2008
@@ -0,0 +1,107 @@
+/****************************************************************
+ * 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.james.mime4j.message.storage;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+public class MultiReferenceStorageTest extends TestCase {
+
+    public void testForwardsGetInputStream() throws Exception {
+        DummyStorage storage = new DummyStorage();
+        MultiReferenceStorage multiReferenceStorage = new 
MultiReferenceStorage(
+                storage);
+
+        assertEquals(ByteArrayInputStream.class, multiReferenceStorage
+                .getInputStream().getClass());
+    }
+
+    public void testSingleReference() throws Exception {
+        DummyStorage storage = new DummyStorage();
+        MultiReferenceStorage multiReferenceStorage = new 
MultiReferenceStorage(
+                storage);
+
+        assertFalse(storage.deleted);
+
+        multiReferenceStorage.delete();
+        assertTrue(storage.deleted);
+    }
+
+    public void testMultiReference() throws Exception {
+        DummyStorage storage = new DummyStorage();
+        MultiReferenceStorage multiReferenceStorage = new 
MultiReferenceStorage(
+                storage);
+
+        multiReferenceStorage.addReference();
+
+        multiReferenceStorage.delete();
+        assertFalse(storage.deleted);
+
+        multiReferenceStorage.delete();
+        assertTrue(storage.deleted);
+    }
+
+    public void testGetInputStreamOnDeleted() throws Exception {
+        DummyStorage storage = new DummyStorage();
+        MultiReferenceStorage multiReferenceStorage = new 
MultiReferenceStorage(
+                storage);
+
+        multiReferenceStorage.delete();
+
+        try {
+            multiReferenceStorage.getInputStream();
+            fail();
+        } catch (IllegalStateException expected) {
+        }
+    }
+
+    public void testAddReferenceOnDeleted() throws Exception {
+        DummyStorage storage = new DummyStorage();
+        MultiReferenceStorage multiReferenceStorage = new 
MultiReferenceStorage(
+                storage);
+
+        multiReferenceStorage.delete();
+
+        try {
+            multiReferenceStorage.addReference();
+            fail();
+        } catch (IllegalStateException expected) {
+        }
+    }
+
+    private static final class DummyStorage implements Storage {
+        public boolean deleted = false;
+
+        public InputStream getInputStream() throws IOException {
+            if (deleted)
+                throw new IllegalStateException("deleted");
+
+            return new ByteArrayInputStream("dummy".getBytes());
+        }
+
+        public void delete() {
+            deleted = true;
+        }
+    }
+
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to