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

Save This Page
Home » glassfish-v2ur2-b04-src » javax » mail » [javadoc | source]