Java tutorial
/* * Copyright (c) 2008-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.application.djigzo.james.smtpserver; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import javax.mail.MessagingException; import mitm.application.djigzo.james.JamesStoreManager; import mitm.application.djigzo.service.SystemServices; import org.apache.avalon.framework.configuration.Configurable; import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceManager; import org.apache.commons.lang.text.StrBuilder; import org.apache.james.services.MailRepository; import org.apache.james.smtpserver.CommandHandler; import org.apache.james.smtpserver.SMTPSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CheckRepositoriesBlockingRcptCmdHandler implements CommandHandler, Configurable { private final static Logger logger = LoggerFactory.getLogger(CheckRepositoriesBlockingRcptCmdHandler.class); /* * The repository URLs that will be monitored to check if they do not grow too big */ private List<String> repositories; /* * If a the number of items in the monitored repositories exceed this limit the message is rejected */ private int repositoryUpperLimit = 1000; /* * If mail was blocked because the number of items in a repository exceeded repositoryUpperLimit and the number of * items becomes below repositoryLowerLimit receiving is restored. * */ private int repositoryLowerLimit = 500; /* * The number of milliseconds between checks for queue full */ private long checkInterval = 60000; /* * The SMTP status to return when one of the repositories is exceeds the upper limit */ private String rejectCode = "452"; /* * Used to track the last time a check was done */ private AtomicLong lastCheck = new AtomicLong(); /* * True if one of the monitored repositories is over the limit */ private AtomicBoolean overLimit = new AtomicBoolean(); @Override public void configure(Configuration handlerConfiguration) throws ConfigurationException { logger.info("Configuring CommandHandler"); Configuration[] repositoryConfigs = handlerConfiguration.getChild("repositories").getChildren("repository"); repositories = Collections.synchronizedList(new ArrayList<String>(repositoryConfigs.length)); for (Configuration repositoryConfig : repositoryConfigs) { repositories.add(repositoryConfig.getValue()); } Configuration config = handlerConfiguration.getChild("rejectCode", false); if (config != null) { rejectCode = config.getValue("452"); } config = handlerConfiguration.getChild("repositoryUpperLimit", false); if (config != null) { repositoryUpperLimit = config.getValueAsInteger(1000); } config = handlerConfiguration.getChild("repositoryLowerLimit", false); if (config != null) { repositoryLowerLimit = config.getValueAsInteger(500); } config = handlerConfiguration.getChild("checkInterval", false); if (config != null) { checkInterval = config.getValueAsLong(60000); } StrBuilder sb = new StrBuilder(); sb.append("Repositories: "); sb.appendWithSeparators(repositories, ", "); sb.appendSeparator("; "); sb.append("rejectCode: "); sb.append(rejectCode); sb.appendSeparator("; "); sb.append("repositoryUpperLimit: "); sb.append(repositoryUpperLimit); sb.appendSeparator("; "); sb.append("repositoryLowerLimit: "); sb.append(repositoryLowerLimit); sb.appendSeparator("; "); sb.append("checkInterval: "); sb.append(checkInterval); logger.info(sb.toString()); } @Override public void onCommand(SMTPSession session) { try { checkRepositories(); } catch (RepositoryOverLimitException e) { logger.warn(e.getMessage()); String response = rejectCode + " " + e.getMessage(); session.writeResponse(response); } } private void checkRepositories() throws RepositoryOverLimitException { long now = System.currentTimeMillis(); if ((now - lastCheck.longValue()) >= checkInterval) { lastCheck.set(now); ServiceManager serviceManager = SystemServices.getAvalonServiceManager(); for (String repositoryURL : repositories) { MailRepository mailRepository; try { mailRepository = new JamesStoreManager(serviceManager).getMailRepository(repositoryURL); } catch (ServiceException e) { logger.error("Error getting mailRepository for URL: " + repositoryURL); continue; } Iterator<?> keyIterator; try { keyIterator = mailRepository.list(); } catch (MessagingException e) { logger.error("Error getting list for URL: " + repositoryURL); continue; } int size = 0; while (keyIterator.hasNext()) { keyIterator.next(); size++; } logger.debug("size of repository " + repositoryURL + " is " + size); if (size > repositoryUpperLimit) { overLimit.set(true); throw new RepositoryOverLimitException( repositoryURL + " repository is over the upperLimit of " + repositoryUpperLimit); } if (overLimit.get() && size > repositoryLowerLimit) { /* * The mail is blocked because there was an overlimit on one of the queue's and the size of the queue is * is now less than the lower limit. It can happen that one queue was over the upper limit but that that * same queue is now less than the lower limit but another queue is not. We will still block it until * all queues are below the lower limit. If we want to track each individual queue we need to keep * these stats for each queue. */ throw new RepositoryOverLimitException( repositoryURL + " repository is over the lowerLimit of " + repositoryLowerLimit); } } } else { if (overLimit.get()) { /* * We did not currently check the queue's but the previous check reported a over limit */ throw new RepositoryOverLimitException( "The cached limit is still over the upperLimit of " + repositoryUpperLimit); } } if (overLimit.get()) { logger.info("Mail is accepted again because all repository queue's are below the lower level."); } overLimit.set(false); } }