From edae19d86af0068ca54c342a9acd2a9e592dfdea Mon Sep 17 00:00:00 2001 From: Jorge Bescos Gascon Date: Mon, 4 Mar 2024 10:53:13 +0100 Subject: [PATCH] Multipart performs blocking call in every instantiation #699 Signed-off-by: Jorge Bescos Gascon --- api/src/main/java/jakarta/mail/Message.java | 33 ++++++++++++++++++- api/src/main/java/jakarta/mail/Multipart.java | 32 ++++++++++++++++-- .../jakarta/mail/internet/MimeMessage.java | 19 ----------- .../jakarta/mail/internet/MimeMultipart.java | 6 ++-- 4 files changed, 64 insertions(+), 26 deletions(-) diff --git a/api/src/main/java/jakarta/mail/Message.java b/api/src/main/java/jakarta/mail/Message.java index 05d2713c..aa6ec409 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,33 @@ protected void setExpunged(boolean expunged) { public boolean match(SearchTerm term) throws MessagingException { return term.match(this); } + + /** + * Obtains the {@link StreamProvider} from the session, if exists. + * 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 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/Multipart.java b/api/src/main/java/jakarta/mail/Multipart.java index ef634454..fc72a715 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 @@ -21,6 +21,8 @@ import java.io.IOException; import java.io.OutputStream; import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Multipart is a container that holds multiple body parts. Multipart @@ -42,6 +44,7 @@ public abstract class Multipart { + private static final Logger LOGGER = Logger.getLogger(Multipart.class.getName()); /** * Vector of BodyPart objects. */ @@ -64,9 +67,9 @@ public abstract class Multipart { /** * Instance of stream provider. * - * @since JavaMail 2.1 + * @since JavaMail 2.2 */ - protected final StreamProvider streamProvider = StreamProvider.provider(); + private volatile StreamProvider streamProvider; /** * Default constructor. An empty Multipart object is created. @@ -266,4 +269,27 @@ public synchronized Part getParent() { public synchronized void setParent(Part parent) { this.parent = parent; } + + protected StreamProvider provider() { + if (streamProvider == null) { + synchronized (this) { + if (streamProvider == null) { + if (parent != null && parent instanceof Message) { + try { + streamProvider = ((Message)parent).provider(); + } catch (MessagingException e) { + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, "Cannot reuse streamProvider", e); + } + } + } + } + if (streamProvider == null) { + streamProvider = StreamProvider.provider(); + } + } + } + return streamProvider; + } + } diff --git a/api/src/main/java/jakarta/mail/internet/MimeMessage.java b/api/src/main/java/jakarta/mail/internet/MimeMessage.java index e832b097..73b7c4c7 100644 --- a/api/src/main/java/jakarta/mail/internet/MimeMessage.java +++ b/api/src/main/java/jakarta/mail/internet/MimeMessage.java @@ -2322,23 +2322,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..4a555e6e 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 = provider().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 = provider().inputLineStream(in, false); StringBuilder preamblesb = null; String line; while ((line = lin.readLine()) != null) {