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     */
019    
020    package org.apache.geronimo.javamail.store.nntp.newsrc;
021    
022    import java.io.BufferedReader;
023    import java.io.IOException;
024    import java.io.Writer;
025    import java.util.HashMap;
026    import java.util.Iterator;
027    import java.util.Map;
028    
029    /**
030     * Base class implementation of a standard news reader news rc file. This is
031     * used to track newsgroup subscriptions and SEEN flags for articles. This is an
032     * abstract class designed for subclasses to bridge to the physical store type
033     * used for the newsgroup information.
034     */
035    public abstract class NNTPNewsrc {
036    
037        // the group information we've read from the news rc file.
038        Map groups = new HashMap();
039    
040        // flag to let us know of we need to persist the newsrc file on close.
041        boolean dirty = false;
042    
043        /**
044         * Base class constructor for NNTPNewsrc items. Subclasses provide their own
045         * domain-specific intialization.
046         */
047        protected NNTPNewsrc() {
048        }
049    
050        /**
051         * Load the data from the newsrc file and parse into an instore group
052         * database.
053         */
054        public void load() {
055            BufferedReader in = null;
056    
057            try {
058                in = getInputReader();
059    
060                String line = in.readLine();
061    
062                while (line != null) {
063                    // parse the line...this returns null if it's something
064                    // unrecognized.
065                    NNTPNewsrcGroup group = NNTPNewsrcGroup.parse(this, line);
066                    // if it parsed ok, add it to the group list, and potentially to
067                    // the subscribed list.
068                    if (group != null) {
069                        groups.put(group.getName(), group);
070                    }
071    
072                    line = in.readLine();
073                }
074    
075                in.close();
076            } catch (IOException e) {
077                // an IOException may mean that the file just doesn't exist, which
078                // is fine. We'll ignore and
079                // proceed with the information we have.
080            } finally {
081                if (in != null) {
082                    try {
083                        in.close();
084                    } catch (IOException e) {
085                        // ignore
086                    }
087                }
088            }
089        }
090    
091        /**
092         * Save the newsrc file data back to the original source file.
093         * 
094         * @exception IOException
095         */
096        public void save() throws IOException {
097            Writer out = getOutputWriter();
098    
099            Iterator i = groups.values().iterator();
100    
101            while (i.hasNext()) {
102                NNTPNewsrcGroup group = (NNTPNewsrcGroup) i.next();
103                group.save(out);
104            }
105    
106            out.close();
107        }
108    
109        /**
110         * Abstract open method intended for sub class initialization. The subclass
111         * is responsible for creating the BufferedReaded used to read the .newsrc
112         * file.
113         * 
114         * @return A BufferedReader for reading the .newsrc file.
115         * @exception IOException
116         */
117        abstract public BufferedReader getInputReader() throws IOException;
118    
119        /**
120         * Abstract open for output method intended for subclass implementation. The
121         * subclasses are reponsible for opening the output stream and creating an
122         * appropriate Writer for saving the .newsrc file.
123         * 
124         * @return A Writer target at the .newsrc file save location.
125         * @exception IOException
126         */
127        abstract public Writer getOutputWriter() throws IOException;
128    
129        /**
130         * Retrieve the newsrc group information for a named group. If the file does
131         * not currently include this group, an unsubscribed group will be added to
132         * the file.
133         * 
134         * @param name
135         *            The name of the target group.
136         * 
137         * @return The NNTPNewsrcGroup item corresponding to this name.
138         */
139        public NNTPNewsrcGroup getGroup(String name) {
140            NNTPNewsrcGroup group = (NNTPNewsrcGroup) groups.get(name);
141            // if we don't know about this, create a new one and add to the list.
142            // This
143            // will be an unsubscribed one.
144            if (group == null) {
145                group = new NNTPNewsrcGroup(this, name, null, false);
146                groups.put(name, group);
147                // we've added a group, so we need to resave
148                dirty = true;
149            }
150            return group;
151        }
152    
153        /**
154         * Mark this newsrc database as dirty.
155         */
156        public void setDirty() {
157            dirty = true;
158        }
159    
160        /**
161         * Close the newsrc file, persisting it back to disk if the file has
162         * changed.
163         */
164        public void close() {
165            if (dirty) {
166                try {
167                    save();
168                } catch (IOException e) {
169                    // ignore
170                }
171            }
172        }
173    
174        /**
175         * Retrieve the current set of loaded groups.
176         * 
177         * @return An iterator for traversing the group set.
178         */
179        public Iterator getGroups() {
180            return groups.values().iterator();
181        }
182    }