1 /**
2 *
3 * Copyright 2003-2006 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package javax.mail;
19
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Vector;
26 import javax.mail.event.TransportEvent;
27 import javax.mail.event.TransportListener;
28
29 /**
30 * Abstract class modeling a message transport.
31 *
32 * @version $Rev: 421852 $ $Date: 2006-07-14 03:02:19 -0700 (Fri, 14 Jul 2006) $
33 */
34 public abstract class Transport extends Service {
35 /**
36 * Send a message to all recipient addresses it contains (as returned by {@link Message#getAllRecipients()})
37 * using message transports appropriate for each address. Message addresses are checked during submission,
38 * but there is no guarantee that the ultimate address is valid or that the message will ever be delivered.
39 * <p/>
40 * {@link Message#saveChanges()} will be called before the message is actually sent.
41 *
42 * @param message the message to send
43 * @throws MessagingException if there was a problem sending the message
44 */
45 public static void send(Message message) throws MessagingException {
46 send(message, message.getAllRecipients());
47 }
48
49 /**
50 * Send a message to all addresses provided irrespective of any recipients contained in the message itself
51 * using message transports appropriate for each address. Message addresses are checked during submission,
52 * but there is no guarantee that the ultimate address is valid or that the message will ever be delivered.
53 * <p/>
54 * {@link Message#saveChanges()} will be called before the message is actually sent.
55 *
56 * @param message the message to send
57 * @param addresses the addesses to send to
58 * @throws MessagingException if there was a problem sending the message
59 */
60 public static void send(Message message, Address[] addresses) throws MessagingException {
61 Session session = message.session;
62 Map msgsByTransport = new HashMap();
63 for (int i = 0; i < addresses.length; i++) {
64 Address address = addresses[i];
65 Transport transport = session.getTransport(address);
66 List addrs = (List) msgsByTransport.get(transport);
67 if (addrs == null) {
68 addrs = new ArrayList();
69 msgsByTransport.put(transport, addrs);
70 }
71 addrs.add(address);
72 }
73
74 message.saveChanges();
75
76
77
78
79
80 MessagingException chainedException = null;
81 ArrayList sentAddresses = new ArrayList();
82 ArrayList unsentAddresses = new ArrayList();
83 ArrayList invalidAddresses = new ArrayList();
84
85
86 for (Iterator i = msgsByTransport.entrySet().iterator(); i.hasNext();) {
87 Map.Entry entry = (Map.Entry) i.next();
88 Transport transport = (Transport) entry.getKey();
89 List addrs = (List) entry.getValue();
90 try {
91
92 transport.connect();
93 transport.sendMessage(message, (Address[]) addrs.toArray(new Address[addrs.size()]));
94
95
96 sentAddresses.addAll(addrs);
97 } catch (SendFailedException e) {
98
99
100
101
102
103 if (chainedException == null) {
104 chainedException = e;
105 }
106 else {
107 chainedException.setNextException(e);
108 }
109
110
111 Address[] exAddrs = e.getValidSentAddresses();
112 if (exAddrs != null) {
113 for (int j = 0; j < exAddrs.length; j++) {
114 sentAddresses.add(exAddrs[j]);
115 }
116 }
117
118 exAddrs = e.getValidUnsentAddresses();
119 if (exAddrs != null) {
120 for (int j = 0; j < exAddrs.length; j++) {
121 unsentAddresses.add(exAddrs[j]);
122 }
123 }
124
125 exAddrs = e.getInvalidAddresses();
126 if (exAddrs != null) {
127 for (int j = 0; j < exAddrs.length; j++) {
128 invalidAddresses.add(exAddrs[j]);
129 }
130 }
131
132 } catch (MessagingException e) {
133
134 if (chainedException == null) {
135 chainedException = e;
136 }
137 else {
138 chainedException.setNextException(e);
139 }
140 }
141 finally {
142 transport.close();
143 }
144 }
145
146
147
148 if (chainedException != null) {
149
150
151
152 if (msgsByTransport.size() == 1 && chainedException instanceof SendFailedException) {
153 throw chainedException;
154 }
155
156
157 Address[] sent = (Address[])sentAddresses.toArray(new Address[0]);
158 Address[] unsent = (Address[])unsentAddresses.toArray(new Address[0]);
159 Address[] invalid = (Address[])invalidAddresses.toArray(new Address[0]);
160
161 throw new SendFailedException("Send failure", chainedException, sent, unsent, invalid);
162 }
163 }
164
165 /**
166 * Constructor taking Session and URLName parameters required for {@link Service#Service(Session, URLName)}.
167 *
168 * @param session the Session this transport is for
169 * @param name the location this transport is for
170 */
171 public Transport(Session session, URLName name) {
172 super(session, name);
173 }
174
175 /**
176 * Send a message to the supplied addresses using this transport; if any of the addresses are
177 * invalid then a {@link SendFailedException} is thrown. Whether the message is actually sent
178 * to any of the addresses is undefined.
179 * <p/>
180 * Unlike the static {@link #send(Message, Address[])} method, {@link Message#saveChanges()} is
181 * not called. A {@link TransportEvent} will be sent to registered listeners once the delivery
182 * attempt has been made.
183 *
184 * @param message the message to send
185 * @param addresses list of addresses to send it to
186 * @throws SendFailedException if the send failed
187 * @throws MessagingException if there was a problem sending the message
188 */
189 public abstract void sendMessage(Message message, Address[] addresses) throws MessagingException;
190
191 private Vector transportListeners = new Vector();
192
193 public void addTransportListener(TransportListener listener) {
194 transportListeners.add(listener);
195 }
196
197 public void removeTransportListener(TransportListener listener) {
198 transportListeners.remove(listener);
199 }
200
201 protected void notifyTransportListeners(int type, Address[] validSent, Address[] validUnsent, Address[] invalid, Message message) {
202 queueEvent(new TransportEvent(this, type, validSent, validUnsent, invalid, message), transportListeners);
203 }
204 }