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