001    package org.rakeshv.mail;
002    
003    import java.io.*;
004    import java.util.*;
005    
006    import org.jdom.*;
007    import org.jdom.input.*;
008    import org.jdom.output.*;
009    
010    /**
011     * This class stores the mail account preferences for the user(s)
012     * currently logged on to the application.  This class populates the
013     * <code>class fields</code> from the information stored in the
014     * underlying <code>preferences XML file</code> that conforms to the
015     * <a href='http://src.rakeshv.org/xml/schema/mailPreferences.xsd'>mail
016     * preferences</a> <code>XML schema</code> using <a 
017     * href='http://www.jdom.org/'>JDOM</a>.
018     *
019     * <p>You can use the {@link #createMailPreferences( String )} method
020     * to create a default mail preferences file.</p>
021     *
022     * <p>Modifiying the class fields do not modify the contents of the
023     * preferences file.  Use {@link #saveMailPreferences()} to write the
024     * modified XML data back to the preferences {@link #fileName file}.</p>
025     *
026     * <p>Copyright 2003, Rakesh Vidyadharan</p>
027     *
028     * @author Rakesh Vidyadharan
029     * @version $Id: MailPreferences.java,v 1.9 2005/09/17 11:13:49 rakesh Exp $
030     */
031    public class MailPreferences extends Object
032    {
033      /**
034       * A constant that is used to indicate that messages being deleted
035       * should be moved to the {@link WebMailBean#trashFolderName} folder.
036       * This constant is currently defined as <code>0</code>.
037       */
038      public static final int MOVE_TO_TRASH = 0;
039    
040      /**
041       * A constant that is used to indicate that message being deleted
042       * should be deleted permanently from the store.  This constant is
043       * currently defined as <code>1</code>.
044       */
045      public static final int DELETE_PERMANENTLY = 1;
046    
047      /**
048       * A constant that is used to indicate that the message being deleted
049       * should be marked as deleted (while left in the current folder).
050       * This constant is currently defined as <code>2</code>.
051       */
052      public static final int MARK_AS_DELETED = 2;
053    
054      /**
055       * A flag that is used to indicate that messages being sent <b>should</b>
056       * be copied to the {@link WebMailBean#sentFolderName}.  At present
057       * a value of <code>true</code> indicates that messages should be 
058       * copied to the folder.
059       */
060      public static final boolean COPY_SENT_MESSAGES = true;
061    
062      /**
063       * A flag that is used to indicate that messages being sent should
064       * <b>not</b> be copied to the {@link WebMailBean#sentFolderName}.  
065       * At present a value of <code>true</code> indicates that messages 
066       * should not be copied to the folder.
067       */
068      public static final boolean DO_NOT_COPY_SENT_MESSAGES = false;
069    
070      /**
071       * A constant that is used to indicate that all available messages
072       * for the chosen folder should be displayed on the page.
073       */
074      public static final int DISPLAY_ALL_MESSAGES = 1000;
075    
076      /**
077       * The fully qualified name of the file that contains the mail 
078       * preferences.
079       */
080      private String fileName = "";
081    
082      /**
083       * This field is used to indicate the type of action the user desires
084       * when deleting a mail message.  Valid values for this variable are
085       * defined by the fields {@link #MOVE_TO_TRASH}, {@link 
086       * #DELETE_PERMANENTLY}, and {@link #MARK_AS_DELETED}.  Setting this
087       * field to other values will cause undefined behaviour.  This field
088       * maps to the <code>deleteAction</code> element in the schema.
089       */
090      private int deleteAction = 0;
091    
092      /**
093       * This field is used to indicate whether message being sent by the 
094       * user are to be copied to the {@link WebMailBean#sentFolderName}
095       * folder or not.  This field maps to the <code>copySentMessages</code>
096       * element in the schema.
097       */
098      private boolean copySentMessages = false;
099    
100      /**
101       * This field is used to indicate the number of days until which
102       * deleted messages in the {@link WebMailBean#trashFolderName} folder 
103       * should be kept.  Message older than the configured number of days
104       * will be automatically deleted when the user logs out of the
105       * web-mail application.  This value will by default be 30 days.
106       */
107      private int daysToKeepDeletedMessages = 30;
108    
109      /**
110       * This field is used to store the user preference for the number of
111       * messages to be displayed on a page.  This field maps to the
112       * <code>messagesPerPage</code> element.  This field is set by default
113       * to {@link #DISPLAY_ALL_MESSAGES}.  This field maps to the
114       * <code>messagesPerPage</code> element in the schema.
115       */
116      private int messagesPerPage = MailPreferences.DISPLAY_ALL_MESSAGES;
117    
118      /**
119       * The JDOM XML document representation.
120       */
121      private Document document = null;
122    
123      /**
124       * The target namespace for the mail preferences XML data.
125       */
126      private Namespace namespace = null;
127    
128      /**
129       * Default constructor.  Cannot be directly invoked.
130       */
131      protected MailPreferences() 
132      {
133        super();
134      }
135    
136      /**
137       * Just invoke {@link #MailPreferences( String, String )} with a value
138       * of <code>null</code> for the preferred SAX Parser to use.
139       *
140       * @param fileName - The fully qualified name of the address
141       *   book XML file.
142       * @throws MailException - If any JDOM/IOExceptions are encountered
143       *   while processing the address book XML file.
144       */
145      public MailPreferences( String fileName ) throws MailException
146      {
147        this( fileName, null );
148      }
149    
150      /**
151       * Load the specified address book XML file using the specified
152       * SAX Parser.
153       *
154       * @see #loadMailPreferences( String )
155       *
156       * @param fileName - The fully qualified name of the address
157       *   book XML file.
158       * @param saxParser - The full class name of the preferred
159       *   SAX Parser to use.
160       * @throws MailException - If any JDOM/IOExceptions are encountered
161       *   while processing the address book XML file.
162       */
163      public MailPreferences( String fileName, String saxParser ) 
164        throws MailException
165      {
166        this.fileName = fileName;
167        loadMailPreferences( saxParser );
168      }
169    
170      /**
171       * Load the address book XML file ({@link #fileName}) using JDOM,
172       * and populate the instance variables.
173       *
174       * @param saxParser - The full class name of the SAX Parser
175       *   to use.  If this is <code>null</code> the default JAXP SAX
176       *   Parser will be used.
177       * @throws MailException - If any JDOM/IOExceptions are encountered
178       *   while processing the address book XML file.
179       */
180      private void loadMailPreferences( String saxParser ) 
181        throws MailException
182      {
183        SAXBuilder builder = null;
184    
185        if ( saxParser == null )
186        {
187          builder = new SAXBuilder();
188        }
189        else
190        {
191          builder = new SAXBuilder( saxParser );
192        }
193    
194        try
195        {
196          document = builder.build( new File( fileName ) );
197        }
198        catch ( Exception ex )
199        {
200          throw new MailException( true, "Error accessing mail preferences file.", ex );
201        }
202    
203        Element rootElement = document.getRootElement();
204        namespace = rootElement.getNamespace( rootElement.getNamespacePrefix() );
205    
206        // Get the delete action preference
207        String value = rootElement.getChildTextTrim( "deleteAction", namespace );
208        if ( value != null && ! value.equals( "" ) )
209        {
210          deleteAction = Integer.parseInt( value );
211        }
212    
213        // Get the sent messages preference
214        value = rootElement.getChildTextTrim( "copySentMessage", namespace );
215        if ( value != null && ! value.equals( "" ) )
216        {
217          if ( value.equals( "true" ) )
218          {
219            copySentMessages = MailPreferences.COPY_SENT_MESSAGES;
220          }
221          else if ( value.equals( "false" ) )
222          {
223            copySentMessages = MailPreferences.DO_NOT_COPY_SENT_MESSAGES;
224          }
225        }
226    
227        // Get the number of days to keep deleted mail preference
228        value = rootElement.getChildTextTrim( "daysToKeepDeletedMessages", namespace );
229        if ( value != null && ! value.equals( "" ) )
230        {
231          try
232          {
233            daysToKeepDeletedMessages = Integer.parseInt( value );
234          }
235          catch ( NumberFormatException nfex )
236          {
237            // Do nothing.  Just ignore it.
238            nfex.printStackTrace();
239          }
240        }
241    
242        // Get the number of messages per page preference
243        value = rootElement.getChildTextTrim( "messagesPerPage", namespace );
244        if ( value != null && ! value.equals( "" ) )
245        {
246          if ( value.equals( "all" ) )
247          {
248            messagesPerPage = MailPreferences.DISPLAY_ALL_MESSAGES;
249          }
250          else
251          {
252            try
253            {
254              messagesPerPage = Integer.parseInt( value );
255            }
256            catch ( NumberFormatException nfex )
257            {
258              // Do nothing.  Just ignore it.
259              nfex.printStackTrace();
260            }
261          }
262        }
263      }
264    
265      /**
266       * Just invokes {@link #createMailPreferences( String, String )} with 
267       * a <code>null</code> value for the default SAX Parser.
268       *
269       * @param file - The fully qualified name of the file ie. the
270       *   full path and name of file to use as the address book.
271       * @throws MailException - If any exceptions are encountered while
272       *   creating or writing to the specified file.
273       */
274      public static MailPreferences createMailPreferences( String file ) 
275        throws MailException
276      {
277        return createMailPreferences( file, null );
278      }
279    
280      /**
281       * Write the JDOM tree back to the address book file.
282       *
283       * @throws MailException - If any exceptions are encountered while
284       *   serialising the JDOM tree to the mail preferences file.
285       */
286      public void saveMailPreferences() throws MailException
287      {
288        FileOutputStream out = null;
289        try
290        {
291          out = new FileOutputStream( fileName );
292        }
293        catch ( FileNotFoundException fnfex )
294        {
295          throw new MailException( true, "The mail preferences file could not be found.", fnfex );
296        }
297    
298        XMLOutputter outputter = new XMLOutputter();
299        outputter.getFormat().setLineSeparator( "\n" );
300        outputter.getFormat().setIndent( "  " );
301        try
302        {
303          outputter.output( document, out );
304          out.close();
305        }
306        catch ( IOException ioex )
307        {
308          throw new MailException( true, "Error while writing to mail preferences file.", ioex );
309        }
310      }
311    
312      /**
313       * Create a new mail preferences file using the fully qualified file 
314       * name specified, and using the specified SAX Parser to load the XML
315       * file that has been created.
316       *
317       * @param file - The fully qualified name of the file ie. the
318       *   full path and name of file to use as the address book.
319       * @param saxParser - The full class name of the preferred
320       *   SAX Parser.  If this is <code>null</code> the default JAXP
321       *   SAX Parser will be used.
322       * @throws MailException - If any exceptions are encountered while
323       *   creating or writing to the specified file.
324       */
325      public static MailPreferences createMailPreferences( String file, 
326          String saxParser ) throws MailException
327      {
328        MailPreferences mailPreferences = new MailPreferences();
329        mailPreferences.setFileName( file );
330    
331        try
332        {
333          PrintWriter out = new PrintWriter( 
334               new BufferedWriter( new FileWriter( file ) ) 
335          );
336          out.println( "<?xml version='1.0' encoding='UTF-8'?>" );
337          out.println( "<mailPreferences xmlns='http://src.rakeshv.org/xml/schema/' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='http://src.rakeshv.org/xml/schema/ http://src.rakeshv.org/xml/schema/mailPreferences.xsd'>" );
338          out.println( "  <deleteAction>0</deleteAction>" );
339          out.println( "  <copySentMessage>true</copySentMessage>" );
340          out.println( "  <daysToKeepDeletedMessages>30</daysToKeepDeletedMessages>" );
341          out.println( "  <messagesPerPage>10</messagesPerPage>" );
342          out.println( "</mailPreferences>" );
343          out.flush();
344          out.close();
345        }
346        catch ( IOException iex )
347        {
348          throw new MailException( true, "Error creating/writing new address book " + file + ".", iex );
349        }
350    
351        mailPreferences.loadMailPreferences( saxParser );
352    
353        return mailPreferences;
354      }
355      
356      /**
357       * Set the value of {@link #fileName}.
358       *
359       * @param fileName - The value to set.
360       */
361      public final void setFileName( String fileName )
362      {
363        this.fileName = fileName;
364      }
365      
366      /**
367       * Return the value/reference of the {@link #deleteAction}.
368       *
369       * @return int - The value/reference of deleteAction.
370       */
371      public final int getDeleteAction()
372      {
373        return deleteAction;
374      }
375      
376      /**
377       * Set the value of {@link #deleteAction}.  Also updates the
378       * underlying JDOM tree with the new value.  Use {@link
379       * #saveMailPreferences()} to actually write the modified XML data
380       * back to the mail preferences {@link #fileName file}.
381       *
382       * @param deleteAction - The value to set.
383       */
384      public final void setDeleteAction( int deleteAction )
385      {
386        this.deleteAction = deleteAction;
387    
388        document.getRootElement().getChild( "deleteAction", namespace ).setText( String.valueOf( deleteAction ) );
389      }
390      
391      /**
392       * Return the value/reference of the {@link #copySentMessages}.
393       *
394       * @return boolean - The value/reference of copySentMessages.
395       */
396      public final boolean getCopySentMessages()
397      {
398        return copySentMessages;
399      }
400      
401      /**
402       * Set the value of {@link #copySentMessages}.  Also updates the 
403       * underlying JDOM tree with the new value.  Use {@link 
404       * #saveMailPreferences()}, to actually write the modified XML back
405       * to the mail preferences {@link #fileName file}.
406       *
407       * @param copySentMessages - The value to set.
408       */
409      public final void setCopySentMessages( boolean copySentMessages )
410      {
411        this.copySentMessages = copySentMessages;
412    
413        document.getRootElement().getChild( "copySentMessage", namespace ).setText( String.valueOf( copySentMessages ) );
414      }
415      
416      /**
417       * Return the value/reference of the {@link #messagesPerPage}.
418       *
419       * @return int - The value/reference of messagesPerPage.
420       */
421      public final int getMessagesPerPage()
422      {
423        return messagesPerPage;
424      }
425      
426      /**
427       * Set the value of {@link #messagesPerPage}.  Use {@link
428       * #DISPLAY_ALL_MESSAGES} if you wish to display all the messages on
429       * one page.  This method also updates the underlying JDOM tree with
430       * the new value.  Use {@link #saveMailPreferences()} to actually
431       * write the modified XML back to the mail preferences {@link
432       * #fileName file}.
433       *
434       * @param messagesPerPage - The value to set.
435       */
436      public final void setMessagesPerPage( int messagesPerPage )
437      {
438        this.messagesPerPage = messagesPerPage;
439    
440        document.getRootElement().getChild( "messagesPerPage", namespace ).setText( String.valueOf( messagesPerPage ) );
441      }
442      
443      /**
444       * Return the value/reference of the {@link #daysToKeepDeletedMessages}.
445       *
446       * @return int - The value/reference of daysToKeepDeletedMessages.
447       */
448      public final int getDaysToKeepDeletedMessages()
449      {
450        return daysToKeepDeletedMessages;
451      }
452      
453      /**
454       * Set the value of {@link #daysToKeepDeletedMessages}.  This method
455       * also updates the underlying JDOM tree with the new value.  Use
456       * {@link #saveMailPreferences()} to actually write the modified
457       * XML back to the mail preferences {@link #fileName file}.
458       *
459       * @param daysToKeepDeletedMessages - The value to set.
460       */
461      public final void setDaysToKeepDeletedMessages( int daysToKeepDeletedMessages )
462      {
463        this.daysToKeepDeletedMessages = daysToKeepDeletedMessages;
464    
465        document.getRootElement().getChild( "daysToKeepDeletedMessages", namespace ).setText( String.valueOf( daysToKeepDeletedMessages ) );
466      }
467    }