mitm.common.mail.repository.MailRepositoryMaintainer.java Source code

Java tutorial

Introduction

Here is the source code for mitm.common.mail.repository.MailRepositoryMaintainer.java

Source

/*
 * 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);
        }
    }
}