Skip to content

Package: Session

Session

nameinstructionbranchcomplexitylinemethod
Session(Properties, Authenticator)
M: 82 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 21 C: 0
0%
M: 1 C: 0
0%
addProvider(Provider)
M: 26 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
containsDefaultProvider(Provider)
M: 30 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 5 C: 0
0%
M: 1 C: 0
0%
getContextClassLoader()
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getDebug()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getDebugOut()
M: 8 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getDefaultInstance(Properties)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getDefaultInstance(Properties, Authenticator)
M: 41 C: 0
0%
M: 12 C: 0
0%
M: 7 C: 0
0%
M: 14 C: 0
0%
M: 1 C: 0
0%
getEventQueue()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getFolder(URLName)
M: 10 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getInstance(Properties)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getInstance(Properties, Authenticator)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getPasswordAuthentication(URLName)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getProperties()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getProperty(String)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getProvider(String)
M: 97 C: 0
0%
M: 14 C: 0
0%
M: 8 C: 0
0%
M: 16 C: 0
0%
M: 1 C: 0
0%
getProviders()
M: 12 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getResourceAsStream(Class, String)
M: 13 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getResources(ClassLoader, String)
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getService(Provider, URLName, Class)
M: 170 C: 0
0%
M: 16 C: 0
0%
M: 9 C: 0
0%
M: 40 C: 0
0%
M: 1 C: 0
0%
getStore()
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getStore(Provider)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getStore(Provider, URLName)
M: 18 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getStore(String)
M: 12 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getStore(URLName)
M: 12 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getStreamProvider()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getSystemResources(String)
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getTransport()
M: 26 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
getTransport(Address)
M: 44 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
getTransport(Provider)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getTransport(Provider, URLName)
M: 18 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getTransport(String)
M: 12 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getTransport(URLName)
M: 12 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
initLogger()
M: 13 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
loadAddressMap(Class)
M: 46 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 10 C: 0
0%
M: 1 C: 0
0%
loadAllResources(String, Class, StreamLoader)
M: 111 C: 0
0%
M: 14 C: 0
0%
M: 8 C: 0
0%
M: 33 C: 0
0%
M: 1 C: 0
0%
loadFile(String, StreamLoader)
M: 65 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 15 C: 0
0%
M: 1 C: 0
0%
loadProviders(Class)
M: 175 C: 0
0%
M: 14 C: 0
0%
M: 8 C: 0
0%
M: 31 C: 0
0%
M: 1 C: 0
0%
loadProvidersFromStream(InputStream)
M: 151 C: 0
0%
M: 34 C: 0
0%
M: 18 C: 0
0%
M: 37 C: 0
0%
M: 1 C: 0
0%
loadResource(String, Class, StreamLoader, boolean)
M: 47 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 15 C: 0
0%
M: 1 C: 0
0%
openStream(URL)
M: 12 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
requestPasswordAuthentication(InetAddress, int, String, String, String)
M: 14 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
setDebug(boolean)
M: 12 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
setDebugOut(PrintStream)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
setPasswordAuthentication(URLName, PasswordAuthentication)
M: 15 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
setProtocolForAddress(String, String)
M: 15 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
setProvider(Provider)
M: 39 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
static {...}
M: 15 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 1997, 2022 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 java.io.BufferedInputStream;
20: import java.io.File;
21: import java.io.FileInputStream;
22: import java.io.FileNotFoundException;
23: import java.io.IOException;
24: import java.io.InputStream;
25: import java.io.PrintStream;
26: import java.lang.annotation.Annotation;
27: import java.lang.reflect.Constructor;
28: import java.net.InetAddress;
29: import java.net.URL;
30: import java.security.AccessController;
31: import java.security.PrivilegedAction;
32: import java.security.PrivilegedActionException;
33: import java.security.PrivilegedExceptionAction;
34: import java.util.ArrayList;
35: import java.util.Collections;
36: import java.util.HashMap;
37: import java.util.Hashtable;
38: import java.util.List;
39: import java.util.Map;
40: import java.util.Properties;
41: import java.util.ServiceLoader;
42: import java.util.StringTokenizer;
43: import java.util.concurrent.Executor;
44: import java.util.logging.Level;
45:
46: import jakarta.mail.util.LineInputStream;
47: import jakarta.mail.util.StreamProvider;
48:
49: /**
50: * The Session class represents a mail session and is not subclassed.
51: * It collects together properties and defaults used by the mail API's.
52: * A single default session can be shared by multiple applications on the
53: * desktop. Unshared sessions can also be created. <p>
54: *
55: * The Session class provides access to the protocol providers that
56: * implement the <code>Store</code>, <code>Transport</code>, and related
57: * classes. The protocol providers are configured using the following files:
58: * <ul>
59: * <li> <code>javamail.providers</code> and
60: *         <code>javamail.default.providers</code> </li>
61: * <li> <code>javamail.address.map</code> and
62: *         <code>javamail.default.address.map</code> </li>
63: * </ul>
64: * <p>
65: * Each <code>javamail.</code><i>X</i> resource file is searched for using
66: * three methods in the following order:
67: * <ol>
68: * <li> <code><i>java.home</i>/<i>conf</i>/javamail.</code><i>X</i> </li>
69: * <li> <code>META-INF/javamail.</code><i>X</i> </li>
70: * <li> <code>META-INF/javamail.default.</code><i>X</i> </li>
71: * </ol>
72: * <p>
73: * (Where <i>java.home</i> is the value of the "java.home" System property
74: * and <i>conf</i> is the directory named "conf" if it exists,
75: * otherwise the directory named "lib"; the "conf" directory was
76: * introduced in JDK 1.9.)
77: * <p>
78: * The first method allows the user to include their own version of the
79: * resource file by placing it in the <i>conf</i> directory where the
80: * <code>java.home</code> property points. The second method allows an
81: * application that uses the Jakarta Mail APIs to include their own resource
82: * files in their application's or jar file's <code>META-INF</code>
83: * directory. The <code>javamail.default.</code><i>X</i> default files
84: * are part of the Jakarta Mail <code>mail.jar</code> file and should not be
85: * supplied by users. <p>
86: *
87: * File location depends upon how the <code>ClassLoader</code> method
88: * <code>getResource</code> is implemented. Usually, the
89: * <code>getResource</code> method searches through CLASSPATH until it
90: * finds the requested file and then stops. <p>
91: *
92: * The ordering of entries in the resource files matters. If multiple
93: * entries exist, the first entries take precedence over the later
94: * entries. For example, the first IMAP provider found will be set as the
95: * default IMAP implementation until explicitly changed by the
96: * application. The user- or system-supplied resource files augment, they
97: * do not override, the default files included with the Jakarta Mail APIs.
98: * This means that all entries in all files loaded will be available. <p>
99: *
100: * <b><code>javamail.providers</code></b> and
101: * <b><code>javamail.default.providers</code></b><p>
102: *
103: * These resource files specify the stores and transports that are
104: * available on the system, allowing an application to "discover" what
105: * store and transport implementations are available. The protocol
106: * implementations are listed one per line. The file format defines four
107: * attributes that describe a protocol implementation. Each attribute is
108: * an "="-separated name-value pair with the name in lowercase. Each
109: * name-value pair is semi-colon (";") separated. The following names
110: * are defined.
111: *
112: * <table border=1>
113: * <caption>
114: * Attribute Names in Providers Files
115: * </caption>
116: * <tr>
117: * <th>Name</th><th>Description</th>
118: * </tr>
119: * <tr>
120: * <td>protocol</td>
121: * <td>Name assigned to protocol.
122: * For example, <code>smtp</code> for Transport.</td>
123: * </tr>
124: * <tr>
125: * <td>type</td>
126: * <td>Valid entries are <code>store</code> and <code>transport</code>.</td>
127: * </tr>
128: * <tr>
129: * <td>class</td>
130: * <td>Class name that implements this protocol.</td>
131: * </tr>
132: * <tr>
133: * <td>vendor</td>
134: * <td>Optional string identifying the vendor.</td>
135: * </tr>
136: * <tr>
137: * <td>version</td>
138: * <td>Optional string identifying the version.</td>
139: * </tr>
140: * </table><p>
141: *
142: * Here's an example of <code>META-INF/javamail.default.providers</code>
143: * file contents:
144: * <pre>
145: * protocol=imap; type=store; class=com.sun.mail.imap.IMAPStore; vendor=Oracle;
146: * protocol=smtp; type=transport; class=com.sun.mail.smtp.SMTPTransport; vendor=Oracle;
147: * </pre><p>
148: *
149: * The current implementation also supports configuring providers using
150: * the Java SE {@link java.util.ServiceLoader ServiceLoader} mechanism.
151: * When creating your own provider, create a {@link Provider} subclass,
152: * for example:
153: * <pre>
154: * package com.example;
155: *
156: * import jakarta.mail.Provider;
157: *
158: * public class MyProvider extends Provider {
159: * public MyProvider() {
160: * super(Provider.Type.STORE, "myprot", MyStore.class.getName(),
161: * "Example", null);
162: * }
163: * }
164: * </pre>
165: * Then include a file named <code>META-INF/services/jakarta.mail.Provider</code>
166: * in your jar file that lists the name of your Provider class:
167: * <pre>
168: * com.example.MyProvider
169: * </pre>
170: * <p>
171: *
172: * <b><code>javamail.address.map</code></b> and
173: * <b><code>javamail.default.address.map</code></b><p>
174: *
175: * These resource files map transport address types to the transport
176: * protocol. The <code>getType</code> method of
177: * <code>jakarta.mail.Address</code> returns the address type. The
178: * <code>javamail.address.map</code> file maps the transport type to the
179: * protocol. The file format is a series of name-value pairs. Each key
180: * name should correspond to an address type that is currently installed
181: * on the system; there should also be an entry for each
182: * <code>jakarta.mail.Address</code> implementation that is present if it is
183: * to be used. For example, the
184: * <code>jakarta.mail.internet.InternetAddress</code> method
185: * <code>getType</code> returns "rfc822". Each referenced protocol should
186: * be installed on the system. For the case of <code>news</code>, below,
187: * the client should install a Transport provider supporting the nntp
188: * protocol. <p>
189: *
190: * Here are the typical contents of a <code>javamail.address.map</code> file:
191: * <pre>
192: * rfc822=smtp
193: * news=nntp
194: * </pre>
195: *
196: * @author John Mani
197: * @author Bill Shannon
198: * @author Max Spivak
199: */
200:
201: public final class Session {
202:
203:         // Support legacy @DefaultProvider
204:         private static final String DEFAULT_PROVIDER = "com.sun.mail.util.DefaultProvider";
205:
206:         private final StreamProvider streamProvider;
207: private final Properties props;
208: private final Authenticator authenticator;
209: private final Hashtable<URLName, PasswordAuthentication> authTable
210:          = new Hashtable<>();
211: private boolean debug = false;
212: private PrintStream out;                        // debug output stream
213: private MailLogger logger;
214: private final List<Provider> providers = new ArrayList<>();
215: private final Map<String, Provider> providersByProtocol = new HashMap<>();
216: private final Map<String, Provider> providersByClassName = new HashMap<>();
217: private final Properties addressMap = new Properties();
218:                                                 // maps type to protocol
219: // the queue of events to be delivered, if mail.event.scope===session
220: private final EventQueue q;
221:
222: // The default session.
223: private static Session defaultSession = null;
224:
225: private static final String confDir;
226:
227: static {
228:                 String dir = null;
229:                 try {
230:                  dir = AccessController.doPrivileged(
231:                         new PrivilegedAction<String>() {
232:                          @Override
233:                          public String run() {
234:                                 String home = System.getProperty("java.home");
235:                                 String newdir = home + File.separator + "conf";
236:                                 File conf = new File(newdir);
237:                                 if (conf.exists())
238:                                  return newdir + File.separator;
239:                                 else
240:                                  return home + File.separator +
241:                                          "lib" + File.separator;
242:                          }
243:                         });
244:                 } catch (Exception ex) {
245:                  // ignore any exceptions
246:                 }
247:                 confDir = dir;
248: }
249:
250: // Constructor is not public
251: private Session(Properties props, Authenticator authenticator) {
252:                 this.props = props;
253:                 this.authenticator = authenticator;
254:                 this.streamProvider = StreamProvider.provider();
255:         
256:•                if (Boolean.valueOf(props.getProperty("mail.debug")).booleanValue())
257:                  debug = true;
258:         
259:                 initLogger();
260:                 logger.log(Level.CONFIG, "Jakarta Mail version {0}", Version.version);
261:         
262:                 // get the Class associated with the Authenticator
263:                 Class<?> cl;
264:•                if (authenticator != null) {
265:                  cl = authenticator.getClass();
266:                 } else {
267:                  // Use implementation class, because that class loader has access to jakarta.mail module and implementation resources
268:                  cl = streamProvider.getClass();
269:                 }
270:                 // load the resources
271:                 loadProviders(cl);
272:                 loadAddressMap(cl);
273:                 q = new EventQueue((Executor)props.get("mail.event.executor"));
274: }
275:
276: /**
277: * Get the stream provider instance of the session.
278: *
279: * @return the stream provider
280: *
281: * @since JavaMail 2.1
282: */
283: public StreamProvider getStreamProvider() {
284: return streamProvider;
285: }
286:
287: private final synchronized void initLogger() {
288:         logger = new MailLogger(this.getClass(), "DEBUG", debug, getDebugOut());
289: }
290:
291: /**
292: * Get a new Session object.
293: *
294: * @param        props        Properties object that hold relevant properties.<br>
295: * It is expected that the client supplies values
296: * for the properties listed in Appendix A of the
297: * Jakarta Mail spec (particularly mail.store.protocol,
298: * mail.transport.protocol, mail.host, mail.user,
299: * and mail.from) as the defaults are unlikely to
300: * work in all cases.
301: * @param        authenticator Authenticator object used to call back to
302: *                        the application when a user name and password is
303: *                        needed.
304: * @return                a new Session object
305: * @see        jakarta.mail.Authenticator
306: */
307: public static Session getInstance(Properties props, Authenticator authenticator) {
308:         return new Session(props, authenticator);
309: }
310:
311: /**
312: * Get a new Session object.
313: *
314: * @param        props        Properties object that hold relevant properties.<br>
315: * It is expected that the client supplies values
316: * for the properties listed in Appendix A of the
317: * Jakarta Mail spec (particularly mail.store.protocol,
318: * mail.transport.protocol, mail.host, mail.user,
319: * and mail.from) as the defaults are unlikely to
320: * work in all cases.
321: * @return                a new Session object
322: * @since                JavaMail 1.2
323: */
324: public static Session getInstance(Properties props) {
325:         return new Session(props, null);
326: }
327:
328: /**
329: * Get the default Session object. If a default has not yet been
330: * setup, a new Session object is created and installed as the
331: * default. <p>
332: *
333: * Since the default session is potentially available to all
334: * code executing in the same Java virtual machine, and the session
335: * can contain security sensitive information such as user names
336: * and passwords, access to the default session is restricted.
337: * The Authenticator object, which must be created by the caller,
338: * is used indirectly to check access permission. The Authenticator
339: * object passed in when the session is created is compared with
340: * the Authenticator object passed in to subsequent requests to
341: * get the default session. If both objects are the same, or are
342: * from the same ClassLoader, the request is allowed. Otherwise,
343: * it is denied. <p>
344: *
345: * Note that if the Authenticator object used to create the session
346: * is null, anyone can get the default session by passing in null. <p>
347: *
348: * Note also that the Properties object is used only the first time
349: * this method is called, when a new Session object is created.
350: * Subsequent calls return the Session object that was created by the
351: * first call, and ignore the passed Properties object. Use the
352: * <code>getInstance</code> method to get a new Session object every
353: * time the method is called. <p>
354: *
355: * Additional security Permission objects may be used to
356: * control access to the default session. <p>
357: *
358: * In the current implementation, if a SecurityManager is set, the
359: * caller must have the <code>RuntimePermission("setFactory")</code>
360: * permission.
361: *
362: * @param        props        Properties object. Used only if a new Session
363: *                        object is created.<br>
364: * It is expected that the client supplies values
365: * for the properties listed in Appendix A of the
366: * Jakarta Mail spec (particularly mail.store.protocol,
367: * mail.transport.protocol, mail.host, mail.user,
368: * and mail.from) as the defaults are unlikely to
369: * work in all cases.
370: * @param        authenticator Authenticator object. Used only if a
371: *                        new Session object is created. Otherwise,
372: *                        it must match the Authenticator used to create
373: *                        the Session.
374: * @return                the default Session object
375: */
376: public static synchronized Session getDefaultInstance(Properties props, Authenticator authenticator) {
377:•                if (defaultSession == null) {
378:                  SecurityManager security = System.getSecurityManager();
379:•                 if (security != null)
380:                         security.checkSetFactory();
381:                  defaultSession = new Session(props, authenticator);
382:                 } else {
383:                  // have to check whether caller is allowed to see default session
384:•                 if (defaultSession.authenticator == authenticator)
385:                                 // either same object or both null, either way OK
386:•                 else if (defaultSession.authenticator != null &&
387:                          authenticator != null &&
388:                          defaultSession.authenticator.getClass().getClassLoader() ==
389:•                                authenticator.getClass().getClassLoader())
390:                                 // both objects came from the same class loader, OK
391:                  else
392:                         // anything else is not allowed
393:                         throw new SecurityException("Access to default session denied");
394:                 }
395:         
396:                 return defaultSession;
397: }
398:
399: /**
400: * Get the default Session object. If a default has not yet been
401: * setup, a new Session object is created and installed as the
402: * default. <p>
403: *
404: * Note that a default session created with no Authenticator is
405: * available to all code executing in the same Java virtual
406: * machine, and the session can contain security sensitive
407: * information such as user names and passwords.
408: *
409: * @param        props        Properties object. Used only if a new Session
410: *                        object is created.<br>
411: * It is expected that the client supplies values
412: * for the properties listed in Appendix A of the
413: * Jakarta Mail spec (particularly mail.store.protocol,
414: * mail.transport.protocol, mail.host, mail.user,
415: * and mail.from) as the defaults are unlikely to
416: * work in all cases.
417: * @return                the default Session object
418: * @since                JavaMail 1.2
419: */
420: public static Session getDefaultInstance(Properties props) {
421: return getDefaultInstance(props, null);
422: }
423:
424: /**
425: * Set the debug setting for this Session.
426: * <p>
427: * Since the debug setting can be turned on only after the Session
428: * has been created, to turn on debugging in the Session
429: * constructor, set the property <code>mail.debug</code> in the
430: * Properties object passed in to the constructor to true. The
431: * value of the <code>mail.debug</code> property is used to
432: * initialize the per-Session debugging flag. Subsequent calls to
433: * the <code>setDebug</code> method manipulate the per-Session
434: * debugging flag and have no affect on the <code>mail.debug</code>
435: * property.
436: *
437: * @param debug        Debug setting
438: */
439: public synchronized void setDebug(boolean debug) {
440:                 this.debug = debug;
441:                 initLogger();
442:                 logger.log(Level.CONFIG, "setDebug: Jakarta Mail version {0}", Version.version);
443: }
444:
445: /**
446: * Get the debug setting for this Session.
447: *
448: * @return current debug setting
449: */
450: public synchronized boolean getDebug() {
451:         return debug;
452: }
453:
454: /**
455: * Set the stream to be used for debugging output for this session.
456: * If <code>out</code> is null, <code>System.out</code> will be used.
457: * Note that debugging output that occurs before any session is created,
458: * as a result of setting the <code>mail.debug</code> system property,
459: * will always be sent to <code>System.out</code>.
460: *
461: * @param        out        the PrintStream to use for debugging output
462: * @since                JavaMail 1.3
463: */
464: public synchronized void setDebugOut(PrintStream out) {
465:                 this.out = out;
466:                 initLogger();
467: }
468:
469: /**
470: * Returns the stream to be used for debugging output. If no stream
471: * has been set, <code>System.out</code> is returned.
472: *
473: * @return                the PrintStream to use for debugging output
474: * @since                JavaMail 1.3
475: */
476: public synchronized PrintStream getDebugOut() {
477:•                if (out == null)
478:                  return System.out;
479:                 else
480:                  return out;
481: }
482:
483: /**
484: * This method returns an array of all the implementations installed
485: * via the javamail.[default.]providers files that can
486: * be loaded using the ClassLoader available to this application.
487: *
488: * @return Array of configured providers
489: */
490: public synchronized Provider[] getProviders() {
491:                 Provider[] _providers = new Provider[providers.size()];
492:                 providers.toArray(_providers);
493:                 return _providers;
494: }
495:
496: /**
497: * Returns the default Provider for the protocol
498: * specified. Checks mail.<protocol>.class property
499: * first and if it exists, returns the Provider
500: * associated with this implementation. If it doesn't exist,
501: * returns the Provider that appeared first in the
502: * configuration files. If an implementation for the protocol
503: * isn't found, throws NoSuchProviderException
504: *
505: * @param protocol Configured protocol (i.e. smtp, imap, etc)
506: * @return Currently configured Provider for the specified protocol
507: * @exception        NoSuchProviderException If a provider for the given
508: *                        protocol is not found.
509: */
510: public synchronized Provider getProvider(String protocol) throws NoSuchProviderException {
511:
512:•                if (protocol == null || protocol.length() <= 0) {
513:                  throw new NoSuchProviderException("Invalid protocol: null");
514:                 }
515:         
516:                 Provider _provider = null;
517:         
518:                 // check if the mail.<protocol>.class property exists
519:                 String _className = props.getProperty("mail."+protocol+".class");
520:•                if (_className != null) {
521:•                 if (logger.isLoggable(Level.FINE)) {
522:                         logger.fine("mail."+protocol+
523:                                          ".class property exists and points to " +
524:                                          _className);
525:                  }
526:                  _provider = providersByClassName.get(_className);
527:                 }
528:         
529:•                if (_provider != null) {
530:                  return _provider;
531:                 } else {
532:                  // returning currently default protocol in providersByProtocol
533:                  _provider = providersByProtocol.get(protocol);
534:                 }
535:         
536:•                if (_provider == null) {
537:                  throw new NoSuchProviderException("No provider for " + protocol);
538:                 } else {
539:•                 if (logger.isLoggable(Level.FINE)) {
540:                         logger.fine("getProvider() returning " + _provider.toString());
541:                  }
542:                  return _provider;
543:                 }
544: }
545:
546: /**
547: * Set the passed Provider to be the default implementation
548: * for the protocol in Provider.protocol overriding any previous values.
549: *
550: * @param provider Currently configured Provider which will be
551: * set as the default for the protocol
552: * @exception        NoSuchProviderException If the provider passed in
553: *                        is invalid.
554: */
555: public synchronized void setProvider(Provider provider)
556:                                 throws NoSuchProviderException {
557:•                if (provider == null) {
558:                  throw new NoSuchProviderException("Can't set null provider");
559:                 }
560:                 providersByProtocol.put(provider.getProtocol(), provider);
561:                 providersByClassName.put(provider.getClassName(), provider);
562:                 props.put("mail." + provider.getProtocol() + ".class", provider.getClassName());
563: }
564:
565:
566: /**
567: * Get a Store object that implements this user's desired Store
568: * protocol. The <code>mail.store.protocol</code> property specifies the
569: * desired protocol. If an appropriate Store object is not obtained,
570: * NoSuchProviderException is thrown
571: *
572: * @return                 a Store object
573: * @exception        NoSuchProviderException If a provider for the given
574: *                        protocol is not found.
575: */
576: public Store getStore() throws NoSuchProviderException {
577:         return getStore(getProperty("mail.store.protocol"));
578: }
579:
580: /**
581: * Get a Store object that implements the specified protocol. If an
582: * appropriate Store object cannot be obtained,
583: * NoSuchProviderException is thrown.
584: *
585: * @param         protocol        the Store protocol
586: * @return                a Store object
587: * @exception        NoSuchProviderException If a provider for the given
588: *                        protocol is not found.
589: */
590: public Store getStore(String protocol) throws NoSuchProviderException {
591:         return getStore(new URLName(protocol, null, -1, null, null, null));
592: }
593:
594:
595: /**
596: * Get a Store object for the given URLName. If the requested Store
597: * object cannot be obtained, NoSuchProviderException is thrown.
598: *
599: * The "scheme" part of the URL string (Refer RFC 1738) is used
600: * to locate the Store protocol. <p>
601: *
602: * @param        url        URLName that represents the desired Store
603: * @return                a closed Store object
604: * @see                #getFolder(URLName)
605: * @see                jakarta.mail.URLName
606: * @exception        NoSuchProviderException If a provider for the given
607: *                        URLName is not found.
608: */
609: public Store getStore(URLName url) throws NoSuchProviderException {
610:                 String protocol = url.getProtocol();
611:                 Provider p = getProvider(protocol);
612:                 return getStore(p, url);
613: }
614:
615: /**
616: * Get an instance of the store specified by Provider. Instantiates
617: * the store and returns it.
618: *
619: * @param provider Store Provider that will be instantiated
620: * @return Instantiated Store
621: * @exception        NoSuchProviderException If a provider for the given
622: *                        Provider is not found.
623: */
624: public Store getStore(Provider provider) throws NoSuchProviderException {
625:         return getStore(provider, null);
626: }
627:
628:
629: /**
630: * Get an instance of the store specified by Provider. If the URLName
631: * is not null, uses it, otherwise creates a new one. Instantiates
632: * the store and returns it. This is a private method used by
633: * getStore(Provider) and getStore(URLName)
634: *
635: * @param provider Store Provider that will be instantiated
636: * @param url URLName used to instantiate the Store
637: * @return Instantiated Store
638: * @exception        NoSuchProviderException If a provider for the given
639: *                        Provider/URLName is not found.
640: */
641: private Store getStore(Provider provider, URLName url) throws NoSuchProviderException {
642:
643:                 // make sure we have the correct type of provider
644:•                if (provider == null || provider.getType() != Provider.Type.STORE ) {
645:                  throw new NoSuchProviderException("invalid provider");
646:                 }
647:         
648:                 return getService(provider, url, Store.class);
649: }
650:
651: /**
652: * Get a closed Folder object for the given URLName. If the requested
653: * Folder object cannot be obtained, null is returned. <p>
654: *
655: * The "scheme" part of the URL string (Refer RFC 1738) is used
656: * to locate the Store protocol. The rest of the URL string (that is,
657: * the "schemepart", as per RFC 1738) is used by that Store
658: * in a protocol dependent manner to locate and instantiate the
659: * appropriate Folder object. <p>
660: *
661: * Note that RFC 1738 also specifies the syntax for the
662: * "schemepart" for IP-based protocols (IMAP4, POP3, etc.).
663: * Providers of IP-based mail Stores should implement that
664: * syntax for referring to Folders. <p>
665: *
666: * @param        url        URLName that represents the desired folder
667: * @return                Folder
668: * @see                #getStore(URLName)
669: * @see                jakarta.mail.URLName
670: * @exception        NoSuchProviderException If a provider for the given
671: *                        URLName is not found.
672: * @exception        MessagingException if the Folder could not be
673: *                        located or created.
674: */
675: public Folder getFolder(URLName url) throws MessagingException {
676:                 // First get the Store
677:                 Store store = getStore(url);
678:                 store.connect();
679:                 return store.getFolder(url);
680: }
681:
682: /**
683: * Get a Transport object that implements this user's desired
684: * Transport protcol. The <code>mail.transport.protocol</code> property
685: * specifies the desired protocol. If an appropriate Transport
686: * object cannot be obtained, MessagingException is thrown.
687: *
688: * @return                 a Transport object
689: * @exception        NoSuchProviderException If the provider is not found.
690: */
691: public Transport getTransport() throws NoSuchProviderException {
692:                 String prot = getProperty("mail.transport.protocol");
693:•                if (prot != null)
694:                  return getTransport(prot);
695:                 // if the property isn't set, use the protocol for "rfc822"
696:                 prot = (String)addressMap.get("rfc822");
697:•                if (prot != null)
698:                  return getTransport(prot);
699:                 return getTransport("smtp");        // if all else fails
700: }
701:
702: /**
703: * Get a Transport object that implements the specified protocol.
704: * If an appropriate Transport object cannot be obtained, null is
705: * returned.
706: *
707: * @param        protocol the Transport protocol
708: * @return                 a Transport object
709: * @exception        NoSuchProviderException If provider for the given
710: *                        protocol is not found.
711: */
712: public Transport getTransport(String protocol)
713:                                 throws NoSuchProviderException {
714:         return getTransport(new URLName(protocol, null, -1, null, null, null));
715: }
716:
717:
718: /**
719: * Get a Transport object for the given URLName. If the requested
720: * Transport object cannot be obtained, NoSuchProviderException is thrown.
721: *
722: * The "scheme" part of the URL string (Refer RFC 1738) is used
723: * to locate the Transport protocol. <p>
724: *
725: * @param        url        URLName that represents the desired Transport
726: * @return                a closed Transport object
727: * @see                jakarta.mail.URLName
728: * @exception        NoSuchProviderException If a provider for the given
729: *                        URLName is not found.
730: */
731: public Transport getTransport(URLName url) throws NoSuchProviderException {
732:                 String protocol = url.getProtocol();
733:                 Provider p = getProvider(protocol);
734:                 return getTransport(p, url);
735: }
736:
737: /**
738: * Get an instance of the transport specified in the Provider. Instantiates
739: * the transport and returns it.
740: *
741: * @param provider Transport Provider that will be instantiated
742: * @return Instantiated Transport
743: * @exception        NoSuchProviderException If provider for the given
744: *                        provider is not found.
745: */
746: public Transport getTransport(Provider provider) throws NoSuchProviderException {
747:         return getTransport(provider, null);
748: }
749:
750: /**
751: * Get a Transport object that can transport a Message of the
752: * specified address type.
753: *
754: * @param        address        an address for which a Transport is needed
755: * @return        A Transport object
756: * @see jakarta.mail.Address
757: * @exception        NoSuchProviderException If provider for the
758: *                        Address type is not found
759: */
760: public Transport getTransport(Address address) throws NoSuchProviderException {
761:
762:                 String transportProtocol;
763:                 transportProtocol =
764:                  getProperty("mail.transport.protocol." + address.getType());
765:•                if (transportProtocol != null)
766:                  return getTransport(transportProtocol);
767:                 transportProtocol = (String)addressMap.get(address.getType());
768:•                if (transportProtocol != null)
769:                  return getTransport(transportProtocol);
770:                 throw new NoSuchProviderException("No provider for Address type: " + address.getType());
771: }
772:
773: /**
774: * Get a Transport object using the given provider and urlname.
775: *
776: * @param        provider        the provider to use
777: * @param        url                urlname to use (can be null)
778: * @return A Transport object
779: * @exception        NoSuchProviderException        If no provider or the provider
780: *                        was the wrong class.        
781: */
782:
783: private Transport getTransport(Provider provider, URLName url) throws NoSuchProviderException {
784:                 // make sure we have the correct type of provider
785:•                if (provider == null || provider.getType() != Provider.Type.TRANSPORT) {
786:                  throw new NoSuchProviderException("invalid provider");
787:                 }
788:         
789:                 return getService(provider, url, Transport.class);
790: }
791:
792: /**
793: * Get a Service object. Needs a provider object, but will
794: * create a URLName if needed. It attempts to instantiate
795: * the correct class.
796: *
797: * @param provider        which provider to use
798: * @param url        which URLName to use (can be null)
799: * @param type        the service type (class)
800: * @exception        NoSuchProviderException        thrown when the class cannot be
801: *                        found or when it does not have the correct constructor
802: *                        (Session, URLName), or if it is not derived from
803: *                        Service.
804: */
805: private <T extends Service> T getService(Provider provider, URLName url, Class<T> type) throws NoSuchProviderException {
806:                 // need a provider and url
807:•                if (provider == null) {
808:                  throw new NoSuchProviderException("null");
809:                 }
810:         
811:                 // create a url if needed
812:•                if (url == null) {
813:                  url = new URLName(provider.getProtocol(), null, -1,
814:                                  null, null, null);
815:                 }
816:         
817:                 Object service = null;
818:                 
819:                 // get the ClassLoader associated with the Authenticator
820:                 ClassLoader cl;
821:•                if (authenticator != null)
822:                  cl = authenticator.getClass().getClassLoader();
823:                 else
824:                  cl = this.getClass().getClassLoader();
825:         
826:                 // now load the class
827:                 Class<?> serviceClass = null;
828:                 try {
829:                  // First try the "application's" class loader.
830:                  ClassLoader ccl = getContextClassLoader();
831:•                 if (ccl != null)
832:                         try {
833:                          serviceClass =
834:                                 Class.forName(provider.getClassName(), false, ccl);
835:                         } catch (ClassNotFoundException ex) {
836:                          // ignore it
837:                         }
838:•                 if (serviceClass == null || !type.isAssignableFrom(serviceClass))
839:                         serviceClass =
840:                          Class.forName(provider.getClassName(), false, cl);
841:         
842:•                 if (!type.isAssignableFrom(serviceClass))
843:                         throw new ClassCastException(
844:                                         type.getName() + " " + serviceClass.getName());
845:                 } catch (Exception ex1) {
846:                  // That didn't work, now try the "system" class loader.
847:                  // (Need both of these because JDK 1.1 class loaders
848:                  // may not delegate to their parent class loader.)
849:                  try {
850:                         serviceClass = Class.forName(provider.getClassName());
851:•                        if (!type.isAssignableFrom(serviceClass))
852:                          throw new ClassCastException(
853:                                         type.getName() + " " + serviceClass.getName());
854:                  } catch (Exception ex) {
855:                         // Nothing worked, give up.
856:                         logger.log(Level.FINE, "Exception loading provider", ex);
857:                         throw new NoSuchProviderException(provider.getProtocol());
858:                  }
859:                 }
860:         
861:                 // construct an instance of the class
862:                 try {
863:                  Class<?>[] c = {jakarta.mail.Session.class, jakarta.mail.URLName.class};
864:                  Constructor<?> cons = serviceClass.getConstructor(c);
865:         
866:                  Object[] o = {this, url};
867:                  service = cons.newInstance(o);
868:         
869:                 } catch (Exception ex) {
870:                  logger.log(Level.FINE, "Exception loading provider", ex);
871:                  throw new NoSuchProviderException(provider.getProtocol());
872:                 }
873:         
874:                 return type.cast(service);
875: }
876:
877: /**
878: * Save a PasswordAuthentication for this (store or transport) URLName.
879: * If pw is null the entry corresponding to the URLName is removed.
880: * <p>
881: * This is normally used only by the store or transport implementations
882: * to allow authentication information to be shared among multiple
883: * uses of a session.
884: *
885: * @param        url        the URLName
886: * @param        pw        the PasswordAuthentication to save
887: */
888: public void setPasswordAuthentication(URLName url, PasswordAuthentication pw) {
889:•                if (pw == null)
890:                  authTable.remove(url);
891:                 else
892:                  authTable.put(url, pw);
893: }
894:
895: /**
896: * Return any saved PasswordAuthentication for this (store or transport)
897: * URLName. Normally used only by store or transport implementations.
898: *
899: * @param        url        the URLName
900: * @return        the PasswordAuthentication corresponding to the URLName
901: */
902: public PasswordAuthentication getPasswordAuthentication(URLName url) {
903:         return authTable.get(url);
904: }
905:
906: /**
907: * Call back to the application to get the needed user name and password.
908: * The application should put up a dialog something like:
909: * <pre>
910: * Connecting to <protocol> mail service on host <addr>, port <port>.
911: * <prompt>
912: *
913: * User Name: <defaultUserName>
914: * Password:
915: * </pre>
916: *
917: * @param        addr                InetAddress of the host. may be null.
918: * @param        port                the port on the host
919: * @param        protocol        protocol scheme (e.g. imap, pop3, etc.)
920: * @param        prompt                any additional String to show as part of
921: * the prompt; may be null.
922: * @param        defaultUserName        the default username. may be null.
923: * @return        the authentication which was collected by the authenticator;
924: * may be null.
925: */
926: public PasswordAuthentication requestPasswordAuthentication(InetAddress addr, int port, String protocol, String prompt, String defaultUserName) {
927:•                if (authenticator != null) {
928:                  return authenticator.requestPasswordAuthentication(
929:                         addr, port, protocol, prompt, defaultUserName);
930:                 } else {
931:                  return null;
932:                 }
933: }
934:
935: /**
936: * Returns the Properties object associated with this Session
937: *
938: * @return                Properties object
939: */
940: public Properties getProperties() {
941:         return props;
942: }
943:
944: /**
945: * Returns the value of the specified property. Returns null
946: * if this property does not exist.
947: *
948: * @param        name        the property name
949: * @return                String that is the property value
950: */
951: public String getProperty(String name) {
952:         return props.getProperty(name);
953: }
954:
955: static boolean containsDefaultProvider(Provider provider) {
956:         Annotation[] annotations = provider.getClass().getDeclaredAnnotations();
957:•         for (Annotation annotation : annotations) {
958:•                 if (DEFAULT_PROVIDER.equals(annotation.annotationType().getName())) {
959:                         return true;
960:                 }
961:         }
962:         return false;
963: }
964:
965: /**
966: * Load the protocol providers config files.
967: */
968: private void loadProviders(Class<?> cl) {
969:                 StreamLoader loader = new StreamLoader() {
970:                  @Override
971:                  public void load(InputStream is) throws IOException {
972:                          loadProvidersFromStream(is);
973:                  }
974:                 };
975:         
976:                 // load system-wide javamail.providers from the
977:                 // <java.home>/{conf,lib} directory
978:                 try {
979:•                 if (confDir != null)
980:                         loadFile(confDir + "javamail.providers", loader);
981:                 } catch (SecurityException ex) {}
982:         
983:                 // next, add all the non-default services
984:                 ServiceLoader<Provider> sl = ServiceLoader.load(Provider.class);
985:•                for (Provider p : sl) {
986:•                 if (!containsDefaultProvider(p))
987:                          addProvider(p);
988:                 }
989:         
990:                 // load the META-INF/javamail.providers file supplied by an application
991:                 loadAllResources("META-INF/javamail.providers", cl, loader);
992:         
993:                 // load default META-INF/javamail.default.providers from mail.jar file
994:                 loadResource("/META-INF/javamail.default.providers", cl, loader, false);
995:         
996:                 // finally, add all the default services
997:                 sl = ServiceLoader.load(Provider.class);
998:•                for (Provider p : sl) {
999:•                 if (containsDefaultProvider(p))
1000:                          addProvider(p);
1001:                 }
1002:         
1003:                 /*
1004:                  * If we haven't loaded any providers, fake it.
1005:                  */
1006:•                if (providers.size() == 0) {
1007:                  logger.config("failed to load any providers, using defaults");
1008:                  // failed to load any providers, initialize with our defaults
1009:                  addProvider(new Provider(Provider.Type.STORE,
1010:                                 "imap", "com.sun.mail.imap.IMAPStore",
1011:                                 "Oracle", Version.version));
1012:                  addProvider(new Provider(Provider.Type.STORE,
1013:                                 "imaps", "com.sun.mail.imap.IMAPSSLStore",
1014:                                 "Oracle", Version.version));
1015:                  addProvider(new Provider(Provider.Type.STORE,
1016:                                 "pop3", "com.sun.mail.pop3.POP3Store",
1017:                                 "Oracle", Version.version));
1018:                  addProvider(new Provider(Provider.Type.STORE,
1019:                                 "pop3s", "com.sun.mail.pop3.POP3SSLStore",
1020:                                 "Oracle", Version.version));
1021:                  addProvider(new Provider(Provider.Type.TRANSPORT,
1022:                                 "smtp", "com.sun.mail.smtp.SMTPTransport",
1023:                                 "Oracle", Version.version));
1024:                  addProvider(new Provider(Provider.Type.TRANSPORT,
1025:                                 "smtps", "com.sun.mail.smtp.SMTPSSLTransport",
1026:                                 "Oracle", Version.version));
1027:                 }
1028:         
1029:•                if (logger.isLoggable(Level.CONFIG)) {
1030:                  // dump the output of the tables for debugging
1031:                  logger.config("Tables of loaded providers");
1032:                  logger.config("Providers Listed By Class Name: " +
1033:                  providersByClassName.toString());
1034:                  logger.config("Providers Listed By Protocol: " +
1035:                  providersByProtocol.toString());
1036:                 }
1037: }
1038:
1039: private void loadProvidersFromStream(InputStream is) throws IOException {
1040:•                if (is != null) {
1041:                  LineInputStream lis = streamProvider.inputLineStream(is, false);
1042:                  String currLine;
1043:         
1044:                  // load and process one line at a time using LineInputStream
1045:•                 while ((currLine = lis.readLine()) != null) {
1046:         
1047:•                                if (currLine.startsWith("#"))
1048:                                  continue;
1049:•                                if (currLine.trim().length() == 0)
1050:                                  continue;        // skip blank line
1051:                                 Provider.Type type = null;
1052:                                 String protocol = null, className = null;
1053:                                 String vendor = null, version = null;
1054:                                 
1055:                                 // separate line into key-value tuples
1056:                                 StringTokenizer tuples = new StringTokenizer(currLine,";");
1057:•                                while (tuples.hasMoreTokens()) {
1058:                                  String currTuple = tuples.nextToken().trim();
1059:                                         
1060:                                  // set the value of each attribute based on its key
1061:                                  int sep = currTuple.indexOf("=");
1062:•                                 if (currTuple.startsWith("protocol=")) {
1063:                                         protocol = currTuple.substring(sep+1);
1064:•                                 } else if (currTuple.startsWith("type=")) {
1065:                                         String strType = currTuple.substring(sep+1);
1066:•                                        if (strType.equalsIgnoreCase("store")) {
1067:                                          type = Provider.Type.STORE;
1068:•                                        } else if (strType.equalsIgnoreCase("transport")) {
1069:                                          type = Provider.Type.TRANSPORT;
1070:                                          }
1071:•                                 } else if (currTuple.startsWith("class=")) {
1072:                                         className = currTuple.substring(sep+1);
1073:•                                 } else if (currTuple.startsWith("vendor=")) {
1074:                                         vendor = currTuple.substring(sep+1);
1075:•                                 } else if (currTuple.startsWith("version=")) {
1076:                                         version = currTuple.substring(sep+1);
1077:                                  }
1078:                                 }
1079:                 
1080:                                 // check if a valid Provider; else, continue
1081:•                                if (type == null || protocol == null || className == null
1082:•                                 || protocol.length() <= 0 || className.length() <= 0) {
1083:                                         
1084:                                  logger.log(Level.CONFIG, "Bad provider entry: {0}",
1085:                                                                 currLine);
1086:                                  continue;
1087:                                 }
1088:                                 Provider provider = new Provider(type, protocol, className,
1089:                                                          vendor, version);
1090:                 
1091:                                 // add the newly-created Provider to the lookup tables
1092:                                 addProvider(provider);
1093:                  }
1094:                 }
1095: }
1096:
1097: /**
1098: * Add a provider to the session.
1099: *
1100: * @param        provider        the provider to add
1101: * @since        JavaMail 1.4
1102: */
1103: public synchronized void addProvider(Provider provider) {
1104:                 providers.add(provider);
1105:                 providersByClassName.put(provider.getClassName(), provider);
1106:•                if (!providersByProtocol.containsKey(provider.getProtocol()))
1107:                  providersByProtocol.put(provider.getProtocol(), provider);
1108:         }
1109:         
1110: // load maps in reverse order of preference so that the preferred
1111: // map is loaded last since its entries will override the previous ones
1112: private void loadAddressMap(Class<?> cl) {
1113:                 StreamLoader loader = new StreamLoader() {
1114:                  @Override
1115:                  public void load(InputStream is) throws IOException {
1116:                         addressMap.load(is);
1117:                  }
1118:                 };
1119:         
1120:                 // load default META-INF/javamail.default.address.map from mail.jar
1121:                 loadResource("/META-INF/javamail.default.address.map", cl, loader, true);
1122:         
1123:                 // load the META-INF/javamail.address.map file supplied by an app
1124:                 loadAllResources("META-INF/javamail.address.map", cl, loader);
1125:         
1126:                 // load system-wide javamail.address.map from the
1127:                 // <java.home>/{conf,lib} directory
1128:                 try {
1129:•                 if (confDir != null)
1130:                         loadFile(confDir + "javamail.address.map", loader);
1131:                 } catch (SecurityException ex) {}
1132:         
1133:•                if (addressMap.isEmpty()) {
1134:                  logger.config("failed to load address map, using defaults");
1135:                  addressMap.put("rfc822", "smtp");
1136:                 }
1137: }
1138:
1139: /**
1140: * Set the default transport protocol to use for addresses of
1141: * the specified type. Normally the default is set by the
1142: * <code>javamail.default.address.map</code> or
1143: * <code>javamail.address.map</code> files or resources.
1144: *
1145: * @param        addresstype        type of address
1146: * @param        protocol        name of protocol
1147: * @see #getTransport(Address)
1148: * @since        JavaMail 1.4
1149: */
1150: public synchronized void setProtocolForAddress(String addresstype, String protocol) {
1151:•                if (protocol == null)
1152:                  addressMap.remove(addresstype);
1153:                 else
1154:                  addressMap.put(addresstype, protocol);
1155:          }
1156:         
1157:          /**
1158:          * Load from the named file.
1159:          */
1160:          private void loadFile(String name, StreamLoader loader) {
1161:                 InputStream clis = null;
1162:                 try {
1163:                  clis = new BufferedInputStream(new FileInputStream(name));
1164:                  loader.load(clis);
1165:                  logger.log(Level.CONFIG, "successfully loaded file: {0}", name);
1166:                 } catch (FileNotFoundException fex) {
1167:                  // ignore it
1168:                 } catch (IOException e) {
1169:•                 if (logger.isLoggable(Level.CONFIG))
1170:                         logger.log(Level.CONFIG, "not loading file: " + name, e);
1171:                 } catch (SecurityException sex) {
1172:•                 if (logger.isLoggable(Level.CONFIG))
1173:                         logger.log(Level.CONFIG, "not loading file: " + name, sex);
1174:                 } finally {
1175:                  try {
1176:•                        if (clis != null)
1177:                          clis.close();
1178:                  } catch (IOException ex) { }        // ignore it
1179:                 }
1180: }
1181:
1182: /**
1183: * Load from the named resource.
1184: */
1185: private void loadResource(String name, Class<?> cl, StreamLoader loader, boolean expected) {
1186:                 InputStream clis = null;
1187:                 try {
1188:                  clis = getResourceAsStream(cl, name);
1189:•                 if (clis != null) {
1190:                         loader.load(clis);
1191:                         logger.log(Level.CONFIG, "successfully loaded resource: {0}",
1192:                                                  name);
1193:                  } else {
1194:•                        if (expected)
1195:                          logger.log(Level.WARNING,
1196:                                          "expected resource not found: {0}", name);
1197:                  }
1198:                 } catch (IOException e) {
1199:                  logger.log(Level.CONFIG, "Exception loading resource", e);
1200:                 } catch (SecurityException sex) {
1201:                  logger.log(Level.CONFIG, "Exception loading resource", sex);
1202:                 } finally {
1203:                  try {
1204:•                        if (clis != null)
1205:                          clis.close();
1206:                  } catch (IOException ex) { }        // ignore it
1207:                 }
1208: }
1209:
1210: /**
1211: * Load all of the named resource.
1212: */
1213: private void loadAllResources(String name, Class<?> cl, StreamLoader loader) {
1214:                 boolean anyLoaded = false;
1215:                 try {
1216:                  URL[] urls;
1217:                  ClassLoader cld = null;
1218:                  // First try the "application's" class loader.
1219:                  cld = getContextClassLoader();
1220:•                 if (cld == null)
1221:                         cld = cl.getClassLoader();
1222:•                 if (cld != null)
1223:                         urls = getResources(cld, name);
1224:                  else
1225:                         urls = getSystemResources(name);
1226:•                 if (urls != null) {
1227:•                        for (int i = 0; i < urls.length; i++) {
1228:                          URL url = urls[i];
1229:                          InputStream clis = null;
1230:                          logger.log(Level.CONFIG, "URL {0}", url);
1231:                          try {
1232:                                 clis = openStream(url);
1233:•                                if (clis != null) {
1234:                                  loader.load(clis);
1235:                                  anyLoaded = true;
1236:                                  logger.log(Level.CONFIG,
1237:                                         "successfully loaded resource: {0}", url);
1238:                                 } else {
1239:                                  logger.log(Level.CONFIG,
1240:                                         "not loading resource: {0}", url);
1241:                                 }
1242:                          } catch (FileNotFoundException fex) {
1243:                                 // ignore it
1244:                          } catch (IOException ioex) {
1245:                                 logger.log(Level.CONFIG, "Exception loading resource",
1246:                                          ioex);
1247:                          } catch (SecurityException sex) {
1248:                                 logger.log(Level.CONFIG, "Exception loading resource",
1249:                                          sex);
1250:                          } finally {
1251:                                 try {
1252:•                                 if (clis != null)
1253:                                         clis.close();
1254:                                 } catch (IOException cex) { }
1255:                          }
1256:                         }
1257:                  }
1258:                 } catch (Exception ex) {
1259:                  logger.log(Level.CONFIG, "Exception loading resource", ex);
1260:                 }
1261:         
1262:                 // if failed to load anything, fall back to old technique, just in case
1263:•                if (!anyLoaded) {
1264:                  /*
1265:                  logger.config("!anyLoaded");
1266:                  */
1267:                  loadResource("/" + name, cl, loader, false);
1268:                 }
1269: }
1270:
1271: /*
1272: * Following are security related methods that work on JDK 1.2 or newer.
1273: */
1274:
1275: static ClassLoader getContextClassLoader() {
1276:                 return AccessController.doPrivileged(
1277:                         new PrivilegedAction<ClassLoader>() {
1278:                          @Override
1279:                          public ClassLoader run() {
1280:                                 ClassLoader cl = null;
1281:                                 try {
1282:                                  cl = Thread.currentThread().getContextClassLoader();
1283:                                 } catch (SecurityException ex) {
1284:                                 }
1285:                                 return cl;
1286:                          }
1287:                         }
1288:                 );
1289: }
1290:
1291: private static InputStream getResourceAsStream(final Class<?> c, final String name) throws IOException {
1292:                 try {
1293:                  return AccessController.doPrivileged(
1294:                          new PrivilegedExceptionAction<InputStream>() {
1295:                                 @Override
1296:                                 public InputStream run() throws IOException {
1297:                                  try {
1298:                                         return c.getResourceAsStream(name);
1299:                                  } catch (RuntimeException e) {
1300:                                         // gracefully handle ClassLoader bugs (Tomcat)
1301:                                         IOException ioex = new IOException(
1302:                                          "ClassLoader.getResourceAsStream failed");
1303:                                         ioex.initCause(e);
1304:                                         throw ioex;
1305:                                  }
1306:                                 }
1307:                          }
1308:                  );
1309:                 } catch (PrivilegedActionException e) {
1310:                  throw (IOException)e.getException();
1311:                 }
1312: }
1313:
1314: private static URL[] getResources(final ClassLoader cl, final String name) {
1315:                 return AccessController.doPrivileged(new PrivilegedAction<URL[]>() {
1316:                  @Override
1317:                  public URL[] run() {
1318:                         URL[] ret = null;
1319:                         try {
1320:                          List<URL> v = Collections.list(cl.getResources(name));
1321:                          if (!v.isEmpty()) {
1322:                                 ret = new URL[v.size()];
1323:                                 v.toArray(ret);
1324:                          }
1325:                         } catch (IOException ioex) {
1326:                         } catch (SecurityException ex) { }
1327:                         return ret;
1328:                  }
1329:                 });
1330: }
1331:
1332: private static URL[] getSystemResources(final String name) {
1333:                 return AccessController.doPrivileged(new PrivilegedAction<URL[]>() {
1334:                  @Override
1335:                  public URL[] run() {
1336:                         URL[] ret = null;
1337:                         try {
1338:                          List<URL> v = Collections.list(
1339:                                  ClassLoader.getSystemResources(name));
1340:                          if (!v.isEmpty()) {
1341:                                 ret = new URL[v.size()];
1342:                                 v.toArray(ret);
1343:                          }
1344:                         } catch (IOException ioex) {
1345:                         } catch (SecurityException ex) { }
1346:                         return ret;
1347:                  }
1348:                 });
1349: }
1350:
1351: private static InputStream openStream(final URL url) throws IOException {
1352:                 try {
1353:                  return AccessController.doPrivileged(
1354:                          new PrivilegedExceptionAction<InputStream>() {
1355:                                 @Override
1356:                                 public InputStream run() throws IOException {
1357:                                  return url.openStream();
1358:                                 }
1359:                          }
1360:                  );
1361:                 } catch (PrivilegedActionException e) {
1362:                  throw (IOException)e.getException();
1363:                 }
1364: }
1365:
1366: EventQueue getEventQueue() {
1367:         return q;
1368: }
1369: }
1370:
1371: /**
1372: * Support interface to generalize
1373: * code that loads resources from stream.
1374: */
1375: interface StreamLoader {
1376: public void load(InputStream is) throws IOException;
1377: }