1 /************************************************************************ 2 * Copyright (c) 2003-2006 The Apache Software Foundation. * 3 * All rights reserved. * 4 * ------------------------------------------------------------------- * 5 * Licensed under the Apache License, Version 2.0 (the "License"); you * 6 * may not use this file except in compliance with the License. You * 7 * may obtain a copy of the License at: * 8 * * 9 * http://www.apache.org/licenses/LICENSE-2.0 * 10 * * 11 * Unless required by applicable law or agreed to in writing, software * 12 * distributed under the License is distributed on an "AS IS" BASIS, * 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * 14 * implied. See the License for the specific language governing * 15 * permissions and limitations under the License. * 16 ***********************************************************************/ 17 18 package org.apache.james.transport.matchers; 19 20 import java.util.Iterator; 21 import java.util.Collection; 22 import java.util.ArrayList; 23 import javax.mail.MessagingException; 24 import org.apache.mailet.GenericMatcher; 25 import org.apache.mailet.MailAddress; 26 import org.apache.mailet.Mail; 27 28 /*** 29 * <P>Abstract matcher checking whether a recipient has exceeded a maximum allowed quota.</P> 30 * <P>"Quota" at this level is an abstraction whose specific interpretation 31 * will be done by subclasses.</P> 32 * <P>Although extending GenericMatcher, its logic is recipient oriented.</P> 33 * 34 * @version CVS $Revision: 365582 $ $Date: 2006-01-03 08:51:21 +0000 (mar, 03 gen 2006) $ 35 * @since 2.2.0 36 */ 37 abstract public class AbstractQuotaMatcher extends GenericMatcher { 38 39 /*** 40 * Standard matcher entrypoint. 41 * First of all, checks the sender using {@link #isSenderChecked}. 42 * Then, for each recipient checks it using {@link #isRecipientChecked} and 43 * {@link #isOverQuota}. 44 * 45 * @throws MessagingException if either <CODE>isSenderChecked</CODE> or isRecipientChecked throw an exception 46 */ 47 public final Collection match(Mail mail) throws MessagingException { 48 Collection matching = null; 49 if (isSenderChecked(mail.getSender())) { 50 matching = new ArrayList(); 51 for (Iterator i = mail.getRecipients().iterator(); i.hasNext(); ) { 52 MailAddress recipient = (MailAddress) i.next(); 53 if (isRecipientChecked(recipient) && isOverQuota(recipient, mail)) { 54 matching.add(recipient); 55 } 56 } 57 } 58 return matching; 59 } 60 61 /*** 62 * Does the quota check. 63 * Checks if {@link #getQuota} < {@link #getUsed} for a recipient. 64 * Catches any throwable returning false, and so should any override do. 65 * 66 * @param address the recipient addresss to check 67 * @param mail the mail involved in the check 68 * @return true if over quota 69 */ 70 protected boolean isOverQuota(MailAddress address, Mail mail) { 71 String user = address.getUser(); 72 try { 73 boolean over = getQuota(address, mail) < getUsed(address, mail); 74 if (over) log(address + " is over quota."); 75 return over; 76 } catch (Throwable e) { 77 log("Exception checking quota for: " + address, e); 78 return false; 79 } 80 } 81 82 /*** 83 * Checks the sender. 84 * The default behaviour is to check that the sender <I>is not</I> null nor the local postmaster. 85 * If a subclass overrides this method it should "and" <CODE>super.isSenderChecked</CODE> 86 * to its check. 87 * 88 * @param sender the sender to check 89 */ 90 protected boolean isSenderChecked(MailAddress sender) throws MessagingException { 91 return !(sender == null || getMailetContext().getPostmaster().equals(sender)); 92 } 93 94 /*** 95 * Checks the recipient. 96 * The default behaviour is to check that the recipient <I>is not</I> the local postmaster. 97 * If a subclass overrides this method it should "and" <CODE>super.isRecipientChecked</CODE> 98 * to its check. 99 * 100 * @param recipient the recipient to check 101 */ 102 protected boolean isRecipientChecked(MailAddress recipient) throws MessagingException { 103 return !(getMailetContext().getPostmaster().equals(recipient)); 104 } 105 106 /*** 107 * Gets the quota to check against. 108 * 109 * @param address the address holding the quota if applicable 110 * @param mail the mail involved if needed 111 */ 112 abstract protected long getQuota(MailAddress address, Mail mail) throws MessagingException; 113 114 /*** 115 * Gets the used amount to check against the quota. 116 * 117 * @param address the address involved 118 * @param mail the mail involved if needed 119 */ 120 abstract protected long getUsed(MailAddress address, Mail mail) throws MessagingException; 121 122 /*** 123 * Utility method that parses an amount string. 124 * You can use 'k' and 'm' as optional postfixes to the amount (both upper and lowercase). 125 * In other words, "1m" is the same as writing "1024k", which is the same as 126 * "1048576". 127 * 128 * @param amount the amount string to parse 129 */ 130 protected long parseQuota(String amount) throws MessagingException { 131 long quota; 132 try { 133 if (amount.endsWith("k")) { 134 amount = amount.substring(0, amount.length() - 1); 135 quota = Long.parseLong(amount) * 1024; 136 } else if (amount.endsWith("m")) { 137 amount = amount.substring(0, amount.length() - 1); 138 quota = Long.parseLong(amount) * 1024 * 1024; 139 } else { 140 quota = Long.parseLong(amount); 141 } 142 return quota; 143 } 144 catch (Exception e) { 145 throw new MessagingException("Exception parsing quota", e); 146 } 147 } 148 }