View Javadoc

1   /**
2    *
3    * Copyright 2003-2005 The Apache Software Foundation
4    *
5    *  Licensed under the Apache License, Version 2.0 (the "License");
6    *  you may not use this file except in compliance with the License.
7    *  You 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 implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  
18  package org.apache.geronimo.javamail.store.nntp;
19  
20  import javax.mail.Flags;
21  import javax.mail.Folder;
22  import javax.mail.IllegalWriteException;
23  import javax.mail.Message;
24  import javax.mail.MessagingException;
25  import javax.mail.MethodNotSupportedException;
26  import javax.mail.Session;
27  import javax.mail.event.ConnectionEvent;
28  
29  import org.apache.geronimo.javamail.transport.nntp.NNTPConnection;
30  
31  /**
32   * The base NNTP implementation of the javax.mail.Folder This is a base class
33   * for both the Root NNTP server and each NNTP group folder.
34   * 
35   * @see javax.mail.Folder
36   * 
37   * @version $Rev: 432884 $
38   */
39  public class NNTPFolder extends Folder {
40  
41      // our active connection.
42      protected NNTPConnection connection;
43  
44      // our attached session
45      protected Session session;
46  
47      // the name of this folder (either the name of the server for the root or
48      // the news group name).
49      protected String name;
50  
51      // the "full" name of the folder. For the root folder, this is the name
52      // returned by the connection
53      // welcome string. Otherwise, this is the same as the name.
54      protected String fullName;
55  
56      // the parent folder. For the root folder, this is null. For a group folder,
57      // this is the root.
58      protected Folder parent;
59  
60      // the folder open state
61      protected boolean folderOpen = false;
62  
63      // the folder message count. For the root folder, this is always 0.
64      protected int messageCount = 0;
65  
66      // the persistent flags we save in the store (basically just the SEEN flag).
67      protected Flags permanentFlags;
68  
69      /**
70       * Super class constructor the base NNTPFolder class.
71       * 
72       * @param store
73       *            The javamail store this folder is attached to.
74       */
75      protected NNTPFolder(NNTPStore store) {
76          super(store);
77          // get the active connection from the store...all commands are sent
78          // there
79          this.connection = store.getConnection();
80          this.session = store.getSession();
81  
82          // set up our permanent flags bit.
83          permanentFlags = new Flags();
84          permanentFlags.add(Flags.Flag.SEEN);
85      }
86  
87      /**
88       * Retrieve the folder name.
89       * 
90       * @return The folder's name.
91       */
92      public String getName() {
93          return name;
94      }
95  
96      /**
97       * Retrieve the folder's full name (including hierarchy information). NNTP
98       * folders are flat, so the full name is generally the same as the name.
99       * 
100      * @return The full name value.
101      */
102     public String getFullName() {
103         return fullName;
104     }
105 
106     /**
107      * Returns the parent folder for this folder. Returns null if this is the
108      * root folder.
109      */
110     public Folder getParent() throws MessagingException {
111         return parent;
112     }
113 
114     /**
115      * Indicated whether the folder "exists" or not. Existance in this context
116      * indicates that the group still exists on the server.
117      * 
118      * @return
119      * @exception MessagingException
120      */
121     public boolean exists() throws MessagingException {
122         // by default, return true. This is really only the case for the root.
123         // The group folder will
124         // need to override this.
125         return true;
126     }
127 
128     /**
129      * List the subfolders. For group folders, this is a meaningless so we throw
130      * a MethodNotSupportedException.
131      * 
132      * @param pattern
133      *            The folder pattern string.
134      * 
135      * @return Never returns.
136      * @exception MessagingException
137      */
138     public Folder[] list(String pattern) throws MessagingException {
139         throw new MethodNotSupportedException("NNTP group folders cannot contain sub folders");
140     }
141 
142     /**
143      * Retrieve the list of subscribed folders that match the given pattern
144      * string.
145      * 
146      * @param pattern
147      *            The pattern string used for the matching
148      * 
149      * @return An array of matching folders from the subscribed list.
150      */
151     public Folder[] listSubscribed(String pattern) throws MessagingException {
152         throw new MethodNotSupportedException("NNTP group folders cannot contain sub folders");
153     }
154 
155     /**
156      * No sub folders, hence there is no notion of a seperator. We return a null
157      * character (consistent with what Sun returns for POP3 folders).
158      */
159     public char getSeparator() throws MessagingException {
160         return '\0';
161     }
162 
163     /**
164      * Return whether this folder can hold just messages or also subfolders.
165      * Only the root folder can hold other folders, so it will need to override.
166      * 
167      * @return Either Folder.HOLDS_MESSAGES or Folder.HOLDS_FOLDERS.
168      * @exception MessagingException
169      */
170     public int getType() throws MessagingException {
171         return HOLDS_MESSAGES;
172     }
173 
174     /**
175      * Create a new folder. NNTP folders are read only, so this is a nop.
176      * 
177      * @param type
178      *            The type of folder.
179      * 
180      * @return Not support, throws an exception.
181      * @exception MessagingException
182      */
183     public boolean create(int type) throws MessagingException {
184         throw new MethodNotSupportedException("Sub folders cannot be created in NNTP");
185     }
186 
187     /**
188      * Check for new messages. We always return false for the root folder. The
189      * group folders will need to override.
190      * 
191      * @return Always returns false.
192      * @exception MessagingException
193      */
194     public boolean hasNewMessages() throws MessagingException {
195         return false;
196     }
197 
198     /**
199      * Get a named subfolder from this folder. This only has meaning from the
200      * root NNTP folder.
201      * 
202      * @param name
203      *            The requested name.
204      * 
205      * @return If the folder exists, returns a Folder object representing the
206      *         named folder.
207      * @exception MessagingException
208      */
209     public Folder getFolder(String name) throws MessagingException {
210         throw new MethodNotSupportedException("NNTP Group folders do not support sub folders");
211     }
212 
213     /**
214      * Delete a folder. This is not supported for NNTP.
215      * 
216      * @param recurse
217      *            The recusion flag.
218      * 
219      * @return Never returns.
220      * @exception MessagingException
221      */
222     public boolean delete(boolean recurse) throws MessagingException {
223         throw new MethodNotSupportedException("Deleting of NNTP folders is not supported");
224     }
225 
226     /**
227      * Rename a folder. Not supported for NNTP folders.
228      * 
229      * @param f
230      *            The new folder specifying the rename location.
231      * 
232      * @return
233      * @exception MessagingException
234      */
235     public boolean renameTo(Folder f) throws MessagingException {
236         throw new MethodNotSupportedException("Renaming of NNTP folders is not supported.");
237     }
238 
239     /**
240      * @see javax.mail.Folder#open(int)
241      */
242     public void open(int mode) throws MessagingException {
243 
244         // we don't support READ_WRITE mode, so don't allow opening in that
245         // mode.
246         if (mode == READ_WRITE) {
247             throw new IllegalWriteException("Newsgroup folders cannot be opened read/write");
248         }
249 
250         // an only be performed on a closed folder
251         checkClosed();
252 
253         this.mode = mode;
254 
255         // perform folder type-specific open actions.
256         openFolder();
257 
258         folderOpen = true;
259 
260         notifyConnectionListeners(ConnectionEvent.OPENED);
261     }
262 
263     /**
264      * Perform folder type-specific open actions. The default action is to do
265      * nothing.
266      * 
267      * @exception MessagingException
268      */
269     protected void openFolder() throws MessagingException {
270     }
271 
272     /**
273      * Peform folder type-specific close actions. The default action is to do
274      * nothing.
275      * 
276      * @exception MessagingException
277      */
278     protected void closeFolder() throws MessagingException {
279     }
280 
281     /**
282      * Close the folder. Cleans up resources, potentially expunges messages
283      * marked for deletion, and sends an event notification.
284      * 
285      * @param expunge
286      *            The expunge flag, which is ignored for NNTP folders.
287      * 
288      * @exception MessagingException
289      */
290     public void close(boolean expunge) throws MessagingException {
291         // Can only be performed on an open folder
292         checkOpen();
293 
294         // give the subclasses an opportunity to do some cleanup
295         closeFolder();
296 
297         folderOpen = false;
298         notifyConnectionListeners(ConnectionEvent.CLOSED);
299     }
300 
301     /**
302      * Tests the open status of the folder.
303      * 
304      * @return true if the folder is open, false otherwise.
305      */
306     public boolean isOpen() {
307         return folderOpen;
308     }
309 
310     /**
311      * Get the permanentFlags
312      * 
313      * @return The set of permanent flags we support (only SEEN).
314      */
315     public Flags getPermanentFlags() {
316         // we need a copy of our master set.
317         return new Flags(permanentFlags);
318     }
319 
320     /**
321      * Get the count of messages in this folder.
322      * 
323      * @return The message count.
324      * @exception MessagingException
325      */
326     public int getMessageCount() throws MessagingException {
327         return messageCount;
328     }
329 
330     /**
331      * Checks wether the message is in cache, if not will create a new message
332      * object and return it.
333      * 
334      * @see javax.mail.Folder#getMessage(int)
335      */
336     public Message getMessage(int msgNum) throws MessagingException {
337         // for the base, we just throw an exception.
338         throw new MethodNotSupportedException("Root NNTP folder does not contain messages");
339     }
340 
341     /**
342      * Append messages to a folder. NNTP folders are read only, so this is not
343      * supported.
344      * 
345      * @param msgs
346      *            The list of messages to append.
347      * 
348      * @exception MessagingException
349      */
350     public void appendMessages(Message[] msgs) throws MessagingException {
351         throw new MethodNotSupportedException("Root NNTP folder does not contain messages");
352 
353     }
354 
355     /**
356      * Expunge messages marked for deletion and return a list of the Messages.
357      * Not supported for NNTP.
358      * 
359      * @return Never returns.
360      * @exception MessagingException
361      */
362     public Message[] expunge() throws MessagingException {
363         throw new MethodNotSupportedException("Root NNTP folder does not contain messages");
364     }
365 
366     /**
367      * Below is a list of convenience methods that avoid repeated checking for a
368      * value and throwing an exception
369      */
370 
371     /** Ensure the folder is open */
372     protected void checkOpen() throws IllegalStateException {
373         if (!folderOpen) {
374             throw new IllegalStateException("Folder is not Open");
375         }
376     }
377 
378     /** Ensure the folder is not open */
379     protected void checkClosed() throws IllegalStateException {
380         if (folderOpen) {
381             throw new IllegalStateException("Folder is Open");
382         }
383     }
384 
385     /**
386      * @see javax.mail.Folder#notifyMessageChangedListeners(int,
387      *      javax.mail.Message)
388      * 
389      * this method is protected and cannot be used outside of Folder, therefore
390      * had to explicitly expose it via a method in NNTPFolder, so that
391      * NNTPMessage has access to it
392      * 
393      * Bad design on the part of the Java Mail API.
394      */
395     public void notifyMessageChangedListeners(int type, Message m) {
396         super.notifyMessageChangedListeners(type, m);
397     }
398 
399     /**
400      * Retrieve the subscribed status for a folder. This default implementation
401      * just returns false (which is true for the root folder).
402      * 
403      * @return Always returns true.
404      */
405     public boolean isSubscribed() {
406         return false;
407     }
408 
409     /**
410      * Set the subscribed status for a folder.
411      * 
412      * @param flag
413      *            The new subscribed status.
414      * 
415      * @exception MessagingException
416      */
417     public void setSubscribed(boolean flag) throws MessagingException {
418         throw new MessagingException("Root NNTP folder cannot be subscribed to");
419     }
420 
421     /**
422      * Test if a given article number is marked as SEEN.
423      * 
424      * @param article
425      *            The target article number.
426      * 
427      * @return The articles current seen status.
428      */
429     public boolean isSeen(int article) {
430         return false;
431     }
432 
433     /**
434      * Set the SEEN status for an article.
435      * 
436      * @param article
437      *            The target article.
438      * @param flag
439      *            The new seen setting.
440      * 
441      * @exception MessagingException
442      */
443     public void setSeen(int article, boolean flag) throws MessagingException {
444         throw new MessagingException("Root NNTP folder does not contain articles");
445     }
446 
447 }