Skip to content

Package: Service

Service

nameinstructionbranchcomplexitylinemethod
Service(Session, URLName)
M: 164 C: 0
0%
M: 18 C: 0
0%
M: 10 C: 0
0%
M: 45 C: 0
0%
M: 1 C: 0
0%
addConnectionListener(ConnectionListener)
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
close()
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
connect()
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
connect(String, String)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
connect(String, String, String)
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
connect(String, int, String, String)
M: 265 C: 0
0%
M: 52 C: 0
0%
M: 27 C: 0
0%
M: 71 C: 0
0%
M: 1 C: 0
0%
finalize()
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getEventQueue()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getSession()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getURLName()
M: 27 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
isConnected()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
notifyConnectionListeners(int)
M: 22 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
protocolConnect(String, int, String, String)
M: 2 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
queueEvent(MailEvent, Vector)
M: 10 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
removeConnectionListener(ConnectionListener)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
setConnected(boolean)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
setURLName(URLName)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
toString()
M: 11 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 1997, 2021 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Public License v. 2.0, which is available at
6: * http://www.eclipse.org/legal/epl-2.0.
7: *
8: * This Source Code may also be made available under the following Secondary
9: * Licenses when the conditions for such availability set forth in the
10: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11: * version 2 with the GNU Classpath Exception, which is available at
12: * https://www.gnu.org/software/classpath/license.html.
13: *
14: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15: */
16:
17: package jakarta.mail;
18:
19: import java.io.*;
20: import java.net.*;
21: import java.util.*;
22: import java.util.concurrent.Executor;
23: import jakarta.mail.event.*;
24:
25: /**
26: * An abstract class that contains the functionality
27: * common to messaging services, such as stores and transports. <p>
28: * A messaging service is created from a <code>Session</code> and is
29: * named using a <code>URLName</code>. A service must be connected
30: * before it can be used. Connection events are sent to reflect
31: * its connection status.
32: *
33: * @author Christopher Cotton
34: * @author Bill Shannon
35: * @author Kanwar Oberoi
36: */
37:
38: public abstract class Service implements AutoCloseable {
39:
40: /**
41: * The session from which this service was created.
42: */
43: protected Session        session;
44:
45: /**
46: * The <code>URLName</code> of this service.
47: */
48: protected volatile URLName        url = null;
49:
50: /**
51: * Debug flag for this service. Set from the session's debug
52: * flag when this service is created.
53: */
54: protected boolean        debug = false;
55:
56: private boolean        connected = false;
57:
58: /*
59: * connectionListeners is a Vector, initialized here,
60: * because we depend on it always existing and depend
61: * on the synchronization that Vector provides.
62: * (Sychronizing on the Service object itself can cause
63: * deadlocks when notifying listeners.)
64: */
65: private final Vector<ConnectionListener> connectionListeners
66:          = new Vector<>();
67:
68: /**
69: * The queue of events to be delivered.
70: */
71: private final EventQueue q;
72:
73: /**
74: * Constructor.
75: *
76: * @param        session Session object for this service
77: * @param        urlname        URLName object to be used for this service
78: */
79: protected Service(Session session, URLName urlname) {
80:         this.session = session;
81:         debug = session.getDebug();
82:         url = urlname;
83:
84:         /*
85:          * Initialize the URLName with default values.
86:          * The URLName will be updated when connect is called.
87:          */
88:         String protocol = null;
89:         String host = null;
90:         int port = -1;
91:         String user = null;
92:         String password = null;
93:         String file = null;
94:
95:         // get whatever information we can from the URL
96:         // XXX - url should always be non-null here, Session
97:         // passes it into the constructor
98:•        if (url != null) {
99:          protocol = url.getProtocol();
100:          host = url.getHost();
101:          port = url.getPort();
102:          user = url.getUsername();
103:          password = url.getPassword();
104:          file = url.getFile();
105:         }
106:
107:         // try to get protocol-specific default properties
108:•        if (protocol != null) {
109:•         if (host == null)
110:                 host = session.getProperty("mail." + protocol + ".host");
111:•         if (user == null)
112:                 user = session.getProperty("mail." + protocol + ".user");
113:         }
114:
115:         // try to get mail-wide default properties
116:•        if (host == null)
117:          host = session.getProperty("mail.host");
118:
119:•        if (user == null)
120:          user = session.getProperty("mail.user");
121:
122:         // try using the system username
123:•        if (user == null) {
124:          try {
125:                 user = System.getProperty("user.name");
126:          } catch (SecurityException sex) {
127:                 // XXX - it's not worth creating a MailLogger just for this
128:                 //logger.log(Level.CONFIG, "Can't get user.name property", sex);
129:          }
130:         }
131:
132:         url = new URLName(protocol, host, port, file, user, password);
133:
134:         // create or choose the appropriate event queue
135:         String scope =
136:          session.getProperties().getProperty("mail.event.scope", "folder");
137:         Executor executor =
138:                 (Executor)session.getProperties().get("mail.event.executor");
139:•        if (scope.equalsIgnoreCase("application"))
140:          q = EventQueue.getApplicationEventQueue(executor);
141:•        else if (scope.equalsIgnoreCase("session"))
142:          q = session.getEventQueue();
143:         else // if (scope.equalsIgnoreCase("store") ||
144:          // scope.equalsIgnoreCase("folder"))
145:          q = new EventQueue(executor);
146: }
147:
148: /**
149: * A generic connect method that takes no parameters. Subclasses
150: * can implement the appropriate authentication schemes. Subclasses
151: * that need additional information might want to use some properties
152: * or might get it interactively using a popup window. <p>
153: *
154: * If the connection is successful, an "open" <code>ConnectionEvent</code>
155: * is delivered to any <code>ConnectionListeners</code> on this service. <p>
156: *
157: * Most clients should just call this method to connect to the service.<p>
158: *
159: * It is an error to connect to an already connected service. <p>
160: *
161: * The implementation provided here simply calls the following
162: * <code>connect(String, String, String)</code> method with nulls.
163: *
164: * @exception AuthenticationFailedException        for authentication failures
165: * @exception MessagingException        for other failures
166: * @exception IllegalStateException        if the service is already connected
167: *
168: * @see jakarta.mail.event.ConnectionEvent
169: */
170: public void connect() throws MessagingException {
171:         connect(null, null, null);
172: }
173:
174: /**
175: * Connect to the specified address. This method provides a simple
176: * authentication scheme that requires a username and password. <p>
177: *
178: * If the connection is successful, an "open" <code>ConnectionEvent</code>
179: * is delivered to any <code>ConnectionListeners</code> on this service. <p>
180: *
181: * It is an error to connect to an already connected service. <p>
182: *
183: * The implementation in the Service class will collect defaults
184: * for the host, user, and password from the session, from the
185: * <code>URLName</code> for this service, and from the supplied
186: * parameters and then call the <code>protocolConnect</code> method.
187: * If the <code>protocolConnect</code> method returns <code>false</code>,
188: * the user will be prompted for any missing information and the
189: * <code>protocolConnect</code> method will be called again. The
190: * subclass should override the <code>protocolConnect</code> method.
191: * The subclass should also implement the <code>getURLName</code>
192: * method, or use the implementation in this class. <p>
193: *
194: * On a successful connection, the <code>setURLName</code> method is
195: * called with a URLName that includes the information used to make
196: * the connection, including the password. <p>
197: *
198: * If the username passed in is null, a default value will be chosen
199: * as described above.
200: *
201: * If the password passed in is null and this is the first successful
202: * connection to this service, the user name and the password
203: * collected from the user will be saved as defaults for subsequent
204: * connection attempts to this same service when using other Service object
205: * instances (the connection information is typically always saved within
206: * a particular Service object instance). The password is saved using the
207: * Session method <code>setPasswordAuthentication</code>. If the
208: * password passed in is not null, it is not saved, on the assumption
209: * that the application is managing passwords explicitly.
210: *
211: * @param host         the host to connect to
212: * @param user        the user name
213: * @param password        this user's password
214: * @exception AuthenticationFailedException        for authentication failures
215: * @exception MessagingException                for other failures
216: * @exception IllegalStateException        if the service is already connected
217: * @see jakarta.mail.event.ConnectionEvent
218: * @see jakarta.mail.Session#setPasswordAuthentication
219: */
220: public void connect(String host, String user, String password)
221:                         throws MessagingException {
222:         connect(host, -1, user, password);
223: }
224:
225: /**
226: * Connect to the current host using the specified username
227: * and password. This method is equivalent to calling the
228: * <code>connect(host, user, password)</code> method with null
229: * for the host name.
230: *
231: * @param user the user name
232: * @param password this user's password
233: * @exception AuthenticationFailedException for authentication failures
234: * @exception MessagingException for other failures
235: * @exception IllegalStateException if the service is already connected
236: * @see jakarta.mail.event.ConnectionEvent
237: * @see jakarta.mail.Session#setPasswordAuthentication
238: * @see #connect(java.lang.String, java.lang.String, java.lang.String)
239: * @since JavaMail 1.4
240: */
241: public void connect(String user, String password)
242:          throws MessagingException {
243: connect(null, user, password);
244: }
245:
246: /**
247: * Similar to connect(host, user, password) except a specific port
248: * can be specified.
249: *
250: * @param host         the host to connect to
251: * @param port        the port to connect to (-1 means the default port)
252: * @param user        the user name
253: * @param password        this user's password
254: * @exception AuthenticationFailedException        for authentication failures
255: * @exception MessagingException                for other failures
256: * @exception IllegalStateException        if the service is already connected
257: * @see #connect(java.lang.String, java.lang.String, java.lang.String)
258: * @see jakarta.mail.event.ConnectionEvent
259: */
260: public synchronized void connect(String host, int port,
261:                 String user, String password) throws MessagingException {
262:
263:         // see if the service is already connected
264:•        if (isConnected())
265:          throw new IllegalStateException("already connected");
266:
267:         PasswordAuthentication pw;
268:         boolean connected = false;
269:         boolean save = false;
270:         String protocol = null;
271:         String file = null;
272:
273:         // get whatever information we can from the URL
274:         // XXX - url should always be non-null here, Session
275:         // passes it into the constructor
276:•        if (url != null) {
277:          protocol = url.getProtocol();
278:•         if (host == null)
279:                 host = url.getHost();
280:•         if (port == -1)
281:                 port = url.getPort();
282:
283:•         if (user == null) {
284:                 user = url.getUsername();
285:•                if (password == null)        // get password too if we need it
286:                  password = url.getPassword();
287:          } else {
288:•                if (password == null && user.equals(url.getUsername()))
289:                  // only get the password if it matches the username
290:                  password = url.getPassword();
291:          }
292:
293:          file = url.getFile();
294:         }
295:
296:         // try to get protocol-specific default properties
297:•        if (protocol != null) {
298:•         if (host == null)
299:                 host = session.getProperty("mail." + protocol + ".host");
300:•         if (user == null)
301:                 user = session.getProperty("mail." + protocol + ".user");
302:         }
303:
304:         // try to get mail-wide default properties
305:•        if (host == null)
306:          host = session.getProperty("mail.host");
307:
308:•        if (user == null)
309:          user = session.getProperty("mail.user");
310:
311:         // try using the system username
312:•        if (user == null) {
313:          try {
314:                 user = System.getProperty("user.name");
315:          } catch (SecurityException sex) {
316:                 // XXX - it's not worth creating a MailLogger just for this
317:                 //logger.log(Level.CONFIG, "Can't get user.name property", sex);
318:          }
319:         }
320:
321:         // if we don't have a password, look for saved authentication info
322:•        if (password == null && url != null) {
323:          // canonicalize the URLName
324:          setURLName(new URLName(protocol, host, port, file, user, null));
325:          pw = session.getPasswordAuthentication(getURLName());
326:•         if (pw != null) {
327:•                if (user == null) {
328:                  user = pw.getUserName();
329:                  password = pw.getPassword();
330:•                } else if (user.equals(pw.getUserName())) {
331:                  password = pw.getPassword();
332:                 }
333:          } else
334:                 save = true;
335:         }
336:
337:         // try connecting, if the protocol needs some missing
338:         // information (user, password) it will not connect.
339:         // if it tries to connect and fails, remember why for later.
340:         AuthenticationFailedException authEx = null;
341:         try {
342:          connected = protocolConnect(host, port, user, password);
343:         } catch (AuthenticationFailedException ex) {
344:          authEx = ex;
345:         }
346:
347:         // if not connected, ask the user and try again
348:•        if (!connected) {
349:          InetAddress addr;
350:          try {
351:                 addr = InetAddress.getByName(host);
352:          } catch (UnknownHostException e) {
353:                 addr = null;
354:          }
355:          pw = session.requestPasswordAuthentication(
356:                          addr, port,
357:                          protocol,
358:                          null, user);
359:•         if (pw != null) {
360:                 user = pw.getUserName();
361:                 password = pw.getPassword();
362:
363:                 // have the service connect again
364:                 connected = protocolConnect(host, port, user, password);
365:          }
366:         }
367:
368:         // if we're not connected by now, we give up
369:•        if (!connected) {
370:•         if (authEx != null)
371:                 throw authEx;
372:•         else if (user == null)
373:                 throw new AuthenticationFailedException(
374:                         "failed to connect, no user name specified?");
375:•         else if (password == null)
376:                 throw new AuthenticationFailedException(
377:                         "failed to connect, no password specified?");
378:          else
379:                 throw new AuthenticationFailedException("failed to connect");
380:         }
381:
382:         setURLName(new URLName(protocol, host, port, file, user, password));
383:
384:•        if (save)
385:          session.setPasswordAuthentication(getURLName(),
386:                          new PasswordAuthentication(user, password));
387:
388:         // set our connected state
389:         setConnected(true);
390:
391:         // finally, deliver the connection event
392:         notifyConnectionListeners(ConnectionEvent.OPENED);
393: }
394:
395:
396: /**
397: * The service implementation should override this method to
398: * perform the actual protocol-specific connection attempt.
399: * The default implementation of the <code>connect</code> method
400: * calls this method as needed. <p>
401: *
402: * The <code>protocolConnect</code> method should return
403: * <code>false</code> if a user name or password is required
404: * for authentication but the corresponding parameter is null;
405: * the <code>connect</code> method will prompt the user when
406: * needed to supply missing information. This method may
407: * also return <code>false</code> if authentication fails for
408: * the supplied user name or password. Alternatively, this method
409: * may throw an AuthenticationFailedException when authentication
410: * fails. This exception may include a String message with more
411: * detail about the failure. <p>
412: *
413: * The <code>protocolConnect</code> method should throw an
414: * exception to report failures not related to authentication,
415: * such as an invalid host name or port number, loss of a
416: * connection during the authentication process, unavailability
417: * of the server, etc.
418: *
419: * @param        host                the name of the host to connect to
420: * @param        port                the port to use (-1 means use default port)
421: * @param        user                the name of the user to login as
422: * @param        password        the user's password
423: * @return        true if connection successful, false if authentication failed
424: * @exception AuthenticationFailedException        for authentication failures
425: * @exception MessagingException        for non-authentication failures
426: */
427: protected boolean protocolConnect(String host, int port, String user,
428:                                 String password) throws MessagingException {
429:         return false;
430: }
431:
432: /**
433: * Is this service currently connected? <p>
434: *
435: * This implementation uses a private boolean field to
436: * store the connection state. This method returns the value
437: * of that field. <p>
438: *
439: * Subclasses may want to override this method to verify that any
440: * connection to the message store is still alive.
441: *
442: * @return        true if the service is connected, false if it is not connected
443: */
444: public synchronized boolean isConnected() {
445:         return connected;
446: }
447:
448: /**
449: * Set the connection state of this service. The connection state
450: * will automatically be set by the service implementation during the
451: * <code>connect</code> and <code>close</code> methods.
452: * Subclasses will need to call this method to set the state
453: * if the service was automatically disconnected. <p>
454: *
455: * The implementation in this class merely sets the private field
456: * returned by the <code>isConnected</code> method.
457: *
458: * @param connected true if the service is connected,
459: * false if it is not connected
460: */
461: protected synchronized void setConnected(boolean connected) {
462:         this.connected = connected;
463: }
464:
465: /**
466: * Close this service and terminate its connection. A close
467: * ConnectionEvent is delivered to any ConnectionListeners. Any
468: * Messaging components (Folders, Messages, etc.) belonging to this
469: * service are invalid after this service is closed. Note that the service
470: * is closed even if this method terminates abnormally by throwing
471: * a MessagingException. <p>
472: *
473: * This implementation uses <code>setConnected(false)</code> to set
474: * this service's connected state to <code>false</code>. It will then
475: * send a close ConnectionEvent to any registered ConnectionListeners.
476: * Subclasses overriding this method to do implementation specific
477: * cleanup should call this method as a last step to insure event
478: * notification, probably by including a call to <code>super.close()</code>
479: * in a <code>finally</code> clause.
480: *
481: * @see jakarta.mail.event.ConnectionEvent
482: * @throws        MessagingException        for errors while closing
483: */
484: public synchronized void close() throws MessagingException {
485:         setConnected(false);
486:         notifyConnectionListeners(ConnectionEvent.CLOSED);
487: }
488:
489: /**
490: * Return a URLName representing this service. The returned URLName
491: * does <em>not</em> include the password field. <p>
492: *
493: * Subclasses should only override this method if their
494: * URLName does not follow the standard format. <p>
495: *
496: * The implementation in the Service class returns (usually a copy of)
497: * the <code>url</code> field with the password and file information
498: * stripped out.
499: *
500: * @return        the URLName representing this service
501: * @see        URLName
502: */
503: public URLName getURLName() {
504:         URLName url = this.url;        // snapshot
505:•        if (url != null && (url.getPassword() != null || url.getFile() != null))
506:          return new URLName(url.getProtocol(), url.getHost(),
507:                         url.getPort(), null /* no file */,
508:                         url.getUsername(), null /* no password */);
509:         else
510:          return url;
511: }
512:
513: /**
514: * Set the URLName representing this service.
515: * Normally used to update the <code>url</code> field
516: * after a service has successfully connected. <p>
517: *
518: * Subclasses should only override this method if their
519: * URL does not follow the standard format. In particular,
520: * subclasses should override this method if their URL
521: * does not require all the possible fields supported by
522: * <code>URLName</code> a new <code>URLName</code> should
523: * be constructed with any unneeded fields removed. <p>
524: *
525: * The implementation in the Service class simply sets the
526: * <code>url</code> field.
527: *
528: * @param        url        the URLName
529: * @see URLName
530: */
531: protected void setURLName(URLName url) {
532:         this.url = url;
533: }
534:
535: /**
536: * Add a listener for Connection events on this service. <p>
537: *
538: * The default implementation provided here adds this listener
539: * to an internal list of ConnectionListeners.
540: *
541: * @param l the Listener for Connection events
542: * @see jakarta.mail.event.ConnectionEvent
543: */
544: public void addConnectionListener(ConnectionListener l) {
545:         connectionListeners.addElement(l);
546: }
547:
548: /**
549: * Remove a Connection event listener. <p>
550: *
551: * The default implementation provided here removes this listener
552: * from the internal list of ConnectionListeners.
553: *
554: * @param l the listener
555: * @see #addConnectionListener
556: */
557: public void removeConnectionListener(ConnectionListener l) {
558:         connectionListeners.removeElement(l);
559: }
560:
561: /**
562: * Notify all ConnectionListeners. Service implementations are
563: * expected to use this method to broadcast connection events. <p>
564: *
565: * The provided default implementation queues the event into
566: * an internal event queue. An event dispatcher thread dequeues
567: * events from the queue and dispatches them to the registered
568: * ConnectionListeners. Note that the event dispatching occurs
569: * in a separate thread, thus avoiding potential deadlock problems.
570: *
571: * @param        type        the ConnectionEvent type
572: */
573: protected void notifyConnectionListeners(int type) {
574:         /*
575:          * Don't bother queuing an event if there's no listeners.
576:          * Yes, listeners could be removed after checking, which
577:          * just makes this an expensive no-op.
578:          */
579:•        if (connectionListeners.size() > 0) {
580:          ConnectionEvent e = new ConnectionEvent(this, type);
581:          queueEvent(e, connectionListeners);
582:         }
583:
584: /* Fix for broken JDK1.1.x Garbage collector :
585: * The 'conservative' GC in JDK1.1.x occasionally fails to
586: * garbage-collect Threads which are in the wait state.
587: * This would result in thread (and consequently memory) leaks.
588: *
589: * We attempt to fix this by sending a 'terminator' event
590: * to the queue, after we've sent the CLOSED event. The
591: * terminator event causes the event-dispatching thread to
592: * self destruct.
593: */
594:• if (type == ConnectionEvent.CLOSED)
595: q.terminateQueue();
596: }
597:
598: /**
599: * Return <code>getURLName.toString()</code> if this service has a URLName,
600: * otherwise it will return the default <code>toString</code>.
601: */
602: @Override
603: public String toString() {
604:         URLName url = getURLName();
605:•        if (url != null)
606:          return url.toString();
607:         else
608:          return super.toString();
609: }
610:
611: /**
612: * Add the event and vector of listeners to the queue to be delivered.
613: *
614: * @param        event        the event
615: * @param        vector        the vector of listeners
616: */
617: protected void queueEvent(MailEvent event,
618:          Vector<? extends EventListener> vector) {
619:         /*
620: * Copy the vector in order to freeze the state of the set
621: * of EventListeners the event should be delivered to prior
622: * to delivery. This ensures that any changes made to the
623: * Vector from a target listener's method during the delivery
624: * of this event will not take effect until after the event is
625: * delivered.
626: */
627:         @SuppressWarnings("unchecked")
628:         Vector<? extends EventListener> v = (Vector)vector.clone();
629:         q.enqueue(event, v);
630: }
631:
632: /**
633: * Stop the event dispatcher thread so the queue can be garbage collected.
634: */
635: @Override
636: protected void finalize() throws Throwable {
637:         try {
638:          q.terminateQueue();
639:         } finally {
640:          super.finalize();
641:         }
642: }
643:
644: /**
645: * Package private method to allow Folder to get the Session for a Store.
646: */
647: Session getSession() {
648:         return session;
649: }
650:
651: /**
652: * Package private method to allow Folder to get the EventQueue for a Store.
653: */
654: EventQueue getEventQueue() {
655:         return q;
656: }
657: }