FileDocCategorySizeDatePackage
AbstractStorageQuota.javaAPI DocApache James 2.3.15858Fri Jan 12 12:56:30 GMT 2007org.apache.james.transport.matchers

AbstractStorageQuota.java

/****************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one   *
 * or more contributor license agreements.  See the NOTICE file *
 * distributed with this work for additional information        *
 * regarding copyright ownership.  The ASF licenses this file   *
 * to you under the Apache License, Version 2.0 (the            *
 * "License"); you may not use this file except in compliance   *
 * with the License.  You may obtain a copy of the License at   *
 *                                                              *
 *   http://www.apache.org/licenses/LICENSE-2.0                 *
 *                                                              *
 * Unless required by applicable law or agreed to in writing,   *
 * software distributed under the License is distributed on an  *
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
 * KIND, either express or implied.  See the License for the    *
 * specific language governing permissions and limitations      *
 * under the License.                                           *
 ****************************************************************/

package org.apache.james.transport.matchers;

import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.james.Constants;
import org.apache.james.services.JamesUser;
import org.apache.james.services.MailRepository;
import org.apache.james.services.MailServer;
import org.apache.james.services.UsersRepository;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
import org.apache.mailet.MailetContext;

import javax.mail.MessagingException;

import java.util.Iterator;

/**
 * <P>Experimental: Abstract matcher checking whether a recipient has exceeded a maximum allowed
 * <I>storage</I> quota for messages standing in his inbox.</P>
 * <P>"Storage quota" at this level is still an abstraction whose specific interpretation
 * will be done by subclasses (e.g. could be specific for each user or common to all of them).</P> 
 *
 * <P>This matcher need to calculate the mailbox size everytime it is called. This can slow down things if there are many mails in
 * the mailbox. Some users also report big problems with the matcher if a JDBC based mailrepository is used. </P>
 *
 * @version CVS $Revision: 494058 $ $Date: 2007-01-08 14:18:22 +0100 (Mo, 08 Jan 2007) $
 * @since 2.2.0
 */
abstract public class AbstractStorageQuota extends AbstractQuotaMatcher { 

    private MailServer mailServer;

    /** The user repository for this mail server.  Contains all the users with inboxes
     * on this server.
     */
    private UsersRepository localusers;

    /**
     * Standard matcher initialization.
     * Overriding classes must do a <CODE>super.init()</CODE>.
     */
    public void init() throws MessagingException {
        super.init();
        ServiceManager compMgr = (ServiceManager)getMailetContext().getAttribute(Constants.AVALON_COMPONENT_MANAGER);
        try {
            mailServer = (MailServer) compMgr.lookup(MailServer.ROLE);
        } catch (ServiceException e) {
            log("Exception in getting the MailServer: " + e.getMessage() + e.getKey());
        }
        try {
            localusers = (UsersRepository) compMgr.lookup(UsersRepository.ROLE);
        } catch (ServiceException e) {
            log("Exception in getting the UsersStore: " + e.getMessage() + e.getKey());
        }
    }

    /** 
     * Checks the recipient.
     * Does a <CODE>super.isRecipientChecked</CODE> and checks that the recipient
     * is a known user in the local server.
     * If a subclass overrides this method it should "and" <CODE>super.isRecipientChecked</CODE>
     * to its check.
     *
     * @param recipient the recipient to check
     */    
    protected boolean isRecipientChecked(MailAddress recipient) throws MessagingException {
        MailetContext mailetContext = getMailetContext();
        return super.isRecipientChecked(recipient) && (mailetContext.isLocalServer(recipient.getHost()) && mailetContext.isLocalUser(recipient.getUser()));
    }

    /** 
     * Gets the storage used in the recipient's inbox.
     *
     * @param recipient the recipient to check
     */    
    protected long getUsed(MailAddress recipient, Mail _) throws MessagingException {
        long size = 0;
        MailRepository userInbox = mailServer.getUserInbox(getPrimaryName(recipient.getUser()));
        for (Iterator it = userInbox.list(); it.hasNext(); ) {
            String key = (String) it.next();
            Mail mc = userInbox.retrieve(key);
            // Retrieve can return null if the mail is no longer in the store.
            if (mc != null) try {
                size += mc.getMessageSize();
            } catch (Throwable e) {
                // MailRepository.retrieve() does NOT lock the message.
                // It could be deleted while we're looping.
                log("Exception in getting message size: " + e.getMessage());
            }
        }
        return size;
    }

    /**
     * Gets the main name of a local customer, handling aliases.
     *
     * @param originalUsername the user name to look for; it can be already the primary name or an alias
     * @return the primary name, or originalUsername unchanged if not found
     */
    protected String getPrimaryName(String originalUsername) {
        String username;
        try {
            username = localusers.getRealName(originalUsername);
            JamesUser user = (JamesUser) localusers.getUserByName(username);
            if (user.getAliasing()) {
                username = user.getAlias();
            }
        }
        catch (Exception e) {
            username = originalUsername;
        }
        return username;
    }
    
}