001/****************************************************************
002 * Licensed to the Apache Software Foundation (ASF) under one   *
003 * or more contributor license agreements.  See the NOTICE file *
004 * distributed with this work for additional information        *
005 * regarding copyright ownership.  The ASF licenses this file   *
006 * to you under the Apache License, Version 2.0 (the            *
007 * "License"); you may not use this file except in compliance   *
008 * with the License.  You may obtain a copy of the License at   *
009 *                                                              *
010 *   http://www.apache.org/licenses/LICENSE-2.0                 *
011 *                                                              *
012 * Unless required by applicable law or agreed to in writing,   *
013 * software distributed under the License is distributed on an  *
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015 * KIND, either express or implied.  See the License for the    *
016 * specific language governing permissions and limitations      *
017 * under the License.                                           *
018 ****************************************************************/
019package org.apache.james.mailbox.maildir.user;
020
021import java.io.BufferedReader;
022import java.io.File;
023import java.io.FileReader;
024import java.io.FileWriter;
025import java.io.IOException;
026import java.io.PrintWriter;
027import java.util.ArrayList;
028import java.util.Collections;
029import java.util.HashSet;
030import java.util.List;
031import java.util.Set;
032
033import org.apache.james.mailbox.exception.SubscriptionException;
034import org.apache.james.mailbox.maildir.MaildirStore;
035import org.apache.james.mailbox.store.transaction.NonTransactionalMapper;
036import org.apache.james.mailbox.store.user.SubscriptionMapper;
037import org.apache.james.mailbox.store.user.model.Subscription;
038import org.apache.james.mailbox.store.user.model.impl.SimpleSubscription;
039
040public class MaildirSubscriptionMapper extends NonTransactionalMapper implements SubscriptionMapper {
041
042    private static final String FILE_SUBSCRIPTION = "subscriptions";
043    private MaildirStore store;
044    
045    public MaildirSubscriptionMapper(MaildirStore store) {
046        this.store = store;
047    }
048    
049    /**
050     * @see org.apache.james.mailbox.store.user.SubscriptionMapper#delete(org.apache.james.mailbox.store.user.model.Subscription)
051     */
052    @Override
053    public void delete(Subscription subscription) throws SubscriptionException {
054     // TODO: we need some kind of file locking here
055        Set<String> subscriptionNames = readSubscriptionsForUser(subscription.getUser());
056        boolean changed = subscriptionNames.remove(subscription.getMailbox());
057        if (changed) {
058            try {
059                writeSubscriptions(new File(store.userRoot(subscription.getUser())), subscriptionNames);
060            } catch (IOException e) {
061                throw new SubscriptionException(e);
062            }
063        }
064    }
065
066    /**
067     * @see org.apache.james.mailbox.store.user.SubscriptionMapper#findSubscriptionsForUser(java.lang.String)
068     */
069    @Override
070    public List<Subscription> findSubscriptionsForUser(String user) throws SubscriptionException {
071        Set<String> subscriptionNames = readSubscriptionsForUser(user);
072        ArrayList<Subscription> subscriptions = new ArrayList<Subscription>();
073        for (String subscription : subscriptionNames) {
074            subscriptions.add(new SimpleSubscription(user, subscription));
075        }
076        return subscriptions;
077    }
078
079    /**
080     * @see org.apache.james.mailbox.store.user.SubscriptionMapper#findMailboxSubscriptionForUser(java.lang.String, java.lang.String)
081     */
082    @Override
083    public Subscription findMailboxSubscriptionForUser(String user, String mailbox) throws SubscriptionException {
084        File userRoot = new File(store.userRoot(user));
085        Set<String> subscriptionNames;
086        try {
087            subscriptionNames = readSubscriptions(userRoot);
088        } catch (IOException e) {
089            throw new SubscriptionException(e);
090        }
091        if (subscriptionNames.contains(mailbox))
092            return new SimpleSubscription(user, mailbox);
093        return null;
094    }
095
096    /**
097     * @see org.apache.james.mailbox.store.user.SubscriptionMapper#save(org.apache.james.mailbox.store.user.model.Subscription)
098     */
099    @Override
100    public void save(Subscription subscription) throws SubscriptionException {
101        // TODO: we need some kind of file locking here
102        Set<String> subscriptionNames = readSubscriptionsForUser(subscription.getUser());
103        boolean changed = subscriptionNames.add(subscription.getMailbox());
104        if (changed) {
105            try {
106                writeSubscriptions(new File(store.userRoot(subscription.getUser())), subscriptionNames);
107            } catch (IOException e) {
108                throw new SubscriptionException(e);
109            }
110        }
111    }
112
113    /**
114     * @see org.apache.james.mailbox.store.transaction.TransactionalMapper#endRequest()
115     */
116    @Override
117    public void endRequest() {
118        // nothing to do
119    }
120    
121    
122    /**
123     * Read the subscriptions for a particular user
124     * @param user The user to get the subscriptions for
125     * @return A Set of names of subscribed mailboxes of the user
126     * @throws SubscriptionException
127     */
128    private Set<String> readSubscriptionsForUser(String user) throws SubscriptionException { 
129        File userRoot = new File(store.userRoot(user));
130        Set<String> subscriptionNames;
131        try {
132            subscriptionNames = readSubscriptions(userRoot);
133        } catch (IOException e) {
134            throw new SubscriptionException(e);
135        }
136        return subscriptionNames;
137    }
138
139    /**
140     * Read the names of the mailboxes which are subscribed from the specified folder
141     * @param mailboxFolder The folder which contains the subscription file
142     * @return A Set of names of subscribed mailboxes
143     * @throws IOException
144     */
145    private Set<String> readSubscriptions(File mailboxFolder) throws IOException {
146        File subscriptionFile = new File(mailboxFolder, FILE_SUBSCRIPTION);
147        HashSet<String> subscriptions = new HashSet<String>();
148        if (!subscriptionFile.exists()) {
149            return subscriptions;
150        }
151        FileReader fileReader = new FileReader(subscriptionFile);
152        BufferedReader reader = new BufferedReader(fileReader);
153        String subscription;
154        while ((subscription = reader.readLine()) != null)
155            if (!subscription.equals(""))
156                subscriptions.add(subscription);
157        reader.close();
158        fileReader.close();
159        return subscriptions;
160    }
161    
162    /**
163     * Write the set of mailbox names into the subscriptions file in the specified folder
164     * @param mailboxFolder Folder which contains the subscriptions file
165     * @param subscriptions Set of names of subscribed mailboxes
166     * @throws IOException
167     */
168    private void writeSubscriptions(File mailboxFolder, final Set<String> subscriptions) throws IOException {
169        List<String> sortedSubscriptions = new ArrayList<String>(subscriptions);
170        Collections.sort(sortedSubscriptions);
171        if (!mailboxFolder.exists())
172            if (!mailboxFolder.mkdirs())
173                throw new IOException("Could not create folder " + mailboxFolder);
174        
175        File subscriptionFile = new File(mailboxFolder, FILE_SUBSCRIPTION);
176        if (!subscriptionFile.exists())
177            if (!subscriptionFile.createNewFile())
178                throw new IOException("Could not create file " + subscriptionFile);
179                
180        FileWriter fileWriter = new FileWriter(subscriptionFile);
181        PrintWriter writer = new PrintWriter(fileWriter);
182        for (String subscription : sortedSubscriptions)
183            writer.println(subscription);
184        writer.close();
185        fileWriter.close();
186    }
187
188}