我正在尝试在Tomcat中实现javax.mail.event.MessageCountListener。当我启动应用程序时,似乎运行contextInitialized方法并读取邮箱。但是,我看到了日志消息"空闲"只有一次。我希望它会不断闲置,并在收到或删除电子邮件时调用AnalyzerService()。
更新:发现idle()方法没有返回。它运行直到com.sun.mail.iap.ResponseInputStream.readResponse(ByteArray ba)方法,它运行到一个永远不会出来的while循环。
我是否滥用idle()方法做一些我不应该做的事情?这是com.sun.mail.iap包中的错误吗?
AnalyzerContextListener.java:
import com.sun.mail.imap.IMAPStore;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.mail.Folder;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.event.MessageCountListener;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class AnalyzerContextListener implements ServletContextListener {
private ExecutorService executorService;
private final String username = "myemail@gmail.com";
private final String password = "mypassword";
private final String mailhost = "imap.gmail.com";
private final String foldername = "INBOX";
@Override
public void contextInitialized(ServletContextEvent sce) {
final ServletContext servletContext = sce.getServletContext();
executorService = Executors.newFixedThreadPool(3);
Session session = Session.getInstance(new Properties());
try {
final IMAPStore store = (IMAPStore) session.getStore("imaps");
store.connect(mailhost, username, password);
final Folder folder = store.getFolder(foldername);
if (folder == null) {
servletContext.log("Folder in mailbox bestaat niet.");
return;
}
folder.open(Folder.READ_ONLY);
MessageCountListener countListener = new AnalyzerService();
folder.addMessageCountListener(countListener);
Runnable runnable = new Runnable() {
@Override
public void run() {
while (true) {
try {
servletContext.log("Aantal berichten in folder: " + folder.getMessageCount());
servletContext.log("Idling");
store.idle();
} catch (MessagingException ex) {
servletContext.log(ex.getMessage());
return;
}
}
}
};
executorService.execute(runnable);
servletContext.log("Executorservice gestart");
} catch (MessagingException ex) {
servletContext.log(ex.getMessage());
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
sce.getServletContext().log("Context wordt vernietigd");
executorService.shutdown();
sce.getServletContext().log("Executorservice gestopt");
}
}
AnalyzerService.java:
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.event.MessageCountEvent;
import javax.mail.event.MessageCountListener;
class AnalyzerService implements MessageCountListener {
public AnalyzerService() {
}
@Override
public void messagesAdded(MessageCountEvent event) {
Message[] addedMessages = event.getMessages();
for (Message message : addedMessages) {
try {
System.out.println(message.getSubject());
} catch (MessagingException ex) {
System.out.println(ex.getMessage());
}
}
}
@Override
public void messagesRemoved(MessageCountEvent event) {
Message[] removedMessages = event.getMessages();
for (Message message : removedMessages) {
try {
System.out.println(message.getSubject());
} catch (MessagingException ex) {
System.out.println(ex.getMessage());
}
}
}
}
答案 0 :(得分:2)
while (true) {
try {
servletContext.log("Aantal berichten in folder: " + folder.getMessageCount());
servletContext.log("Idling");
store.idle();
} catch (MessagingException ex) {
servletContext.log(ex.getMessage());
return;
}
}
有 2 3种可能性早于>>只运行一次
循环实际上结束了:
如果是return
,请通过明确MessagingException
。看看你的日志,有一条消息或类似的东西,比如" null"。考虑使用正确的堆栈跟踪日志(.log(String message, Throwable throwable)
),因为Exception#getMessage()
通常是空的或者没有告诉您太多。
通过任何未经检查的异常。您应该注意到在某些日志中,因为未被捕获的异常通过executorService.execute
应该调用最近的未捕获的exeption处理程序,这通常是坏的。请参阅Choose between ExecutorService's submit and ExecutorService's execute
循环在记录"Idling"
store.idle()
永远不会回来。 (每隔一行代码也可以在理论上做到这一点,例如第二次迭代中的folder.getMessageCount()
调用,但这种情况不太可能发生)关于3号 - documentation
如果服务器支持,请使用IMAP IDLE命令(请参阅RFC 2177)进入空闲模式,以便服务器可以发送未经请求的通知,而无需客户端不断轮询服务器。使用 ConnectionListener 通知事件。 当另一个线程(例如,侦听器线程)需要为此Store发出IMAP命令时,将终止空闲模式,此方法将返回。通常,调用者将循环调用此方法。
如果设置了mail.imap.enableimapevents属性,则在IDLE命令处于活动状态时收到的通知将作为具有IMAPStore.RESPONSE类型的事件传递给 ConnectionListeners 。该事件的消息将是原始IMAP响应字符串。请注意,在未选择邮箱的连接(即此方法)上使用IDLE命令时,大多数IMAP服务器不会传递任何事件。在大多数情况下,您将要在IMAPFolder上使用idle方法。
听起来这个方法并不是为了很快就能回归。在您的情况下,永远不要因为您在进入空闲状态后不向服务器发出任何命令。除此之外
folder.idle()
可能就是你应该做的事情ConnectionListener
和MessageCountListener
是两回事。