Skip to content

Package: Transport

Transport

nameinstructionbranchcomplexitylinemethod
Transport(Session, URLName)
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
addTransportListener(TransportListener)
M: 13 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
notifyTransportListeners(int, Address[], Address[], Address[], Message)
M: 20 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
removeTransportListener(TransportListener)
M: 9 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
send(Message)
M: 9 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
send(Message, Address[])
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
send(Message, Address[], String, String)
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
send(Message, String, String)
M: 9 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
send0(Message, Address[], String, String)
M: 312 C: 0
0%
M: 50 C: 0
0%
M: 26 C: 0
0%
M: 75 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Public License v. 2.0, which is available at
6: * http://www.eclipse.org/legal/epl-2.0.
7: *
8: * This Source Code may also be made available under the following Secondary
9: * Licenses when the conditions for such availability set forth in the
10: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11: * version 2 with the GNU Classpath Exception, which is available at
12: * https://www.gnu.org/software/classpath/license.html.
13: *
14: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15: */
16:
17: package jakarta.mail;
18:
19: import jakarta.mail.event.TransportEvent;
20: import jakarta.mail.event.TransportListener;
21:
22: import java.util.ArrayList;
23: import java.util.HashMap;
24: import java.util.List;
25: import java.util.Map;
26: import java.util.Vector;
27:
28: /**
29: * An abstract class that models a message transport.
30: * Subclasses provide actual implementations. <p>
31: *
32: * Note that <code>Transport</code> extends the <code>Service</code>
33: * class, which provides many common methods for naming transports,
34: * connecting to transports, and listening to connection events.
35: *
36: * @author John Mani
37: * @author Max Spivak
38: * @author Bill Shannon
39: * @see jakarta.mail.Service
40: * @see jakarta.mail.event.ConnectionEvent
41: * @see jakarta.mail.event.TransportEvent
42: */
43:
44: public abstract class Transport extends Service {
45:
46: /**
47: * Constructor.
48: *
49: * @param session Session object for this Transport.
50: * @param urlname URLName object to be used for this Transport
51: */
52: public Transport(Session session, URLName urlname) {
53: super(session, urlname);
54: }
55:
56: /**
57: * Send a message. The message will be sent to all recipient
58: * addresses specified in the message (as returned from the
59: * <code>Message</code> method <code>getAllRecipients</code>),
60: * using message transports appropriate to each address. The
61: * <code>send</code> method calls the <code>saveChanges</code>
62: * method on the message before sending it. <p>
63: *
64: * If any of the recipient addresses is detected to be invalid by
65: * the Transport during message submission, a SendFailedException
66: * is thrown. Clients can get more detail about the failure by examining
67: * the exception. Whether or not the message is still sent successfully
68: * to any valid addresses depends on the Transport implementation. See
69: * SendFailedException for more details. Note also that success does
70: * not imply that the message was delivered to the ultimate recipient,
71: * as failures may occur in later stages of delivery. Once a Transport
72: * accepts a message for delivery to a recipient, failures that occur later
73: * should be reported to the user via another mechanism, such as
74: * returning the undeliverable message. <p>
75: *
76: * In typical usage, a SendFailedException reflects an error detected
77: * by the server. The details of the SendFailedException will usually
78: * contain the error message from the server (such as an SMTP error
79: * message). An address may be detected as invalid for a variety of
80: * reasons - the address may not exist, the address may have invalid
81: * syntax, the address may have exceeded its quota, etc. <p>
82: *
83: * Note that <code>send</code> is a static method that creates and
84: * manages its own connection. Any connection associated with any
85: * Transport instance used to invoke this method is ignored and not
86: * used. This method should only be invoked using the form
87: * <code>Transport.send(msg);</code>, and should never be invoked
88: * using an instance variable.
89: *
90: * @param msg the message to send
91: * @throws SendFailedException if the message could not
92: * be sent to some or any of the recipients.
93: * @throws MessagingException for other failures
94: * @see Message#saveChanges
95: * @see Message#getAllRecipients
96: * @see #send(Message, Address[])
97: * @see jakarta.mail.SendFailedException
98: */
99: public static void send(Message msg) throws MessagingException {
100: msg.saveChanges(); // do this first
101: send0(msg, msg.getAllRecipients(), null, null);
102: }
103:
104: /**
105: * Send the message to the specified addresses, ignoring any
106: * recipients specified in the message itself. The
107: * <code>send</code> method calls the <code>saveChanges</code>
108: * method on the message before sending it.
109: *
110: * @param msg the message to send
111: * @param addresses the addresses to which to send the message
112: * @throws SendFailedException if the message could not
113: * be sent to some or any of the recipients.
114: * @throws MessagingException for other failures
115: * @see Message#saveChanges
116: * @see jakarta.mail.SendFailedException
117: * @see #send(Message)
118: */
119: public static void send(Message msg, Address[] addresses)
120: throws MessagingException {
121:
122: msg.saveChanges();
123: send0(msg, addresses, null, null);
124: }
125:
126: /**
127: * Send a message. The message will be sent to all recipient
128: * addresses specified in the message (as returned from the
129: * <code>Message</code> method <code>getAllRecipients</code>).
130: * The <code>send</code> method calls the <code>saveChanges</code>
131: * method on the message before sending it. <p>
132: *
133: * Use the specified user name and password to authenticate to
134: * the mail server.
135: *
136: * @param msg the message to send
137: * @param user the user name
138: * @param password this user's password
139: * @throws SendFailedException if the message could not
140: * be sent to some or any of the recipients.
141: * @throws MessagingException for other failures
142: * @see Message#saveChanges
143: * @see jakarta.mail.SendFailedException
144: * @see #send(Message)
145: * @since JavaMail 1.5
146: */
147: public static void send(Message msg,
148: String user, String password) throws MessagingException {
149:
150: msg.saveChanges();
151: send0(msg, msg.getAllRecipients(), user, password);
152: }
153:
154: /**
155: * Send the message to the specified addresses, ignoring any
156: * recipients specified in the message itself. The
157: * <code>send</code> method calls the <code>saveChanges</code>
158: * method on the message before sending it. <p>
159: *
160: * Use the specified user name and password to authenticate to
161: * the mail server.
162: *
163: * @param msg the message to send
164: * @param addresses the addresses to which to send the message
165: * @param user the user name
166: * @param password this user's password
167: * @throws SendFailedException if the message could not
168: * be sent to some or any of the recipients.
169: * @throws MessagingException for other failures
170: * @see Message#saveChanges
171: * @see jakarta.mail.SendFailedException
172: * @see #send(Message)
173: * @since JavaMail 1.5
174: */
175: public static void send(Message msg, Address[] addresses,
176: String user, String password) throws MessagingException {
177:
178: msg.saveChanges();
179: send0(msg, addresses, user, password);
180: }
181:
182: // send, but without the saveChanges
183: private static void send0(Message msg, Address[] addresses,
184: String user, String password) throws MessagingException {
185:
186:• if (addresses == null || addresses.length == 0)
187: throw new SendFailedException("No recipient addresses");
188:
189: /*
190: * protocols is a map containing the addresses
191: * indexed by address type
192: */
193: Map<String, List<Address>> protocols
194: = new HashMap<>();
195:
196: // Lists of addresses
197: List<Address> invalid = new ArrayList<>();
198: List<Address> validSent = new ArrayList<>();
199: List<Address> validUnsent = new ArrayList<>();
200:
201:• for (int i = 0; i < addresses.length; i++) {
202: // is this address type already in the map?
203:• if (protocols.containsKey(addresses[i].getType())) {
204: List<Address> v = protocols.get(addresses[i].getType());
205: v.add(addresses[i]);
206: } else {
207: // need to add a new protocol
208: List<Address> w = new ArrayList<>();
209: w.add(addresses[i]);
210: protocols.put(addresses[i].getType(), w);
211: }
212: }
213:
214: int dsize = protocols.size();
215:• if (dsize == 0)
216: throw new SendFailedException("No recipient addresses");
217:
218:• Session s = (msg.session != null) ? msg.session :
219: Session.getDefaultInstance(System.getProperties(), null);
220: Transport transport;
221:
222: /*
223: * Optimize the case of a single protocol.
224: */
225:• if (dsize == 1) {
226: transport = s.getTransport(addresses[0]);
227: try {
228:• if (user != null)
229: transport.connect(user, password);
230: else
231: transport.connect();
232: transport.sendMessage(msg, addresses);
233: } finally {
234: transport.close();
235: }
236: return;
237: }
238:
239: /*
240: * More than one protocol. Have to do them one at a time
241: * and collect addresses and chain exceptions.
242: */
243: MessagingException chainedEx = null;
244: boolean sendFailed = false;
245:
246:• for (List<Address> v : protocols.values()) {
247: Address[] protaddresses = new Address[v.size()];
248: v.toArray(protaddresses);
249:
250: // Get a Transport that can handle this address type.
251:• if ((transport = s.getTransport(protaddresses[0])) == null) {
252: // Could not find an appropriate Transport ..
253: // Mark these addresses invalid.
254:• for (int j = 0; j < protaddresses.length; j++)
255: invalid.add(protaddresses[j]);
256: continue;
257: }
258: try {
259: transport.connect();
260: transport.sendMessage(msg, protaddresses);
261: } catch (SendFailedException sex) {
262: sendFailed = true;
263: // chain the exception we're catching to any previous ones
264:• if (chainedEx == null)
265: chainedEx = sex;
266: else
267: chainedEx.setNextException(sex);
268:
269: // retrieve invalid addresses
270: Address[] a = sex.getInvalidAddresses();
271:• if (a != null)
272:• for (int j = 0; j < a.length; j++)
273: invalid.add(a[j]);
274:
275: // retrieve validSent addresses
276: a = sex.getValidSentAddresses();
277:• if (a != null)
278:• for (int k = 0; k < a.length; k++)
279: validSent.add(a[k]);
280:
281: // retrieve validUnsent addresses
282: Address[] c = sex.getValidUnsentAddresses();
283:• if (c != null)
284:• for (int l = 0; l < c.length; l++)
285: validUnsent.add(c[l]);
286: } catch (MessagingException mex) {
287: sendFailed = true;
288: // chain the exception we're catching to any previous ones
289:• if (chainedEx == null)
290: chainedEx = mex;
291: else
292: chainedEx.setNextException(mex);
293: } finally {
294: transport.close();
295: }
296: }
297:
298: // done with all protocols. throw exception if something failed
299:• if (sendFailed || invalid.size() != 0 || validUnsent.size() != 0) {
300: Address[] a = null, b = null, c = null;
301:
302: // copy address lists into arrays
303:• if (validSent.size() > 0) {
304: a = new Address[validSent.size()];
305: validSent.toArray(a);
306: }
307:• if (validUnsent.size() > 0) {
308: b = new Address[validUnsent.size()];
309: validUnsent.toArray(b);
310: }
311:• if (invalid.size() > 0) {
312: c = new Address[invalid.size()];
313: invalid.toArray(c);
314: }
315: throw new SendFailedException("Sending failed", chainedEx,
316: a, b, c);
317: }
318: }
319:
320: /**
321: * Send the Message to the specified list of addresses. An appropriate
322: * TransportEvent indicating the delivery status is delivered to any
323: * TransportListener registered on this Transport. Also, if any of
324: * the addresses is invalid, a SendFailedException is thrown.
325: * Whether or not the message is still sent succesfully to
326: * any valid addresses depends on the Transport implementation. <p>
327: *
328: * Unlike the static <code>send</code> method, the <code>sendMessage</code>
329: * method does <em>not</em> call the <code>saveChanges</code> method on
330: * the message; the caller should do so.
331: *
332: * @param msg The Message to be sent
333: * @param addresses array of addresses to send this message to
334: * @throws SendFailedException if the send failed because of
335: * invalid addresses.
336: * @throws MessagingException if the connection is dead or not in the
337: * connected state
338: * @see jakarta.mail.event.TransportEvent
339: */
340: public abstract void sendMessage(Message msg, Address[] addresses)
341: throws MessagingException;
342:
343: // Vector of Transport listeners
344: private volatile Vector<TransportListener> transportListeners = null;
345:
346: /**
347: * Add a listener for Transport events. <p>
348: *
349: * The default implementation provided here adds this listener
350: * to an internal list of TransportListeners.
351: *
352: * @param l the Listener for Transport events
353: * @see jakarta.mail.event.TransportEvent
354: */
355: public synchronized void addTransportListener(TransportListener l) {
356:• if (transportListeners == null)
357: transportListeners = new Vector<>();
358: transportListeners.addElement(l);
359: }
360:
361: /**
362: * Remove a listener for Transport events. <p>
363: *
364: * The default implementation provided here removes this listener
365: * from the internal list of TransportListeners.
366: *
367: * @param l the listener
368: * @see #addTransportListener
369: */
370: public synchronized void removeTransportListener(TransportListener l) {
371:• if (transportListeners != null)
372: transportListeners.removeElement(l);
373: }
374:
375: /**
376: * Notify all TransportListeners. Transport implementations are
377: * expected to use this method to broadcast TransportEvents.<p>
378: *
379: * The provided default implementation queues the event into
380: * an internal event queue. An event dispatcher thread dequeues
381: * events from the queue and dispatches them to the registered
382: * TransportListeners. Note that the event dispatching occurs
383: * in a separate thread, thus avoiding potential deadlock problems.
384: *
385: * @param type the TransportEvent type
386: * @param validSent valid addresses to which message was sent
387: * @param validUnsent valid addresses to which message was not sent
388: * @param invalid the invalid addresses
389: * @param msg the message
390: */
391: protected void notifyTransportListeners(int type, Address[] validSent,
392: Address[] validUnsent,
393: Address[] invalid, Message msg) {
394:• if (transportListeners == null)
395: return;
396:
397: TransportEvent e = new TransportEvent(this, type, validSent,
398: validUnsent, invalid, msg);
399: queueEvent(e, transportListeners);
400: }
401: }