diff --git a/api/src/main/java/jakarta/mail/BodyPart.java b/api/src/main/java/jakarta/mail/BodyPart.java
index 975a393e..876a2214 100644
--- a/api/src/main/java/jakarta/mail/BodyPart.java
+++ b/api/src/main/java/jakarta/mail/BodyPart.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -39,13 +39,6 @@ public abstract class BodyPart implements Part {
*/
protected Multipart parent;
- /**
- * Instance of stream provider.
- *
- * @since JavaMail 2.1
- */
- protected final StreamProvider streamProvider = StreamProvider.provider();
-
/**
* Creates a default {@code BodyPart}.
*/
@@ -74,4 +67,14 @@ public Multipart getParent() {
void setParent(Multipart parent) {
this.parent = parent;
}
+
+ @Override
+ public StreamProvider getStreamProvider() throws MessagingException {
+ if (parent != null) {
+ return parent.getStreamProvider();
+ } else {
+ return Part.super.getStreamProvider();
+ }
+ }
+
}
diff --git a/api/src/main/java/jakarta/mail/Message.java b/api/src/main/java/jakarta/mail/Message.java
index 05d2713c..b12586e7 100644
--- a/api/src/main/java/jakarta/mail/Message.java
+++ b/api/src/main/java/jakarta/mail/Message.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -17,11 +17,13 @@
package jakarta.mail;
import jakarta.mail.search.SearchTerm;
+import jakarta.mail.util.StreamProvider;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.Date;
+import java.util.ServiceConfigurationError;
/**
* This class models an email message. This is an abstract class.
@@ -705,4 +707,22 @@ protected void setExpunged(boolean expunged) {
public boolean match(SearchTerm term) throws MessagingException {
return term.match(this);
}
+
+ @Override
+ public StreamProvider getStreamProvider() throws MessagingException {
+ try {
+ try {
+ final Session s = this.session;
+ if (s != null) {
+ return s.getStreamProvider();
+ } else {
+ return Session.getDefaultInstance(System.getProperties(), null).getStreamProvider();
+ }
+ } catch (ServiceConfigurationError sce) {
+ throw new IllegalStateException(sce);
+ }
+ } catch (RuntimeException re) {
+ throw new NoSuchProviderException("Unable to get " + StreamProvider.class.getName(), re);
+ }
+ }
}
diff --git a/api/src/main/java/jakarta/mail/Multipart.java b/api/src/main/java/jakarta/mail/Multipart.java
index ef634454..5702c64a 100644
--- a/api/src/main/java/jakarta/mail/Multipart.java
+++ b/api/src/main/java/jakarta/mail/Multipart.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -20,6 +20,7 @@
import java.io.IOException;
import java.io.OutputStream;
+import java.util.ServiceConfigurationError;
import java.util.Vector;
/**
@@ -61,13 +62,6 @@ public abstract class Multipart {
*/
protected Part parent;
- /**
- * Instance of stream provider.
- *
- * @since JavaMail 2.1
- */
- protected final StreamProvider streamProvider = StreamProvider.provider();
-
/**
* Default constructor. An empty Multipart object is created.
*/
@@ -266,4 +260,32 @@ public synchronized Part getParent() {
public synchronized void setParent(Part parent) {
this.parent = parent;
}
+
+ /**
+ * Obtains the {@link StreamProvider} from the parent, if possible.
+ * Otherwise it obtains it from
+ * {@link Session#getDefaultInstance(java.util.Properties, Authenticator)}.
+ *
+ * @return the StreamProvider implementation from the session.
+ * @throws MessagingException if errors.
+ *
+ * @since JavaMail 2.2
+ */
+ protected StreamProvider getStreamProvider() throws MessagingException {
+ Part parent = this.parent;
+ if (parent != null) {
+ return parent.getStreamProvider();
+ } else {
+ try {
+ try {
+ return Session.getDefaultInstance(System.getProperties(), null).getStreamProvider();
+ } catch (ServiceConfigurationError sce) {
+ throw new IllegalStateException(sce);
+ }
+ } catch (RuntimeException re) {
+ throw new NoSuchProviderException("Unable to get " + StreamProvider.class.getName(), re);
+ }
+ }
+ }
+
}
diff --git a/api/src/main/java/jakarta/mail/Part.java b/api/src/main/java/jakarta/mail/Part.java
index 9743ed1b..68cb4680 100644
--- a/api/src/main/java/jakarta/mail/Part.java
+++ b/api/src/main/java/jakarta/mail/Part.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -17,11 +17,13 @@
package jakarta.mail;
import jakarta.activation.DataHandler;
+import jakarta.mail.util.StreamProvider;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
+import java.util.ServiceConfigurationError;
/**
* The Part
interface is the common base interface for
@@ -453,4 +455,25 @@ Enumeration getMatchingHeaders(String[] header_names)
*/
Enumeration getNonMatchingHeaders(String[] header_names)
throws MessagingException;
+
+ /**
+ * Obtains the {@link StreamProvider}.
+ * It defaults to {@link Session#getDefaultInstance(java.util.Properties, Authenticator)}.
+ *
+ * @return the StreamProvider.
+ * @throws MessagingException if errors.
+ *
+ * @since JavaMail 2.2
+ */
+ default StreamProvider getStreamProvider() throws MessagingException {
+ try {
+ try {
+ return Session.getDefaultInstance(System.getProperties(), null).getStreamProvider();
+ } catch (ServiceConfigurationError sce) {
+ throw new IllegalStateException(sce);
+ }
+ } catch (RuntimeException re) {
+ throw new NoSuchProviderException("Unable to get " + StreamProvider.class.getName(), re);
+ }
+ }
}
diff --git a/api/src/main/java/jakarta/mail/internet/MimeBodyPart.java b/api/src/main/java/jakarta/mail/internet/MimeBodyPart.java
index 7c6c3a67..b0fa7a50 100644
--- a/api/src/main/java/jakarta/mail/internet/MimeBodyPart.java
+++ b/api/src/main/java/jakarta/mail/internet/MimeBodyPart.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -30,7 +30,6 @@
import jakarta.mail.Multipart;
import jakarta.mail.Part;
import jakarta.mail.util.LineOutputStream;
-import jakarta.mail.util.StreamProvider;
import jakarta.mail.util.StreamProvider.EncoderTypes;
import java.io.BufferedInputStream;
@@ -1641,7 +1640,7 @@ static void writeTo(MimePart part, OutputStream os, String[] ignoreList)
} else {
Map params = new HashMap<>();
params.put("allowutf8", allowutf8);
- los = StreamProvider.provider().outputLineStream(os, allowutf8);
+ los = part.getStreamProvider().outputLineStream(os, allowutf8);
}
// First, write out the header
diff --git a/api/src/main/java/jakarta/mail/internet/MimeMessage.java b/api/src/main/java/jakarta/mail/internet/MimeMessage.java
index e832b097..b9ab9f50 100644
--- a/api/src/main/java/jakarta/mail/internet/MimeMessage.java
+++ b/api/src/main/java/jakarta/mail/internet/MimeMessage.java
@@ -29,7 +29,6 @@
import jakarta.mail.Multipart;
import jakarta.mail.Session;
import jakarta.mail.util.LineOutputStream;
-import jakarta.mail.util.StreamProvider;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
@@ -45,8 +44,6 @@
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
-import java.util.ServiceConfigurationError;
-
/**
* This class represents a MIME style email message. It implements
@@ -245,7 +242,7 @@ public MimeMessage(MimeMessage source) throws MessagingException {
strict = source.strict;
source.writeTo(bos);
bos.close();
- try (InputStream bis = provider().inputSharedByteArray(bos.toByteArray())) {
+ try (InputStream bis = getStreamProvider().inputSharedByteArray(bos.toByteArray())) {
parse(bis);
}
saved = true;
@@ -1410,7 +1407,7 @@ protected InputStream getContentStream() throws MessagingException {
if (contentStream != null)
return ((SharedInputStream) contentStream).newStream(0, -1);
if (content != null) {
- return provider().inputSharedByteArray(content);
+ return getStreamProvider().inputSharedByteArray(content);
}
throw new MessagingException("No MimeMessage content");
}
@@ -1917,7 +1914,7 @@ public void writeTo(OutputStream os, String[] ignoreList)
// Else, the content is untouched, so we can just output it
// First, write out the header
Enumeration hdrLines = getNonMatchingHeaderLines(ignoreList);
- LineOutputStream los = provider().outputLineStream(os, allowutf8);
+ LineOutputStream los = getStreamProvider().outputLineStream(os, allowutf8);
while (hdrLines.hasMoreElements())
los.writeln(hdrLines.nextElement());
@@ -2322,23 +2319,4 @@ protected MimeMessage createMimeMessage(Session session)
throws MessagingException {
return new MimeMessage(session);
}
-
- private StreamProvider provider() throws MessagingException {
- try {
- try {
- final Session s = this.session;
- if (s != null) {
- return s.getStreamProvider();
- } else {
- return Session.getDefaultInstance(System.getProperties(),
- null).getStreamProvider();
- }
- } catch (ServiceConfigurationError sce) {
- throw new IllegalStateException(sce);
- }
- } catch (RuntimeException re) {
- throw new MessagingException("Unable to get "
- + StreamProvider.class.getName(), re);
- }
- }
}
diff --git a/api/src/main/java/jakarta/mail/internet/MimeMultipart.java b/api/src/main/java/jakarta/mail/internet/MimeMultipart.java
index 88a149a1..dee43113 100644
--- a/api/src/main/java/jakarta/mail/internet/MimeMultipart.java
+++ b/api/src/main/java/jakarta/mail/internet/MimeMultipart.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -520,7 +520,7 @@ public synchronized void writeTo(OutputStream os)
String boundary = "--" +
(new ContentType(contentType)).getParameter("boundary");
- LineOutputStream los = streamProvider.outputLineStream(os, false);
+ LineOutputStream los = getStreamProvider().outputLineStream(os, false);
// if there's a preamble, write it out
if (preamble != null) {
byte[] pb = MimeUtility.getBytes(preamble);
@@ -601,7 +601,7 @@ protected synchronized void parse() throws MessagingException {
try {
// Skip and save the preamble
- LineInputStream lin = streamProvider.inputLineStream(in, false);
+ LineInputStream lin = getStreamProvider().inputLineStream(in, false);
StringBuilder preamblesb = null;
String line;
while ((line = lin.readLine()) != null) {
diff --git a/api/src/main/java/jakarta/mail/internet/PreencodedMimeBodyPart.java b/api/src/main/java/jakarta/mail/internet/PreencodedMimeBodyPart.java
index 48f663f8..19cdce4c 100644
--- a/api/src/main/java/jakarta/mail/internet/PreencodedMimeBodyPart.java
+++ b/api/src/main/java/jakarta/mail/internet/PreencodedMimeBodyPart.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
@@ -78,7 +78,7 @@ public void writeTo(OutputStream os)
if (os instanceof LineOutputStream) {
los = (LineOutputStream) os;
} else {
- los = streamProvider.outputLineStream(os, false);
+ los = getStreamProvider().outputLineStream(os, false);
}
// First, write out the header
diff --git a/api/src/test/java/jakarta/mail/PartTest.java b/api/src/test/java/jakarta/mail/PartTest.java
new file mode 100644
index 00000000..cce883ae
--- /dev/null
+++ b/api/src/test/java/jakarta/mail/PartTest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0, which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * This Source Code may also be made available under the following Secondary
+ * Licenses when the conditions for such availability set forth in the
+ * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
+ * version 2 with the GNU Classpath Exception, which is available at
+ * https://www.gnu.org/software/classpath/license.html.
+ *
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
+ */
+
+package jakarta.mail;
+
+import static org.junit.Assert.assertEquals;
+
+import jakarta.mail.internet.MimeBodyPart;
+import jakarta.mail.internet.MimeMessage;
+import jakarta.mail.internet.MimeMultipart;
+import jakarta.mail.util.DummyStreamProvider;
+import jakarta.mail.util.LineInputStream;
+import jakarta.mail.util.LineOutputStream;
+import jakarta.mail.util.StreamProvider;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Properties;
+
+import org.junit.Test;
+
+public class PartTest {
+
+ // Sessions with different StreamProviders
+ private static final Session SESSION_DEFAULT = Session.getDefaultInstance(new Properties());
+ private static final Session SESSION_1;
+ private static final Session SESSION_2;
+
+ static {
+ SESSION_1 = Session.getDefaultInstance(new Properties());
+ System.setProperty(StreamProvider.class.getName(), CustomStreamProvider.class.getName());
+ SESSION_2 = Session.getInstance(new Properties());
+ System.clearProperty(StreamProvider.class.getName());
+ }
+
+ @Test
+ public void streamProvidersChecker() {
+ assertEquals(DummyStreamProvider.class, SESSION_DEFAULT.getStreamProvider().getClass());
+ assertEquals(DummyStreamProvider.class, SESSION_1.getStreamProvider().getClass());
+ assertEquals(CustomStreamProvider.class, SESSION_2.getStreamProvider().getClass());
+ assertEquals(SESSION_DEFAULT.getStreamProvider(), SESSION_1.getStreamProvider());
+ }
+
+ @Test
+ public void sameInstance() throws MessagingException {
+ MimeBodyPart body = new MimeBodyPart();
+ MimeMultipart multiPart = new MimeMultipart();
+ assertEquals(SESSION_DEFAULT.getStreamProvider(), body.getStreamProvider());
+ assertEquals(SESSION_DEFAULT.getStreamProvider(), multiPart.getStreamProvider());
+ }
+
+ @Test
+ public void specifySession1() throws MessagingException {
+ Message message = new MimeMessage(SESSION_1);
+ Multipart multipart = new MimeMultipart();
+ message.setContent(multipart);
+ assertEquals(SESSION_1.getStreamProvider(), multipart.getStreamProvider());
+ }
+
+ @Test
+ public void specifySession2() throws MessagingException {
+ Message message = new MimeMessage(SESSION_2);
+ Multipart multipart = new MimeMultipart();
+ message.setContent(multipart);
+ assertEquals(SESSION_2.getStreamProvider(), multipart.getStreamProvider());
+ }
+
+ @Test
+ public void multipartBodyPart() throws Exception {
+ MimeMessage m = new MimeMessage(SESSION_2);
+ MimeMultipart mmp = new MimeMultipart("mixed");
+ MimeBodyPart mbp = new MimeBodyPart();
+ mbp.setDisposition(Part.INLINE);
+ mbp.setText("none");
+ mmp.addBodyPart(mbp);
+ m.setContent(mmp);
+
+ StreamProvider root = SESSION_2.getStreamProvider();
+ assertEquals(root, m.getStreamProvider());
+ assertEquals(root, mmp.getStreamProvider());
+ assertEquals(root, mbp.getStreamProvider());
+ }
+
+ public static class CustomStreamProvider implements StreamProvider {
+
+ @Override
+ public InputStream inputBase64(InputStream in) {
+ return null;
+ }
+
+ @Override
+ public OutputStream outputBase64(OutputStream out) {
+ return null;
+ }
+
+ @Override
+ public InputStream inputBinary(InputStream in) {
+ return null;
+ }
+
+ @Override
+ public OutputStream outputBinary(OutputStream out) {
+ return null;
+ }
+
+ @Override
+ public OutputStream outputB(OutputStream out) {
+ return null;
+ }
+
+ @Override
+ public InputStream inputQ(InputStream in) {
+ return null;
+ }
+
+ @Override
+ public OutputStream outputQ(OutputStream out, boolean encodingWord) {
+ return null;
+ }
+
+ @Override
+ public LineInputStream inputLineStream(InputStream in, boolean allowutf8) {
+ return null;
+ }
+
+ @Override
+ public LineOutputStream outputLineStream(OutputStream out, boolean allowutf8) {
+ return null;
+ }
+
+ @Override
+ public InputStream inputQP(InputStream in) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public OutputStream outputQP(OutputStream out) {
+ return null;
+ }
+
+ @Override
+ public InputStream inputSharedByteArray(byte[] buff) {
+ return null;
+ }
+
+ @Override
+ public InputStream inputUU(InputStream in) {
+ return null;
+ }
+
+ @Override
+ public OutputStream outputUU(OutputStream out, String filename) {
+ return null;
+ }
+ }
+}
diff --git a/doc/release/CHANGES.txt b/doc/release/CHANGES.txt
index efaf7d43..089a457c 100644
--- a/doc/release/CHANGES.txt
+++ b/doc/release/CHANGES.txt
@@ -19,6 +19,10 @@ Bug IDs that start with "G" can be found in the GlassFish Issue Tracker
Seven digit bug numbers are from the old Sun bug database, which is no
longer available.
+ CHANGES IN THE 2.2.0 RELEASE
+ ----------------------------
+E 699 Multipart performs blocking call in every instantiation
+
CHANGES IN THE 2.1.3 RELEASE
----------------------------
E 631 Session.getService does not use proper classloader in OSGI environment