KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > mail > Session


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  * @(#)Session.java 1.71 05/12/12
24  *
25  * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
26  */

27
28 package javax.mail;
29
30 import java.lang.reflect.*;
31 import java.io.*;
32 import java.net.*;
33 import java.security.*;
34 import java.util.Enumeration JavaDoc;
35 import java.util.Hashtable JavaDoc;
36 import java.util.Properties JavaDoc;
37 import java.util.StringTokenizer JavaDoc;
38 import java.util.Vector JavaDoc;
39
40 import javax.activation.*;
41
42 import com.sun.mail.util.LineInputStream;
43
44 /**
45  * The Session class represents a mail session and is not subclassed.
46  * It collects together properties and defaults used by the mail API's.
47  * A single default session can be shared by multiple applications on the
48  * desktop. Unshared sessions can also be created. <p>
49  *
50  * The Session class provides access to the protocol providers that
51  * implement the <code>Store</code>, <code>Transport</code>, and related
52  * classes. The protocol providers are configured using the following files:
53  * <ul>
54  * <li> <code>javamail.providers</code> and
55  * <code>javamail.default.providers</code> </li>
56  * <li> <code>javamail.address.map</code> and
57  * <code>javamail.default.address.map</code> </li>
58  * </ul>
59  * <p>
60  * Each <code>javamail.</code><i>X</i> resource file is searched for using
61  * three methods in the following order:
62  * <ol>
63  * <li> <code>java.home/lib/javamail.</code><i>X</i> </li>
64  * <li> <code>META-INF/javamail.</code><i>X</i> </li>
65  * <li> <code>META-INF/javamail.default.</code><i>X</i> </li>
66  * </ol>
67  * <p>
68  * The first method allows the user to include their own version of the
69  * resource file by placing it in the <code>lib</code> directory where the
70  * <code>java.home</code> property points. The second method allows an
71  * application that uses the JavaMail APIs to include their own resource
72  * files in their application's or jar file's <code>META-INF</code>
73  * directory. The <code>javamail.default.</code><i>X</i> default files
74  * are part of the JavaMail <code>mail.jar</code> file. <p>
75  *
76  * File location depends upon how the <code>ClassLoader</code> method
77  * <code>getResource</code> is implemented. Usually, the
78  * <code>getResource</code> method searches through CLASSPATH until it
79  * finds the requested file and then stops. JDK 1.1 has a limitation that
80  * the number of files of each name that will be found in the CLASSPATH is
81  * limited to one. However, this only affects method two, above; method
82  * one is loaded from a specific location (if allowed by the
83  * SecurityManager) and method three uses a different name to ensure that
84  * the default resource file is always loaded successfully. J2SE 1.2 and
85  * later are not limited to one file of a given name. <p>
86  *
87  * The ordering of entries in the resource files matters. If multiple
88  * entries exist, the first entries take precedence over the later
89  * entries. For example, the first IMAP provider found will be set as the
90  * default IMAP implementation until explicitly changed by the
91  * application. The user- or system-supplied resource files augment, they
92  * do not override, the default files included with the JavaMail APIs.
93  * This means that all entries in all files loaded will be available. <p>
94  *
95  * <b><code>javamail.providers</code></b> and
96  * <b><code>javamail.default.providers</code></b><p>
97  *
98  * These resource files specify the stores and transports that are
99  * available on the system, allowing an application to "discover" what
100  * store and transport implementations are available. The protocol
101  * implementations are listed one per line. The file format defines four
102  * attributes that describe a protocol implementation. Each attribute is
103  * an "="-separated name-value pair with the name in lowercase. Each
104  * name-value pair is semi-colon (";") separated. The following names
105  * are defined. <p>
106  *
107  * <table border=1>
108  * <caption>
109  * Attribute Names in Providers Files
110  * </caption>
111  * <tr>
112  * <th>Name</th><th>Description</th>
113  * </tr>
114  * <tr>
115  * <td>protocol</td>
116  * <td>Name assigned to protocol.
117  * For example, <code>smtp</code> for Transport.</td>
118  * </tr>
119  * <tr>
120  * <td>type</td>
121  * <td>Valid entries are <code>store</code> and <code>transport</code>.</td>
122  * </tr>
123  * <tr>
124  * <td>class</td>
125  * <td>Class name that implements this protocol.</td>
126  * </tr>
127  * <tr>
128  * <td>vendor</td>
129  * <td>Optional string identifying the vendor.</td>
130  * </tr>
131  * <tr>
132  * <td>version</td>
133  * <td>Optional string identifying the version.</td>
134  * </tr>
135  * </table><p>
136  *
137  * Here's an example of <code>META-INF/javamail.default.providers</code>
138  * file contents:
139  * <pre>
140  * protocol=imap; type=store; class=com.sun.mail.imap.IMAPStore; vendor=Sun Microsystems, Inc.;
141  * protocol=smtp; type=transport; class=com.sun.mail.smtp.SMTPTransport; vendor=Sun Microsystems, Inc.;
142  * </pre><p>
143  *
144  * <b><code>javamail.address.map</code></b> and
145  * <b><code>javamail.default.address.map</code></b><p>
146  *
147  * These resource files map transport address types to the transport
148  * protocol. The <code>getType</code> method of
149  * </code>javax.mail.Address</code> returns the address type. The
150  * <code>javamail.address.map</code> file maps the transport type to the
151  * protocol. The file format is a series of name-value pairs. Each key
152  * name should correspond to an address type that is currently installed
153  * on the system; there should also be an entry for each
154  * <code>javax.mail.Address</code> implementation that is present if it is
155  * to be used. For example, the
156  * <code>javax.mail.internet.InternetAddress</code> method
157  * <code>getType</code> returns "rfc822". Each referenced protocol should
158  * be installed on the system. For the case of <code>news</code>, below,
159  * the client should install a Transport provider supporting the nntp
160  * protocol. <p>
161  *
162  * Here are the typical contents of a <code>javamail.address.map</code> file:
163  * <pre>
164  * rfc822=smtp
165  * news=nntp
166  * </pre>
167  *
168  * @version 1.71, 05/12/12
169  * @author John Mani
170  * @author Bill Shannon
171  * @author Max Spivak
172  */

173
174 public final class Session {
175
176     private final Properties JavaDoc props;
177     private final Authenticator JavaDoc authenticator;
178     private final Hashtable JavaDoc authTable = new Hashtable JavaDoc();
179     private boolean debug = false;
180     private PrintStream out; // debug output stream
181
private final Vector JavaDoc providers = new Vector JavaDoc();
182     private final Hashtable JavaDoc providersByProtocol = new Hashtable JavaDoc();
183     private final Hashtable JavaDoc providersByClassName = new Hashtable JavaDoc();
184     private final Properties JavaDoc addressMap = new Properties JavaDoc();
185                         // maps type to protocol
186
// The default session.
187
private static Session JavaDoc defaultSession = null;
188
189     // The version of JavaMail, for debug output
190
private static final String JavaDoc version = "1.4ea";
191
192     // Constructor is not public
193
private Session(Properties JavaDoc props, Authenticator JavaDoc authenticator) {
194     this.props = props;
195     this.authenticator = authenticator;
196
197     if (Boolean.valueOf(props.getProperty("mail.debug")).booleanValue())
198         debug = true;
199
200     if (debug)
201         pr("DEBUG: JavaMail version " + version);
202
203     // get the Class associated with the Authenticator
204
Class JavaDoc cl;
205     if (authenticator != null)
206         cl = authenticator.getClass();
207     else
208         cl = this.getClass();
209     // load the resources
210
loadProviders(cl);
211     loadAddressMap(cl);
212     }
213
214     /**
215      * Get a new Session object.
216      *
217      * @param props Properties object that hold relevant properties.<br>
218      * It is expected that the client supplies values
219      * for the properties listed in Appendix A of the
220      * JavaMail spec (particularly mail.store.protocol,
221      * mail.transport.protocol, mail.host, mail.user,
222      * and mail.from) as the defaults are unlikely to
223      * work in all cases.
224      * @param authenticator Authenticator object used to call back to
225      * the application when a user name and password is
226      * needed.
227      * @return a new Session object
228      * @see javax.mail.Authenticator
229      */

230     public static Session JavaDoc getInstance(Properties JavaDoc props,
231                     Authenticator JavaDoc authenticator) {
232     return new Session JavaDoc(props, authenticator);
233     }
234
235     /**
236      * Get a new Session object.
237      *
238      * @param props Properties object that hold relevant properties.<br>
239      * It is expected that the client supplies values
240      * for the properties listed in Appendix A of the
241      * JavaMail spec (particularly mail.store.protocol,
242      * mail.transport.protocol, mail.host, mail.user,
243      * and mail.from) as the defaults are unlikely to
244      * work in all cases.
245      * @return a new Session object
246      * @since JavaMail 1.2
247      */

248     public static Session JavaDoc getInstance(Properties JavaDoc props) {
249     return new Session JavaDoc(props, null);
250     }
251
252     /**
253      * Get the default Session object. If a default has not yet been
254      * setup, a new Session object is created and installed as the
255      * default. <p>
256      *
257      * Since the default session is potentially available to all
258      * code executing in the same Java virtual machine, and the session
259      * can contain security sensitive information such as user names
260      * and passwords, access to the default session is restricted.
261      * The Authenticator object, which must be created by the caller,
262      * is used indirectly to check access permission. The Authenticator
263      * object passed in when the session is created is compared with
264      * the Authenticator object passed in to subsequent requests to
265      * get the default session. If both objects are the same, or are
266      * from the same ClassLoader, the request is allowed. Otherwise,
267      * it is denied. <p>
268      *
269      * Note that if the Authenticator object used to create the session
270      * is null, anyone can get the default session by passing in null. <p>
271      *
272      * Note also that the Properties object is used only the first time
273      * this method is called, when a new Session object is created.
274      * Subsequent calls return the Session object that was created by the
275      * first call, and ignore the passed Properties object. Use the
276      * <code>getInstance</code> method to get a new Session object every
277      * time the method is called. <p>
278      *
279      * In JDK 1.2, additional security Permission objects may be used to
280      * control access to the default session.
281      *
282      * @param props Properties object. Used only if a new Session
283      * object is created.<br>
284      * It is expected that the client supplies values
285      * for the properties listed in Appendix A of the
286      * JavaMail spec (particularly mail.store.protocol,
287      * mail.transport.protocol, mail.host, mail.user,
288      * and mail.from) as the defaults are unlikely to
289      * work in all cases.
290      * @param authenticator Authenticator object. Used only if a
291      * new Session object is created. Otherwise,
292      * it must match the Authenticator used to create
293      * the Session.
294      * @return the default Session object
295      */

296     public static synchronized Session JavaDoc getDefaultInstance(Properties JavaDoc props,
297                     Authenticator JavaDoc authenticator) {
298     if (defaultSession == null)
299         defaultSession = new Session JavaDoc(props, authenticator);
300     else {
301         // have to check whether caller is allowed to see default session
302
if (defaultSession.authenticator == authenticator)
303         ; // either same object or both null, either way OK
304
else if (defaultSession.authenticator != null &&
305             authenticator != null &&
306             defaultSession.authenticator.getClass().getClassLoader() ==
307             authenticator.getClass().getClassLoader())
308         ; // both objects came from the same class loader, OK
309
else
310         // anything else is not allowed
311
throw new SecurityException JavaDoc("Access to default session denied");
312     }
313
314     return defaultSession;
315     }
316
317     /**
318      * Get the default Session object. If a default has not yet been
319      * setup, a new Session object is created and installed as the
320      * default. <p>
321      *
322      * Note that a default session created with no Authenticator is
323      * available to all code executing in the same Java virtual
324      * machine, and the session can contain security sensitive
325      * information such as user names and passwords.
326      *
327      * @param props Properties object. Used only if a new Session
328      * object is created.<br>
329      * It is expected that the client supplies values
330      * for the properties listed in Appendix A of the
331      * JavaMail spec (particularly mail.store.protocol,
332      * mail.transport.protocol, mail.host, mail.user,
333      * and mail.from) as the defaults are unlikely to
334      * work in all cases.
335      * @return the default Session object
336      * @since JavaMail 1.2
337      */

338     public static Session JavaDoc getDefaultInstance(Properties JavaDoc props) {
339         return getDefaultInstance(props, null);
340     }
341
342     /**
343      * Set the debug setting for this Session.
344      * <p>
345      * Since the debug setting can be turned on only after the Session
346      * has been created, to turn on debugging in the Session
347      * constructor, set the property <code>mail.debug</code> in the
348      * Properties object passed in to the constructor to true. The
349      * value of the <code>mail.debug</code> property is used to
350      * initialize the per-Session debugging flag. Subsequent calls to
351      * the <code>setDebug</code> method manipulate the per-Session
352      * debugging flag and have no affect on the <code>mail.debug</code>
353      * property.
354      *
355      * @param debug Debug setting
356      */

357     public synchronized void setDebug(boolean debug) {
358     this.debug = debug;
359     if (debug)
360         pr("DEBUG: setDebug: JavaMail version " + version);
361     }
362
363     /**
364      * Get the debug setting for this Session.
365      *
366      * @return current debug setting
367      */

368     public synchronized boolean getDebug() {
369     return debug;
370     }
371
372     /**
373      * Set the stream to be used for debugging output for this session.
374      * If <code>out</code> is null, <code>System.out</code> will be used.
375      * Note that debugging output that occurs before any session is created,
376      * as a result of setting the <code>mail.debug</code> system property,
377      * will always be sent to <code>System.out</code>.
378      *
379      * @param out the PrintStream to use for debugging output
380      * @since JavaMail 1.3
381      */

382     public synchronized void setDebugOut(PrintStream out) {
383     this.out = out;
384     }
385
386     /**
387      * Returns the stream to be used for debugging output. If no stream
388      * has been set, <code>System.out</code> is returned.
389      *
390      * @return the PrintStream to use for debugging output
391      * @since JavaMail 1.3
392      */

393     public synchronized PrintStream getDebugOut() {
394     if (out == null)
395         return System.out;
396     else
397         return out;
398     }
399
400     /**
401      * This method returns an array of all the implementations installed
402      * via the javamail.[default.]providers files that can
403      * be loaded using the ClassLoader available to this application.
404      *
405      * @return Array of configured providers
406      */

407     public synchronized Provider JavaDoc[] getProviders() {
408     Provider JavaDoc[] _providers = new Provider JavaDoc[providers.size()];
409     providers.copyInto(_providers);
410     return _providers;
411     }
412
413     /**
414      * Returns the default Provider for the protocol
415      * specified. Checks mail.&lt;protocol&gt;.class property
416      * first and if it exists, returns the Provider
417      * associated with this implementation. If it doesn't exist,
418      * returns the Provider that appeared first in the
419      * configuration files. If an implementation for the protocol
420      * isn't found, throws NoSuchProviderException
421      *
422      * @param protocol Configured protocol (i.e. smtp, imap, etc)
423      * @return Currently configured Provider for the specified protocol
424      * @exception NoSuchProviderException If a provider for the given
425      * protocol is not found.
426      */

427     public synchronized Provider JavaDoc getProvider(String JavaDoc protocol)
428                                     throws NoSuchProviderException JavaDoc {
429
430     if (protocol == null || protocol.length() <= 0) {
431         throw new NoSuchProviderException JavaDoc("Invalid protocol: null");
432     }
433
434     Provider JavaDoc _provider = null;
435
436     // check if the mail.<protocol>.class property exists
437
String JavaDoc _className = props.getProperty("mail."+protocol+".class");
438     if (_className != null) {
439         if (debug) {
440         pr("DEBUG: mail."+protocol+
441                    ".class property exists and points to " +
442                    _className);
443         }
444         _provider = (Provider JavaDoc)providersByClassName.get(_className);
445     }
446
447     if (_provider != null) {
448         return _provider;
449     } else {
450         // returning currently default protocol in providersByProtocol
451
_provider = (Provider JavaDoc)providersByProtocol.get(protocol);
452     }
453
454     if (_provider == null) {
455         throw new NoSuchProviderException JavaDoc("No provider for " + protocol);
456     } else {
457         if (debug) {
458         pr("DEBUG: getProvider() returning " +
459                    _provider.toString());
460         }
461         return _provider;
462     }
463     }
464
465     /**
466      * Set the passed Provider to be the default implementation
467      * for the protocol in Provider.protocol overriding any previous values.
468      *
469      * @param provider Currently configured Provider which will be
470      * set as the default for the protocol
471      * @exception NoSuchProviderException If the provider passed in
472      * is invalid.
473      */

474     public synchronized void setProvider(Provider JavaDoc provider)
475                 throws NoSuchProviderException JavaDoc {
476     if (provider == null) {
477         throw new NoSuchProviderException JavaDoc("Can't set null provider");
478     }
479     providersByProtocol.put(provider.getProtocol(), provider);
480     props.put("mail." + provider.getProtocol() + ".class",
481           provider.getClassName());
482     }
483
484
485     /**
486      * Get a Store object that implements this user's desired Store
487      * protocol. The <code>mail.store.protocol</code> property specifies the
488      * desired protocol. If an appropriate Store object is not obtained,
489      * NoSuchProviderException is thrown
490      *
491      * @return a Store object
492      * @exception NoSuchProviderException If a provider for the given
493      * protocol is not found.
494      */

495     public Store JavaDoc getStore() throws NoSuchProviderException JavaDoc {
496     return getStore(getProperty("mail.store.protocol"));
497     }
498
499     /**
500      * Get a Store object that implements the specified protocol. If an
501      * appropriate Store object cannot be obtained,
502      * NoSuchProviderException is thrown.
503      *
504      * @param protocol
505      * @return a Store object
506      * @exception NoSuchProviderException If a provider for the given
507      * protocol is not found.
508      */

509     public Store JavaDoc getStore(String JavaDoc protocol) throws NoSuchProviderException JavaDoc {
510     return getStore(new URLName JavaDoc(protocol, null, -1, null, null, null));
511     }
512
513
514     /**
515      * Get a Store object for the given URLName. If the requested Store
516      * object cannot be obtained, NoSuchProviderException is thrown.
517      *
518      * The "scheme" part of the URL string (Refer RFC 1738) is used
519      * to locate the Store protocol. <p>
520      *
521      * @param url URLName that represents the desired Store
522      * @return a closed Store object
523      * @see #getFolder(URLName)
524      * @see javax.mail.URLName
525      * @exception NoSuchProviderException If a provider for the given
526      * URLName is not found.
527      */

528     public Store JavaDoc getStore(URLName JavaDoc url) throws NoSuchProviderException JavaDoc {
529     String JavaDoc protocol = url.getProtocol();
530     Provider JavaDoc p = getProvider(protocol);
531     return getStore(p, url);
532     }
533
534     /**
535      * Get an instance of the store specified by Provider. Instantiates
536      * the store and returns it.
537      *
538      * @param provider Store Provider that will be instantiated
539      * @return Instantiated Store
540      * @exception NoSuchProviderException If a provider for the given
541      * Provider is not found.
542      */

543     public Store JavaDoc getStore(Provider JavaDoc provider) throws NoSuchProviderException JavaDoc {
544     return getStore(provider, null);
545     }
546
547
548     /**
549      * Get an instance of the store specified by Provider. If the URLName
550      * is not null, uses it, otherwise creates a new one. Instantiates
551      * the store and returns it. This is a private method used by
552      * getStore(Provider) and getStore(URLName)
553      *
554      * @param provider Store Provider that will be instantiated
555      * @param url URLName used to instantiate the Store
556      * @return Instantiated Store
557      * @exception NoSuchProviderException If a provider for the given
558      * Provider/URLName is not found.
559      */

560     private Store JavaDoc getStore(Provider JavaDoc provider, URLName JavaDoc url)
561     throws NoSuchProviderException JavaDoc {
562
563     // make sure we have the correct type of provider
564
if (provider == null || provider.getType() != Provider.Type.STORE ) {
565         throw new NoSuchProviderException JavaDoc("invalid provider");
566     }
567         
568     try {
569         return (Store JavaDoc) getService(provider, url);
570     } catch (ClassCastException JavaDoc cce) {
571         throw new NoSuchProviderException JavaDoc("incorrect class");
572     }
573     }
574
575     /**
576      * Get a closed Folder object for the given URLName. If the requested
577      * Folder object cannot be obtained, null is returned. <p>
578      *
579      * The "scheme" part of the URL string (Refer RFC 1738) is used
580      * to locate the Store protocol. The rest of the URL string (that is,
581      * the "schemepart", as per RFC 1738) is used by that Store
582      * in a protocol dependent manner to locate and instantiate the
583      * appropriate Folder object. <p>
584      *
585      * Note that RFC 1738 also specifies the syntax for the
586      * "schemepart" for IP-based protocols (IMAP4, POP3, etc.).
587      * Providers of IP-based mail Stores should implement that
588      * syntax for referring to Folders. <p>
589      *
590      * @param url URLName that represents the desired folder
591      * @return Folder
592      * @see #getStore(URLName)
593      * @see javax.mail.URLName
594      * @exception NoSuchProviderException If a provider for the given
595      * URLName is not found.
596      * @exception MessagingException if the Folder could not be
597      * located or created.
598      */

599     public Folder JavaDoc getFolder(URLName JavaDoc url)
600         throws MessagingException JavaDoc {
601     // First get the Store
602
Store JavaDoc store = getStore(url);
603     store.connect();
604     return store.getFolder(url);
605     }
606
607     /**
608      * Get a Transport object that implements this user's desired
609      * Transport protcol. The <code>mail.transport.protocol</code> property
610      * specifies the desired protocol. If an appropriate Transport
611      * object cannot be obtained, MessagingException is thrown.
612      *
613      * @return a Transport object
614      * @exception NoSuchProviderException If the provider is not found.
615      */

616     public Transport JavaDoc getTransport() throws NoSuchProviderException JavaDoc {
617         return getTransport(getProperty("mail.transport.protocol"));
618     }
619
620     /**
621      * Get a Transport object that implements the specified protocol.
622      * If an appropriate Transport object cannot be obtained, null is
623      * returned.
624      *
625      * @return a Transport object
626      * @exception NoSuchProviderException If provider for the given
627      * protocol is not found.
628      */

629     public Transport JavaDoc getTransport(String JavaDoc protocol)
630                 throws NoSuchProviderException JavaDoc {
631     return getTransport(new URLName JavaDoc(protocol, null, -1, null, null, null));
632     }
633
634
635     /**
636      * Get a Transport object for the given URLName. If the requested
637      * Transport object cannot be obtained, NoSuchProviderException is thrown.
638      *
639      * The "scheme" part of the URL string (Refer RFC 1738) is used
640      * to locate the Transport protocol. <p>
641      *
642      * @param url URLName that represents the desired Transport
643      * @return a closed Transport object
644      * @see javax.mail.URLName
645      * @exception NoSuchProviderException If a provider for the given
646      * URLName is not found.
647      */

648     public Transport JavaDoc getTransport(URLName JavaDoc url) throws NoSuchProviderException JavaDoc {
649     String JavaDoc protocol = url.getProtocol();
650     Provider JavaDoc p = getProvider(protocol);
651     return getTransport(p, url);
652     }
653
654     /**
655      * Get an instance of the transport specified in the Provider. Instantiates
656      * the transport and returns it.
657      *
658      * @param provider Transport Provider that will be instantiated
659      * @return Instantiated Transport
660      * @exception NoSuchProviderException If provider for the given
661      * provider is not found.
662      */

663     public Transport JavaDoc getTransport(Provider JavaDoc provider)
664                                          throws NoSuchProviderException JavaDoc {
665     return getTransport(provider, null);
666     }
667
668     /**
669      * Get a Transport object that can transport a Message to the
670      * specified address type.
671      *
672      * @param address
673      * @return A Transport object
674      * @see javax.mail.Address
675      * @exception NoSuchProviderException If provider for the
676      * Address type is not found
677      */

678     public Transport JavaDoc getTransport(Address JavaDoc address)
679                                          throws NoSuchProviderException JavaDoc {
680
681     String JavaDoc transportProtocol = (String JavaDoc)addressMap.get(address.getType());
682     if (transportProtocol == null) {
683         throw new NoSuchProviderException JavaDoc("No provider for Address type: "+
684                           address.getType());
685     } else {
686         return getTransport(transportProtocol);
687     }
688     }
689
690     /**
691      * Get a Transport object using the given provider and urlname.
692      *
693      * @param provider the provider to use
694      * @param url urlname to use (can be null)
695      * @return A Transport object
696      * @exception NoSuchProviderException If no provider or the provider
697      * was the wrong class.
698      */

699
700     private Transport JavaDoc getTransport(Provider JavaDoc provider, URLName JavaDoc url)
701                     throws NoSuchProviderException JavaDoc {
702     // make sure we have the correct type of provider
703
if (provider == null || provider.getType() != Provider.Type.TRANSPORT) {
704         throw new NoSuchProviderException JavaDoc("invalid provider");
705     }
706
707     try {
708         return (Transport JavaDoc) getService(provider, url);
709     } catch (ClassCastException JavaDoc cce) {
710         throw new NoSuchProviderException JavaDoc("incorrect class");
711     }
712     }
713
714     /**
715      * Get a Service object. Needs a provider object, but will
716      * create a URLName if needed. It attempts to instantiate
717      * the correct class.
718      *
719      * @param provider which provider to use
720      * @param url which URLName to use (can be null)
721      * @exception NoSuchProviderException thrown when the class cannot be
722      * found or when it does not have the correct constructor
723      * (Session, URLName), or if it is not derived from
724      * Service.
725      */

726     private Object JavaDoc getService(Provider JavaDoc provider, URLName JavaDoc url)
727                     throws NoSuchProviderException JavaDoc {
728     // need a provider and url
729
if (provider == null) {
730         throw new NoSuchProviderException JavaDoc("null");
731     }
732
733     // create a url if needed
734
if (url == null) {
735         url = new URLName JavaDoc(provider.getProtocol(), null, -1,
736                   null, null, null);
737     }
738
739     Object JavaDoc service = null;
740     
741     // get the ClassLoader associated with the Authenticator
742
ClassLoader JavaDoc cl;
743     if (authenticator != null)
744         cl = authenticator.getClass().getClassLoader();
745     else
746         cl = this.getClass().getClassLoader();
747
748     // now load the class
749
Class JavaDoc serviceClass = null;
750     try {
751         // First try the "application's" class loader.
752
ClassLoader JavaDoc ccl = getContextClassLoader();
753         if (ccl != null)
754         try {
755             serviceClass = ccl.loadClass(provider.getClassName());
756         } catch (ClassNotFoundException JavaDoc ex) { }
757         if (serviceClass == null)
758         serviceClass = cl.loadClass(provider.getClassName());
759     } catch (Exception JavaDoc ex1) {
760         // That didn't work, now try the "system" class loader.
761
// (Need both of these because JDK 1.1 class loaders
762
// may not delegate to their parent class loader.)
763
try {
764         serviceClass = Class.forName(provider.getClassName());
765         } catch (Exception JavaDoc ex) {
766         // Nothing worked, give up.
767
if (debug) ex.printStackTrace(getDebugOut());
768         throw new NoSuchProviderException JavaDoc(provider.getProtocol());
769         }
770     }
771
772     // construct an instance of the class
773
try {
774         Class JavaDoc[] c = {javax.mail.Session JavaDoc.class, javax.mail.URLName JavaDoc.class};
775         Constructor cons = serviceClass.getConstructor(c);
776
777         Object JavaDoc[] o = {this, url};
778         service = cons.newInstance(o);
779
780     } catch (Exception JavaDoc ex) {
781         if (debug) ex.printStackTrace(getDebugOut());
782         throw new NoSuchProviderException JavaDoc(provider.getProtocol());
783     }
784
785     return service;
786     }
787
788     /**
789      * Save a PasswordAuthentication for this (store or transport) URLName.
790      * If pw is null the entry corresponding to the URLName is removed.
791      * <p>
792      * This is normally used only by the store or transport implementations
793      * to allow authentication information to be shared among multiple
794      * uses of a session.
795      */

796     public void setPasswordAuthentication(URLName JavaDoc url,
797                       PasswordAuthentication JavaDoc pw) {
798     if (pw == null)
799         authTable.remove(url);
800     else
801         authTable.put(url, pw);
802     }
803
804     /**
805      * Return any saved PasswordAuthentication for this (store or transport)
806      * URLName. Normally used only by store or transport implementations.
807      *
808      * @return the PasswordAuthentication corresponding to the URLName
809      */

810     public PasswordAuthentication JavaDoc getPasswordAuthentication(URLName JavaDoc url) {
811     return (PasswordAuthentication JavaDoc)authTable.get(url);
812     }
813
814     /**
815      * Call back to the application to get the needed user name and password.
816      * The application should put up a dialog something like:
817      * <p> <pre>
818      * Connecting to &lt;protocol&gt; mail service on host &lt;addr&gt;, port &lt;port&gt;.
819      * &lt;prompt&gt;
820      *
821      * User Name: &lt;defaultUserName&gt;
822      * Password:
823      * </pre>
824      *
825      * @param addr InetAddress of the host. may be null.
826      * @param protocol protocol scheme (e.g. imap, pop3, etc.)
827      * @param prompt any additional String to show as part of
828      * the prompt; may be null.
829      * @param defaultUserName the default username. may be null.
830      * @return the authentication which was collected by the authenticator;
831      * may be null.
832      */

833     public PasswordAuthentication JavaDoc requestPasswordAuthentication(
834     InetAddress addr, int port,
835     String JavaDoc protocol, String JavaDoc prompt, String JavaDoc defaultUserName) {
836
837     if (authenticator != null) {
838         return authenticator.requestPasswordAuthentication(
839         addr, port, protocol, prompt, defaultUserName);
840     } else {
841         return null;
842     }
843     }
844
845     /**
846      * Returns the Properties object associated with this Session
847      *
848      * @return Properties object
849      */

850     public Properties JavaDoc getProperties() {
851     return props;
852     }
853
854     /**
855      * Returns the value of the specified property. Returns null
856      * if this property does not exist.
857      *
858      * @return String that is the property value
859      */

860     public String JavaDoc getProperty(String JavaDoc name) {
861     return props.getProperty(name);
862     }
863
864     /**
865      * Load the protocol providers config files.
866      */

867     private void loadProviders(Class JavaDoc cl) {
868     StreamLoader loader = new StreamLoader() {
869         public void load(InputStream is) throws IOException {
870         loadProvidersFromStream(is);
871         }
872     };
873
874     // load system-wide javamail.providers from the <java.home>/lib dir
875
try {
876         String JavaDoc res = System.getProperty("java.home") +
877                 File.separator + "lib" +
878                 File.separator + "javamail.providers";
879         loadFile(res, loader);
880     } catch (SecurityException JavaDoc sex) {
881         if (debug)
882         pr("DEBUG: can't get java.home: " + sex);
883     }
884
885     // load the META-INF/javamail.providers file supplied by an application
886
loadAllResources("META-INF/javamail.providers", cl, loader);
887
888     // load default META-INF/javamail.default.providers from mail.jar file
889
loadResource("/META-INF/javamail.default.providers", cl, loader);
890
891     if (providers.size() == 0) {
892         if (debug)
893         pr("DEBUG: failed to load any providers, using defaults");
894         // failed to load any providers, initialize with our defaults
895
addProvider(new Provider JavaDoc(Provider.Type.STORE,
896             "imap", "com.sun.mail.imap.IMAPStore",
897             "Sun Microsystems, Inc.", version));
898         addProvider(new Provider JavaDoc(Provider.Type.STORE,
899             "imaps", "com.sun.mail.imap.IMAPSSLStore",
900             "Sun Microsystems, Inc.", version));
901         addProvider(new Provider JavaDoc(Provider.Type.STORE,
902             "pop3", "com.sun.mail.pop3.POP3Store",
903             "Sun Microsystems, Inc.", version));
904         addProvider(new Provider JavaDoc(Provider.Type.STORE,
905             "pop3s", "com.sun.mail.pop3.POP3SSLStore",
906             "Sun Microsystems, Inc.", version));
907         addProvider(new Provider JavaDoc(Provider.Type.TRANSPORT,
908             "smtp", "com.sun.mail.smtp.SMTPTransport",
909             "Sun Microsystems, Inc.", version));
910         addProvider(new Provider JavaDoc(Provider.Type.TRANSPORT,
911             "smtps", "com.sun.mail.smtp.SMTPSSLTransport",
912             "Sun Microsystems, Inc.", version));
913     }
914
915     if (debug) {
916         // dump the output of the tables for debugging
917
pr("DEBUG: Tables of loaded providers");
918         pr("DEBUG: Providers Listed By Class Name: " +
919            providersByClassName.toString());
920         pr("DEBUG: Providers Listed By Protocol: " +
921            providersByProtocol.toString());
922     }
923     }
924
925     private void loadProvidersFromStream(InputStream is)
926                 throws IOException {
927     if (is != null) {
928         LineInputStream lis = new LineInputStream(is);
929         String JavaDoc currLine;
930
931         // load and process one line at a time using LineInputStream
932
while ((currLine = lis.readLine()) != null) {
933
934         if (currLine.startsWith("#"))
935             continue;
936         Provider.Type JavaDoc type = null;
937         String JavaDoc protocol = null, className = null;
938         String JavaDoc vendor = null, version = null;
939             
940         // separate line into key-value tuples
941
StringTokenizer JavaDoc tuples = new StringTokenizer JavaDoc(currLine,";");
942         while (tuples.hasMoreTokens()) {
943             String JavaDoc currTuple = tuples.nextToken().trim();
944             
945             // set the value of each attribute based on its key
946
int sep = currTuple.indexOf("=");
947             if (currTuple.startsWith("protocol=")) {
948             protocol = currTuple.substring(sep+1);
949             } else if (currTuple.startsWith("type=")) {
950             String JavaDoc strType = currTuple.substring(sep+1);
951             if (strType.equalsIgnoreCase("store")) {
952                 type = Provider.Type.STORE;
953             } else if (strType.equalsIgnoreCase("transport")) {
954                 type = Provider.Type.TRANSPORT;
955                 }
956             } else if (currTuple.startsWith("class=")) {
957             className = currTuple.substring(sep+1);
958             } else if (currTuple.startsWith("vendor=")) {
959             vendor = currTuple.substring(sep+1);
960             } else if (currTuple.startsWith("version=")) {
961             version = currTuple.substring(sep+1);
962             }
963         }
964
965         // check if a valid Provider; else, continue
966
if (type == null || protocol == null || className == null
967             || protocol.length() <= 0 || className.length() <= 0) {
968             
969             if (debug)
970             pr("DEBUG: Bad provider entry: " + currLine);
971             continue;
972         }
973         Provider JavaDoc provider = new Provider JavaDoc(type, protocol, className,
974                              vendor, version);
975
976         // add the newly-created Provider to the lookup tables
977
addProvider(provider);
978         }
979     }
980     }
981
982     /**
983      * Add a provider to the session.
984      *
985      * @param provider the provider to add
986      * @since JavaMail 1.4
987      */

988     public synchronized void addProvider(Provider JavaDoc provider) {
989     providers.addElement(provider);
990     providersByClassName.put(provider.getClassName(), provider);
991     if (!providersByProtocol.containsKey(provider.getProtocol()))
992         providersByProtocol.put(provider.getProtocol(), provider);
993     }
994
995     // load maps in reverse order of preference so that the preferred
996
// map is loaded last since its entries will override the previous ones
997
private void loadAddressMap(Class JavaDoc cl) {
998     StreamLoader loader = new StreamLoader() {
999         public void load(InputStream is) throws IOException {
1000        addressMap.load(is);
1001        }
1002    };
1003
1004    // load default META-INF/javamail.default.address.map from mail.jar
1005
loadResource("/META-INF/javamail.default.address.map", cl, loader);
1006
1007    // load the META-INF/javamail.address.map file supplied by an app
1008
loadAllResources("META-INF/javamail.address.map", cl, loader);
1009
1010    // load system-wide javamail.address.map from the <java.home>/lib dir
1011
try {
1012        String JavaDoc res = System.getProperty("java.home") +
1013                File.separator + "lib" +
1014                File.separator + "javamail.address.map";
1015        loadFile(res, loader);
1016    } catch (SecurityException JavaDoc sex) {
1017        if (debug)
1018        pr("DEBUG: can't get java.home: " + sex);
1019    }
1020
1021    if (addressMap.isEmpty()) {
1022        if (debug)
1023        pr("DEBUG: failed to load address map, using defaults");
1024        addressMap.put("rfc822", "smtp");
1025    }
1026    }
1027
1028    /**
1029     * Set the default transport protocol to use for addresses of
1030     * the specified type. Normally the default is set by the
1031     * <code>javamail.default.address.map</code> or
1032     * <code>javamail.address.map</code> files or resources.
1033     *
1034     * @param addresstype type of address
1035     * @param protocol name of protocol
1036     * @see #getTransport(Address)
1037     * @since JavaMail 1.4
1038     */

1039    public synchronized void setProtocolForAddress(String JavaDoc addresstype,
1040                String JavaDoc protocol) {
1041    if (protocol == null)
1042        addressMap.remove(addresstype);
1043    else
1044        addressMap.put(addresstype, protocol);
1045    }
1046
1047    /**
1048     * Load from the named file.
1049     */

1050    private void loadFile(String JavaDoc name, StreamLoader loader) {
1051    InputStream clis = null;
1052    try {
1053        clis = new BufferedInputStream(new FileInputStream(name));
1054        if (clis != null) {
1055        loader.load(clis);
1056        if (debug)
1057            pr("DEBUG: successfully loaded file: " + name);
1058        } else {
1059        if (debug)
1060            pr("DEBUG: not loading file: " + name);
1061        }
1062    } catch (IOException e) {
1063        if (debug)
1064        pr("DEBUG: " + e);
1065    } catch (SecurityException JavaDoc sex) {
1066        if (debug)
1067        pr("DEBUG: " + sex);
1068    } finally {
1069        try {
1070        if (clis != null)
1071            clis.close();
1072        } catch (IOException ex) { } // ignore it
1073
}
1074    }
1075
1076    /**
1077     * Load from the named resource.
1078     */

1079    private void loadResource(String JavaDoc name, Class JavaDoc cl, StreamLoader loader) {
1080    InputStream clis = null;
1081    try {
1082        clis = getResourceAsStream(cl, name);
1083        if (clis != null) {
1084        loader.load(clis);
1085        if (debug)
1086            pr("DEBUG: successfully loaded resource: " + name);
1087        } else {
1088        if (debug)
1089            pr("DEBUG: not loading resource: " + name);
1090        }
1091    } catch (IOException e) {
1092        if (debug)
1093        pr("DEBUG: " + e);
1094    } catch (SecurityException JavaDoc sex) {
1095        if (debug)
1096        pr("DEBUG: " + sex);
1097    } finally {
1098        try {
1099        if (clis != null)
1100            clis.close();
1101        } catch (IOException ex) { } // ignore it
1102
}
1103    }
1104
1105    /**
1106     * Load all of the named resource.
1107     */

1108    private void loadAllResources(String JavaDoc name, Class JavaDoc cl, StreamLoader loader) {
1109    boolean anyLoaded = false;
1110    try {
1111        URL[] urls;
1112        ClassLoader JavaDoc cld = null;
1113        // First try the "application's" class loader.
1114
cld = getContextClassLoader();
1115        if (cld == null)
1116        cld = cl.getClassLoader();
1117        if (cld != null)
1118        urls = getResources(cld, name);
1119        else
1120        urls = getSystemResources(name);
1121        if (urls != null) {
1122        for (int i = 0; i < urls.length; i++) {
1123            URL url = urls[i];
1124            InputStream clis = null;
1125            if (debug)
1126            pr("DEBUG: URL " + url);
1127            try {
1128            clis = openStream(url);
1129            if (clis != null) {
1130                loader.load(clis);
1131                anyLoaded = true;
1132                if (debug)
1133                pr("DEBUG: successfully loaded resource: " +
1134                    url);
1135            } else {
1136                if (debug)
1137                pr("DEBUG: not loading resource: " + url);
1138            }
1139            } catch (IOException ioex) {
1140            if (debug)
1141                pr("DEBUG: " + ioex);
1142            } catch (SecurityException JavaDoc sex) {
1143            if (debug)
1144                pr("DEBUG: " + sex);
1145            } finally {
1146            try {
1147                if (clis != null)
1148                clis.close();
1149            } catch (IOException cex) { }
1150            }
1151        }
1152        }
1153    } catch (Exception JavaDoc ex) {
1154        if (debug)
1155        pr("DEBUG: " + ex);
1156    }
1157
1158    // if failed to load anything, fall back to old technique, just in case
1159
if (!anyLoaded) {
1160        if (debug)
1161        pr("DEBUG: !anyLoaded");
1162        loadResource("/" + name, cl, loader);
1163    }
1164    }
1165
1166    private void pr(String JavaDoc str) {
1167    getDebugOut().println(str);
1168    }
1169
1170    /*
1171     * Following are security related methods that work on JDK 1.2 or newer.
1172     */

1173
1174    private static ClassLoader JavaDoc getContextClassLoader() {
1175    return (ClassLoader JavaDoc)
1176        AccessController.doPrivileged(new PrivilegedAction() {
1177        public Object JavaDoc run() {
1178        ClassLoader JavaDoc cl = null;
1179        try {
1180            cl = Thread.currentThread().getContextClassLoader();
1181        } catch (SecurityException JavaDoc ex) { }
1182        return cl;
1183        }
1184    });
1185    }
1186
1187    private static InputStream getResourceAsStream(final Class JavaDoc c,
1188                final String JavaDoc name) throws IOException {
1189    try {
1190        return (InputStream)
1191        AccessController.doPrivileged(new PrivilegedExceptionAction() {
1192            public Object JavaDoc run() throws IOException {
1193            return c.getResourceAsStream(name);
1194            }
1195        });
1196    } catch (PrivilegedActionException e) {
1197        throw (IOException)e.getException();
1198    }
1199    }
1200
1201    private static URL[] getResources(final ClassLoader JavaDoc cl, final String JavaDoc name) {
1202    return (URL[])
1203        AccessController.doPrivileged(new PrivilegedAction() {
1204        public Object JavaDoc run() {
1205        URL[] ret = null;
1206        try {
1207            Vector JavaDoc v = new Vector JavaDoc();
1208            Enumeration JavaDoc e = cl.getResources(name);
1209            while (e != null && e.hasMoreElements()) {
1210            URL url = (URL)e.nextElement();
1211            if (url != null)
1212                v.addElement(url);
1213            }
1214            if (v.size() > 0) {
1215            ret = new URL[v.size()];
1216            v.copyInto(ret);
1217            }
1218        } catch (IOException ioex) {
1219        } catch (SecurityException JavaDoc ex) { }
1220        return ret;
1221        }
1222    });
1223    }
1224
1225    private static URL[] getSystemResources(final String JavaDoc name) {
1226    return (URL[])
1227        AccessController.doPrivileged(new PrivilegedAction() {
1228        public Object JavaDoc run() {
1229        URL[] ret = null;
1230        try {
1231            Vector JavaDoc v = new Vector JavaDoc();
1232            Enumeration JavaDoc e = ClassLoader.getSystemResources(name);
1233            while (e != null && e.hasMoreElements()) {
1234            URL url = (URL)e.nextElement();
1235            if (url != null)
1236                v.addElement(url);
1237            }
1238            if (v.size() > 0) {
1239            ret = new URL[v.size()];
1240            v.copyInto(ret);
1241            }
1242        } catch (IOException ioex) {
1243        } catch (SecurityException JavaDoc ex) { }
1244        return ret;
1245        }
1246    });
1247    }
1248
1249    private static InputStream openStream(final URL url) throws IOException {
1250    try {
1251        return (InputStream)
1252        AccessController.doPrivileged(new PrivilegedExceptionAction() {
1253            public Object JavaDoc run() throws IOException {
1254            return url.openStream();
1255            }
1256        });
1257    } catch (PrivilegedActionException e) {
1258        throw (IOException)e.getException();
1259    }
1260    }
1261}
1262
1263/**
1264 * Support interface to generalize
1265 * code that loads resources from stream.
1266 */

1267interface StreamLoader {
1268    public void load(InputStream is) throws IOException;
1269}
1270
Popular Tags