/[classpathx]/mail/source/javax/mail/Service.java
ViewVC logotype

Contents of /mail/source/javax/mail/Service.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.9 - (show annotations) (download)
Wed Jan 5 19:05:44 2005 UTC (19 years, 4 months ago) by dog
Branch: MAIN
Changes since 1.8: +7 -7 lines
2005-01-05  Chris Burdess  <dog@bluezoo.org>

        * UUDecoderStream.java: Fixed case where EOF is reached before buffer
        is full.
        * POP3Message.java: Make Message.setFlag(DELETED) work.
        * mbox: Converted to GNU style.

1 /*
2 * Service.java
3 * Copyright(C) 2002 The Free Software Foundation
4 *
5 * This file is part of GNU JavaMail, a library.
6 *
7 * GNU JavaMail is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 *(at your option) any later version.
11 *
12 * GNU JavaMail is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 * As a special exception, if you link this library with other files to
22 * produce an executable, this library does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * This exception does not however invalidate any other reasons why the
25 * executable file might be covered by the GNU General Public License.
26 */
27
28 package javax.mail;
29
30 import java.net.InetAddress;
31 import java.net.UnknownHostException;
32 import java.util.ArrayList;
33 import javax.mail.event.ConnectionEvent;
34 import javax.mail.event.ConnectionListener;
35 import javax.mail.event.MailEvent;
36
37 /**
38 * An abstract class that contains the functionality common to messaging
39 * services, such as stores and transports.
40 * <p>
41 * A messaging service is created from a Session and is named using a URLName.
42 * A service must be connected before it can be used.
43 * Connection events are sent to reflect its connection status.
44 *
45 * @author <a href="mailto:dog@gnu.org">Chris Burdess</a>
46 * @version 1.3
47 */
48 public abstract class Service
49 {
50
51 /**
52 * The session from which this service was created.
53 */
54 protected Session session;
55
56 /**
57 * The URLName of this service.
58 */
59 protected URLName url;
60
61 /**
62 * Debug flag for this service.
63 * Set from the session's debug flag when this service is created.
64 */
65 protected boolean debug;
66
67 /*
68 * @see #isConnected
69 */
70 private boolean connected = false;
71
72 private ArrayList connectionListeners = null;
73
74 /**
75 * Constructor.
76 * @param session Session object for this service
77 * @param url URLName object to be used for this service
78 */
79 protected Service(Session session, URLName url)
80 {
81 this.session = session;
82 this.url = url;
83 debug = session.getDebug();
84 }
85
86 /**
87 * A generic connect method that takes no parameters.
88 * Subclasses can implement the appropriate authentication schemes.
89 * Subclasses that need additional information might want to use
90 * some properties or might get it interactively using a popup window.
91 * <p>
92 * If the connection is successful, an "open" ConnectionEvent is delivered
93 * to any ConnectionListeners on this service.
94 * <p>
95 * Most clients should just call this method to connect to the service.
96 * <p>
97 * It is an error to connect to an already connected service.
98 * <p>
99 * The implementation provided here simply calls the following
100 * <code>connect(String, String, String)</code> method with nulls.
101 * @exception AuthenticationFailedException for authentication failures
102 * @exception MessagingException for other failures
103 * @exception IllegalStateException if the service is already connected
104 */
105 public void connect()
106 throws MessagingException
107 {
108 connect(null, null, null);
109 }
110
111 /**
112 * Connect to the specified address.
113 * This method provides a simple authentication scheme
114 * that requires a username and password.
115 * <p>
116 * If the connection is successful, an "open" ConnectionEvent is delivered
117 * to any ConnectionListeners on this service.
118 * <p>
119 * It is an error to connect to an already connected service.
120 * <p>
121 * The implementation in the Service class will collect defaults for the
122 * host, user, and password from the session, from the URLName for this
123 * service, and from the supplied parameters and then call the
124 * <code>protocolConnect</code> method. If the <code>protocolConnect</code>
125 * method returns false, the user will be prompted for any missing
126 * information and the <code>protocolConnect</code> method will be called
127 * again. The subclass should override the <code>protocolConnect</code>
128 * method. The subclass should also implement the <code>getURLName</code>
129 * method, or use the implementation in this class.
130 * <p>
131 * On a successful connection, the <code>setURLName</code> method is called
132 * with a URLName that includes the information used to make the connection,
133 * including the password.
134 * <p>
135 * If the password passed in is null and this is the first successful
136 * connection to this service, the user name and the password collected from
137 * the user will be saved as defaults for subsequent connection attempts to
138 * this same service when using other Service object instances(the
139 * connection information is typically always saved within a particular
140 * Service object instance). The password is saved using the Session method
141 * <code>setPasswordAuthenticaiton</code>. If the password passed in is not
142 * null, it is not saved, on the assumption that the application is managing
143 * passwords explicitly.
144 * @param host the host to connect to
145 * @param user the user name
146 * @param password this user's password
147 * @exception AuthenticationFailedException for authentication failures
148 * @exception MessagingException for other failures
149 * @exception IllegalStateException if the service is already connected
150 */
151 public void connect(String host, String user, String password)
152 throws MessagingException
153 {
154 connect(host, -1, user, password);
155 }
156
157 /**
158 * Similar to connect(host, user, password) except a specific port can be
159 * specified.
160 * @param host the host to connect to
161 * @param port the port to use(-1 means use default port)
162 * @param user the user name
163 * @param password this user's password
164 * @exception AuthenticationFailedException for authentication failures
165 * @exception MessagingException for other failures
166 * @exception IllegalStateException if the service is already connected
167 */
168 public void connect(String host, int port, String user, String password)
169 throws MessagingException
170 {
171 if (isConnected())
172 {
173 throw new MessagingException("already connected");
174 }
175
176 boolean success = false;
177 boolean authenticated = false;
178 String protocol = null;
179 String file = null;
180 if (url != null)
181 {
182 protocol = url.getProtocol();
183 if (host == null)
184 {
185 host = url.getHost();
186 }
187 if (port == -1)
188 {
189 port = url.getPort();
190 }
191 if (user == null)
192 {
193 user = url.getUsername();
194 if (password == null)
195 {
196 password = url.getPassword();
197 }
198 }
199 else if (password == null && user.equals(url.getUsername()))
200 {
201 password = url.getPassword();
202 }
203 file = url.getFile();
204 }
205 if (protocol != null)
206 {
207 if (host == null)
208 {
209 host = session.getProperty("mail." + protocol + ".host");
210 }
211 if (user == null)
212 {
213 user = session.getProperty("mail." + protocol + ".user");
214 }
215 }
216 if (host == null)
217 {
218 host = session.getProperty("mail.host");
219 }
220 if (user == null)
221 {
222 user = session.getProperty("mail.user");
223 }
224 if (user == null)
225 {
226 try
227 {
228 user = System.getProperty("user.name");
229 }
230 catch (SecurityException e)
231 {
232 if (debug)
233 {
234 e.printStackTrace();
235 }
236 }
237 }
238 if (password == null && url != null)
239 {
240 setURLName(new URLName(protocol, host, port, file, user, password));
241 PasswordAuthentication auth =
242 session.getPasswordAuthentication(getURLName());
243 if (auth != null)
244 {
245 if (user == null)
246 {
247 user = auth.getUserName();
248 password = auth.getPassword();
249 }
250 else if (user.equals(auth.getUserName()))
251 {
252 password = auth.getPassword();
253 }
254 }
255 else
256 {
257 authenticated = true;
258 }
259 }
260 AuthenticationFailedException afex = null;
261 try
262 {
263 success = protocolConnect(host, port, user, password);
264 }
265 catch (AuthenticationFailedException afex2)
266 {
267 afex = afex2;
268 }
269 if (!success)
270 {
271 InetAddress address = null;
272 try
273 {
274 address = InetAddress.getByName(host);
275 }
276 catch (UnknownHostException e)
277 {
278 }
279 PasswordAuthentication auth =
280 session.requestPasswordAuthentication(address, port, protocol,
281 null, user);
282 if (auth != null)
283 {
284 user = auth.getUserName();
285 password = auth.getPassword();
286 success = protocolConnect(host, port, user, password);
287 }
288 }
289 if (!success)
290 {
291 if (afex!=null)
292 {
293 throw afex;
294 }
295 throw new AuthenticationFailedException();
296 }
297 setURLName(new URLName(protocol, host, port, file, user, password));
298 if (authenticated)
299 {
300 PasswordAuthentication auth =
301 new PasswordAuthentication(user, password);
302 session.setPasswordAuthentication(getURLName(), auth);
303 }
304 setConnected(true);
305 notifyConnectionListeners(ConnectionEvent.OPENED);
306 }
307
308 /**
309 * The service implementation should override this method to perform the
310 * actual protocol-specific connection attempt.
311 * The default implementation of the <code>connect</code> method calls
312 * this method as needed.
313 * <p>
314 * The <code>protocolConnect</code> method should return false if a user
315 * name or password is required for authentication but the corresponding
316 * parameter is null; the connect method will prompt the user when needed
317 * to supply missing information. This method may also return false if
318 * authentication fails for the supplied user name or password.
319 * Alternatively, this method may throw an AuthenticationFailedException
320 * when authentication fails. This exception may include a String message
321 * with more detail about the failure.
322 * <p>
323 * The <code>protocolConnect</code> method should throw an exception to
324 * report failures not related to authentication, such as an invalid host
325 * name or port number, loss of a connection during the authentication
326 * process, unavailability of the server, etc.
327 * @param host the name of the host to connect to
328 * @param port the port to use(-1 means use default port)
329 * @param user the name of the user to login as
330 * @param password the user's password
331 * @return true if connection successful, false if authentication failed
332 * @exception AuthenticationFailedException for authentication failures
333 * @exception MessagingException for non-authentication failures
334 */
335 protected boolean protocolConnect(String host, int port,
336 String user, String password)
337 throws MessagingException
338 {
339 return false;
340 }
341
342 /**
343 * Is this service currently connected?
344 * <p>
345 * This implementation uses a private boolean field to store the connection
346 * state. This method returns the value of that field.
347 * <p>
348 * Subclasses may want to override this method to verify that any connection
349 * to the message store is still alive.
350 */
351 public boolean isConnected()
352 {
353 return connected;
354 }
355
356 /**
357 * Set the connection state of this service.
358 * The connection state will automatically be set by the service
359 * implementation during the connect and close methods.
360 * Subclasses will need to call this method to set the state if
361 * the service was automatically disconnected.
362 * <p>
363 * The implementation in this class merely sets the private field
364 * returned by the <code>isConnected</code> method.
365 */
366 protected void setConnected(boolean connected)
367 {
368 this.connected = connected;
369 }
370
371 /**
372 * Close this service and terminate its connection.
373 * A close ConnectionEvent is delivered to any ConnectionListeners.
374 * Any Messaging components(Folders, Messages, etc.) belonging to
375 * this service are invalid after this service is closed. Note that
376 * the service is closed even if this method terminates abnormally
377 * by throwing a MessagingException.
378 * <p>
379 * This implementation uses <code>setConnected(false)</code> to set
380 * this service's connected state to false. It will then send a close
381 * ConnectionEvent to any registered ConnectionListeners. Subclasses
382 * overriding this method to do implementation specific cleanup should
383 * call this method as a last step to insure event notification,
384 * probably by including a call to <code>super.close()</code> in
385 * a finally clause.
386 */
387 public synchronized void close()
388 throws MessagingException
389 {
390 setConnected(false);
391 notifyConnectionListeners(ConnectionEvent.CLOSED);
392 }
393
394 /**
395 * Return a URLName representing this service.
396 * The returned URLName does not include the password field.
397 * <p>
398 * Subclasses should only override this method if their URLName does not
399 * follow the standard format.
400 * <p>
401 * The implementation in the Service class returns(usually a copy of)
402 * the url field with the password and file information stripped out.
403 */
404 public URLName getURLName()
405 {
406 if (url != null &&(url.getPassword() != null || url.getFile() != null))
407 {
408 return new URLName(url.getProtocol(), url.getHost(), url.getPort(),
409 null, url.getUsername(), null);
410 }
411 return url;
412 }
413
414 /**
415 * Set the URLName representing this service.
416 * Normally used to update the url field after a service has
417 * successfully connected.
418 * <p>
419 * Subclasses should only override this method if their URL does not
420 * follow the standard format. In particular, subclasses should override
421 * this method if their URL does not require all the possible fields
422 * supported by URLName; a new URLName should be constructed with any
423 * unneeded fields removed.
424 * <p>
425 * The implementation in the Service class simply sets the url field.
426 */
427 protected void setURLName(URLName url)
428 {
429 this.url = url;
430 }
431
432 // -- Event management --
433
434 /*
435 * Because the propagation of events of different kinds in the JavaMail
436 * API is so haphazard, I have here sacrificed a small time advantage for
437 * readability and consistency.
438 *
439 * All the various propagation methods now call a method with a name based
440 * on the eventual listener method name prefixed by 'fire', as is the
441 * preferred pattern for usage of the EventListenerList in Swing.
442 *
443 * Note that all events are currently delivered synchronously, where in
444 * Sun's implementation a different thread is used for event delivery.
445 *
446 * TODO Examine the impact of this.
447 */
448
449 // -- Connection events --
450
451 /**
452 * Add a listener for Connection events on this service.
453 */
454 public void addConnectionListener(ConnectionListener l)
455 {
456 if (connectionListeners == null)
457 {
458 connectionListeners = new ArrayList();
459 }
460 synchronized (connectionListeners)
461 {
462 connectionListeners.add(l);
463 }
464 }
465
466 /**
467 * Remove a Connection event listener.
468 */
469 public void removeConnectionListener(ConnectionListener l)
470 {
471 if (connectionListeners != null)
472 {
473 synchronized (connectionListeners)
474 {
475 connectionListeners.remove(l);
476 }
477 }
478 }
479
480 /**
481 * Notify all ConnectionListeners.
482 * Service implementations are expected to use this method
483 * to broadcast connection events.
484 */
485 protected void notifyConnectionListeners(int type)
486 {
487 ConnectionEvent event = new ConnectionEvent(this, type);
488 switch (type)
489 {
490 case ConnectionEvent.OPENED:
491 fireOpened(event);
492 break;
493 case ConnectionEvent.DISCONNECTED:
494 fireDisconnected(event);
495 break;
496 case ConnectionEvent.CLOSED:
497 fireClosed(event);
498 break;
499 }
500 }
501
502 /*
503 * Propagates an OPENED ConnectionEvent to all registered listeners.
504 */
505 void fireOpened(ConnectionEvent event)
506 {
507 if (connectionListeners != null)
508 {
509 ConnectionListener[] l = null;
510 synchronized (connectionListeners)
511 {
512 l = new ConnectionListener[connectionListeners.size()];
513 connectionListeners.toArray(l);
514 }
515 for (int i = 0; i < l.length; i++)
516 {
517 l[i].opened(event);
518 }
519 }
520 }
521
522 /*
523 * Propagates a DISCONNECTED ConnectionEvent to all registered listeners.
524 */
525 void fireDisconnected(ConnectionEvent event)
526 {
527 if (connectionListeners != null)
528 {
529 ConnectionListener[] l = null;
530 synchronized (connectionListeners)
531 {
532 l = new ConnectionListener[connectionListeners.size()];
533 connectionListeners.toArray(l);
534 }
535 for (int i = 0; i < l.length; i++)
536 {
537 l[i].disconnected(event);
538 }
539 }
540 }
541
542 /*
543 * Propagates a CLOSED ConnectionEvent to all registered listeners.
544 */
545 void fireClosed(ConnectionEvent event)
546 {
547 if (connectionListeners != null)
548 {
549 ConnectionListener[] l = null;
550 synchronized (connectionListeners)
551 {
552 l = new ConnectionListener[connectionListeners.size()];
553 connectionListeners.toArray(l);
554 }
555 for (int i = 0; i < l.length; i++)
556 {
557 l[i].closed(event);
558 }
559 }
560 }
561
562 /**
563 * Return getURLName.toString() if this service has a URLName,
564 * otherwise it will return the default toString.
565 */
566 public String toString()
567 {
568 URLName urlName = getURLName();
569 return (urlName != null) ? urlName.toString() : super.toString();
570 }
571
572 }

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26