package mireka.transmission.queue; import java.util.Date; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import javax.annotation.PostConstruct; import mireka.transmission.Mail; import org.slf4j.LoggerFactory; /** * This mail queue, working with a mail store, passes the mails to a mail * processors according to the schedule. The schedule is defined by the time * point in {@link Mail#scheduleDate} in each mail. */ public class ScheduleFileDirQueue { private final org.slf4j.Logger logger = LoggerFactory .getLogger(ScheduleFileDirQueue.class); private FileDirStore store; private MailProcessorFactory mailProcessorFactory; private ScheduledThreadPoolExecutor executor; /** * use this constructor with setters */ public ScheduleFileDirQueue() { // nothing to do } /** * @param executor * {@link ScheduledThreadPoolExecutor#setExecuteExistingDelayedTasksAfterShutdownPolicy} * will be called on it with false, to switch off waiting for * tasks which are not even started on shutdown. */ public ScheduleFileDirQueue(FileDirStore store, MailProcessorFactory mailProcessorFactory, ScheduledThreadPoolExecutor executor) { this.store = store; this.mailProcessorFactory = mailProcessorFactory; this.executor = executor; this.executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); } @PostConstruct public void start() { logger.info("Initializing queue. [store=" + store + "]"); MailName[] mailNames; try { mailNames = store.initializeAndQueryMailNamesOrderedBySchedule(); } catch (QueueStorageException e) { throw new RuntimeException("Queue initialization failed", e); } scheduleMailNames(mailNames); } private void scheduleMailNames(MailName[] mailNames) { for (MailName name : mailNames) { scheduleMailName(name); logger.debug( "Mail name, read from store, was scheduled for processing: {}", name); } } private void scheduleMailName(MailName mailName) { MailProcessingTask task = new MailProcessingTask(this, store, mailProcessorFactory, mailName); executor.schedule(task, mailName.scheduleDate - System.currentTimeMillis(), TimeUnit.MILLISECONDS); } /** * store a copy of the mail in the queue and schedule it */ public void add(Mail srcMail) throws QueueStorageException { if (srcMail.scheduleDate == null) srcMail.scheduleDate = new Date(); MailName mailName = store.save(srcMail); scheduleMailName(mailName); logger.debug("Mail was sceduled for processing: {}, {}", mailName, srcMail); } /** * Initiates an orderly shutdown, no new mails will be accepted and * processing of mails which are not yet started will not be started */ public void shutdown() { executor.shutdown(); } void rescheduleFailedTask(MailProcessingTask task) { executor.schedule(task, 5, TimeUnit.MINUTES); } /** * @x.category GETSET */ public void setStore(FileDirStore store) { this.store = store; } /** * @x.category GETSET */ public void setMailProcessorFactory( MailProcessorFactory mailProcessorFactory) { this.mailProcessorFactory = mailProcessorFactory; } /** * @x.category GETSET */ public void setExecutor(ScheduledThreadPoolExecutor executor) { this.executor = executor; } /** * @x.category GETSET */ public void setThreadCount(int count) { this.executor = new ScheduledThreadPoolExecutor(count); } @Override public String toString() { return "ScheduleFileDirQueue [store=" + store + "]"; } }