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 857d0146f AXIOM-506: Make DataHandlerBlob distinguish between read and
write errors
857d0146f is described below
commit 857d0146fb2fec245f149346fe223511c13a160a
Author: Andreas Veithen <[email protected]>
AuthorDate: Wed Sep 18 12:42:00 2024 +0100
AXIOM-506: Make DataHandlerBlob distinguish between read and write errors
---
.../axiom/util/activation/DataHandlerBlob.java | 10 ++-
.../axiom/util/activation/OutputStreamWrapper.java | 95 ++++++++++++++++++++++
.../util/activation/DataHandlerUtilsTest.java | 72 ++++++++++++++++
.../axiom/testutils/io/ExceptionOutputStream.java | 3 +-
4 files changed, 176 insertions(+), 4 deletions(-)
diff --git
a/axiom-jakarta-activation/src/main/java/org/apache/axiom/util/activation/DataHandlerBlob.java
b/axiom-jakarta-activation/src/main/java/org/apache/axiom/util/activation/DataHandlerBlob.java
index 424c39733..75d7e6ccc 100644
---
a/axiom-jakarta-activation/src/main/java/org/apache/axiom/util/activation/DataHandlerBlob.java
+++
b/axiom-jakarta-activation/src/main/java/org/apache/axiom/util/activation/DataHandlerBlob.java
@@ -45,11 +45,15 @@ final class DataHandlerBlob implements Blob {
@Override
public void writeTo(OutputStream out) throws StreamCopyException {
+ OutputStreamWrapper wrapper = new OutputStreamWrapper(out);
try {
- dataHandler.writeTo(out);
+ dataHandler.writeTo(wrapper);
} catch (IOException ex) {
- // TODO(AXIOM-506): maybe we can do some wrapping to determine the
operation that failed
- throw new StreamCopyException(StreamCopyException.WRITE, ex);
+ IOException wrapperException = wrapper.getException();
+ if (wrapperException != null) {
+ throw new StreamCopyException(StreamCopyException.WRITE,
wrapperException);
+ }
+ throw new StreamCopyException(StreamCopyException.READ, ex);
}
}
diff --git
a/axiom-jakarta-activation/src/main/java/org/apache/axiom/util/activation/OutputStreamWrapper.java
b/axiom-jakarta-activation/src/main/java/org/apache/axiom/util/activation/OutputStreamWrapper.java
new file mode 100644
index 000000000..8fca99791
--- /dev/null
+++
b/axiom-jakarta-activation/src/main/java/org/apache/axiom/util/activation/OutputStreamWrapper.java
@@ -0,0 +1,95 @@
+/*
+ * 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.util.activation;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+final class OutputStreamWrapper extends OutputStream {
+ private final OutputStream parent;
+ private IOException exception;
+
+ OutputStreamWrapper(OutputStream parent) {
+ this.parent = parent;
+ }
+
+ IOException getException() {
+ return exception;
+ }
+
+ @Override
+ public void close() throws IOException {
+ try {
+ parent.close();
+ } catch (IOException ex) {
+ if (exception == null) {
+ exception = ex;
+ }
+ throw ex;
+ }
+ }
+
+ @Override
+ public void flush() throws IOException {
+ try {
+ parent.flush();
+ } catch (IOException ex) {
+ if (exception == null) {
+ exception = ex;
+ }
+ throw ex;
+ }
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ try {
+ parent.write(b);
+ } catch (IOException ex) {
+ if (exception == null) {
+ exception = ex;
+ }
+ throw ex;
+ }
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ try {
+ parent.write(b);
+ } catch (IOException ex) {
+ if (exception == null) {
+ exception = ex;
+ }
+ throw ex;
+ }
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ try {
+ parent.write(b, off, len);
+ } catch (IOException ex) {
+ if (exception == null) {
+ exception = ex;
+ }
+ throw ex;
+ }
+ }
+}
diff --git
a/axiom-jakarta-activation/src/test/java/org/apache/axiom/util/activation/DataHandlerUtilsTest.java
b/axiom-jakarta-activation/src/test/java/org/apache/axiom/util/activation/DataHandlerUtilsTest.java
new file mode 100644
index 000000000..d685d9f1e
--- /dev/null
+++
b/axiom-jakarta-activation/src/test/java/org/apache/axiom/util/activation/DataHandlerUtilsTest.java
@@ -0,0 +1,72 @@
+package org.apache.axiom.util.activation;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertThrows;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.axiom.ext.io.StreamCopyException;
+import org.apache.axiom.testutils.io.ExceptionOutputStream;
+import org.apache.commons.io.output.NullOutputStream;
+import org.junit.jupiter.api.Test;
+
+import jakarta.activation.DataHandler;
+import jakarta.activation.DataSource;
+import jakarta.mail.util.ByteArrayDataSource;
+
+public class DataHandlerUtilsTest {
+ @Test
+ public void testToBlobWriteError() {
+ ExceptionOutputStream out = new ExceptionOutputStream(0);
+ StreamCopyException ex =
+ assertThrows(
+ StreamCopyException.class,
+ () -> {
+ DataHandlerUtils.toBlob(
+ new DataHandler(
+ new ByteArrayDataSource(
+ new byte[10],
+
"application/octet-stream")))
+ .writeTo(out);
+ });
+ assertThat(ex.getOperation()).isEqualTo(StreamCopyException.WRITE);
+ assertThat(ex.getCause()).isSameAs(out.getException());
+ }
+
+ @Test
+ public void testToBlobReadError() {
+ DataSource ds =
+ new DataSource() {
+ @Override
+ public String getContentType() {
+ return "application/octet-stream";
+ }
+
+ @Override
+ public InputStream getInputStream() throws IOException {
+ throw new IOException("Read error");
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+ };
+ StreamCopyException ex =
+ assertThrows(
+ StreamCopyException.class,
+ () -> {
+ DataHandlerUtils.toBlob(new DataHandler(ds))
+ .writeTo(NullOutputStream.INSTANCE);
+ });
+ assertThat(ex.getOperation()).isEqualTo(StreamCopyException.READ);
+ assertThat(ex.getCause().getMessage()).isEqualTo("Read error");
+ }
+}
diff --git
a/testing/testutils/src/main/java/org/apache/axiom/testutils/io/ExceptionOutputStream.java
b/testing/testutils/src/main/java/org/apache/axiom/testutils/io/ExceptionOutputStream.java
index 6f419de7d..1edabbd79 100644
---
a/testing/testutils/src/main/java/org/apache/axiom/testutils/io/ExceptionOutputStream.java
+++
b/testing/testutils/src/main/java/org/apache/axiom/testutils/io/ExceptionOutputStream.java
@@ -31,9 +31,10 @@ public class ExceptionOutputStream extends OutputStream {
@Override
public void write(int b) throws IOException {
- if (--remaining == 0) {
+ if (remaining == 0) {
throw exception = new IOException("Maximum number of bytes
written");
}
+ remaining--;
}
public IOException getException() {