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