View Javadoc

1   /****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  
21  
22  package org.apache.james.transport.matchers;
23  
24  import org.apache.avalon.framework.container.ContainerUtil;
25  import org.apache.avalon.framework.service.ServiceException;
26  import org.apache.avalon.framework.service.ServiceManager;
27  import org.apache.james.Constants;
28  import org.apache.james.api.user.JamesUser;
29  import org.apache.james.api.user.UsersRepository;
30  import org.apache.james.services.MailRepository;
31  import org.apache.james.services.MailServer;
32  import org.apache.mailet.Mail;
33  import org.apache.mailet.MailAddress;
34  import org.apache.mailet.MailetContext;
35  
36  import javax.mail.MessagingException;
37  
38  import java.util.Iterator;
39  
40  /**
41   * <P>Experimental: Abstract matcher checking whether a recipient has exceeded a maximum allowed
42   * <I>storage</I> quota for messages standing in his inbox.</P>
43   * <P>"Storage quota" at this level is still an abstraction whose specific interpretation
44   * will be done by subclasses (e.g. could be specific for each user or common to all of them).</P> 
45   *
46   * <P>This matcher need to calculate the mailbox size everytime it is called. This can slow down things if there are many mails in
47   * the mailbox. Some users also report big problems with the matcher if a JDBC based mailrepository is used. </P>
48   *
49   * @version CVS $Revision: 684470 $ $Date: 2008-08-10 12:47:55 +0100 (Sun, 10 Aug 2008) $
50   * @since 2.2.0
51   */
52  abstract public class AbstractStorageQuota extends AbstractQuotaMatcher { 
53  
54      private MailServer mailServer;
55  
56      /** The user repository for this mail server.  Contains all the users with inboxes
57       * on this server.
58       */
59      private UsersRepository localusers;
60  
61      /**
62       * Standard matcher initialization.
63       * Overriding classes must do a <CODE>super.init()</CODE>.
64       */
65      public void init() throws MessagingException {
66          super.init();
67          ServiceManager compMgr = (ServiceManager)getMailetContext().getAttribute(Constants.AVALON_COMPONENT_MANAGER);
68          try {
69              mailServer = (MailServer) compMgr.lookup(MailServer.ROLE);
70          } catch (ServiceException e) {
71              log("Exception in getting the MailServer: " + e.getMessage() + e.getKey());
72          }
73          try {
74              localusers = (UsersRepository) compMgr.lookup(UsersRepository.ROLE);
75          } catch (ServiceException e) {
76              log("Exception in getting the UsersStore: " + e.getMessage() + e.getKey());
77          }
78      }
79  
80      /** 
81       * Checks the recipient.
82       * Does a <CODE>super.isRecipientChecked</CODE> and checks that the recipient
83       * is a known user in the local server.
84       * If a subclass overrides this method it should "and" <CODE>super.isRecipientChecked</CODE>
85       * to its check.
86       *
87       * @param recipient the recipient to check
88       */    
89      protected boolean isRecipientChecked(MailAddress recipient) throws MessagingException {
90          MailetContext mailetContext = getMailetContext();
91          return super.isRecipientChecked(recipient) && (mailetContext.isLocalEmail(recipient));
92      }
93  
94      /** 
95       * Gets the storage used in the recipient's inbox.
96       *
97       * @param recipient the recipient to check
98       */    
99      protected long getUsed(MailAddress recipient, Mail _) throws MessagingException {
100         long size = 0;
101         MailRepository userInbox = mailServer.getUserInbox(getPrimaryName(recipient.getUser()));
102         for (Iterator it = userInbox.list(); it.hasNext(); ) {
103             String key = (String) it.next();
104             Mail mc = userInbox.retrieve(key);
105             // Retrieve can return null if the mail is no longer in the store.
106             if (mc != null) try {
107                 size += mc.getMessageSize();
108             } catch (Throwable e) {
109                 // MailRepository.retrieve() does NOT lock the message.
110                 // It could be deleted while we're looping.
111                 log("Exception in getting message size: " + e.getMessage());
112             }
113             ContainerUtil.dispose(mc);
114         }
115         return size;
116     }
117 
118     /**
119      * Gets the main name of a local customer, handling aliases.
120      *
121      * @param originalUsername the user name to look for; it can be already the primary name or an alias
122      * @return the primary name, or originalUsername unchanged if not found
123      */
124     protected String getPrimaryName(String originalUsername) {
125         String username;
126         try {
127             username = localusers.getRealName(originalUsername);
128             JamesUser user = (JamesUser) localusers.getUserByName(username);
129             if (user.getAliasing()) {
130                 username = user.getAlias();
131             }
132         }
133         catch (Exception e) {
134             username = originalUsername;
135         }
136         return username;
137     }
138     
139 }