Java tutorial
/* * Copyright (c) 2011, Martijn Brinkers, Djigzo. * * This file is part of Djigzo email encryption. * * Djigzo is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License * version 3, 19 November 2007 as published by the Free Software * Foundation. * * Djigzo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public * License along with Djigzo. If not, see <http://www.gnu.org/licenses/> * * Additional permission under GNU AGPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or * combining it with aspectjrt.jar, aspectjweaver.jar, tyrex-1.0.3.jar, * freemarker.jar, dom4j.jar, mx4j-jmx.jar, mx4j-tools.jar, * spice-classman-1.0.jar, spice-loggerstore-0.5.jar, spice-salt-0.8.jar, * spice-xmlpolicy-1.0.jar, saaj-api-1.3.jar, saaj-impl-1.3.jar, * wsdl4j-1.6.1.jar (or modified versions of these libraries), * containing parts covered by the terms of Eclipse Public License, * tyrex license, freemarker license, dom4j license, mx4j license, * Spice Software License, Common Development and Distribution License * (CDDL), Common Public License (CPL) the licensors of this Program grant * you additional permission to convey the resulting work. */ package mitm.common.mail.repository; import java.util.Collection; import java.util.Date; import java.util.List; import mitm.common.hibernate.DatabaseAction; import mitm.common.hibernate.DatabaseActionExecutor; import mitm.common.hibernate.DatabaseActionExecutorBuilder; import mitm.common.hibernate.DatabaseException; import mitm.common.hibernate.SessionManager; import mitm.common.util.Check; import mitm.common.util.ThreadUtils; import org.apache.commons.lang.time.DateUtils; import org.hibernate.Session; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class MailRepositoryMaintainer { private final static Logger logger = LoggerFactory.getLogger(MailRepositoryMaintainer.class); /* * The name of the maintainer thread. */ private final static String THREAD_NAME = "Mail Repository Maintainer"; /* * The MailRepository's which should be maintained */ private final Collection<MailRepository> repositories; /* * Is used to tell listeners that something has happened for on the mailRepository. */ private final MailRepositoryEventListener mailRepositoryEventListener; /* * manages database sessions */ private final SessionManager sessionManager; /* * Used for excuting database actions within a transaction */ private final DatabaseActionExecutor databaseActionExecutor; /* * How long (in milliseconds) is a mail in quarantine is valid. */ private long expirationTime = DateUtils.MILLIS_PER_DAY * 5; /* * Time (in milliseconds) the thread will sleep if there are no items which expire. */ private long sleepTime = DateUtils.MILLIS_PER_MINUTE * 5; /* * Time (in milliseconds) to settle down at start before the maintainer thread will start. */ private long settleTime = DateUtils.MILLIS_PER_SECOND * 10; /* * The maximum number of MailRepository's items that will be removed in obe batch */ private int maxBatchSize = 50; /* * True if the thread should stop */ private boolean stopped; /* * Thread that periodically checks for expired items */ private MaintainThread thread; public MailRepositoryMaintainer(Collection<MailRepository> repositories, MailRepositoryEventListener mailRepositoryEventListener, SessionManager sessionManager) { Check.notNull(repositories, "repositories"); Check.notNull(mailRepositoryEventListener, "mailRepositoryEventListener"); Check.notNull(sessionManager, "sessionManager"); this.repositories = repositories; this.mailRepositoryEventListener = mailRepositoryEventListener; this.sessionManager = sessionManager; this.databaseActionExecutor = DatabaseActionExecutorBuilder.createDatabaseActionExecutor(sessionManager); } public long getExpirationTime() { return expirationTime; } /** * Sets the expirationTime (in milliseconds). * * Note: should not be called after start has been called. */ public void setExpirationTime(long expirationTime) { if (expirationTime < 0) { throw new IllegalArgumentException("expirationTime must be > 0"); } this.expirationTime = expirationTime; } public long getSleepTime() { return sleepTime; } /** * Sets the updateInterval (in milliseconds). * * Note: should not be called after start has been called. */ public void setSleepTime(long sleepTime) { if (sleepTime < 0) { throw new IllegalArgumentException("sleepTime must be > 0"); } this.sleepTime = sleepTime; } /** * Sets the maximum nr of MailRepository's items that will be maintained at the same time (i.e, handled * in one transcation) * * Note: should not be called after start has been called. */ public void setMaxBatchSize(int maxBatchSize) { this.maxBatchSize = maxBatchSize; } /** * The maximum nr of MailRepository's items that will be maintained at the same time (i.e, handled * in one transcation) * * Note: should not be called after start has been called. */ public int getMaxBatchSize() { return maxBatchSize; } /** * set the time (in milliseconds) to settle down at start before the maintainer thread will start. */ public void setSettleTime(long settleTime) { this.settleTime = settleTime; } /** * Time (in milliseconds) to settle down at start before the maintainer thread will start. */ public long getSettleTime() { return settleTime; } /** * Tries to stop the maintainer thread */ public synchronized void start() { if (thread == null) { thread = new MaintainThread(); thread.setDaemon(true); thread.start(); } } /** * Tries to stop the maintainer thread */ public synchronized void stop() { if (thread != null) { stopped = true; thread.interrupt(); thread = null; } } /* * Removes items from the MailRepository which are no longer valid because they expired. */ private boolean maintainRepositoryTransacted(MailRepository repository) { List<? extends MailRepositoryItem> expired = repository .getItemsBefore(DateUtils.addMilliseconds(new Date(), (int) -expirationTime), 0, maxBatchSize); for (MailRepositoryItem item : expired) { repository.deleteItem(item.getID()); mailRepositoryEventListener.onExpired(repository.getName(), item); } /* * If the maximum nr of items were returned, assume there are more items */ return expired.size() == maxBatchSize; } /* * Starts a transaction and maintains the repository */ private boolean maintainRepository(final MailRepository repository) { boolean more = false; logger.debug("Maintaning Mail repository " + repository.getName()); try { more = databaseActionExecutor.executeTransaction(new DatabaseAction<Boolean>() { @Override public Boolean doAction(Session session) throws DatabaseException { Session previousSession = sessionManager.getSession(); sessionManager.setSession(session); try { return maintainRepositoryTransacted(repository); } finally { sessionManager.setSession(previousSession); } } }); } catch (Exception e) { logger.error("Error while maintaining repository " + repository.getName()); } return more; } private class MaintainThread extends Thread { public MaintainThread() { super(THREAD_NAME); } @Override public void run() { logger.info("Starting " + THREAD_NAME + ". Expiration time: " + expirationTime + ", Sleep time: " + sleepTime + ", Settle time: " + settleTime); ThreadUtils.sleepQuietly(settleTime); do { try { boolean more = false; for (MailRepository repository : repositories) { more = more | maintainRepository(repository); } /* * Sleep for some time if there is nothing to do. */ if (!more) { try { logger.debug("Thread will sleep."); Thread.sleep(sleepTime); } catch (InterruptedException e) { // ignore } } } catch (Exception e) { logger.error("Error in " + THREAD_NAME + " thread.", e); } } while (!stopped); } } }