Clover coverage report - Maven Clover report
Coverage timestamp: Sun Aug 20 2006 04:01:44 PDT
file stats: LOC: 797   Methods: 38
NCLOC: 406   Classes: 2
 
 Source file Conditionals Statements Methods TOTAL
Session.java 25.6% 42.9% 57.9% 40.1%
coverage coverage
 1    /**
 2    *
 3    * Copyright 2003-2006 The Apache Software Foundation
 4    *
 5    * Licensed under the Apache License, Version 2.0 (the "License");
 6    * you may not use this file except in compliance with the License.
 7    * You may obtain a copy of the License at
 8    *
 9    * http://www.apache.org/licenses/LICENSE-2.0
 10    *
 11    * Unless required by applicable law or agreed to in writing, software
 12    * distributed under the License is distributed on an "AS IS" BASIS,
 13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14    * See the License for the specific language governing permissions and
 15    * limitations under the License.
 16    */
 17   
 18    package javax.mail;
 19   
 20    import java.io.BufferedReader;
 21    import java.io.File;
 22    import java.io.FileInputStream;
 23    import java.io.IOException;
 24    import java.io.InputStream;
 25    import java.io.InputStreamReader;
 26    import java.io.PrintStream;
 27    import java.lang.reflect.Constructor;
 28    import java.lang.reflect.InvocationTargetException;
 29    import java.net.InetAddress;
 30    import java.net.URL;
 31    import java.util.ArrayList;
 32    import java.util.Enumeration;
 33    import java.util.HashMap;
 34    import java.util.List;
 35    import java.util.Map;
 36    import java.util.Properties;
 37    import java.util.StringTokenizer;
 38    import java.util.WeakHashMap;
 39   
 40   
 41    /**
 42    * OK, so we have a final class in the API with a heck of a lot of implementation required...
 43    * let's try and figure out what it is meant to do.
 44    * <p/>
 45    * It is supposed to collect together properties and defaults so that they can be
 46    * shared by multiple applications on a desktop; with process isolation and no
 47    * real concept of shared memory, this seems challenging. These properties and
 48    * defaults rely on system properties, making management in a app server harder,
 49    * and on resources loaded from "mail.jar" which may lead to skew between
 50    * differnet independent implementations of this API.
 51    *
 52    * @version $Rev: 421852 $ $Date: 2006-07-14 03:02:19 -0700 (Fri, 14 Jul 2006) $
 53    */
 54    public final class Session {
 55    private static final Class[] PARAM_TYPES = {Session.class, URLName.class};
 56    private static final WeakHashMap addressMapsByClassLoader = new WeakHashMap();
 57    private static Session DEFAULT_SESSION;
 58   
 59    private Map passwordAuthentications = new HashMap();
 60   
 61    private final Properties properties;
 62    private final Authenticator authenticator;
 63    private boolean debug;
 64    private PrintStream debugOut = System.out;
 65   
 66    private static final WeakHashMap providersByClassLoader = new WeakHashMap();
 67   
 68    /**
 69    * No public constrcutor allowed.
 70    */
 71  16 private Session(Properties properties, Authenticator authenticator) {
 72  16 this.properties = properties;
 73  16 this.authenticator = authenticator;
 74  16 debug = Boolean.valueOf(properties.getProperty("mail.debug")).booleanValue();
 75    }
 76   
 77    /**
 78    * Create a new session initialized with the supplied properties which uses the supplied authenticator.
 79    * Clients should ensure the properties listed in Appendix A of the JavaMail specification are
 80    * set as the defaults are unlikey to work in most scenarios; particular attention should be given
 81    * to:
 82    * <ul>
 83    * <li>mail.store.protocol</li>
 84    * <li>mail.transport.protocol</li>
 85    * <li>mail.host</li>
 86    * <li>mail.user</li>
 87    * <li>mail.from</li>
 88    * </ul>
 89    *
 90    * @param properties the session properties
 91    * @param authenticator an authenticator for callbacks to the user
 92    * @return a new session
 93    */
 94  16 public static Session getInstance(Properties properties, Authenticator authenticator) {
 95  16 return new Session(new Properties(properties), authenticator);
 96    }
 97   
 98    /**
 99    * Create a new session initialized with the supplied properties with no authenticator.
 100    *
 101    * @param properties the session properties
 102    * @return a new session
 103    * @see #getInstance(java.util.Properties, Authenticator)
 104    */
 105  10 public static Session getInstance(Properties properties) {
 106  10 return getInstance(properties, null);
 107    }
 108   
 109    /**
 110    * Get the "default" instance assuming no authenticator is required.
 111    *
 112    * @param properties the session properties
 113    * @return if "default" session
 114    * @throws SecurityException if the does not have permission to access the default session
 115    */
 116  15 public synchronized static Session getDefaultInstance(Properties properties) {
 117  15 return getDefaultInstance(properties, null);
 118    }
 119   
 120    /**
 121    * Get the "default" session.
 122    * If there is not current "default", a new Session is created and installed as the default.
 123    *
 124    * @param properties
 125    * @param authenticator
 126    * @return if "default" session
 127    * @throws SecurityException if the does not have permission to access the default session
 128    */
 129  17 public synchronized static Session getDefaultInstance(Properties properties, Authenticator authenticator) {
 130  17 if (DEFAULT_SESSION == null) {
 131  1 DEFAULT_SESSION = getInstance(properties, authenticator);
 132    } else {
 133  16 if (authenticator != DEFAULT_SESSION.authenticator) {
 134  0 if (authenticator == null || DEFAULT_SESSION.authenticator == null || authenticator.getClass().getClassLoader() != DEFAULT_SESSION.authenticator.getClass().getClassLoader()) {
 135  0 throw new SecurityException();
 136    }
 137    }
 138    // todo we should check with the SecurityManager here as well
 139    }
 140  17 return DEFAULT_SESSION;
 141    }
 142   
 143    /**
 144    * Enable debugging for this session.
 145    * Debugging can also be enabled by setting the "mail.debug" property to true when
 146    * the session is being created.
 147    *
 148    * @param debug the debug setting
 149    */
 150  1 public void setDebug(boolean debug) {
 151  1 this.debug = debug;
 152    }
 153   
 154    /**
 155    * Get the debug setting for this session.
 156    *
 157    * @return the debug setting
 158    */
 159  16 public boolean getDebug() {
 160  16 return debug;
 161    }
 162   
 163    /**
 164    * Set the output stream where debug information should be sent.
 165    * If set to null, System.out will be used.
 166    *
 167    * @param out the stream to write debug information to
 168    */
 169  0 public void setDebugOut(PrintStream out) {
 170  0 debugOut = out == null ? System.out : out;
 171    }
 172   
 173    /**
 174    * Return the debug output stream.
 175    *
 176    * @return the debug output stream
 177    */
 178  0 public PrintStream getDebugOut() {
 179  0 return debugOut;
 180    }
 181   
 182    /**
 183    * Return the list of providers available to this application.
 184    * This method searches for providers that are defined in the javamail.providers
 185    * and javamail.default.providers resources available through the current context
 186    * classloader, or if that is not available, the classloader that loaded this class.
 187    * <p/>
 188    * As searching for providers is potentially expensive, this implementation maintains
 189    * a WeakHashMap of providers indexed by ClassLoader.
 190    *
 191    * @return an array of providers
 192    */
 193  0 public Provider[] getProviders() {
 194  0 ProviderInfo info = getProviderInfo();
 195  0 return (Provider[]) info.all.toArray(new Provider[info.all.size()]);
 196    }
 197   
 198    /**
 199    * Return the provider for a specific protocol.
 200    * This implementation initially looks in the Session properties for an property with the name
 201    * "mail.<protocol>.class"; if found it attempts to create an instance of the class named in that
 202    * property throwing a NoSuchProviderException if the class cannot be loaded.
 203    * If this property is not found, it searches the providers returned by {@link #getProviders()}
 204    * for a entry for the specified protocol.
 205    *
 206    * @param protocol the protocol to get a provider for
 207    * @return a provider for that protocol
 208    * @throws NoSuchProviderException
 209    */
 210  2 public Provider getProvider(String protocol) throws NoSuchProviderException {
 211  2 ProviderInfo info = getProviderInfo();
 212  2 Provider provider = null;
 213  2 String providerName = properties.getProperty("mail." + protocol + ".class");
 214  2 if (providerName != null) {
 215  0 provider = (Provider) info.byClassName.get(providerName);
 216  0 if (debug) {
 217  0 writeDebug("DEBUG: new provider loaded: " + provider.toString());
 218    }
 219    }
 220   
 221    // if not able to locate this by class name, just grab a registered protocol.
 222  2 if (provider == null) {
 223  2 provider = (Provider) info.byProtocol.get(protocol);
 224    }
 225   
 226  2 if (provider == null) {
 227  0 throw new NoSuchProviderException("Unable to locate provider for protocol: " + protocol);
 228    }
 229  2 if (debug) {
 230  0 writeDebug("DEBUG: getProvider() returning provider " + provider.toString());
 231    }
 232  2 return provider;
 233    }
 234   
 235    /**
 236    * Make the supplied Provider the default for its protocol.
 237    *
 238    * @param provider the new default Provider
 239    * @throws NoSuchProviderException
 240    */
 241  0 public void setProvider(Provider provider) throws NoSuchProviderException {
 242  0 ProviderInfo info = getProviderInfo();
 243  0 info.byProtocol.put(provider.getProtocol(), provider);
 244    }
 245   
 246    /**
 247    * Return a Store for the default protocol defined by the mail.store.protocol property.
 248    *
 249    * @return the store for the default protocol
 250    * @throws NoSuchProviderException
 251    */
 252  0 public Store getStore() throws NoSuchProviderException {
 253  0 String protocol = properties.getProperty("mail.store.protocol");
 254  0 if (protocol == null) {
 255  0 throw new NoSuchProviderException("mail.store.protocol property is not set");
 256    }
 257  0 return getStore(protocol);
 258    }
 259   
 260    /**
 261    * Return a Store for the specified protocol.
 262    *
 263    * @param protocol the protocol to get a Store for
 264    * @return a Store
 265    * @throws NoSuchProviderException if no provider is defined for the specified protocol
 266    */
 267  0 public Store getStore(String protocol) throws NoSuchProviderException {
 268  0 Provider provider = getProvider(protocol);
 269  0 return getStore(provider);
 270    }
 271   
 272    /**
 273    * Return a Store for the protocol specified in the given URL
 274    *
 275    * @param url the URL of the Store
 276    * @return a Store
 277    * @throws NoSuchProviderException if no provider is defined for the specified protocol
 278    */
 279  0 public Store getStore(URLName url) throws NoSuchProviderException {
 280  0 return (Store) getService(getProvider(url.getProtocol()), url);
 281    }
 282   
 283    /**
 284    * Return the Store specified by the given provider.
 285    *
 286    * @param provider the provider to create from
 287    * @return a Store
 288    * @throws NoSuchProviderException if there was a problem creating the Store
 289    */
 290  0 public Store getStore(Provider provider) throws NoSuchProviderException {
 291  0 if (Provider.Type.STORE != provider.getType()) {
 292  0 throw new NoSuchProviderException("Not a Store Provider: " + provider);
 293    }
 294  0 return (Store) getService(provider, null);
 295    }
 296   
 297    /**
 298    * Return a closed folder for the supplied URLName, or null if it cannot be obtained.
 299    * <p/>
 300    * The scheme portion of the URL is used to locate the Provider and create the Store;
 301    * the returned Store is then used to obtain the folder.
 302    *
 303    * @param name the location of the folder
 304    * @return the requested folder, or null if it is unavailable
 305    * @throws NoSuchProviderException if there is no provider
 306    * @throws MessagingException if there was a problem accessing the Store
 307    */
 308  0 public Folder getFolder(URLName name) throws MessagingException {
 309  0 Store store = getStore(name);
 310  0 return store.getFolder(name);
 311    }
 312   
 313    /**
 314    * Return a Transport for the default protocol specified by the
 315    * <code>mail.transport.protocol</code> property.
 316    *
 317    * @return a Transport
 318    * @throws NoSuchProviderException
 319    */
 320  0 public Transport getTransport() throws NoSuchProviderException {
 321  0 String protocol = properties.getProperty("mail.transport.protocol");
 322  0 if (protocol == null) {
 323  0 throw new NoSuchProviderException("mail.transport.protocol property is not set");
 324    }
 325  0 return getTransport(protocol);
 326    }
 327   
 328    /**
 329    * Return a Transport for the specified protocol.
 330    *
 331    * @param protocol the protocol to use
 332    * @return a Transport
 333    * @throws NoSuchProviderException
 334    */
 335  2 public Transport getTransport(String protocol) throws NoSuchProviderException {
 336  2 Provider provider = getProvider(protocol);
 337  2 return getTransport(provider);
 338    }
 339   
 340    /**
 341    * Return a transport for the protocol specified in the URL.
 342    *
 343    * @param name the URL whose scheme specifies the protocol
 344    * @return a Transport
 345    * @throws NoSuchProviderException
 346    */
 347  0 public Transport getTransport(URLName name) throws NoSuchProviderException {
 348  0 return (Transport) getService(getProvider(name.getProtocol()), name);
 349    }
 350   
 351    /**
 352    * Return a transport for the protocol associated with the type of this address.
 353    *
 354    * @param address the address we are trying to deliver to
 355    * @return a Transport
 356    * @throws NoSuchProviderException
 357    */
 358  1 public Transport getTransport(Address address) throws NoSuchProviderException {
 359  1 String type = address.getType();
 360    // load the address map from the resource files.
 361  1 Map addressMap = getAddressMap();
 362  1 String protocolName = (String)addressMap.get(type);
 363  1 if (protocolName == null) {
 364  0 throw new NoSuchProviderException("No provider for address type " + type);
 365    }
 366  1 return getTransport(protocolName);
 367    }
 368   
 369    /**
 370    * Return the Transport specified by a Provider
 371    *
 372    * @param provider the defining Provider
 373    * @return a Transport
 374    * @throws NoSuchProviderException
 375    */
 376  2 public Transport getTransport(Provider provider) throws NoSuchProviderException {
 377  2 return (Transport) getService(provider, null);
 378    }
 379   
 380    /**
 381    * Set the password authentication associated with a URL.
 382    *
 383    * @param name the url
 384    * @param authenticator the authenticator
 385    */
 386  0 public void setPasswordAuthentication(URLName name, PasswordAuthentication authenticator) {
 387  0 if (authenticator == null) {
 388  0 passwordAuthentications.remove(name);
 389    } else {
 390  0 passwordAuthentications.put(name, authenticator);
 391    }
 392    }
 393   
 394    /**
 395    * Get the password authentication associated with a URL
 396    *
 397    * @param name the URL
 398    * @return any authenticator for that url, or null if none
 399    */
 400  0 public PasswordAuthentication getPasswordAuthentication(URLName name) {
 401  0 return (PasswordAuthentication) passwordAuthentications.get(name);
 402    }
 403   
 404    /**
 405    * Call back to the application supplied authenticator to get the needed username add password.
 406    *
 407    * @param host the host we are trying to connect to, may be null
 408    * @param port the port on that host
 409    * @param protocol the protocol trying to be used
 410    * @param prompt a String to show as part of the prompt, may be null
 411    * @param defaultUserName the default username, may be null
 412    * @return the authentication information collected by the authenticator; may be null
 413    */
 414  0 public PasswordAuthentication requestPasswordAuthentication(InetAddress host, int port, String protocol, String prompt, String defaultUserName) {
 415  0 if (authenticator == null) {
 416  0 return null;
 417    }
 418  0 return authenticator.authenticate(host, port, protocol, prompt, defaultUserName);
 419    }
 420   
 421    /**
 422    * Return the properties object for this Session; this is a live collection.
 423    *
 424    * @return the properties for the Session
 425    */
 426  97 public Properties getProperties() {
 427  97 return properties;
 428    }
 429   
 430    /**
 431    * Return the specified property.
 432    *
 433    * @param property the property to get
 434    * @return its value, or null if not present
 435    */
 436  97 public String getProperty(String property) {
 437  97 return getProperties().getProperty(property);
 438    }
 439   
 440   
 441    /**
 442    * Add a provider to the Session managed provider list.
 443    *
 444    * @param provider The new provider to add.
 445    */
 446  1 public synchronized void addProvider(Provider provider) {
 447  1 ProviderInfo info = getProviderInfo();
 448  1 info.addProvider(provider);
 449    }
 450   
 451   
 452   
 453    /**
 454    * Add a mapping between an address type and a protocol used
 455    * to process that address type.
 456    *
 457    * @param addressType
 458    * The address type identifier.
 459    * @param protocol The protocol name mapping.
 460    */
 461  1 public void setProtocolForAddress(String addressType, String protocol) {
 462  1 Map addressMap = getAddressMap();
 463   
 464    // no protocol specified is a removal
 465  1 if (protocol == null) {
 466  0 addressMap.remove(addressType);
 467    }
 468    else {
 469  1 addressMap.put(addressType, protocol);
 470    }
 471    }
 472   
 473   
 474  2 private Service getService(Provider provider, URLName name) throws NoSuchProviderException {
 475  2 try {
 476  2 ClassLoader cl = getClassLoader();
 477  2 Class clazz = cl.loadClass(provider.getClassName());
 478  2 Constructor ctr = clazz.getConstructor(PARAM_TYPES);
 479  2 return (Service) ctr.newInstance(new Object[]{this, name});
 480    } catch (ClassNotFoundException e) {
 481  0 throw (NoSuchProviderException) new NoSuchProviderException("Unable to load class for provider: " + provider).initCause(e);
 482    } catch (NoSuchMethodException e) {
 483  0 throw (NoSuchProviderException) new NoSuchProviderException("Provider class does not have a constructor(Session, URLName): " + provider).initCause(e);
 484    } catch (InstantiationException e) {
 485  0 throw (NoSuchProviderException) new NoSuchProviderException("Unable to instantiate provider class: " + provider).initCause(e);
 486    } catch (IllegalAccessException e) {
 487  0 throw (NoSuchProviderException) new NoSuchProviderException("Unable to instantiate provider class: " + provider).initCause(e);
 488    } catch (InvocationTargetException e) {
 489  0 throw (NoSuchProviderException) new NoSuchProviderException("Exception from constructor of provider class: " + provider).initCause(e.getCause());
 490    }
 491    }
 492   
 493  3 private ProviderInfo getProviderInfo() {
 494  3 ClassLoader cl = getClassLoader();
 495  3 ProviderInfo info = (ProviderInfo) providersByClassLoader.get(cl);
 496  3 if (info == null) {
 497  1 info = loadProviders(cl);
 498    }
 499  3 return info;
 500    }
 501   
 502  2 private Map getAddressMap() {
 503  2 ClassLoader cl = getClassLoader();
 504  2 Map addressMap = (Map)addressMapsByClassLoader.get(cl);
 505  2 if (addressMap == null) {
 506  1 addressMap = loadAddressMap(cl);
 507    }
 508  2 return addressMap;
 509    }
 510   
 511   
 512    /**
 513    * Resolve a class loader used to resolve context resources. The
 514    * class loader used is either a current thread context class
 515    * loader (if set), the class loader used to load an authenticator
 516    * we've been initialized with, or the class loader used to load
 517    * this class instance (which may be a subclass of Session).
 518    *
 519    * @return The class loader used to load resources.
 520    */
 521  7 private ClassLoader getClassLoader() {
 522  7 ClassLoader cl = Thread.currentThread().getContextClassLoader();
 523  7 if (cl == null) {
 524  0 if (authenticator != null) {
 525  0 cl = authenticator.getClass().getClassLoader();
 526    }
 527    else {
 528  0 cl = this.getClass().getClassLoader();
 529    }
 530    }
 531  7 return cl;
 532    }
 533   
 534  1 private ProviderInfo loadProviders(ClassLoader cl) {
 535    // we create a merged map from reading all of the potential address map entries. The locations
 536    // searched are:
 537    // 1. java.home/lib/javamail.address.map
 538    // 2. META-INF/javamail.address.map
 539    // 3. META-INF/javamail.default.address.map
 540    //
 541  1 ProviderInfo info = new ProviderInfo();
 542   
 543    // make sure this is added to the global map.
 544  1 providersByClassLoader.put(cl, info);
 545   
 546   
 547    // NOTE: Unlike the addressMap, we process these in the defined order. The loading routine
 548    // will not overwrite entries if they already exist in the map.
 549   
 550  1 try {
 551  1 Enumeration e = cl.getResources("META-INF/javamail.default.providers");
 552  1 while (e.hasMoreElements()) {
 553  0 URL url = (URL) e.nextElement();
 554  0 if (debug) {
 555  0 writeDebug("Loading javamail.default.providers from " + url.toString());
 556    }
 557   
 558  0 InputStream is = url.openStream();
 559  0 try {
 560  0 loadProviders(info, is);
 561    } finally{
 562  0 is.close();
 563    }
 564    }
 565    } catch (SecurityException e) {
 566    // ignore
 567    } catch (IOException e) {
 568    // ignore
 569    }
 570   
 571   
 572  1 try {
 573  1 File file = new File(System.getProperty("java.home"), "lib/javamail.providers");
 574  1 InputStream is = new FileInputStream(file);
 575  0 try {
 576  0 loadProviders(info, is);
 577  0 if (debug) {
 578  0 writeDebug("Loaded lib/javamail.providers from " + file.toString());
 579    }
 580    } finally{
 581  0 is.close();
 582    }
 583    } catch (SecurityException e) {
 584    // ignore
 585    } catch (IOException e) {
 586    // ignore
 587    }
 588   
 589  1 try {
 590  1 Enumeration e = cl.getResources("META-INF/javamail.providers");
 591  1 while (e.hasMoreElements()) {
 592  0 URL url = (URL) e.nextElement();
 593  0 if (debug) {
 594  0 writeDebug("Loading META-INF/javamail.providers from " + url.toString());
 595    }
 596  0 InputStream is = url.openStream();
 597  0 try {
 598  0 loadProviders(info, is);
 599    } finally{
 600  0 is.close();
 601    }
 602    }
 603    } catch (SecurityException e) {
 604    // ignore
 605    } catch (IOException e) {
 606    // ignore
 607    }
 608   
 609  1 return info;
 610    }
 611   
 612  0 private void loadProviders(ProviderInfo info, InputStream is) throws IOException {
 613  0 BufferedReader reader = new BufferedReader(new InputStreamReader(is));
 614  0 String line;
 615  0 while ((line = reader.readLine()) != null) {
 616  0 StringTokenizer tok = new StringTokenizer(line, ";");
 617  0 String protocol = null;
 618  0 Provider.Type type = null;
 619  0 String className = null;
 620  0 String vendor = null;
 621  0 String version = null;
 622  0 while (tok.hasMoreTokens()) {
 623  0 String property = tok.nextToken();
 624  0 int index = property.indexOf('=');
 625  0 if (index == -1) {
 626  0 continue;
 627    }
 628  0 String key = property.substring(0, index).trim().toLowerCase();
 629  0 String value = property.substring(index+1).trim();
 630  0 if (protocol == null && "protocol".equals(key)) {
 631  0 protocol = value;
 632  0 } else if (type == null && "type".equals(key)) {
 633  0 if ("store".equals(value)) {
 634  0 type = Provider.Type.STORE;
 635  0 } else if ("transport".equals(value)) {
 636  0 type = Provider.Type.TRANSPORT;
 637    }
 638  0 } else if (className == null && "class".equals(key)) {
 639  0 className = value;
 640  0 } else if ("vendor".equals(key)) {
 641  0 vendor = value;
 642  0 } else if ("version".equals(key)) {
 643  0 version = value;
 644    }
 645    }
 646  0 if (protocol == null || type == null || className == null) {
 647    //todo should we log a warning?
 648  0 continue;
 649    }
 650   
 651  0 if (debug) {
 652  0 writeDebug("DEBUG: loading new provider protocol=" + protocol + ", className=" + className + ", vendor=" + vendor + ", version=" + version);
 653    }
 654  0 Provider provider = new Provider(type, protocol, className, vendor, version);
 655    // add to the info list.
 656  0 info.addProvider(provider);
 657    }
 658    }
 659   
 660    /**
 661    * Load up an address map associated with a using class loader
 662    * instance.
 663    *
 664    * @param cl The class loader used to resolve the address map.
 665    *
 666    * @return A map containing the entries associated with this classloader
 667    * instance.
 668    */
 669  1 private static Map loadAddressMap(ClassLoader cl) {
 670    // we create a merged map from reading all of the potential address map entries. The locations
 671    // searched are:
 672    // 1. java.home/lib/javamail.address.map
 673    // 2. META-INF/javamail.address.map
 674    // 3. META-INF/javamail.default.address.map
 675    //
 676    // if all of the above searches fail, we just set up some "default" defaults.
 677   
 678    // the format of the address.map file is defined as a property file. We can cheat and
 679    // just use Properties.load() to read in the files.
 680  1 Properties addressMap = new Properties();
 681   
 682    // add this to the tracking map.
 683  1 addressMapsByClassLoader.put(cl, addressMap);
 684   
 685    // NOTE: We are reading these resources in reverse order of what's cited above. This allows
 686    // user defined entries to overwrite default entries if there are similarly named items.
 687   
 688  1 try {
 689  1 Enumeration e = cl.getResources("META-INF/javamail.default.address.map");
 690  1 while (e.hasMoreElements()) {
 691  0 URL url = (URL) e.nextElement();
 692  0 InputStream is = url.openStream();
 693  0 try {
 694    // load as a property file
 695  0 addressMap.load(is);
 696    } finally{
 697  0 is.close();
 698    }
 699    }
 700    } catch (SecurityException e) {
 701    // ignore
 702    } catch (IOException e) {
 703    // ignore
 704    }
 705   
 706   
 707  1 try {
 708  1 Enumeration e = cl.getResources("META-INF/javamail.address.map");
 709  1 while (e.hasMoreElements()) {
 710  0 URL url = (URL) e.nextElement();
 711  0 InputStream is = url.openStream();
 712  0 try {
 713    // load as a property file
 714  0 addressMap.load(is);
 715    } finally{
 716  0 is.close();
 717    }
 718    }
 719    } catch (SecurityException e) {
 720    // ignore
 721    } catch (IOException e) {
 722    // ignore
 723    }
 724   
 725   
 726  1 try {
 727  1 File file = new File(System.getProperty("java.home"), "lib/javamail.address.map");
 728  1 InputStream is = new FileInputStream(file);
 729  0 try {
 730    // load as a property file
 731  0 addressMap.load(is);
 732    } finally{
 733  0 is.close();
 734    }
 735    } catch (SecurityException e) {
 736    // ignore
 737    } catch (IOException e) {
 738    // ignore
 739    }
 740   
 741  1 try {
 742  1 Enumeration e = cl.getResources("META-INF/javamail.address.map");
 743  1 while (e.hasMoreElements()) {
 744  0 URL url = (URL) e.nextElement();
 745  0 InputStream is = url.openStream();
 746  0 try {
 747    // load as a property file
 748  0 addressMap.load(is);
 749    } finally{
 750  0 is.close();
 751    }
 752    }
 753    } catch (SecurityException e) {
 754    // ignore
 755    } catch (IOException e) {
 756    // ignore
 757    }
 758   
 759   
 760    // if unable to load anything, at least create the MimeMessage-smtp protocol mapping.
 761  1 if (addressMap.isEmpty()) {
 762  1 addressMap.put("rfc822", "smtp");
 763    }
 764   
 765  1 return addressMap;
 766    }
 767   
 768    /**
 769    * Private convenience routine for debug output.
 770    *
 771    * @param msg The message to write out to the debug stream.
 772    */
 773  0 private void writeDebug(String msg) {
 774  0 debugOut.println(msg);
 775    }
 776   
 777   
 778    private static class ProviderInfo {
 779    private final Map byClassName = new HashMap();
 780    private final Map byProtocol = new HashMap();
 781    private final List all = new ArrayList();
 782   
 783  1 public void addProvider(Provider provider) {
 784  1 String className = provider.getClassName();
 785   
 786  1 if (!byClassName.containsKey(className)) {
 787  1 byClassName.put(className, provider);
 788    }
 789   
 790  1 String protocol = provider.getProtocol();
 791  1 if (!byProtocol.containsKey(protocol)) {
 792  1 byProtocol.put(protocol, provider);
 793    }
 794  1 all.add(provider);
 795    }
 796    }
 797    }