KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > mail > Transport


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the "License"). You may not use this file except
5  * in compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * glassfish/bootstrap/legal/CDDLv1.0.txt or
9  * https://glassfish.dev.java.net/public/CDDLv1.0.html.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * HEADER in each file and include the License file at
15  * glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
16  * add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your
18  * own identifying information: Portions Copyright [yyyy]
19  * [name of copyright owner]
20  */

21
22 /*
23  * @(#)Transport.java 1.38 05/08/29
24  *
25  * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
26  */

27
28 package javax.mail;
29
30 import java.io.IOException JavaDoc;
31 import java.net.*;
32 import java.util.Vector JavaDoc;
33 import java.util.Hashtable JavaDoc;
34 import java.util.Enumeration JavaDoc;
35 import javax.mail.event.*;
36
37 /**
38  * An abstract class that models a message transport.
39  * Subclasses provide actual implementations. <p>
40  *
41  * Note that <code>Transport</code> extends the <code>Service</code>
42  * class, which provides many common methods for naming transports,
43  * connecting to transports, and listening to connection events.
44  *
45  * @author John Mani
46  * @author Max Spivak
47  * @author Bill Shannon
48  * @version 1.38, 05/08/29
49  *
50  * @see javax.mail.Service
51  * @see javax.mail.event.ConnectionEvent
52  * @see javax.mail.event.TransportEvent
53  */

54
55 public abstract class Transport extends Service JavaDoc {
56
57     /**
58      * Constructor.
59      *
60      * @param session Session object for this Transport.
61      * @param urlname URLName object to be used for this Transport
62      */

63     public Transport(Session JavaDoc session, URLName JavaDoc urlname) {
64     super(session, urlname);
65     }
66
67     /**
68      * Send a message. The message will be sent to all recipient
69      * addresses specified in the message (as returned from the
70      * <code>Message</code> method <code>getAllRecipients</code>),
71      * using message transports appropriate to each address. The
72      * <code>send</code> method calls the <code>saveChanges</code>
73      * method on the message before sending it. <p>
74      *
75      * If any of the recipient addresses is detected to be invalid by
76      * the Transport during message submission, a SendFailedException
77      * is thrown. Clients can get more detail about the failure by examining
78      * the exception. Whether or not the message is still sent succesfully to
79      * any valid addresses depends on the Transport implementation. See
80      * SendFailedException for more details. Note also that success does
81      * not imply that the message was delivered to the ultimate recipient,
82      * as failures may occur in later stages of delivery. Once a Transport
83      * accepts a message for delivery to a recipient, failures that occur later
84      * should be reported to the user via another mechanism, such as
85      * returning the undeliverable message. <p>
86      *
87      * @param msg the message to send
88      * @exception SendFailedException if the message could not
89      * be sent to some or any of the recipients.
90      * @exception MessagingException
91      * @see Message#saveChanges
92      * @see Message#getAllRecipients
93      * @see #send(Message, Address[])
94      * @see javax.mail.SendFailedException
95      */

96     public static void send(Message JavaDoc msg) throws MessagingException JavaDoc {
97     msg.saveChanges(); // do this first
98
send0(msg, msg.getAllRecipients());
99     }
100
101     /**
102      * Send the message to the specified addresses, ignoring any
103      * recipients specified in the message itself. The
104      * <code>send</code> method calls the <code>saveChanges</code>
105      * method on the message before sending it. <p>
106      *
107      * @param msg the message to send
108      * @param addresses the addresses to which to send the message
109      * @exception SendFailedException if the message could not
110      * be sent to some or any of the recipients.
111      * @exception MessagingException
112      * @see Message#saveChanges
113      * @see #send(Message)
114      * @see javax.mail.SendFailedException
115      */

116     public static void send(Message JavaDoc msg, Address JavaDoc[] addresses)
117         throws MessagingException JavaDoc {
118
119     msg.saveChanges();
120     send0(msg, addresses);
121     }
122
123     // send, but without the saveChanges
124
private static void send0(Message JavaDoc msg, Address JavaDoc[] addresses)
125         throws MessagingException JavaDoc {
126
127     if (addresses == null || addresses.length == 0)
128         throw new SendFailedException JavaDoc("No recipient addresses");
129
130     /*
131      * protocols is a hashtable containing the addresses
132      * indexed by address type
133      */

134     Hashtable JavaDoc protocols = new Hashtable JavaDoc();
135
136     // Vectors of addresses
137
Vector JavaDoc invalid = new Vector JavaDoc();
138     Vector JavaDoc validSent = new Vector JavaDoc();
139     Vector JavaDoc validUnsent = new Vector JavaDoc();
140
141     for (int i = 0; i < addresses.length; i++) {
142         // is this address type already in the hashtable?
143
if (protocols.containsKey(addresses[i].getType())) {
144         Vector JavaDoc v = (Vector JavaDoc)protocols.get(addresses[i].getType());
145         v.addElement(addresses[i]);
146         } else {
147         // need to add a new protocol
148
Vector JavaDoc w = new Vector JavaDoc();
149         w.addElement(addresses[i]);
150         protocols.put(addresses[i].getType(), w);
151         }
152     }
153
154     int dsize = protocols.size();
155     if (dsize == 0)
156         throw new SendFailedException JavaDoc("No recipient addresses");
157
158     Session JavaDoc s = (msg.session != null) ? msg.session :
159              Session.getDefaultInstance(System.getProperties(), null);
160     Transport JavaDoc transport;
161
162     /*
163      * Optimize the case of a single protocol.
164      */

165     if (dsize == 1) {
166         transport = s.getTransport(addresses[0]);
167         try {
168         transport.connect();
169         transport.sendMessage(msg, addresses);
170         } finally {
171         transport.close();
172         }
173         return;
174     }
175
176     /*
177      * More than one protocol. Have to do them one at a time
178      * and collect addresses and chain exceptions.
179      */

180     MessagingException JavaDoc chainedEx = null;
181     boolean sendFailed = false;
182
183     Enumeration JavaDoc e = protocols.elements();
184     while (e.hasMoreElements()) {
185         Vector JavaDoc v = (Vector JavaDoc)e.nextElement();
186         Address JavaDoc[] protaddresses = new Address JavaDoc[v.size()];
187         v.copyInto(protaddresses);
188
189         // Get a Transport that can handle this address type.
190
if ((transport = s.getTransport(protaddresses[0])) == null) {
191         // Could not find an appropriate Transport ..
192
// Mark these addresses invalid.
193
for (int j = 0; j < protaddresses.length; j++)
194             invalid.addElement(protaddresses[j]);
195         continue;
196         }
197         try {
198         transport.connect();
199         transport.sendMessage(msg, protaddresses);
200         } catch (SendFailedException JavaDoc sex) {
201         sendFailed = true;
202         // chain the exception we're catching to any previous ones
203
if (chainedEx == null)
204             chainedEx = sex;
205         else
206             chainedEx.setNextException(sex);
207
208         // retrieve invalid addresses
209
Address JavaDoc[] a = sex.getInvalidAddresses();
210         if (a != null)
211             for (int j = 0; j < a.length; j++)
212             invalid.addElement(a[j]);
213
214         // retrieve validSent addresses
215
a = sex.getValidSentAddresses();
216         if (a != null)
217             for (int k = 0; k < a.length; k++)
218             validSent.addElement(a[k]);
219
220         // retrieve validUnsent addresses
221
Address JavaDoc[] c = sex.getValidUnsentAddresses();
222         if (c != null)
223             for (int l = 0; l < c.length; l++)
224             validUnsent.addElement(c[l]);
225         } catch (MessagingException JavaDoc mex) {
226         sendFailed = true;
227         // chain the exception we're catching to any previous ones
228
if (chainedEx == null)
229             chainedEx = mex;
230         else
231             chainedEx.setNextException(mex);
232         } finally {
233         transport.close();
234         }
235     }
236
237     // done with all protocols. throw exception if something failed
238
if (sendFailed || invalid.size() != 0 || validUnsent.size() != 0) {
239         Address JavaDoc[] a = null, b = null, c = null;
240
241         // copy address vectors into arrays
242
if (validSent.size() > 0) {
243         a = new Address JavaDoc[validSent.size()];
244         validSent.copyInto(a);
245         }
246         if (validUnsent.size() > 0) {
247         b = new Address JavaDoc[validUnsent.size()];
248         validUnsent.copyInto(b);
249         }
250         if (invalid.size() > 0) {
251         c = new Address JavaDoc[invalid.size()];
252         invalid.copyInto(c);
253         }
254         throw new SendFailedException JavaDoc("Sending failed", chainedEx,
255                       a, b, c);
256     }
257     }
258
259     /**
260      * Send the Message to the specified list of addresses. An appropriate
261      * TransportEvent indicating the delivery status is delivered to any
262      * TransportListener registered on this Transport. Also, if any of
263      * the addresses is invalid, a SendFailedException is thrown.
264      * Whether or not the message is still sent succesfully to
265      * any valid addresses depends on the Transport implementation. <p>
266      *
267      * Unlike the static <code>send</code> method, the <code>sendMessage</code>
268      * method does <em>not</em> call the <code>saveChanges</code> method on
269      * the message; the caller should do so.
270      *
271      * @param msg The Message to be sent
272      * @param addresses array of addresses to send this message to
273      * @see javax.mail.event.TransportEvent
274      * @exception SendFailedException if the send failed because of
275      * invalid addresses.
276      * @exception MessagingException if the connection is dead or not in the
277      * connected state
278      */

279     public abstract void sendMessage(Message JavaDoc msg, Address JavaDoc[] addresses)
280                 throws MessagingException JavaDoc;
281
282     // Vector of Transport listeners
283
private Vector JavaDoc transportListeners = null;
284
285     /**
286      * Add a listener for Transport events. <p>
287      *
288      * The default implementation provided here adds this listener
289      * to an internal list of TransportListeners.
290      *
291      * @param l the Listener for Transport events
292      * @see javax.mail.event.TransportEvent
293      */

294     public synchronized void addTransportListener(TransportListener l) {
295     if (transportListeners == null)
296         transportListeners = new Vector JavaDoc();
297     transportListeners.addElement(l);
298     }
299
300     /**
301      * Remove a listener for Transport events. <p>
302      *
303      * The default implementation provided here removes this listener
304      * from the internal list of TransportListeners.
305      *
306      * @param l the listener
307      * @see #addTransportListener
308      */

309     public synchronized void removeTransportListener(TransportListener l) {
310     if (transportListeners != null)
311         transportListeners.removeElement(l);
312     }
313
314     /**
315      * Notify all TransportListeners. Transport implementations are
316      * expected to use this method to broadcast TransportEvents.<p>
317      *
318      * The provided default implementation queues the event into
319      * an internal event queue. An event dispatcher thread dequeues
320      * events from the queue and dispatches them to the registered
321      * TransportListeners. Note that the event dispatching occurs
322      * in a separate thread, thus avoiding potential deadlock problems.
323      */

324     protected void notifyTransportListeners(int type, Address JavaDoc[] validSent,
325                         Address JavaDoc[] validUnsent,
326                         Address JavaDoc[] invalid, Message JavaDoc msg) {
327     if (transportListeners == null)
328         return;
329     
330     TransportEvent e = new TransportEvent(this, type, validSent,
331                           validUnsent, invalid, msg);
332     queueEvent(e, transportListeners);
333     }
334 }
335
Popular Tags