FileDocCategorySizeDatePackage
Service.javaAPI DocJavaMail 1.4.322857Tue Nov 17 10:38:12 GMT 2009javax.mail

Service

public abstract class Service extends Object
An abstract class that contains the functionality common to messaging services, such as stores and transports.

A messaging service is created from a Session and is named using a URLName. A service must be connected before it can be used. Connection events are sent to reflect its connection status.

author
Christopher Cotton
author
Bill Shannon
author
Kanwar Oberoi

Fields Summary
protected Session
session
The session from which this service was created.
protected URLName
url
The URLName of this service.
protected boolean
debug
Debug flag for this service. Set from the session's debug flag when this service is created.
private boolean
connected
private final Vector
connectionListeners
private EventQueue
q
private Object
qLock
Constructors Summary
protected Service(Session session, URLName urlname)
Constructor.

param
session Session object for this service
param
urlname URLName object to be used for this service


      	      		            
         
	this.session = session;
	url = urlname;
	debug = session.getDebug();
    
Methods Summary
public voidaddConnectionListener(javax.mail.event.ConnectionListener l)
Add a listener for Connection events on this service.

The default implementation provided here adds this listener to an internal list of ConnectionListeners.

param
l the Listener for Connection events
see
javax.mail.event.ConnectionEvent

	connectionListeners.addElement(l);
    
public synchronized voidclose()
Close this service and terminate its connection. A close ConnectionEvent is delivered to any ConnectionListeners. Any Messaging components (Folders, Messages, etc.) belonging to this service are invalid after this service is closed. Note that the service is closed even if this method terminates abnormally by throwing a MessagingException.

This implementation uses setConnected(false) to set this service's connected state to false. It will then send a close ConnectionEvent to any registered ConnectionListeners. Subclasses overriding this method to do implementation specific cleanup should call this method as a last step to insure event notification, probably by including a call to super.close() in a finally clause.

see
javax.mail.event.ConnectionEvent
throws
MessagingException for errors while closing

	setConnected(false);
	notifyConnectionListeners(ConnectionEvent.CLOSED);
    
public voidconnect()
A generic connect method that takes no parameters. Subclasses can implement the appropriate authentication schemes. Subclasses that need additional information might want to use some properties or might get it interactively using a popup window.

If the connection is successful, an "open" ConnectionEvent is delivered to any ConnectionListeners on this service.

Most clients should just call this method to connect to the service.

It is an error to connect to an already connected service.

The implementation provided here simply calls the following connect(String, String, String) method with nulls.

exception
AuthenticationFailedException for authentication failures
exception
MessagingException for other failures
exception
IllegalStateException if the service is already connected
see
javax.mail.event.ConnectionEvent

	connect(null, null, null);
    
public voidconnect(java.lang.String host, java.lang.String user, java.lang.String password)
Connect to the specified address. This method provides a simple authentication scheme that requires a username and password.

If the connection is successful, an "open" ConnectionEvent is delivered to any ConnectionListeners on this service.

It is an error to connect to an already connected service.

The implementation in the Service class will collect defaults for the host, user, and password from the session, from the URLName for this service, and from the supplied parameters and then call the protocolConnect method. If the protocolConnect method returns false, the user will be prompted for any missing information and the protocolConnect method will be called again. The subclass should override the protocolConnect method. The subclass should also implement the getURLName method, or use the implementation in this class.

On a successful connection, the setURLName method is called with a URLName that includes the information used to make the connection, including the password.

If the username passed in is null, a default value will be chosen as described above. If the password passed in is null and this is the first successful connection to this service, the user name and the password collected from the user will be saved as defaults for subsequent connection attempts to this same service when using other Service object instances (the connection information is typically always saved within a particular Service object instance). The password is saved using the Session method setPasswordAuthentication. If the password passed in is not null, it is not saved, on the assumption that the application is managing passwords explicitly.

param
host the host to connect to
param
user the user name
param
password this user's password
exception
AuthenticationFailedException for authentication failures
exception
MessagingException for other failures
exception
IllegalStateException if the service is already connected
see
javax.mail.event.ConnectionEvent
see
javax.mail.Session#setPasswordAuthentication

	connect(host, -1, user, password);
    
public voidconnect(java.lang.String user, java.lang.String password)
Connect to the current host using the specified username and password. This method is equivalent to calling the connect(host, user, password) method with null for the host name.

param
user the user name
param
password this user's password
exception
AuthenticationFailedException for authentication failures
exception
MessagingException for other failures
exception
IllegalStateException if the service is already connected
see
javax.mail.event.ConnectionEvent
see
javax.mail.Session#setPasswordAuthentication
see
#connect(java.lang.String, java.lang.String, java.lang.String)
since
JavaMail 1.4

        connect(null, user, password);
    
public synchronized voidconnect(java.lang.String host, int port, java.lang.String user, java.lang.String password)
Similar to connect(host, user, password) except a specific port can be specified.

param
host the host to connect to
param
port the port to connect to (-1 means the default port)
param
user the user name
param
password this user's password
exception
AuthenticationFailedException for authentication failures
exception
MessagingException for other failures
exception
IllegalStateException if the service is already connected
see
#connect(java.lang.String, java.lang.String, java.lang.String)
see
javax.mail.event.ConnectionEvent


	// see if the service is already connected
	if (isConnected())
	    throw new IllegalStateException("already connected");

	PasswordAuthentication pw;
	boolean connected = false;
	boolean save = false;
	String protocol = null;
	String file = null;

	// get whatever information we can from the URL
	// XXX - url should always be non-null here, Session
	//       passes it into the constructor
	if (url != null) {
	    protocol = url.getProtocol();
	    if (host == null)
		host = url.getHost();
	    if (port == -1)
		port = url.getPort();

	    if (user == null) {
		user = url.getUsername();
		if (password == null)	// get password too if we need it
		    password = url.getPassword();
	    } else {
		if (password == null && user.equals(url.getUsername()))
		    // only get the password if it matches the username
		    password = url.getPassword();
	    }

	    file = url.getFile();
	}

	// try to get protocol-specific default properties
	if (protocol != null) {
	    if (host == null)
		host = session.getProperty("mail." + protocol + ".host");
	    if (user == null)
		user = session.getProperty("mail." + protocol + ".user");
	}

	// try to get mail-wide default properties
	if (host == null)
	    host = session.getProperty("mail.host");

	if (user == null)
	    user = session.getProperty("mail.user");

	// try using the system username
	if (user == null) {
	    try {
		user = System.getProperty("user.name");
	    } catch (SecurityException sex) {
		if (debug)
		    sex.printStackTrace(session.getDebugOut());
	    }
	}

	// if we don't have a password, look for saved authentication info
	if (password == null && url != null) {
	    // canonicalize the URLName
	    setURLName(new URLName(protocol, host, port, file, user, null));
	    pw = session.getPasswordAuthentication(getURLName());
	    if (pw != null) {
		if (user == null) {
		    user = pw.getUserName();
		    password = pw.getPassword();
		} else if (user.equals(pw.getUserName())) {
		    password = pw.getPassword();
		}
	    } else
		save = true;
	}

	// try connecting, if the protocol needs some missing
	// information (user, password) it will not connect.
	// if it tries to connect and fails, remember why for later.
	AuthenticationFailedException authEx = null;
	try {
	    connected = protocolConnect(host, port, user, password);
	} catch (AuthenticationFailedException ex) {
	    authEx = ex;
	}

	// if not connected, ask the user and try again
	if (!connected) {
	    InetAddress addr;
	    try {
		addr = InetAddress.getByName(host);
	    } catch (UnknownHostException e) {
		addr = null;
	    }
	    pw = session.requestPasswordAuthentication(
			    addr, port,
			    protocol,
			    null, user);
	    if (pw != null) {
		user = pw.getUserName();
		password = pw.getPassword();

		// have the service connect again
		connected = protocolConnect(host, port, user, password);
	    }
	}

	// if we're not connected by now, we give up
	if (!connected) {
	    if (authEx != null)
		throw authEx;
	    else if (user == null)
		throw new AuthenticationFailedException(
			"failed to connect, no user name specified?");
	    else if (password == null)
		throw new AuthenticationFailedException(
			"failed to connect, no password specified?");
	    else
		throw new AuthenticationFailedException("failed to connect");
	}

	setURLName(new URLName(protocol, host, port, file, user, password));

	if (save)
	    session.setPasswordAuthentication(getURLName(),
			    new PasswordAuthentication(user, password));

	// set our connected state
	setConnected(true);

	// finally, deliver the connection event
	notifyConnectionListeners(ConnectionEvent.OPENED);
    
protected voidfinalize()
Stop the event dispatcher thread so the queue can be garbage collected.

	super.finalize();
	terminateQueue();
    
public synchronized javax.mail.URLNamegetURLName()
Return a URLName representing this service. The returned URLName does not include the password field.

Subclasses should only override this method if their URLName does not follow the standard format.

The implementation in the Service class returns (usually a copy of) the url field with the password and file information stripped out.

return
the URLName representing this service
see
URLName

	if (url != null && (url.getPassword() != null || url.getFile() != null))
	    return new URLName(url.getProtocol(), url.getHost(),
			url.getPort(), null /* no file */,
			url.getUsername(), null /* no password */);
	else
	    return url;
    
public synchronized booleanisConnected()
Is this service currently connected?

This implementation uses a private boolean field to store the connection state. This method returns the value of that field.

Subclasses may want to override this method to verify that any connection to the message store is still alive.

return
true if the service is connected, false if it is not connected

	return connected;
    
protected voidnotifyConnectionListeners(int type)
Notify all ConnectionListeners. Service implementations are expected to use this method to broadcast connection events.

The provided default implementation queues the event into an internal event queue. An event dispatcher thread dequeues events from the queue and dispatches them to the registered ConnectionListeners. Note that the event dispatching occurs in a separate thread, thus avoiding potential deadlock problems.

	/*
	 * Don't bother queuing an event if there's no listeners.
	 * Yes, listeners could be removed after checking, which
	 * just makes this an expensive no-op.
	 */
	if (connectionListeners.size() > 0) {
	    ConnectionEvent e = new ConnectionEvent(this, type);
	    queueEvent(e, connectionListeners);
	}

        /* Fix for broken JDK1.1.x Garbage collector :
         *  The 'conservative' GC in JDK1.1.x occasionally fails to
         *  garbage-collect Threads which are in the wait state.
         *  This would result in thread (and consequently memory) leaks.
         *
         * We attempt to fix this by sending a 'terminator' event
         * to the queue, after we've sent the CLOSED event. The
         * terminator event causes the event-dispatching thread to
         * self destruct.
         */
        if (type == ConnectionEvent.CLOSED)
            terminateQueue();
    
protected booleanprotocolConnect(java.lang.String host, int port, java.lang.String user, java.lang.String password)
The service implementation should override this method to perform the actual protocol-specific connection attempt. The default implementation of the connect method calls this method as needed.

The protocolConnect method should return false if a user name or password is required for authentication but the corresponding parameter is null; the connect method will prompt the user when needed to supply missing information. This method may also return false if authentication fails for the supplied user name or password. Alternatively, this method may throw an AuthenticationFailedException when authentication fails. This exception may include a String message with more detail about the failure.

The protocolConnect method should throw an exception to report failures not related to authentication, such as an invalid host name or port number, loss of a connection during the authentication process, unavailability of the server, etc.

param
host the name of the host to connect to
param
port the port to use (-1 means use default port)
param
user the name of the user to login as
param
password the user's password
return
true if connection successful, false if authentication failed
exception
AuthenticationFailedException for authentication failures
exception
MessagingException for non-authentication failures

	return false;
    
protected voidqueueEvent(javax.mail.event.MailEvent event, java.util.Vector vector)
Add the event and vector of listeners to the queue to be delivered.


                      
          
	// synchronize creation of the event queue
	synchronized (qLock) {
	    if (q == null)
		q = new EventQueue();
	}

	/*
         * Copy the vector in order to freeze the state of the set
         * of EventListeners the event should be delivered to prior
         * to delivery.  This ensures that any changes made to the
         * Vector from a target listener's method during the delivery
         * of this event will not take effect until after the event is
         * delivered.
         */
	Vector v = (Vector)vector.clone();
	q.enqueue(event, v);
    
public voidremoveConnectionListener(javax.mail.event.ConnectionListener l)
Remove a Connection event listener.

The default implementation provided here removes this listener from the internal list of ConnectionListeners.

param
l the listener
see
#addConnectionListener

	connectionListeners.removeElement(l);
    
protected synchronized voidsetConnected(boolean connected)
Set the connection state of this service. The connection state will automatically be set by the service implementation during the connect and close methods. Subclasses will need to call this method to set the state if the service was automatically disconnected.

The implementation in this class merely sets the private field returned by the isConnected method.

param
connected true if the service is connected, false if it is not connected

	this.connected = connected;
    
protected synchronized voidsetURLName(javax.mail.URLName url)
Set the URLName representing this service. Normally used to update the url field after a service has successfully connected.

Subclasses should only override this method if their URL does not follow the standard format. In particular, subclasses should override this method if their URL does not require all the possible fields supported by URLName; a new URLName should be constructed with any unneeded fields removed.

The implementation in the Service class simply sets the url field.

see
URLName

	this.url = url;
    
private voidterminateQueue()

	synchronized (qLock) {
	    if (q != null) {
		Vector dummyListeners = new Vector();
		dummyListeners.setSize(1); // need atleast one listener
		q.enqueue(new TerminatorEvent(), dummyListeners);
		q = null;
	    }
	}
    
public java.lang.StringtoString()
Return getURLName.toString() if this service has a URLName, otherwise it will return the default toString.

	URLName url = getURLName();
	if (url != null)
	    return url.toString();
	else
	    return super.toString();