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 2022/11/06 12:21:47 UTC

[ws-axiom] branch master updated: [AXIOM-506] Introduce PartBlob

This is an automated email from the ASF dual-hosted git repository.

veithen pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ws-axiom.git


The following commit(s) were added to refs/heads/master by this push:
     new 042218f5b [AXIOM-506] Introduce PartBlob
042218f5b is described below

commit 042218f5b53aabe93e365322586f70404181fc82
Author: Andreas Veithen <an...@gmail.com>
AuthorDate: Sun Nov 6 12:19:59 2022 +0000

    [AXIOM-506] Introduce PartBlob
---
 .../axiom/attachments/LegacyPartDataHandler.java   |  5 +-
 .../axiom/attachments/MultipartBodyAdapter.java    | 15 +++---
 .../java/org/apache/axiom/mime/MultipartBody.java  | 18 +++----
 .../src/main/java/org/apache/axiom/mime/Part.java  |  7 +++
 .../DataHandlerBlobFactory.java => PartBlob.java}  | 26 ++++------
 .../{BlobFactory.java => PartBlobFactory.java}     | 33 ++++++-------
 .../main/java/org/apache/axiom/mime/PartImpl.java  |  9 ++--
 .../axiom/mime/activation/PartDataHandler.java     | 23 ++++++---
 ...artDataSource.java => PartDataHandlerBlob.java} | 36 +++++++-------
 .../activation/PartDataHandlerBlobFactory.java     | 55 ++++++++++++++++++++++
 .../axiom/mime/activation/PartDataSource.java      |  8 +---
 .../activation/DataHandlerContentTypeProvider.java |  5 +-
 .../axiom/util/activation/DataHandlerUtils.java    | 27 +++++++++--
 .../om/impl/common/factory/meta/BuilderSpec.java   |  2 +-
 .../java/org/apache/axiom/samples/MTOMSample.java  |  4 +-
 .../org/apache/axiom/ts/om/xop/TestSerialize.java  |  4 +-
 .../soap12/envelope/TestBuildWithAttachments.java  |  4 +-
 .../soap12/envelope/TestMTOMForwardStreaming.java  |  7 +--
 18 files changed, 182 insertions(+), 106 deletions(-)

diff --git a/axiom-api/src/main/java/org/apache/axiom/attachments/LegacyPartDataHandler.java b/axiom-api/src/main/java/org/apache/axiom/attachments/LegacyPartDataHandler.java
index 7d6b8da84..9cc5d0f24 100644
--- a/axiom-api/src/main/java/org/apache/axiom/attachments/LegacyPartDataHandler.java
+++ b/axiom-api/src/main/java/org/apache/axiom/attachments/LegacyPartDataHandler.java
@@ -20,7 +20,6 @@ package org.apache.axiom.attachments;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.function.Supplier;
 
 import javax.activation.DataSource;
 
@@ -30,8 +29,8 @@ import org.apache.axiom.mime.Part;
 import org.apache.axiom.mime.activation.PartDataHandler;
 
 final class LegacyPartDataHandler extends PartDataHandler implements DataHandlerExt {
-    LegacyPartDataHandler(Part part, Supplier<Blob> contentSupplier) {
-        super(part, contentSupplier);
+    LegacyPartDataHandler(Part part) {
+        super(part);
     }
 
     @Override
diff --git a/axiom-api/src/main/java/org/apache/axiom/attachments/MultipartBodyAdapter.java b/axiom-api/src/main/java/org/apache/axiom/attachments/MultipartBodyAdapter.java
index 60180071a..6d3ed9fbc 100644
--- a/axiom-api/src/main/java/org/apache/axiom/attachments/MultipartBodyAdapter.java
+++ b/axiom-api/src/main/java/org/apache/axiom/attachments/MultipartBodyAdapter.java
@@ -25,14 +25,13 @@ import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
-import java.util.function.Supplier;
 
 import javax.activation.DataHandler;
 
-import org.apache.axiom.blob.Blob;
 import org.apache.axiom.blob.WritableBlobFactory;
 import org.apache.axiom.mime.ContentType;
-import org.apache.axiom.mime.BlobFactory;
+import org.apache.axiom.mime.activation.PartDataHandler;
+import org.apache.axiom.mime.activation.PartDataHandlerBlobFactory;
 import org.apache.axiom.mime.Header;
 import org.apache.axiom.mime.MultipartBody;
 import org.apache.axiom.mime.MultipartBody.PartCreationListener;
@@ -77,10 +76,10 @@ final class MultipartBodyAdapter extends AttachmentsDelegate implements PartCrea
                 .setInputStream(inStream)
                 .setContentType(contentTypeString)
                 .setAttachmentBlobFactory(attachmentBlobFactory)
-                .setBlobFactory(new BlobFactory() {
+                .setPartBlobFactory(new PartDataHandlerBlobFactory() {
                         @Override
-                        public Blob createBlob(Part part, Supplier<Blob> contentSupplier) {
-                            return DataHandlerUtils.toBlob(new LegacyPartDataHandler(part, contentSupplier));
+                        protected PartDataHandler createDataHandler(Part part) {
+                            return new LegacyPartDataHandler(part);
                         }
                     })
                 .setPartCreationListener(this)
@@ -90,7 +89,7 @@ final class MultipartBodyAdapter extends AttachmentsDelegate implements PartCrea
         String rootPartContentID = rootPart.getContentID();
         if (rootPartContentID == null) {
             rootPartContentID = "firstPart_" + UIDGenerator.generateContentId();
-            map.put(rootPartContentID, DataHandlerUtils.toDataHandler(rootPart.getBlob()));
+            map.put(rootPartContentID, DataHandlerUtils.toDataHandler(rootPart.getPartBlob()));
         }
         this.rootPartContentID = rootPartContentID;
     }
@@ -99,7 +98,7 @@ final class MultipartBodyAdapter extends AttachmentsDelegate implements PartCrea
     public void partCreated(Part part) {
         String contentID = part.getContentID();
         if (contentID != null) {
-            map.put(contentID, DataHandlerUtils.toDataHandler(part.getBlob()));
+            map.put(contentID, DataHandlerUtils.toDataHandler(part.getPartBlob()));
         }
     }
 
diff --git a/axiom-api/src/main/java/org/apache/axiom/mime/MultipartBody.java b/axiom-api/src/main/java/org/apache/axiom/mime/MultipartBody.java
index 72f6a77d1..d1065d18c 100644
--- a/axiom-api/src/main/java/org/apache/axiom/mime/MultipartBody.java
+++ b/axiom-api/src/main/java/org/apache/axiom/mime/MultipartBody.java
@@ -58,7 +58,7 @@ public final class MultipartBody implements Iterable<Part> {
         private InputStream inputStream;
         private ContentType contentType;
         private WritableBlobFactory<?> attachmentBlobFactory;
-        private BlobFactory blobFactory;
+        private PartBlobFactory partBlobFactory;
         private PartCreationListener partCreationListener;
         
         Builder() {}
@@ -87,8 +87,8 @@ public final class MultipartBody implements Iterable<Part> {
             return this;
         }
 
-        public Builder setBlobFactory(BlobFactory blobFactory) {
-            this.blobFactory = blobFactory;
+        public Builder setPartBlobFactory(PartBlobFactory partBlobFactory) {
+            this.partBlobFactory = partBlobFactory;
             return this;
         }
 
@@ -108,7 +108,7 @@ public final class MultipartBody implements Iterable<Part> {
                     inputStream,
                     contentType,
                     attachmentBlobFactory == null ? MemoryBlob.FACTORY : attachmentBlobFactory,
-                    blobFactory == null ? BlobFactory.DEFAULT : blobFactory,
+                    partBlobFactory == null ? PartBlobFactory.DEFAULT : partBlobFactory,
                     partCreationListener);
         }
     }
@@ -138,15 +138,15 @@ public final class MultipartBody implements Iterable<Part> {
     private int partCount;
 
     private final WritableBlobFactory<?> attachmentBlobFactory;
-    private final BlobFactory blobFactory;
+    private final PartBlobFactory partBlobFactory;
     private final PartCreationListener partCreationListener;
     
     MultipartBody(InputStream inStream, ContentType contentType,
             WritableBlobFactory<?> attachmentBlobFactory,
-            BlobFactory blobFactory,
+            PartBlobFactory partBlobFactory,
             PartCreationListener partCreationListener) {
         this.attachmentBlobFactory = attachmentBlobFactory;
-        this.blobFactory = blobFactory;
+        this.partBlobFactory = partBlobFactory;
         this.partCreationListener = partCreationListener;
         this.contentType = contentType;
 
@@ -187,8 +187,8 @@ public final class MultipartBody implements Iterable<Part> {
         return contentID;
     }
 
-    BlobFactory getBlobFactory() {
-        return blobFactory;
+    PartBlobFactory getPartBlobFactory() {
+        return partBlobFactory;
     }
 
     public ContentType getContentType() {
diff --git a/axiom-api/src/main/java/org/apache/axiom/mime/Part.java b/axiom-api/src/main/java/org/apache/axiom/mime/Part.java
index 0808b9b88..9adfcba30 100644
--- a/axiom-api/src/main/java/org/apache/axiom/mime/Part.java
+++ b/axiom-api/src/main/java/org/apache/axiom/mime/Part.java
@@ -67,6 +67,13 @@ public interface Part {
      */
     Blob getBlob();
 
+    /**
+     * Get the {@link PartBlob} instance created by the configured {@link PartBlobFactory}.
+     * 
+     * @return the {@link PartBlob} instance
+     */
+    PartBlob getPartBlob();
+
     /**
      * Get the content of this part as an {@link InputStream}.
      * 
diff --git a/axiom-api/src/main/java/org/apache/axiom/mime/activation/DataHandlerBlobFactory.java b/axiom-api/src/main/java/org/apache/axiom/mime/PartBlob.java
similarity index 54%
rename from axiom-api/src/main/java/org/apache/axiom/mime/activation/DataHandlerBlobFactory.java
rename to axiom-api/src/main/java/org/apache/axiom/mime/PartBlob.java
index 3f41a2476..f6b24e0ae 100644
--- a/axiom-api/src/main/java/org/apache/axiom/mime/activation/DataHandlerBlobFactory.java
+++ b/axiom-api/src/main/java/org/apache/axiom/mime/PartBlob.java
@@ -16,26 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.axiom.mime.activation;
-
-import java.util.function.Supplier;
+package org.apache.axiom.mime;
 
 import org.apache.axiom.blob.Blob;
-import org.apache.axiom.mime.BlobFactory;
-import org.apache.axiom.mime.Part;
-import org.apache.axiom.util.activation.DataHandlerUtils;
 
 /**
- * {@link BlobFactory} implementation that creates {@link Blob} instances that wrap
- * {@link PartDataHandler} instances.
+ * A {@link Blob} that enables access to the {@link Part} whose content it represents.
  */
-public final class DataHandlerBlobFactory implements BlobFactory {
-    public static final DataHandlerBlobFactory INSTANCE = new DataHandlerBlobFactory();
-
-    private DataHandlerBlobFactory() {}
-
-    @Override
-    public Blob createBlob(Part part, Supplier<Blob> contentSupplier) {
-        return DataHandlerUtils.toBlob(new PartDataHandler(part, contentSupplier));
-    }
+public interface PartBlob extends Blob {
+    /**
+     * The the MIME part from which this blob was created.
+     * 
+     * @return the MIME part
+     */
+    Part getPart();
 }
diff --git a/axiom-api/src/main/java/org/apache/axiom/mime/BlobFactory.java b/axiom-api/src/main/java/org/apache/axiom/mime/PartBlobFactory.java
similarity index 62%
rename from axiom-api/src/main/java/org/apache/axiom/mime/BlobFactory.java
rename to axiom-api/src/main/java/org/apache/axiom/mime/PartBlobFactory.java
index 53caa05db..c63441036 100644
--- a/axiom-api/src/main/java/org/apache/axiom/mime/BlobFactory.java
+++ b/axiom-api/src/main/java/org/apache/axiom/mime/PartBlobFactory.java
@@ -21,51 +21,52 @@ package org.apache.axiom.mime;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.function.Supplier;
 
-import org.apache.axiom.blob.Blob;
 import org.apache.axiom.ext.io.StreamCopyException;
 
 /**
- * Factory for the {@link Blob} instances returned by {@link Part#getBlob()}. This may be used to
- * create {@link Blob} instances that wrap some other type of objects representing the content of
+ * Factory for the {@link PartBlob} instances returned by {@link Part#getBlob()}. This may be used to
+ * create {@link PartBlob} instances that wrap some other type of objects representing the content of
  * MIME parts.
  */
-public interface BlobFactory {
+public interface PartBlobFactory {
     /**
-     * Default factory that creates {@link Blob} instances that lazily access the underlying
+     * Default factory that creates {@link PartBlob} instances that lazily access the underlying
      * content.
      */
-    BlobFactory DEFAULT = new BlobFactory() {
+    PartBlobFactory DEFAULT = new PartBlobFactory() {
         @Override
-        public Blob createBlob(Part part, Supplier<Blob> contentSupplier) {
-            return new Blob() {
+        public PartBlob createBlob(Part part) {
+            return new PartBlob() {
+                @Override
+                public Part getPart() {
+                    return part;
+                }
+
                 @Override
                 public InputStream getInputStream() throws IOException {
-                    return contentSupplier.get().getInputStream();
+                    return part.getBlob().getInputStream();
                 }
                 
                 @Override
                 public void writeTo(OutputStream out) throws StreamCopyException {
-                    contentSupplier.get().writeTo(out);
+                    part.getBlob().writeTo(out);
                 }
                 
                 @Override
                 public long getSize() {
-                    return contentSupplier.get().getSize();
+                    return part.getBlob().getSize();
                 }
             };
         }
     };
 
     /**
-     * Create a {@link Blob} for the given MIME part.
+     * Create a {@link PartBlob} for the given MIME part.
      * 
      * @param part
      *            the MIME part
-     * @param contentSupplier
-     *            a supplier for the content of the part
      * @return the blob
      */
-    Blob createBlob(Part part, Supplier<Blob> contentSupplier);
+    PartBlob createBlob(Part part);
 }
diff --git a/axiom-api/src/main/java/org/apache/axiom/mime/PartImpl.java b/axiom-api/src/main/java/org/apache/axiom/mime/PartImpl.java
index 1eaddca5b..cec33e239 100644
--- a/axiom-api/src/main/java/org/apache/axiom/mime/PartImpl.java
+++ b/axiom-api/src/main/java/org/apache/axiom/mime/PartImpl.java
@@ -85,7 +85,7 @@ final class PartImpl implements Part {
      */
     private WritableBlob content;
     
-    private Blob blob;
+    private PartBlob blob;
     
     private PartInputStream partInputStream;
     
@@ -138,9 +138,9 @@ final class PartImpl implements Part {
     }
     
     @Override
-    public Blob getBlob() {
+    public PartBlob getPartBlob() {
         if (blob == null) {
-            blob = message.getBlobFactory().createBlob(this, this::getRawBlob);
+            blob = message.getPartBlobFactory().createBlob(this);
         }
         return blob;
     }
@@ -157,7 +157,8 @@ final class PartImpl implements Part {
         }
     }
     
-    private Blob getRawBlob() {
+    @Override
+    public Blob getBlob() {
         WritableBlob blob = getContent();
         if (blob instanceof OverflowableBlob) {
             WritableBlob overflowBlob = ((OverflowableBlob)blob).getOverflowBlob();
diff --git a/axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataHandler.java b/axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataHandler.java
index 4fef99f16..82a08ecb0 100644
--- a/axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataHandler.java
+++ b/axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataHandler.java
@@ -20,32 +20,32 @@ package org.apache.axiom.mime.activation;
 
 import java.io.IOException;
 import java.io.OutputStream;
-import java.util.function.Supplier;
 
 import javax.activation.DataHandler;
 import javax.activation.DataSource;
 
 import org.apache.axiom.blob.Blob;
 import org.apache.axiom.mime.Part;
+import org.apache.axiom.mime.PartBlob;
 
 /**
  * {@link DataHandler} implementation for MIME parts read from a stream.
  */
 public class PartDataHandler extends DataHandler {
     private final Part part;
-    private final Supplier<Blob> contentSupplier;
+    private final PartDataHandlerBlob blob;
     private DataSource dataSource;
 
-    protected PartDataHandler(Part part, Supplier<Blob> contentSupplier) {
+    protected PartDataHandler(Part part) {
         // We can't call PartImpl#getDataSource() here because it would fetch the content of the
         // part and therefore disable streaming. We can't pass null here either because Geronimo's
         // DataHandler implementation would throw a NullPointerException. Therefore we create the
         // default PartDataSource. When the DataSource is requested, we check if for there is an
         // implementation specific to the buffering strategy and return that instead of the default
         // implementation.
-        super(new PartDataSource(part, contentSupplier));
+        super(new PartDataSource(part));
         this.part = part;
-        this.contentSupplier = contentSupplier;
+        this.blob = new PartDataHandlerBlob(this);
     }
 
     /**
@@ -57,10 +57,19 @@ public class PartDataHandler extends DataHandler {
         return part;
     }
 
+    /**
+     * Get the {@link PartBlob} that wraps this instance.
+     * 
+     * @return the blob wrapper
+     */
+    public final PartBlob getBlob() {
+        return blob;
+    }
+
     @Override
     public final DataSource getDataSource() {
         if (dataSource == null) {
-            dataSource = createDataSource(contentSupplier.get(), Util.getDataSourceContentType(part));
+            dataSource = createDataSource(part.getBlob(), Util.getDataSourceContentType(part));
             if (dataSource == null) {
                 // We get here if there is no DataSource implementation specific to the buffering
                 // strategy being used. In this case we use super.getDataSource() to get the
@@ -92,6 +101,6 @@ public class PartDataHandler extends DataHandler {
         // The PartContent may have an implementation of writeTo that is more efficient than the default
         // DataHandler#writeTo method (which requests an input stream and then copies it to the output
         // stream).
-        contentSupplier.get().writeTo(os);
+        part.getBlob().writeTo(os);
     }
 }
diff --git a/axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataSource.java b/axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataHandlerBlob.java
similarity index 58%
copy from axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataSource.java
copy to axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataHandlerBlob.java
index facac683c..6643ab968 100644
--- a/axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataSource.java
+++ b/axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataHandlerBlob.java
@@ -21,46 +21,42 @@ package org.apache.axiom.mime.activation;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.function.Supplier;
 
-import org.apache.axiom.blob.Blob;
-import org.apache.axiom.ext.activation.SizeAwareDataSource;
+import org.apache.axiom.ext.io.StreamCopyException;
 import org.apache.axiom.mime.Part;
+import org.apache.axiom.mime.PartBlob;
 
 /**
- * Default {@link DataSource} implementation for MIME parts.
+ * {@link PartBlob} implementation that wraps a {@link PartDataHandler}.
  */
-final class PartDataSource implements SizeAwareDataSource {
-    private final Part part;
-    private final Supplier<Blob> contentSupplier;
+public final class PartDataHandlerBlob implements PartBlob {
+    private final PartDataHandler dataHandler;
 
-    PartDataSource(Part part, Supplier<Blob> contentSupplier) {
-        this.part = part;
-        this.contentSupplier = contentSupplier;
+    PartDataHandlerBlob(PartDataHandler dataHandler) {
+        this.dataHandler = dataHandler;
     }
 
-    @Override
-    public String getContentType() {
-        return Util.getDataSourceContentType(part);
+    public PartDataHandler getDataHandler() {
+        return dataHandler;
     }
 
     @Override
-    public InputStream getInputStream() throws IOException {
-        return part.getInputStream(true);
+    public Part getPart() {
+        return dataHandler.getPart();
     }
 
     @Override
-    public String getName() {
-        return part.getContentID();
+    public InputStream getInputStream() throws IOException {
+        return dataHandler.getPart().getBlob().getInputStream();
     }
 
     @Override
-    public OutputStream getOutputStream() throws IOException {
-        throw new UnsupportedOperationException();
+    public void writeTo(OutputStream out) throws StreamCopyException {
+        dataHandler.getPart().getBlob().writeTo(out);
     }
 
     @Override
     public long getSize() {
-        return contentSupplier.get().getSize();
+        return dataHandler.getPart().getBlob().getSize();
     }
 }
diff --git a/axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataHandlerBlobFactory.java b/axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataHandlerBlobFactory.java
new file mode 100644
index 000000000..ebe6ceee5
--- /dev/null
+++ b/axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataHandlerBlobFactory.java
@@ -0,0 +1,55 @@
+/*
+ * 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.mime.activation;
+
+import org.apache.axiom.mime.PartBlobFactory;
+import org.apache.axiom.mime.Part;
+import org.apache.axiom.mime.PartBlob;
+
+/**
+ * {@link PartBlobFactory} implementation that creates {@link PartBlob} instances that wrap
+ * {@link PartDataHandler} instances.
+ */
+public abstract class PartDataHandlerBlobFactory implements PartBlobFactory {
+    /**
+     * {@link PartDataHandlerBlobFactory} instance that creates plain {@link PartDataHandler}
+     * instances.
+     */
+    public static final PartDataHandlerBlobFactory DEFAULT = new PartDataHandlerBlobFactory() {
+        @Override
+        protected PartDataHandler createDataHandler(Part part) {
+            return new PartDataHandler(part);
+        }
+    };
+
+    protected PartDataHandlerBlobFactory() {}
+
+    @Override
+    public final PartBlob createBlob(Part part) {
+        return createDataHandler(part).getBlob();
+    }
+
+    /**
+     * Create a {@link PartDataHandler} for the given {@link Part}.
+     * 
+     * @param part the MIME part
+     * @return the data handler
+     */
+    protected abstract PartDataHandler createDataHandler(Part part);
+}
diff --git a/axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataSource.java b/axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataSource.java
index facac683c..acbc0f7ea 100644
--- a/axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataSource.java
+++ b/axiom-api/src/main/java/org/apache/axiom/mime/activation/PartDataSource.java
@@ -21,9 +21,7 @@ package org.apache.axiom.mime.activation;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.function.Supplier;
 
-import org.apache.axiom.blob.Blob;
 import org.apache.axiom.ext.activation.SizeAwareDataSource;
 import org.apache.axiom.mime.Part;
 
@@ -32,11 +30,9 @@ import org.apache.axiom.mime.Part;
  */
 final class PartDataSource implements SizeAwareDataSource {
     private final Part part;
-    private final Supplier<Blob> contentSupplier;
 
-    PartDataSource(Part part, Supplier<Blob> contentSupplier) {
+    PartDataSource(Part part) {
         this.part = part;
-        this.contentSupplier = contentSupplier;
     }
 
     @Override
@@ -61,6 +57,6 @@ final class PartDataSource implements SizeAwareDataSource {
 
     @Override
     public long getSize() {
-        return contentSupplier.get().getSize();
+        return part.getBlob().getSize();
     }
 }
diff --git a/axiom-api/src/main/java/org/apache/axiom/util/activation/DataHandlerContentTypeProvider.java b/axiom-api/src/main/java/org/apache/axiom/util/activation/DataHandlerContentTypeProvider.java
index 2eb083ce8..b5e4da206 100644
--- a/axiom-api/src/main/java/org/apache/axiom/util/activation/DataHandlerContentTypeProvider.java
+++ b/axiom-api/src/main/java/org/apache/axiom/util/activation/DataHandlerContentTypeProvider.java
@@ -41,10 +41,11 @@ public final class DataHandlerContentTypeProvider implements ContentTypeProvider
 
     @Override
     public ContentType getContentType(Blob blob) {
-        if (!(blob instanceof DataHandlerBlob)) {
+        DataHandler dh = DataHandlerUtils.getDataHandler(blob);
+        if (dh == null) {
             return null;
         }
-        String contentType = ((DataHandlerBlob) blob).getDataHandler().getContentType();
+        String contentType = dh.getContentType();
         if (contentType == null) {
             return null;
         }
diff --git a/axiom-api/src/main/java/org/apache/axiom/util/activation/DataHandlerUtils.java b/axiom-api/src/main/java/org/apache/axiom/util/activation/DataHandlerUtils.java
index 9cbd50e69..900af1e3e 100644
--- a/axiom-api/src/main/java/org/apache/axiom/util/activation/DataHandlerUtils.java
+++ b/axiom-api/src/main/java/org/apache/axiom/util/activation/DataHandlerUtils.java
@@ -25,6 +25,8 @@ import javax.activation.DataHandler;
 import javax.activation.DataSource;
 
 import org.apache.axiom.blob.Blob;
+import org.apache.axiom.mime.activation.PartDataHandler;
+import org.apache.axiom.mime.activation.PartDataHandlerBlob;
 
 /**
  * Contains utility methods to work with {@link DataHandler} objects.
@@ -67,6 +69,22 @@ public final class DataHandlerUtils {
         }
     }
 
+    /**
+     * Get the {@link DataHandler} wrapped by the given {@link Blob}.
+     * 
+     * @param blob the {@link Blob} to unwrap
+     * @return the wrapped {@link DataHandler}, or {@code null} if the blob doesn't wrap a {@link DataHandler}
+     */
+    public static DataHandler getDataHandler(Blob blob) {
+        if (blob instanceof DataHandlerBlob) {
+            return ((DataHandlerBlob)blob).getDataHandler();
+        }
+        if (blob instanceof PartDataHandlerBlob) {
+            return ((PartDataHandlerBlob)blob).getDataHandler();
+        }
+        return null;
+    }
+
     /**
      * Get a {@link DataHandler} for the given {@link Blob}. If the blob was obtained from {@link
      * #toBlob(DataHandler)}, the original {@link DataHandler} is returned.
@@ -75,10 +93,8 @@ public final class DataHandlerUtils {
      * @return a {@link DataHandler} representing the {@link Blob}
      */
     public static DataHandler toDataHandler(Blob blob) {
-        if (blob instanceof DataHandlerBlob) {
-            return ((DataHandlerBlob)blob).getDataHandler();
-        }
-        return new BlobDataHandler(blob);
+        DataHandler dh = getDataHandler(blob);
+        return dh != null ? dh : new BlobDataHandler(blob);
     }
 
     /**
@@ -92,6 +108,9 @@ public final class DataHandlerUtils {
         if (dh instanceof BlobDataHandler) {
             return ((BlobDataHandler)dh).getBlob();
         }
+        if (dh instanceof PartDataHandler) {
+            return ((PartDataHandler)dh).getBlob();
+        }
         return new DataHandlerBlob(dh);
     }
 }
diff --git a/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/common/factory/meta/BuilderSpec.java b/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/common/factory/meta/BuilderSpec.java
index a521da6c9..f1d970522 100644
--- a/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/common/factory/meta/BuilderSpec.java
+++ b/mixins/om-mixins/src/main/java/org/apache/axiom/om/impl/common/factory/meta/BuilderSpec.java
@@ -221,7 +221,7 @@ public final class BuilderSpec {
                                     @Override
                                     public Blob getBlob(String contentID) {
                                         Part part = message.getPart(contentID);
-                                        return part == null ? null : part.getBlob();
+                                        return part == null ? null : part.getPartBlob();
                                     }
                                 })),
                 new Detachable() {
diff --git a/samples/src/test/java/org/apache/axiom/samples/MTOMSample.java b/samples/src/test/java/org/apache/axiom/samples/MTOMSample.java
index 4d3921cd3..d67240a33 100644
--- a/samples/src/test/java/org/apache/axiom/samples/MTOMSample.java
+++ b/samples/src/test/java/org/apache/axiom/samples/MTOMSample.java
@@ -30,7 +30,7 @@ import javax.xml.ws.Endpoint;
 import junit.framework.TestCase;
 
 import org.apache.axiom.mime.MultipartBody;
-import org.apache.axiom.mime.activation.DataHandlerBlobFactory;
+import org.apache.axiom.mime.activation.PartDataHandlerBlobFactory;
 import org.apache.axiom.mime.activation.PartDataHandler;
 import org.apache.axiom.om.OMAbstractFactory;
 import org.apache.axiom.om.OMElement;
@@ -69,7 +69,7 @@ public class MTOMSample extends TestCase {
         MultipartBody multipartBody = MultipartBody.builder()
                 .setInputStream(in)
                 .setContentType(connection.getContentType())
-                .setBlobFactory(DataHandlerBlobFactory.INSTANCE)
+                .setPartBlobFactory(PartDataHandlerBlobFactory.DEFAULT)
                 .build();
         SOAPEnvelope response = OMXMLBuilderFactory.createSOAPModelBuilder(multipartBody).getSOAPEnvelope();
         OMElement retrieveContentResponse = response.getBody().getFirstElement();
diff --git a/testing/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/xop/TestSerialize.java b/testing/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/xop/TestSerialize.java
index c12d5909a..6389debbb 100644
--- a/testing/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/xop/TestSerialize.java
+++ b/testing/axiom-testsuite/src/main/java/org/apache/axiom/ts/om/xop/TestSerialize.java
@@ -22,7 +22,7 @@ import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
 
 import org.apache.axiom.mime.MultipartBody;
-import org.apache.axiom.mime.activation.DataHandlerBlobFactory;
+import org.apache.axiom.mime.activation.PartDataHandlerBlobFactory;
 import org.apache.axiom.om.OMElement;
 import org.apache.axiom.om.OMMetaFactory;
 import org.apache.axiom.om.OMOutputFormat;
@@ -51,7 +51,7 @@ public class TestSerialize extends AxiomTestCase {
                 MultipartBody.builder()
                         .setInputStream(inStream)
                         .setContentType(testMessage.getContentType())
-                        .setBlobFactory(DataHandlerBlobFactory.INSTANCE)
+                        .setPartBlobFactory(PartDataHandlerBlobFactory.DEFAULT)
                         .build();
 
         OMOutputFormat oof = new OMOutputFormat();
diff --git a/testing/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap12/envelope/TestBuildWithAttachments.java b/testing/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap12/envelope/TestBuildWithAttachments.java
index be287595e..2cb5103cf 100644
--- a/testing/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap12/envelope/TestBuildWithAttachments.java
+++ b/testing/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap12/envelope/TestBuildWithAttachments.java
@@ -22,7 +22,7 @@ import java.io.InputStream;
 import java.util.Iterator;
 
 import org.apache.axiom.mime.MultipartBody;
-import org.apache.axiom.mime.activation.DataHandlerBlobFactory;
+import org.apache.axiom.mime.activation.PartDataHandlerBlobFactory;
 import org.apache.axiom.om.OMElement;
 import org.apache.axiom.om.OMMetaFactory;
 import org.apache.axiom.om.OMText;
@@ -45,7 +45,7 @@ public class TestBuildWithAttachments extends AxiomTestCase {
                 MultipartBody.builder()
                         .setInputStream(in)
                         .setContentType(sample.getContentType())
-                        .setBlobFactory(DataHandlerBlobFactory.INSTANCE)
+                        .setPartBlobFactory(PartDataHandlerBlobFactory.DEFAULT)
                         .build();
         SOAPEnvelope envelope =
                 OMXMLBuilderFactory.createSOAPModelBuilder(metaFactory, mb).getSOAPEnvelope();
diff --git a/testing/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap12/envelope/TestMTOMForwardStreaming.java b/testing/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap12/envelope/TestMTOMForwardStreaming.java
index 4a7348360..58777bc82 100644
--- a/testing/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap12/envelope/TestMTOMForwardStreaming.java
+++ b/testing/axiom-testsuite/src/main/java/org/apache/axiom/ts/soap12/envelope/TestMTOMForwardStreaming.java
@@ -26,7 +26,7 @@ import javax.activation.DataHandler;
 import javax.activation.DataSource;
 
 import org.apache.axiom.mime.MultipartBody;
-import org.apache.axiom.mime.activation.DataHandlerBlobFactory;
+import org.apache.axiom.mime.activation.PartDataHandlerBlobFactory;
 import org.apache.axiom.mime.activation.PartDataHandler;
 import org.apache.axiom.om.OMElement;
 import org.apache.axiom.om.OMMetaFactory;
@@ -109,7 +109,8 @@ public class TestMTOMForwardStreaming extends AxiomTestCase {
                                             MultipartBody.builder()
                                                     .setInputStream(pipe1In)
                                                     .setContentType(contentType)
-                                                    .setBlobFactory(DataHandlerBlobFactory.INSTANCE)
+                                                    .setPartBlobFactory(
+                                                            PartDataHandlerBlobFactory.DEFAULT)
                                                     .build();
                                     SOAPEnvelope envelope =
                                             OMXMLBuilderFactory.createSOAPModelBuilder(
@@ -138,7 +139,7 @@ public class TestMTOMForwardStreaming extends AxiomTestCase {
                     MultipartBody.builder()
                             .setInputStream(pipe2In)
                             .setContentType(contentType)
-                            .setBlobFactory(DataHandlerBlobFactory.INSTANCE)
+                            .setPartBlobFactory(PartDataHandlerBlobFactory.DEFAULT)
                             .build();
             SOAPEnvelope envelope =
                     OMXMLBuilderFactory.createSOAPModelBuilder(metaFactory, mb).getSOAPEnvelope();