|
|||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
Transport.java | 0% | 1.9% | 16.7% | 2.3% |
|
1 | /** | |
2 | * | |
3 | * Copyright 2003-2004 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: 382388 $ $Date: 2006-03-02 06:20:38 -0800 (Thu, 02 Mar 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 | 0 | public static void send(Message message) throws MessagingException { |
46 | 0 | 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 | 0 | public static void send(Message message, Address[] addresses) throws MessagingException { |
61 | 0 | Session session = message.session; |
62 | 0 | Map msgsByTransport = new HashMap(); |
63 | 0 | for (int i = 0; i < addresses.length; i++) { |
64 | 0 | Address address = addresses[i]; |
65 | 0 | Transport transport = session.getTransport(address); |
66 | 0 | List addrs = (List) msgsByTransport.get(transport); |
67 | 0 | if (addrs == null) { |
68 | 0 | addrs = new ArrayList(); |
69 | 0 | msgsByTransport.put(transport, addrs); |
70 | } | |
71 | 0 | addrs.add(address); |
72 | } | |
73 | ||
74 | 0 | message.saveChanges(); |
75 | ||
76 | // Since we might be sending to multiple protocols, we need to catch and process each exception | |
77 | // when we send and then throw a new SendFailedException when everything is done. Unfortunately, this | |
78 | // also means unwrapping the information in any SendFailedExceptions we receive and building | |
79 | // composite failed list. | |
80 | 0 | MessagingException chainedException = null; |
81 | 0 | ArrayList sentAddresses = new ArrayList(); |
82 | 0 | ArrayList unsentAddresses = new ArrayList(); |
83 | 0 | ArrayList invalidAddresses = new ArrayList(); |
84 | ||
85 | ||
86 | 0 | for (Iterator i = msgsByTransport.entrySet().iterator(); i.hasNext();) { |
87 | 0 | Map.Entry entry = (Map.Entry) i.next(); |
88 | 0 | Transport transport = (Transport) entry.getKey(); |
89 | 0 | List addrs = (List) entry.getValue(); |
90 | 0 | try { |
91 | // we MUST connect to the transport before attempting to send. | |
92 | 0 | transport.connect(); |
93 | 0 | transport.sendMessage(message, (Address[]) addrs.toArray(new Address[addrs.size()])); |
94 | // if we have to throw an exception because of another failure, these addresses need to | |
95 | // be in the valid list. Since we succeeded here, we can add these now. | |
96 | 0 | sentAddresses.addAll(addrs); |
97 | } catch (SendFailedException e) { | |
98 | // a true send failure. The exception contains a wealth of information about | |
99 | // the failures, including a potential chain of exceptions explaining what went wrong. We're | |
100 | // going to send a new one of these, so we need to merge the information. | |
101 | ||
102 | // add this to our exception chain | |
103 | 0 | if (chainedException == null) { |
104 | 0 | chainedException = e; |
105 | } | |
106 | else { | |
107 | 0 | chainedException.setNextException(e); |
108 | } | |
109 | ||
110 | // now extract each of the address categories from | |
111 | 0 | Address[] exAddrs = e.getValidSentAddresses(); |
112 | 0 | if (exAddrs != null) { |
113 | 0 | for (int j = 0; j < exAddrs.length; j++) { |
114 | 0 | sentAddresses.add(exAddrs[j]); |
115 | } | |
116 | } | |
117 | ||
118 | 0 | exAddrs = e.getValidUnsentAddresses(); |
119 | 0 | if (exAddrs != null) { |
120 | 0 | for (int j = 0; j < exAddrs.length; j++) { |
121 | 0 | unsentAddresses.add(exAddrs[j]); |
122 | } | |
123 | } | |
124 | ||
125 | 0 | exAddrs = e.getInvalidAddresses(); |
126 | 0 | if (exAddrs != null) { |
127 | 0 | for (int j = 0; j < exAddrs.length; j++) { |
128 | 0 | invalidAddresses.add(exAddrs[j]); |
129 | } | |
130 | } | |
131 | ||
132 | } catch (MessagingException e) { | |
133 | // add this to our exception chain | |
134 | 0 | if (chainedException == null) { |
135 | 0 | chainedException = e; |
136 | } | |
137 | else { | |
138 | 0 | chainedException.setNextException(e); |
139 | } | |
140 | } | |
141 | finally { | |
142 | 0 | transport.close(); |
143 | } | |
144 | } | |
145 | ||
146 | // if we have an exception chain then we need to throw a new exception giving the failure | |
147 | // information. | |
148 | 0 | if (chainedException != null) { |
149 | // if we're only sending to a single transport (common), and we received a SendFailedException | |
150 | // as a result, then we have a fully formed exception already. Rather than wrap this in another | |
151 | // exception, we can just rethrow the one we have. | |
152 | 0 | if (msgsByTransport.size() == 1 && chainedException instanceof SendFailedException) { |
153 | 0 | throw chainedException; |
154 | } | |
155 | ||
156 | // create our lists for notification and exception reporting from this point on. | |
157 | 0 | Address[] sent = (Address[])sentAddresses.toArray(new Address[0]); |
158 | 0 | Address[] unsent = (Address[])unsentAddresses.toArray(new Address[0]); |
159 | 0 | Address[] invalid = (Address[])invalidAddresses.toArray(new Address[0]); |
160 | ||
161 | 0 | 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 | 3 | public Transport(Session session, URLName name) { |
172 | 3 | 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 | 0 | public void addTransportListener(TransportListener listener) { |
194 | 0 | transportListeners.add(listener); |
195 | } | |
196 | ||
197 | 0 | public void removeTransportListener(TransportListener listener) { |
198 | 0 | transportListeners.remove(listener); |
199 | } | |
200 | ||
201 | 0 | protected void notifyTransportListeners(int type, Address[] validSent, Address[] validUnsent, Address[] invalid, Message message) { |
202 | 0 | queueEvent(new TransportEvent(this, type, validSent, validUnsent, invalid, message), transportListeners); |
203 | } | |
204 | } |
|