For a Java EE 7 application:ExecutorService es = Executors.newCachedThreadPool(); final IdleManager idleManager = new IdleManager(session, es);
To watch for new messages in a folder, open the folder, register a listener, and ask the IdleManager to watch the folder:@Resource ManagedExecutorService es; final IdleManager idleManager = new IdleManager(session, es);
Folder folder = store.getFolder("INBOX");
folder.open(Folder.READ_WRITE);
folder.addMessageCountListener(new MessageCountAdapter() {
public void messagesAdded(MessageCountEvent ev) {
Folder folder = (Folder)ev.getSource();
Message[] msgs = ev.getMessages();
System.out.println("Folder: " + folder +
" got " + msgs.length + " new messages");
try {
// process new messages
idleManager.watch(folder); // keep watching for new messages
} catch (MessagingException mex) {
// handle exception related to the Folder
}
}
});
idleManager.watch(folder);
This delivers the events for each folder in a separate thread, NOT
using the Executor. To deliver all events in a single thread
using the Executor, set the following properties for the Session
(once), and then add listeners and watch the folder as above.
// the following should be done once...
Properties props = session.getProperties();
props.put("mail.event.scope", "session"); // or "application"
props.put("mail.event.executor", es);
Note that, after processing new messages in your listener, or doing any
other operations on the folder in any other thread, you need to tell
the IdleManager to watch for more new messages. Unless, of course, you
close the folder.
The IdleManager is created with a Session, which it uses only to control debug output. A single IdleManager instance can watch multiple Folders from multiple Stores and multiple Sessions.
Due to limitations in the Java SE nio support, a
SocketChannel must be used instead
of a Socket to connect to the server. However,
SocketChannels don't support all the features of Sockets, such as connecting
through a SOCKS proxy server. SocketChannels also don't support
simultaneous read and write, which means that the
idle method can't be used if
SocketChannels are being used; use this IdleManager instead.
To enable support for SocketChannels instead of Sockets, set the
mail.imap.usesocketchannels property in the Session used to
access the IMAP Folder. (Or mail.imaps.usesocketchannels if
you're using the "imaps" protocol.) This will effect all connections in
that Session, but you can create another Session without this property set
if you need to use the features that are incompatible with SocketChannels.
Note
The IdleManager, and all APIs and properties related to it, should be considered EXPERIMENTAL. They may be changed in the future in ways that are incompatible with applications using the current APIs.
| Modifier and Type | Field and Description |
|---|---|
| private volatile boolean | |
| private Executor | |
| private MailLogger | |
| private volatile boolean | |
| private Selector | |
| private Queue | |
| private Queue |
| Access | Constructor and Description |
|---|---|
| public | IdleManager(Session
the Session containing configuration information session, Executor the Executor used to create threads es)Create an IdleManager. |
| Modifier and Type | Method and Description |
|---|---|
| private static String | |
| public boolean | |
| private void | |
| pack-priv void | |
| private void | |
| public synchronized void | |
| private void | |
| public void | |
| private void | watchAll()
Register all of the folders in the queue with the selector, switching them to nonblocking I/O mode first. |
| die | back to summary |
|---|---|
| private volatile boolean die | |
| es | back to summary |
|---|---|
| private Executor es | |
| logger | back to summary |
|---|---|
| private MailLogger logger | |
| running | back to summary |
|---|---|
| private volatile boolean running | |
| selector | back to summary |
|---|---|
| private Selector selector | |
| toAbort | back to summary |
|---|---|
| private Queue<IMAPFolder> toAbort | |
| toWatch | back to summary |
|---|---|
| private Queue<IMAPFolder> toWatch | |
| IdleManager | back to summary |
|---|---|
| public IdleManager(Session session, Executor es) throws IOException Create an IdleManager. The Session is used only to configure debugging output. The Executor is used to create the "select" thread.
| |
| folderName | back to summary |
|---|---|
| private static String folderName(Folder folder) Return the fully qualified name of the folder, for use in log messages. Essentially just the getURLName method, but ignoring the MessagingException that can never happen. | |
| isRunning | back to summary |
|---|---|
| public boolean isRunning() Is the IdleManager currently running? The IdleManager starts
running when the Executor schedules its task. The IdleManager
stops running after its task detects the stop request from the
| |
| processKeys | back to summary |
|---|---|
| private void processKeys() throws IOException Process the selected keys. | |
| requestAbort | back to summary |
|---|---|
| pack-priv void requestAbort(IMAPFolder folder) Request that the specified folder abort an IDLE command. We can't do the abort directly because the DONE message needs to be sent through the (potentially) SSL socket, which means we need to be in blocking I/O mode. We can only switch to blocking I/O mode when not selecting, so wake up the selector, which will process this request when it wakes up. | |
| select | back to summary |
|---|---|
| private void select() Run the | |
| stop | back to summary |
|---|---|
| public synchronized void stop() Stop the IdleManager. The IdleManager can not be restarted. | |
| unwatchAll | back to summary |
|---|---|
| private void unwatchAll() Stop watching all folders. Cancel any selection keys and, most importantly, switch the channel back to blocking mode. If there's any folders waiting to be watched, need to abort them too. | |
| watch | back to summary |
|---|---|
| public void watch(Folder folder) throws MessagingException Watch the Folder for new messages and other events using the IMAP IDLE command.
| |
| watchAll | back to summary |
|---|---|
| private void watchAll() Register all of the folders in the queue with the selector, switching them to nonblocking I/O mode first. | |