You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by ve...@apache.org on 2015/05/16 01:56:51 UTC

svn commit: r1679662 [1/3] - in /webservices/axiom/trunk: modules/axiom-api/src/main/java/org/apache/axiom/attachments/ modules/axiom-api/src/main/java/org/apache/axiom/blob/ modules/axiom-api/src/main/java/org/apache/axiom/util/stax/ modules/axiom-api...

Author: veithen
Date: Fri May 15 23:56:49 2015
New Revision: 1679662

URL: http://svn.apache.org/r1679662
Log:
Improve the blob API and use it to implement MIME part handling (instead of the old PartContent code).

Added:
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/LegacyTempFileBlob.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/LegacyTempFileBlobFactory.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/AbstractWritableBlob.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/Blobs.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/IOUtil.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobImpl.java
      - copied, changed from r1678555, webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlob.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/OverflowableBlob.java
      - copied, changed from r1678555, webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/OverflowBlob.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/OverflowableBlobImpl.java
      - copied, changed from r1678555, webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/OverflowBlob.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/State.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/TempFileBlobFactory.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/TempFileBlobImpl.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/TempFileInputStream.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/WritableBlobFactory.java
      - copied, changed from r1678555, webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/WritableBlobFactory.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/OverflowableBlobTest.java
      - copied, changed from r1678555, webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/OverflowBlobTest.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/TempFileBlobTest.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/ByteArrayOutputStreamWithReadFromSupport.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/CleanupCallback.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/SizeSensitiveWritableBlobTestCase.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/State.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestAvailable.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestGetInputStreamIllegalState.java
      - copied, changed from r1678555, webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/TestGetInputStreamNew.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestGetOutputStreamIllegalState.java
      - copied, changed from r1678555, webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/TestGetOutputStreamCommitted.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestGetSizeIllegalState.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestMarkReset.java
      - copied, changed from r1678555, webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/TestMarkReset.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestRandomReadWrite.java
      - copied, changed from r1678555, webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/TestRandomReadWrite.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestReadEOF.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestReadFrom.java
      - copied, changed from r1678555, webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/TestReadFrom.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestReadFromIllegalState.java
      - copied, changed from r1678555, webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/TestReadFromCommitted.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestReadFromSupport.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestReadFromWithError.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestReadZeroLength.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestReleaseTwice.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestSkip.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestWriteAfterCommit.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestWriteTo.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestWriteToIllegalState.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/TestWriteToWithError.java   (with props)
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/WritableBlobTestCase.java
      - copied, changed from r1678555, webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/WritableBlobTestCase.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/suite/WritableBlobTestSuiteBuilder.java
      - copied, changed from r1678555, webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/WritableBlobTestSuiteBuilder.java
    webservices/axiom/trunk/testing/testutils/src/main/java/org/apache/axiom/testutils/io/CloseSensorOutputStream.java   (with props)
    webservices/axiom/trunk/testing/testutils/src/main/java/org/apache/axiom/testutils/io/ExceptionOutputStream.java   (with props)
Removed:
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PartContent.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PartContentFactory.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PartContentOnFile.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PartContentOnMemory.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/BlobOutputStream.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/OverflowBlob.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/OverflowBlobTest.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/TestGetInputStreamNew.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/TestGetInputStreamUncommitted.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/TestGetOutputStreamCommitted.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/TestGetOutputStreamUncommitted.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/TestMarkReset.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/TestRandomReadWrite.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/TestReadFrom.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/TestReadFromCommitted.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/WritableBlobFactory.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/WritableBlobTestCase.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/WritableBlobTestSuiteBuilder.java
Modified:
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/AttachmentSet.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/Attachments.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/AttachmentsDelegate.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEMessage.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PartImpl.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/Blob.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/BlobDataSource.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlob.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/WritableBlob.java
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/package.html
    webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/util/stax/XMLStreamReaderUtils.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/attachments/PartOnFileTest.java
    webservices/axiom/trunk/modules/axiom-api/src/test/java/org/apache/axiom/blob/MemoryBlobTest.java
    webservices/axiom/trunk/modules/axiom-compat/src/main/java/org/apache/axiom/util/blob/BlobOutputStream.java
    webservices/axiom/trunk/modules/axiom-compat/src/main/java/org/apache/axiom/util/blob/OverflowBlob.java
    webservices/axiom/trunk/systests/integration-tests/src/test/java/org/apache/axiom/om/impl/builder/JAXBCustomBuilderTest.java
    webservices/axiom/trunk/testing/testutils/src/main/java/org/apache/axiom/testutils/io/ExceptionInputStream.java

Modified: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/AttachmentSet.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/AttachmentSet.java?rev=1679662&r1=1679661&r2=1679662&view=diff
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/AttachmentSet.java (original)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/AttachmentSet.java Fri May 15 23:56:49 2015
@@ -27,7 +27,6 @@ import java.util.Set;
 
 import javax.activation.DataHandler;
 
-import org.apache.axiom.attachments.lifecycle.LifecycleManager;
 import org.apache.axiom.mime.ContentType;
 import org.apache.axiom.om.OMException;
 
@@ -42,14 +41,6 @@ class AttachmentSet extends AttachmentsD
         return null;
     }
 
-    LifecycleManager getLifecycleManager() {
-        return null;
-    }
-
-    void setLifecycleManager(LifecycleManager manager) {
-        // Ignore; only stream based attachments need a lifecycle manager
-    }
-
     DataHandler getDataHandler(String contentID) {
         return (DataHandler)attachmentsMap.get(contentID);
     }

Modified: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/Attachments.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/Attachments.java?rev=1679662&r1=1679661&r2=1679662&view=diff
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/Attachments.java (original)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/Attachments.java Fri May 15 23:56:49 2015
@@ -21,6 +21,10 @@ package org.apache.axiom.attachments;
 
 import org.apache.axiom.attachments.lifecycle.DataHandlerExt;
 import org.apache.axiom.attachments.lifecycle.LifecycleManager;
+import org.apache.axiom.attachments.lifecycle.impl.LifecycleManagerImpl;
+import org.apache.axiom.blob.Blobs;
+import org.apache.axiom.blob.WritableBlob;
+import org.apache.axiom.blob.WritableBlobFactory;
 import org.apache.axiom.ext.activation.SizeAwareDataSource;
 import org.apache.axiom.mime.ContentType;
 import org.apache.axiom.om.OMAttachmentAccessor;
@@ -46,12 +50,17 @@ public class Attachments implements OMAt
      */
     private String applicationType;
 
+    private LifecycleManager manager;
+    
     public LifecycleManager getLifecycleManager() {
-        return delegate.getLifecycleManager();
+        if (manager == null) {
+            manager = new LifecycleManagerImpl();
+        }
+        return manager;
     }
 
     public void setLifecycleManager(LifecycleManager manager) {
-        delegate.setLifecycleManager(manager);
+        this.manager = manager;
     }
 
     /**
@@ -84,14 +93,35 @@ public class Attachments implements OMAt
      */
     public Attachments(LifecycleManager manager, InputStream inStream, String contentTypeString, boolean fileCacheEnable,
             String attachmentRepoDir, String fileThreshold, int contentLength) throws OMException {
-        int fileStorageThreshold;
+        this.manager = manager;
+        final int fileStorageThreshold;
         if (fileThreshold != null && (!"".equals(fileThreshold))) {
             fileStorageThreshold = Integer.parseInt(fileThreshold);
         } else {
-            fileStorageThreshold = 1;
+            fileStorageThreshold = 0;
+        }
+        WritableBlobFactory attachmentBlobFactory;
+        if (fileCacheEnable) {
+            final WritableBlobFactory tempFileBlobFactory = new LegacyTempFileBlobFactory(this, attachmentRepoDir);
+            if (fileStorageThreshold > 0) {
+                attachmentBlobFactory = new WritableBlobFactory() {
+                    public WritableBlob createBlob() {
+                        return Blobs.createOverflowableBlob(fileStorageThreshold, tempFileBlobFactory);
+                    }
+                };
+            } else {
+                attachmentBlobFactory = tempFileBlobFactory;
+            }
+        } else {
+            attachmentBlobFactory = new WritableBlobFactory() {
+                public WritableBlob createBlob() {
+                    return Blobs.createMemoryBlob();
+                }
+            };
         }
-        delegate = new MIMEMessage(manager, inStream, contentTypeString, fileCacheEnable,
-                attachmentRepoDir, fileStorageThreshold, contentLength);
+        
+        delegate = new MIMEMessage(inStream, contentTypeString, attachmentBlobFactory,
+                contentLength);
     }
 
     /**

Modified: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/AttachmentsDelegate.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/AttachmentsDelegate.java?rev=1679662&r1=1679661&r2=1679662&view=diff
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/AttachmentsDelegate.java (original)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/AttachmentsDelegate.java Fri May 15 23:56:49 2015
@@ -25,7 +25,6 @@ import java.util.Set;
 
 import javax.activation.DataHandler;
 
-import org.apache.axiom.attachments.lifecycle.LifecycleManager;
 import org.apache.axiom.mime.ContentType;
 import org.apache.axiom.om.OMException;
 
@@ -50,8 +49,6 @@ import org.apache.axiom.om.OMException;
  */
 abstract class AttachmentsDelegate {
     abstract ContentType getContentType();
-    abstract LifecycleManager getLifecycleManager();
-    abstract void setLifecycleManager(LifecycleManager manager);
     abstract DataHandler getDataHandler(String contentID);
     abstract void addDataHandler(String contentID, DataHandler dataHandler);
     abstract void removeDataHandler(String blobContentID);

Added: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/LegacyTempFileBlob.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/LegacyTempFileBlob.java?rev=1679662&view=auto
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/LegacyTempFileBlob.java (added)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/LegacyTempFileBlob.java Fri May 15 23:56:49 2015
@@ -0,0 +1,63 @@
+/*
+ * 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.axiom.attachments;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.activation.DataSource;
+
+import org.apache.axiom.attachments.lifecycle.LifecycleManager;
+import org.apache.axiom.attachments.lifecycle.impl.FileAccessor;
+import org.apache.axiom.blob.AbstractWritableBlob;
+
+final class LegacyTempFileBlob extends AbstractWritableBlob {
+    private final LifecycleManager lifecycleManager;
+    private final String attachmentDir;
+    private FileAccessor fileAccessor;
+
+    LegacyTempFileBlob(LifecycleManager lifecycleManager, String attachmentDir) {
+        this.lifecycleManager = lifecycleManager;
+        this.attachmentDir = attachmentDir;
+    }
+
+    public OutputStream getOutputStream() throws IOException {
+        fileAccessor = lifecycleManager.create(attachmentDir);
+        return fileAccessor.getOutputStream();
+    }
+
+    public InputStream getInputStream() throws IOException {
+        return fileAccessor.getInputStream();
+    }
+
+    DataSource getDataSource(String contentType) {
+        CachedFileDataSource ds = new CachedFileDataSource(fileAccessor.getFile());
+        ds.setContentType(contentType);
+        return ds;
+    }
+    
+    public long getSize() {
+        return fileAccessor.getSize();
+    }
+
+    public void release() throws IOException {
+        lifecycleManager.delete(fileAccessor.getFile());
+    }
+}

Propchange: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/LegacyTempFileBlob.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/LegacyTempFileBlobFactory.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/LegacyTempFileBlobFactory.java?rev=1679662&view=auto
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/LegacyTempFileBlobFactory.java (added)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/LegacyTempFileBlobFactory.java Fri May 15 23:56:49 2015
@@ -0,0 +1,36 @@
+/*
+ * 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.axiom.attachments;
+
+import org.apache.axiom.blob.WritableBlob;
+import org.apache.axiom.blob.WritableBlobFactory;
+
+final class LegacyTempFileBlobFactory implements WritableBlobFactory {
+    private final Attachments attachments;
+    private final String attachmentDir;
+
+    LegacyTempFileBlobFactory(Attachments attachments, String attachmentDir) {
+        this.attachments = attachments;
+        this.attachmentDir = attachmentDir;
+    }
+
+    public WritableBlob createBlob() {
+        return new LegacyTempFileBlob(attachments.getLifecycleManager(), attachmentDir);
+    }
+}

Propchange: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/LegacyTempFileBlobFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEMessage.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEMessage.java?rev=1679662&r1=1679661&r2=1679662&view=diff
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEMessage.java (original)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEMessage.java Fri May 15 23:56:49 2015
@@ -31,8 +31,9 @@ import java.util.Set;
 import javax.activation.DataHandler;
 
 import org.apache.axiom.attachments.lifecycle.DataHandlerExt;
-import org.apache.axiom.attachments.lifecycle.LifecycleManager;
-import org.apache.axiom.attachments.lifecycle.impl.LifecycleManagerImpl;
+import org.apache.axiom.blob.Blobs;
+import org.apache.axiom.blob.WritableBlob;
+import org.apache.axiom.blob.WritableBlobFactory;
 import org.apache.axiom.mime.ContentType;
 import org.apache.axiom.mime.Header;
 import org.apache.axiom.om.OMException;
@@ -53,6 +54,12 @@ import org.apache.james.mime4j.stream.Re
  */
 class MIMEMessage extends AttachmentsDelegate {
     private static final Log log = LogFactory.getLog(MIMEMessage.class);
+    
+    private static final WritableBlobFactory rootPartBlobFactory = new WritableBlobFactory() {
+        public WritableBlob createBlob() {
+            return Blobs.createMemoryBlob();
+        }
+    };
 
     /** <code>ContentType</code> of the MIME message */
     private final ContentType contentType;
@@ -88,24 +95,15 @@ class MIMEMessage extends AttachmentsDel
 
     private String firstPartId;
 
-    private final boolean fileCacheEnable;
-
-    private final String attachmentRepoDir;
-
-    private final int fileStorageThreshold;
+    private final WritableBlobFactory attachmentBlobFactory;
     
-    private LifecycleManager manager;
-    
-    MIMEMessage(LifecycleManager manager, InputStream inStream, String contentTypeString, boolean fileCacheEnable,
-            String attachmentRepoDir, int fileStorageThreshold, int contentLength) throws OMException {
-        this.manager = manager;
+    MIMEMessage(InputStream inStream, String contentTypeString,
+            WritableBlobFactory attachmentBlobFactory, int contentLength) throws OMException {
         this.contentLength = contentLength;
-        this.attachmentRepoDir = attachmentRepoDir;
-        this.fileCacheEnable = fileCacheEnable;
+        this.attachmentBlobFactory = attachmentBlobFactory;
         if (log.isDebugEnabled()) {
             log.debug("Attachments contentLength=" + contentLength + ", contentTypeString=" + contentTypeString);
         }
-        this.fileStorageThreshold = fileStorageThreshold;
         try {
             contentType = new ContentType(contentTypeString);
         } catch (ParseException e) {
@@ -153,17 +151,6 @@ class MIMEMessage extends AttachmentsDel
         return contentType;
     }
 
-    LifecycleManager getLifecycleManager() {
-        if(manager == null) {
-            manager = new LifecycleManagerImpl();   
-        }
-        return manager;
-    }
-
-    void setLifecycleManager(LifecycleManager manager) {
-        this.manager = manager;
-    }
-
     DataHandler getDataHandler(String contentID) {
         do {
             DataHandler dataHandler = (DataHandler)attachmentsMap.get(contentID);
@@ -357,7 +344,7 @@ class MIMEMessage extends AttachmentsDel
             List headers = readHeaders();
             
             partIndex++;
-            currentPart = new PartImpl(this, isRootPart, headers, parser);
+            currentPart = new PartImpl(isRootPart ? rootPartBlobFactory : attachmentBlobFactory, headers, parser);
             return currentPart;
         } catch (IOException ex) {
             throw new OMException(ex);
@@ -366,18 +353,6 @@ class MIMEMessage extends AttachmentsDel
         }
     }
     
-    int getThreshold() {
-        return fileCacheEnable ? fileStorageThreshold : 0;
-    }
-    
-    String getAttachmentRepoDir() {
-        return attachmentRepoDir;
-    }
-
-    int getContentLengthIfKnown() {
-        return contentLength;
-    }
-    
     private List readHeaders() throws IOException, MimeException {
         if(log.isDebugEnabled()){
             log.debug("readHeaders");

Modified: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PartImpl.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PartImpl.java?rev=1679662&r1=1679661&r2=1679662&view=diff
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PartImpl.java (original)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PartImpl.java Fri May 15 23:56:49 2015
@@ -20,6 +20,10 @@
 package org.apache.axiom.attachments;
 
 import org.apache.axiom.attachments.Part;
+import org.apache.axiom.blob.OverflowableBlob;
+import org.apache.axiom.blob.WritableBlob;
+import org.apache.axiom.blob.WritableBlobFactory;
+import org.apache.axiom.ext.io.StreamCopyException;
 import org.apache.axiom.mime.Header;
 import org.apache.axiom.om.OMException;
 import org.apache.axiom.om.util.DetachableInputStream;
@@ -66,8 +70,7 @@ final class PartImpl implements Part {
 
     private static final Log log = LogFactory.getLog(PartImpl.class);
     
-    private final MIMEMessage message;
-    private final boolean isRootPart;
+    private final WritableBlobFactory blobFactory;
     
     private List/*<Header>*/ headers;
     
@@ -82,7 +85,7 @@ final class PartImpl implements Part {
     /**
      * The content of this part. This is only set if the state is {@link #STATE_BUFFERED}.
      */
-    private PartContent content;
+    private WritableBlob content;
     
     private final DataHandler dataHandler;
     
@@ -93,9 +96,8 @@ final class PartImpl implements Part {
      * @see org.apache.axiom.attachments.PartContentFactory
      * @param headers
      */
-    PartImpl(MIMEMessage message, boolean isRootPart, List headers, MimeTokenStream parser) {
-        this.message = message;
-        this.isRootPart = isRootPart;
+    PartImpl(WritableBlobFactory blobFactory, List headers, MimeTokenStream parser) {
+        this.blobFactory = blobFactory;;
         this.headers = headers;
         this.parser = parser;
         this.dataHandler = new PartDataHandler(this);
@@ -143,7 +145,7 @@ final class PartImpl implements Part {
         return getContent().getSize();
     }
 
-    private PartContent getContent() {
+    private WritableBlob getContent() {
         switch (state) {
             case STATE_UNREAD:
                 fetch();
@@ -176,13 +178,19 @@ final class PartImpl implements Part {
                 if (log.isDebugEnabled()) {
                     in = new DebugInputStream(in, log);
                 }
-                // The PartFactory will determine which Part implementation is most appropriate.
-                content = PartContentFactory.createPartContent(message.getLifecycleManager(),
-                                              in, 
-                                              isRootPart, 
-                                              message.getThreshold(),
-                                              message.getAttachmentRepoDir(),
-                                              message.getContentLengthIfKnown());  // content-length for the whole message
+                content = blobFactory.createBlob();
+                if (log.isDebugEnabled()) {
+                    log.debug("Using blob of type " + content.getClass().getName());
+                }
+                try {
+                    content.readFrom(in);
+                } catch (StreamCopyException ex) {
+                    if (ex.getOperation() == StreamCopyException.READ) {
+                        throw new OMException("Failed to fetch the MIME part content", ex.getCause());
+                    } else {
+                        throw new OMException("Failed to write the MIME part content to temporary storage", ex.getCause());
+                    }
+                }
                 moveToNextPart();
                 state = STATE_BUFFERED;
                 break;
@@ -225,7 +233,7 @@ final class PartImpl implements Part {
             detachableInputStream = new DetachableInputStream(parser.getDecodedInputStream());
             return detachableInputStream;
         } else {
-            PartContent content = getContent();
+            WritableBlob content = getContent();
             InputStream stream = content.getInputStream();
             if (!preserve) {
                 stream = new ReadOnceInputStreamWrapper(this, stream);
@@ -235,7 +243,18 @@ final class PartImpl implements Part {
     }
     
     DataSource getDataSource() {
-        return getContent().getDataSource(getDataSourceContentType());
+        WritableBlob blob = getContent();
+        if (blob instanceof OverflowableBlob) {
+            WritableBlob overflowBlob = ((OverflowableBlob)blob).getOverflowBlob();
+            if (overflowBlob != null) {
+                blob = overflowBlob;
+            }
+        }
+        if (blob instanceof LegacyTempFileBlob) {
+            return ((LegacyTempFileBlob)blob).getDataSource(getDataSourceContentType());
+        } else {
+            return null;
+        }
     }
 
     void writeTo(OutputStream out) throws IOException {
@@ -256,7 +275,7 @@ final class PartImpl implements Part {
                 state = STATE_DISCARDED;
                 break;
             case STATE_BUFFERED:
-                content.destroy();
+                content.release();
         }
     }
 }

Added: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/AbstractWritableBlob.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/AbstractWritableBlob.java?rev=1679662&view=auto
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/AbstractWritableBlob.java (added)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/AbstractWritableBlob.java Fri May 15 23:56:49 2015
@@ -0,0 +1,68 @@
+/*
+ * 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.axiom.blob;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.axiom.ext.io.StreamCopyException;
+
+/**
+ * Partial implementation of the {@link WritableBlob} interface that implements
+ * {@link WritableBlob#readFrom(InputStream)} using {@link WritableBlob#getOutputStream()} and
+ * {@link WritableBlob#writeTo(OutputStream)} using {@link WritableBlob#getInputStream()}.
+ */
+public abstract class AbstractWritableBlob implements WritableBlob {
+    public long readFrom(InputStream in) throws StreamCopyException {
+        OutputStream out;
+        try {
+            out = getOutputStream();
+        } catch (IOException ex) {
+            throw new StreamCopyException(StreamCopyException.WRITE, ex);
+        }
+        try {
+            return IOUtil.copy(in, out, -1);
+        } finally {
+            try {
+                out.close();
+            } catch (IOException ex) {
+                throw new StreamCopyException(StreamCopyException.WRITE, ex);
+            }
+        }
+    }
+
+    public void writeTo(OutputStream out) throws StreamCopyException {
+        InputStream in;
+        try {
+            in = getInputStream();
+        } catch (IOException ex) {
+            throw new StreamCopyException(StreamCopyException.READ, ex);
+        }
+        try {
+            IOUtil.copy(in, out, -1);
+        } finally {
+            try {
+                in.close();
+            } catch (IOException ex) {
+                throw new StreamCopyException(StreamCopyException.READ, ex);
+            }
+        }
+    }
+}

Propchange: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/AbstractWritableBlob.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/Blob.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/Blob.java?rev=1679662&r1=1679661&r2=1679662&view=diff
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/Blob.java (original)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/Blob.java Fri May 15 23:56:49 2015
@@ -28,13 +28,18 @@ import org.apache.axiom.ext.io.StreamCop
 /**
  * Stores binary data.
  * <p>
- * Not that blobs are not thread safe. While they support requesting multiple concurrent input
- * streams, these streams must be used in the same thread, unless appropriate synchronization or
- * locking is done.
+ * Blobs are thread safe in the sense that methods defined by this interface may be called
+ * concurrently. In addition, two different threads can safely invoke methods on two different
+ * {@link InputStream} instances retrieved by {@link #getInputStream()} concurrently. However some
+ * blobs (in particular {@link WritableBlob} implementations) may define additional methods and
+ * invoking these methods concurrently with methods defined by this interface is generally not
+ * thread safe.
  */
 public interface Blob {
     /**
-     * Get an input stream to read the data in the blob.
+     * Get an input stream to read the data in the blob. A new {@link InputStream} object is
+     * returned each time this method is called, and the stream is positioned at the beginning of
+     * the data.
      * 
      * @return the input stream to read the data from
      * @throws IOException
@@ -42,7 +47,8 @@ public interface Blob {
     InputStream getInputStream() throws IOException;
 
     /**
-     * Write the data to a given output stream.
+     * Write the data to a given output stream. This method can be called multiple times, i.e. it
+     * doesn't consume the content.
      * 
      * @param out
      *            The output stream to write the data to. This method will not close the stream.
@@ -54,9 +60,9 @@ public interface Blob {
     void writeTo(OutputStream out) throws StreamCopyException;
 
     /**
-     * Get the length of the data in the blob, i.e. the number of bytes.
+     * Get the size of the blob.
      * 
-     * @return the length of the data in the blob
+     * @return the number of bytes in the blob
      */
-    long getLength();
+    long getSize();
 }
\ No newline at end of file

Modified: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/BlobDataSource.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/BlobDataSource.java?rev=1679662&r1=1679661&r2=1679662&view=diff
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/BlobDataSource.java (original)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/BlobDataSource.java Fri May 15 23:56:49 2015
@@ -54,6 +54,6 @@ public class BlobDataSource implements S
     }
 
     public long getSize() {
-        return blob.getLength();
+        return blob.getSize();
     }
 }

Added: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/Blobs.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/Blobs.java?rev=1679662&view=auto
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/Blobs.java (added)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/Blobs.java Fri May 15 23:56:49 2015
@@ -0,0 +1,73 @@
+/*
+ * 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.axiom.blob;
+
+import java.io.File;
+
+/**
+ * Contains factory methods to create various types of blobs.
+ */
+public final class Blobs {
+    private Blobs() {}
+    
+    /**
+     * Create a {@link MemoryBlob} instance.
+     * 
+     * @return the blob
+     */
+    public static MemoryBlob createMemoryBlob() {
+        return new MemoryBlobImpl();
+    }
+    
+    /**
+     * Create an {@link OverflowableBlob}.
+     * 
+     * @param threshold
+     *            the threshold above which data is transferred to the overflow blob
+     * @param overflowBlobFactory
+     *            the factory that will be used to create the overflow blob
+     * @return the blob
+     */
+    public static OverflowableBlob createOverflowableBlob(int threshold, WritableBlobFactory overflowBlobFactory) {
+        int numberOfChunks = Math.max(16, Math.min(1, threshold/4096));
+        int chunkSize = threshold/numberOfChunks;
+        return new OverflowableBlobImpl(numberOfChunks, chunkSize, overflowBlobFactory);
+    }
+    
+    /**
+     * Create an {@link OverflowableBlob} that overflows to a temporary file. Temporary files are
+     * created using {@link File#createTempFile(String, String, File)}.
+     * 
+     * @param threshold
+     *            the overflow threshold
+     * @param tempPrefix
+     *            the prefix to be used in generating the name of the temporary file
+     * @param tempSuffix
+     *            the suffix to be used in generating the name of the temporary file
+     * @param tempDirectory
+     *            the directory in which the temporary file is to be created, or <code>null</code>
+     *            if the default temporary directory is to be used
+     * @return the blob
+     */
+    public static OverflowableBlob createOverflowableBlob(int threshold, String tempPrefix,
+            String tempSuffix, File tempDirectory) {
+        return createOverflowableBlob(threshold,
+                new TempFileBlobFactory(tempPrefix, tempSuffix, tempDirectory));
+    }
+}

Propchange: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/Blobs.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/IOUtil.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/IOUtil.java?rev=1679662&view=auto
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/IOUtil.java (added)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/IOUtil.java Fri May 15 23:56:49 2015
@@ -0,0 +1,59 @@
+/*
+ * 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.axiom.blob;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.axiom.ext.io.ReadFromSupport;
+import org.apache.axiom.ext.io.StreamCopyException;
+
+final class IOUtil {
+    private IOUtil() {}
+    
+    static long copy(InputStream in, OutputStream out, long length) throws StreamCopyException {
+        if (out instanceof ReadFromSupport) {
+            return ((ReadFromSupport)out).readFrom(in, length);
+        } else {
+            byte[] buffer = new byte[4096];
+            long read = 0;
+            long toRead = length == -1 ? Long.MAX_VALUE : length;
+            while (toRead > 0) {
+                int c;
+                try {
+                    c = in.read(buffer, 0, (int)Math.min(toRead, buffer.length));
+                } catch (IOException ex) {
+                    throw new StreamCopyException(StreamCopyException.READ, ex);
+                }
+                if (c == -1) {
+                    break;
+                }
+                try {
+                    out.write(buffer, 0, c);
+                } catch (IOException ex) {
+                    throw new StreamCopyException(StreamCopyException.WRITE, ex);
+                }
+                read += c;
+                toRead -= c;
+            }
+            return read;
+        }
+    }
+}

Propchange: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/IOUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlob.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlob.java?rev=1679662&r1=1679661&r2=1679662&view=diff
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlob.java (original)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlob.java Fri May 15 23:56:49 2015
@@ -16,244 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.axiom.blob;
 
-import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.axiom.ext.io.StreamCopyException;
 
 /**
- * Blob implementation that stores data in memory.
+ * Blob that stores data in memory.
+ * <p>
+ * This interface redefines several methods from {@link Blob} and {@link WritableBlob} to not throw
+ * {@link IOException}. Also note that since data is stored in memory, calling
+ * {@link WritableBlob#release()} is not required.
+ * <p>
+ * Instances are created with {@link Blobs#createMemoryBlob()}.
  */
-public final class MemoryBlob implements WritableBlob {
-    // TODO: this should be configurable
-    final static int BUFFER_SIZE = 4096;
-    
-    class OutputStreamImpl extends BlobOutputStream {
-        public WritableBlob getBlob() {
-            return MemoryBlob.this;
-        }
-
-        public void write(byte[] b, int off, int len) throws IOException {
-           int total = 0;
-           while (total < len) {
-               int copy = Math.min(len-total, BUFFER_SIZE-index);
-               System.arraycopy(b, off, currBuffer, index, copy);
-               total += copy;
-               index += copy;
-               off += copy;
-               if (index >= BUFFER_SIZE) {
-                   addBuffer();
-               }
-           }
-        }
-
-        public void write(byte[] b) throws IOException {
-            this.write(b, 0, b.length);
-        }
-        
-        byte[] writeByte = new byte[1];
-        public void write(int b) throws IOException {
-            writeByte[0] = (byte) b;
-            this.write(writeByte, 0, 1);
-        }
-
-        public void close() throws IOException {
-            committed = true;
-        }
-    }
-
-    class InputStreamImpl extends InputStream {
-        private int i;
-        private int currIndex;
-        private int totalIndex;
-        private int mark;
-        private byte[] currBuffer;
-        private byte[] read_byte = new byte[1];
-        
-        public InputStreamImpl() {
-        }
-
-        public int read() throws IOException {
-            int read = read(read_byte);
-
-            if (read < 0) {
-                return -1;
-            } else {
-                return read_byte[0] & 0xFF;
-            }
-        }
-
-        public int available() throws IOException {
-            return (int)getLength() - totalIndex;
-        }
-
-
-        public synchronized void mark(int readlimit) {
-            mark = totalIndex;
-        }
-
-        public boolean markSupported() {
-            return true;
-        }
-
-        public int read(byte[] b, int off, int len) throws IOException {
-            int size = (int)getLength();
-            int total = 0;
-            if (totalIndex >= size) {
-                return -1;
-            }
-            while (total < len && totalIndex < size) {
-                if (currBuffer == null) {
-                    currBuffer = (byte[]) data.get(i);
-                }
-                int copy = Math.min(len - total, BUFFER_SIZE - currIndex);
-                copy = Math.min(copy, size - totalIndex);
-                System.arraycopy(currBuffer, currIndex, b, off, copy);
-                total += copy;
-                currIndex += copy;
-                totalIndex += copy;
-                off += copy;
-                if (currIndex >= BUFFER_SIZE) {
-                    if (i+1 < data.size()) {
-                        i++;
-                        currIndex = 0;
-                    } else {
-                        currIndex = BUFFER_SIZE;
-                    } 
-                    currBuffer = null;
-                }
-            }
-            return total;
-        }
-
-        public int read(byte[] b) throws IOException {
-            return this.read(b, 0, b.length);
-        }
-
-        public synchronized void reset() throws IOException {
-            i = mark / BUFFER_SIZE;
-            currIndex = mark - (i * BUFFER_SIZE);
-            currBuffer = (byte[]) data.get(i);
-            totalIndex = mark;
-        }
-    }
-    
-    List data; // null here indicates the blob is in state NEW
-    int index;
-    byte[] currBuffer;
-    boolean committed;
-    
-    private void init() {
-        data = new ArrayList();
-        addBuffer();
-    }
-    
-    void addBuffer() {
-        currBuffer = new byte[BUFFER_SIZE];
-        data.add(currBuffer);
-        index = 0;
-    }
-    
-    public boolean isSupportingReadUncommitted() {
-        return true;
-    }
-
-    public long getLength() {
-        if (data == null) {
-            return 0;
-        } else {
-            return (BUFFER_SIZE * (data.size()-1)) + index;
-        }
-    }
-
-    public BlobOutputStream getOutputStream() {
-        if (data != null) {
-            throw new IllegalStateException();
-        } else {
-            init();
-            return new OutputStreamImpl();
-        }
-    }
-
-    public long readFrom(InputStream in, long length, boolean commit) throws StreamCopyException {
-        if (committed) {
-            throw new IllegalStateException();
-        }
-        if (data == null) {
-            init();
-        }
-        
-        if (length == -1) {
-            length = Long.MAX_VALUE;
-        }
-        long bytesReceived = 0;
-        
-        // Now directly write to the buffers
-        boolean done = false;
-        while (!done) {
-            
-            // Don't get more than will fit in the current buffer
-            int len = (int) Math.min(BUFFER_SIZE - index, length-bytesReceived);
-            
-            // Now get the bytes
-            int bytesRead;
-            try {
-                bytesRead = in.read(currBuffer, index, len);
-            } catch (IOException ex) {
-                throw new StreamCopyException(StreamCopyException.READ, ex);
-            }
-            if (bytesRead >= 0) {
-                bytesReceived += bytesRead;
-                index += bytesRead;
-                if (index >= BUFFER_SIZE) {
-                    addBuffer();
-                }
-                if (bytesReceived >= length) {
-                    done = true;
-                }
-            } else {
-                done = true;
-            }
-        }
-        
-        committed = commit;
-        
-        return bytesReceived;
-    }
-
-    public long readFrom(InputStream in, long length) throws StreamCopyException {
-        return readFrom(in, length, data == null);
-    }
-
-    public InputStream getInputStream() {
-        return new InputStreamImpl();
-    }
-
-    public void writeTo(OutputStream os) throws StreamCopyException {
-        int size = (int)getLength();
-        if (data != null) {
-            try {
-                int numBuffers = data.size();
-                for (int j = 0; j < numBuffers-1; j ++) {
-                    os.write( (byte[]) data.get(j), 0, BUFFER_SIZE);
-                }
-                if (numBuffers > 0) {
-                    int writeLimit = size - ((numBuffers-1) * BUFFER_SIZE);
-                    os.write( (byte[]) data.get(numBuffers-1), 0, writeLimit);
-                }
-            } catch (IOException ex) {
-                throw new StreamCopyException(StreamCopyException.WRITE, ex);
-            }
-        }
-    }
-
-    public void release() {
-        // no-op
-    }
+public interface MemoryBlob extends WritableBlob {
+    InputStream getInputStream();
+    OutputStream getOutputStream();
+    long getSize();
+    void release();
 }

Copied: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobImpl.java (from r1678555, webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlob.java)
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobImpl.java?p2=webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobImpl.java&p1=webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlob.java&r1=1678555&r2=1679662&rev=1679662&view=diff
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlob.java (original)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/MemoryBlobImpl.java Fri May 15 23:56:49 2015
@@ -25,32 +25,29 @@ import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.axiom.ext.io.ReadFromSupport;
 import org.apache.axiom.ext.io.StreamCopyException;
 
-/**
- * Blob implementation that stores data in memory.
- */
-public final class MemoryBlob implements WritableBlob {
+final class MemoryBlobImpl implements MemoryBlob {
     // TODO: this should be configurable
     final static int BUFFER_SIZE = 4096;
     
-    class OutputStreamImpl extends BlobOutputStream {
-        public WritableBlob getBlob() {
-            return MemoryBlob.this;
-        }
-
+    class OutputStreamImpl extends OutputStream implements ReadFromSupport {
         public void write(byte[] b, int off, int len) throws IOException {
-           int total = 0;
-           while (total < len) {
-               int copy = Math.min(len-total, BUFFER_SIZE-index);
-               System.arraycopy(b, off, currBuffer, index, copy);
-               total += copy;
-               index += copy;
-               off += copy;
-               if (index >= BUFFER_SIZE) {
-                   addBuffer();
-               }
-           }
+            if (committed) {
+                throw new IllegalStateException();
+            }
+            int total = 0;
+            while (total < len) {
+                int copy = Math.min(len-total, BUFFER_SIZE-index);
+                System.arraycopy(b, off, currBuffer, index, copy);
+                total += copy;
+                index += copy;
+                off += copy;
+                if (index >= BUFFER_SIZE) {
+                    addBuffer();
+                }
+            }
         }
 
         public void write(byte[] b) throws IOException {
@@ -66,6 +63,10 @@ public final class MemoryBlob implements
         public void close() throws IOException {
             committed = true;
         }
+
+        public long readFrom(InputStream in, long length) throws StreamCopyException {
+            return MemoryBlobImpl.this.readFrom(in, length, false);
+        }
     }
 
     class InputStreamImpl extends InputStream {
@@ -90,7 +91,7 @@ public final class MemoryBlob implements
         }
 
         public int available() throws IOException {
-            return (int)getLength() - totalIndex;
+            return (int)getSize() - totalIndex;
         }
 
 
@@ -103,7 +104,7 @@ public final class MemoryBlob implements
         }
 
         public int read(byte[] b, int off, int len) throws IOException {
-            int size = (int)getLength();
+            int size = (int)getSize();
             int total = 0;
             if (totalIndex >= size) {
                 return -1;
@@ -119,13 +120,9 @@ public final class MemoryBlob implements
                 currIndex += copy;
                 totalIndex += copy;
                 off += copy;
-                if (currIndex >= BUFFER_SIZE) {
-                    if (i+1 < data.size()) {
-                        i++;
-                        currIndex = 0;
-                    } else {
-                        currIndex = BUFFER_SIZE;
-                    } 
+                if (currIndex == BUFFER_SIZE) {
+                    i++;
+                    currIndex = 0;
                     currBuffer = null;
                 }
             }
@@ -160,20 +157,16 @@ public final class MemoryBlob implements
         index = 0;
     }
     
-    public boolean isSupportingReadUncommitted() {
-        return true;
-    }
-
-    public long getLength() {
-        if (data == null) {
-            return 0;
+    public long getSize() {
+        if (data == null || !committed) {
+            throw new IllegalStateException();
         } else {
             return (BUFFER_SIZE * (data.size()-1)) + index;
         }
     }
 
-    public BlobOutputStream getOutputStream() {
-        if (data != null) {
+    public OutputStream getOutputStream() {
+        if (data != null || committed) {
             throw new IllegalStateException();
         } else {
             init();
@@ -181,7 +174,7 @@ public final class MemoryBlob implements
         }
     }
 
-    public long readFrom(InputStream in, long length, boolean commit) throws StreamCopyException {
+    long readFrom(InputStream in, long length, boolean commit) throws StreamCopyException {
         if (committed) {
             throw new IllegalStateException();
         }
@@ -227,33 +220,38 @@ public final class MemoryBlob implements
         return bytesReceived;
     }
 
-    public long readFrom(InputStream in, long length) throws StreamCopyException {
-        return readFrom(in, length, data == null);
+    public long readFrom(InputStream in) throws StreamCopyException {
+        if (data != null) {
+            throw new IllegalStateException();
+        }
+        return readFrom(in, -1, true);
     }
 
     public InputStream getInputStream() {
+        if (data == null || !committed) {
+            throw new IllegalStateException();
+        }
         return new InputStreamImpl();
     }
 
     public void writeTo(OutputStream os) throws StreamCopyException {
-        int size = (int)getLength();
-        if (data != null) {
-            try {
-                int numBuffers = data.size();
-                for (int j = 0; j < numBuffers-1; j ++) {
-                    os.write( (byte[]) data.get(j), 0, BUFFER_SIZE);
-                }
-                if (numBuffers > 0) {
-                    int writeLimit = size - ((numBuffers-1) * BUFFER_SIZE);
-                    os.write( (byte[]) data.get(numBuffers-1), 0, writeLimit);
-                }
-            } catch (IOException ex) {
-                throw new StreamCopyException(StreamCopyException.WRITE, ex);
-            }
+        if (data == null || !committed) {
+            throw new IllegalStateException();
+        }
+        int size = (int)getSize();
+        try {
+            int numBuffers = data.size();
+            for (int j = 0; j < numBuffers-1; j ++) {
+                os.write( (byte[]) data.get(j), 0, BUFFER_SIZE);
+            }
+            int writeLimit = size - ((numBuffers-1) * BUFFER_SIZE);
+            os.write( (byte[]) data.get(numBuffers-1), 0, writeLimit);
+        } catch (IOException ex) {
+            throw new StreamCopyException(StreamCopyException.WRITE, ex);
         }
     }
 
     public void release() {
-        // no-op
+        data = null;
     }
 }

Copied: webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/OverflowableBlob.java (from r1678555, webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/OverflowBlob.java)
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/OverflowableBlob.java?p2=webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/OverflowableBlob.java&p1=webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/OverflowBlob.java&r1=1678555&r2=1679662&rev=1679662&view=diff
==============================================================================
--- webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/OverflowBlob.java (original)
+++ webservices/axiom/trunk/modules/axiom-api/src/main/java/org/apache/axiom/blob/OverflowableBlob.java Fri May 15 23:56:49 2015
@@ -16,453 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.axiom.blob;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import org.apache.axiom.ext.io.ReadFromSupport;
-import org.apache.axiom.ext.io.StreamCopyException;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
 /**
- * Blob implementation that stores data in a temporary file if the size exceeds a configurable
- * threshold. The data is first stored into a fixed size buffer. Once this buffer overflows, it is
- * transferred to a temporary file. The buffer is divided into a given number of fixed size chunks
- * that are allocated on demand. Since a temporary file may be created it is mandatory to call
- * {@link #release()} to discard the blob.
+ * Blob that accumulates data in memory and transfers it to a different type of blob if the size
+ * exceeds a certain threshold. Typically the overflow blob (i.e. the blob that is created if the
+ * memory buffer overflows) stores data in a temporary file. It is therefore mandatory to call
+ * {@link WritableBlob#release()} to discard the blob.
+ * <p>
+ * Instances are created with {@link Blobs#createOverflowableBlob(int, WritableBlobFactory)} or any
+ * of the other methods returning {@link OverflowableBlob}.
  */
-public final class OverflowBlob implements WritableBlob {
-    private static final Log log = LogFactory.getLog(OverflowBlob.class);
-    
-    static final int STATE_NEW = 0;
-    static final int STATE_UNCOMMITTED = 1;
-    static final int STATE_COMMITTED = 2;
-    
-    class OutputStreamImpl extends BlobOutputStream {
-        
-        private FileOutputStream fileOutputStream;
-        
-        public WritableBlob getBlob() {
-            return OverflowBlob.this;
-        }
-
-        public void write(byte[] b, int off, int len) throws IOException {
-
-            if (fileOutputStream != null) {
-                fileOutputStream.write(b, off, len);
-            } else if (len > (chunks.length-chunkIndex)*chunkSize - chunkOffset) {
-
-                // The buffer will overflow. Switch to a temporary file.
-                fileOutputStream = switchToTempFile();
-                
-                // Write the new data to the temporary file.
-                fileOutputStream.write(b, off, len);
-
-            } else {
-
-                // The data will fit into the buffer.
-                while (len > 0) {
-
-                    byte[] chunk = getCurrentChunk();
-
-                    // Determine number of bytes that can be copied to the current chunk.
-                    int c = Math.min(len, chunkSize-chunkOffset);
-                    // Copy data to the chunk.
-                    System.arraycopy(b, off, chunk, chunkOffset, c);
-
-                    // Update variables.
-                    len -= c;
-                    off += c;
-                    chunkOffset += c;
-                    if (chunkOffset == chunkSize) {
-                        chunkIndex++;
-                        chunkOffset = 0;
-                    }
-                }
-            }
-        }
-
-        public void write(byte[] b) throws IOException {
-            write(b, 0, b.length);
-        }
-
-        public void write(int b) throws IOException {
-            write(new byte[] { (byte)b }, 0, 1);
-        }
-
-        public void flush() throws IOException {
-            if (fileOutputStream != null) {
-                fileOutputStream.flush();
-            }
-        }
-
-        public void close() throws IOException {
-            if (fileOutputStream != null) {
-                fileOutputStream.close();
-            }
-            state = STATE_COMMITTED;
-        }
-    }
-    
-    class InputStreamImpl extends InputStream {
-
-        private int currentChunkIndex;
-        private int currentChunkOffset;
-        private int markChunkIndex;
-        private int markChunkOffset;
-        
-        public int available() throws IOException {
-            return (chunkIndex-currentChunkIndex)*chunkSize + chunkOffset - currentChunkOffset;
-        }
-
-        public int read(byte[] b, int off, int len) throws IOException {
-
-            if (len == 0) {
-                return 0;
-            }
-
-            int read = 0;
-            while (len > 0 && !(currentChunkIndex == chunkIndex
-                    && currentChunkOffset == chunkOffset)) {
-
-                int c;
-                if (currentChunkIndex == chunkIndex) {
-                    // The current chunk is the last one => take into account the offset
-                    c = Math.min(len, chunkOffset-currentChunkOffset);
-                } else {
-                    c = Math.min(len, chunkSize-currentChunkOffset);
-                }
-
-                // Copy the data.
-                System.arraycopy(chunks[currentChunkIndex], currentChunkOffset, b, off, c);
-
-                // Update variables
-                len -= c;
-                off += c;
-                currentChunkOffset += c;
-                read += c;
-                if (currentChunkOffset == chunkSize) {
-                    currentChunkIndex++;
-                    currentChunkOffset = 0;
-                }
-            }
-
-            if (read == 0) {
-                // We didn't read anything (and the len argument was not 0) => we reached the end of the buffer.
-                return -1;
-            } else {
-                return read;
-            }
-        }
-
-        public int read(byte[] b) throws IOException {
-            return read(b, 0, b.length);
-        }
-
-        public int read() throws IOException {
-            byte[] b = new byte[1];
-            return read(b) == -1 ? -1 : b[0] & 0xFF;
-        }
-
-        public boolean markSupported() {
-            return true;
-        }
-
-        public void mark(int readlimit) {
-            markChunkIndex = currentChunkIndex;
-            markChunkOffset = currentChunkOffset;
-        }
-
-        public void reset() throws IOException {
-            currentChunkIndex = markChunkIndex;
-            currentChunkOffset = markChunkOffset;
-        }
-
-        public long skip(long n) throws IOException {
-
-            int available = available();
-            int c = n < available ? (int)n : available;
-            int newOffset = currentChunkOffset + c;
-            int chunkDelta = newOffset/chunkSize;
-            currentChunkIndex += chunkDelta;
-            currentChunkOffset = newOffset - (chunkDelta*chunkSize);
-            return c;
-        }
-        
-        public void close() throws IOException {
-        }
-    }
-    
-    /**
-     * Size of the chunks that will be allocated in the buffer.
-     */
-    final int chunkSize;
-    
-    /**
-     * The prefix to be used in generating the name of the temporary file.
-     */
-    final String tempPrefix;
-    
-    /**
-     * The suffix to be used in generating the name of the temporary file.
-     */
-    final String tempSuffix;
-    
-    /**
-     * Array of <code>byte[]</code> representing the chunks of the buffer.
-     * A chunk is only allocated when the first byte is written to it.
-     * This attribute is set to <code>null</code> when the buffer overflows and
-     * is written out to a temporary file.
-     */
-    byte[][] chunks;
-    
-    /**
-     * Index of the chunk the next byte will be written to.
-     */
-    int chunkIndex;
-    
-    /**
-     * Offset into the chunk where the next byte will be written.
-     */
-    int chunkOffset;
-    
+public interface OverflowableBlob extends WritableBlob {
     /**
-     * The handle of the temporary file. This is only set when the memory buffer
-     * overflows and is written out to a temporary file.
-     */
-    File temporaryFile;
-    
-    /**
-     * The state of the blob.
-     */
-    int state = STATE_NEW;
-    
-    public OverflowBlob(int numberOfChunks, int chunkSize, String tempPrefix, String tempSuffix) {
-        this.chunkSize = chunkSize;
-        this.tempPrefix = tempPrefix;
-        this.tempSuffix = tempSuffix;
-        chunks = new byte[numberOfChunks][];
-    }
-    
-    public boolean isSupportingReadUncommitted() {
-        // This is actually a limitation of the implementation, not an intrinsic limitation
-        return false;
-    }
-
-    /**
-     * Get the current chunk to write to, allocating it if necessary.
+     * Get a reference to the overflow blob. The overflow blob is created only if the size of the
+     * blob exceeds the threshold. The method returns <code>null</code> if that's not the case.
      * 
-     * @return the current chunk to write to (never null)
+     * @return the overflow blob, or <code>null</code> if this blob hasn't overflown
      */
-    byte[] getCurrentChunk() {
-        if (chunkOffset == 0) {
-            // We will write the first byte to the current chunk. Allocate it.
-            byte[] chunk = new byte[chunkSize];
-            chunks[chunkIndex] = chunk;
-            return chunk;
-        } else {
-            // The chunk has already been allocated.
-            return chunks[chunkIndex];
-        }
-    }
-    
-    /**
-     * Create a temporary file and write the existing in memory data to it.
-     * 
-     * @return an open FileOutputStream to the temporary file
-     * @throws IOException
-     */
-    FileOutputStream switchToTempFile() throws IOException {
-        temporaryFile = File.createTempFile(tempPrefix, tempSuffix);
-        if (log.isDebugEnabled()) {
-            log.debug("Using temporary file " + temporaryFile);
-        }
-        temporaryFile.deleteOnExit();
-
-        FileOutputStream fileOutputStream = new FileOutputStream(temporaryFile);
-        // Write the buffer to the temporary file.
-        for (int i=0; i<chunkIndex; i++) {
-            fileOutputStream.write(chunks[i]);
-        }
-
-        if (chunkOffset > 0) {
-            fileOutputStream.write(chunks[chunkIndex], 0, chunkOffset);
-        }
-
-        // Release references to the buffer so that it can be garbage collected.
-        chunks = null;
-        
-        return fileOutputStream;
-    }
-    
-    public BlobOutputStream getOutputStream() {
-        if (state != STATE_NEW) {
-            throw new IllegalStateException();
-        } else {
-            state = STATE_UNCOMMITTED;
-            return new OutputStreamImpl();
-        }
-    }
-    
-    public long readFrom(InputStream in, long length, boolean commit) throws StreamCopyException {
-        if (state == STATE_COMMITTED) {
-            throw new IllegalStateException();
-        }
-        // TODO: this will not work if the blob is in state UNCOMMITTED and we have already switched to a temporary file
-        long read = 0;
-        long toRead = length == -1 ? Long.MAX_VALUE : length;
-        while (true) {
-            int c;
-            try {
-                int len = chunkSize-chunkOffset;
-                if (len > toRead) {
-                    len = (int)toRead;
-                }
-                c = in.read(getCurrentChunk(), chunkOffset, len);
-            } catch (IOException ex) {
-                throw new StreamCopyException(StreamCopyException.READ, ex);
-            }
-            if (c == -1) {
-                break;
-            }
-            read += c;
-            toRead -= c;
-            chunkOffset += c;
-            if (chunkOffset == chunkSize) {
-                chunkIndex++;
-                chunkOffset = 0;
-                if (chunkIndex == chunks.length) {
-                    FileOutputStream fileOutputStream;
-                    try {
-                        fileOutputStream = switchToTempFile();
-                    } catch (IOException ex) {
-                        throw new StreamCopyException(StreamCopyException.WRITE, ex);
-                    }
-                    byte[] buf = new byte[4096];
-                    while (true) {
-                        int c2;
-                        try {
-                            c2 = in.read(buf, 0, (int)Math.min(toRead, 4096));
-                        } catch (IOException ex) {
-                            throw new StreamCopyException(StreamCopyException.READ, ex);
-                        }
-                        if (c2 == -1) {
-                            break;
-                        }
-                        try {
-                            fileOutputStream.write(buf, 0, c2);
-                        } catch (IOException ex) {
-                            throw new StreamCopyException(StreamCopyException.WRITE, ex);
-                        }
-                        read += c2;
-                        toRead -= c2;
-                    }
-                    try {
-                        fileOutputStream.close();
-                    } catch (IOException ex) {
-                        throw new StreamCopyException(StreamCopyException.WRITE, ex);
-                    }
-                    break;
-                }
-            }
-        }
-        state = commit ? STATE_COMMITTED : STATE_UNCOMMITTED;
-        return read;
-    }
-    
-    public long readFrom(InputStream in, long length) throws StreamCopyException {
-        return readFrom(in, length, state == STATE_NEW);
-    }
-
-    public InputStream getInputStream() throws IOException {
-        if (state != STATE_COMMITTED) {
-            throw new IllegalStateException();
-        } else if (temporaryFile != null) {
-            return new FileInputStream(temporaryFile);
-        } else {
-            return new InputStreamImpl();
-        }
-    }
-    
-    public void writeTo(OutputStream out) throws StreamCopyException {
-        if (temporaryFile != null) {
-            FileInputStream in;
-            try {
-                in = new FileInputStream(temporaryFile);
-            } catch (IOException ex) {
-                throw new StreamCopyException(StreamCopyException.READ, ex);
-            }
-            try {
-                if (out instanceof ReadFromSupport) {
-                    ((ReadFromSupport)out).readFrom(in, -1);
-                } else {
-                    byte[] buf = new byte[4096];
-                    while (true) {
-                        int c;
-                        try {
-                            c = in.read(buf);
-                        } catch (IOException ex) {
-                            throw new StreamCopyException(StreamCopyException.READ, ex);
-                        }
-                        if (c == -1) {
-                            break;
-                        }
-                        try {
-                            out.write(buf, 0, c);
-                        } catch (IOException ex) {
-                            throw new StreamCopyException(StreamCopyException.WRITE, ex);
-                        }
-                    }
-                }
-            } finally {
-                try {
-                    in.close();
-                } catch (IOException ex) {
-                    throw new StreamCopyException(StreamCopyException.READ, ex);
-                }
-            }
-        } else {
-            try {
-                for (int i=0; i<chunkIndex; i++) {
-                    out.write(chunks[i]);
-                }
-                if (chunkOffset > 0) {
-                    out.write(chunks[chunkIndex], 0, chunkOffset);
-                }
-            } catch (IOException ex) {
-                throw new StreamCopyException(StreamCopyException.WRITE, ex);
-            }
-        }
-    }
-    
-    public long getLength() {
-        if (temporaryFile != null) {
-            return temporaryFile.length();
-        } else {
-            return chunkIndex*chunkSize + chunkOffset;
-        }
-    }
-    
-    public void release() {
-        if (temporaryFile != null) {
-            if (log.isDebugEnabled()) {
-                log.debug("Deleting temporary file " + temporaryFile);
-            }
-            temporaryFile.delete();
-        }
-    }
-
-    protected void finalize() throws Throwable {
-        if (temporaryFile != null) {
-            log.warn("Cleaning up unreleased temporary file " + temporaryFile);
-            temporaryFile.delete();
-        }
-    }
+    WritableBlob getOverflowBlob();
 }