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