Servicepublic 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. |
Fields Summary |
---|
protected Session | sessionThe session from which this service was created. | protected URLName | urlThe URLName of this service. | protected boolean | debugDebug flag for this service. Set from the session's debug
flag when this service is created. | private boolean | connected | private Vector | connectionListeners | private EventQueue | q | private Object | qLock |
Constructors Summary |
---|
protected Service(Session session, URLName urlname)Constructor.
this.session = session;
url = urlname;
debug = session.getDebug();
|
Methods Summary |
---|
public synchronized void | addConnectionListener(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.
if (connectionListeners == null)
connectionListeners = new Vector();
connectionListeners.addElement(l);
| public synchronized void | close()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.
setConnected(false);
notifyConnectionListeners(ConnectionEvent.CLOSED);
| public void | connect()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.
connect(null, null, null);
| public void | connect(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.
connect(host, -1, user, password);
| public void | connect(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.
connect(null, user, password);
| public synchronized void | connect(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.
// 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
throw new AuthenticationFailedException();
}
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 void | finalize()Stop the event dispatcher thread so the queue can be garbage collected.
super.finalize();
terminateQueue();
| public synchronized javax.mail.URLName | getURLName()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.
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 boolean | isConnected()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 connected;
| protected synchronized void | notifyConnectionListeners(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.
if (connectionListeners != null) {
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 boolean | protocolConnect(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.
return false;
| protected void | queueEvent(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 synchronized void | removeConnectionListener(javax.mail.event.ConnectionListener l)Remove a Connection event listener.
The default implementation provided here removes this listener
from the internal list of ConnectionListeners.
if (connectionListeners != null)
connectionListeners.removeElement(l);
| protected synchronized void | setConnected(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.
this.connected = connected;
| protected synchronized void | setURLName(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.
this.url = url;
| private void | terminateQueue()
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.String | toString()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();
|
|