• Main Page
  • Related Pages
  • Classes
  • Files
  • File List

SendMailApp.java

Go to the documentation of this file.
00001 
00002 import java.awt.Color;
00003 import java.awt.Dimension;
00004 import java.awt.Font;
00005 import java.awt.Toolkit;
00006 import java.awt.event.ActionEvent;
00007 import java.awt.event.ActionListener;
00008 import java.awt.event.WindowEvent;
00009 import java.text.SimpleDateFormat;
00010 import java.util.Calendar;
00011 
00012 import javax.mail.MessagingException;
00013 import javax.swing.GroupLayout;
00014 import javax.swing.JButton;
00015 import javax.swing.JFrame;
00016 import javax.swing.JLabel;
00017 import javax.swing.JOptionPane;
00018 import javax.swing.JPanel;
00019 import javax.swing.JScrollPane;
00020 import javax.swing.JTabbedPane;
00021 import javax.swing.JTextArea;
00022 import javax.swing.JTextField;
00023 import javax.swing.WindowConstants;
00024 import javax.swing.plaf.metal.MetalBorders;
00025 
00026 /**
00027  *  Simple SMTP send mail application that demonstrates usage of the MailTransport class.
00028  *  It also offers presentation context for instances of MailTransport. 
00029  *  
00030  *  @author Mikica B Kocic
00031  */
00032 public class SendMailApp extends JFrame 
00033     implements ActionListener, MailTransport.Context
00034 {
00035     /**
00036      *  Implements java.io.Serializable interface
00037      */
00038     private static final long serialVersionUID = 6679954030573701419L;
00039 
00040     /**
00041      *  Common application title prefix.
00042      */
00043     private final static String appTitle = "IP1-6.1: SMTP Send Mail";
00044     
00045     /**
00046      *  GUI components
00047      */
00048     private JButton     buttonEnqueue;
00049     private JButton     buttonSend;
00050     
00051     private JLabel      labelServer;
00052     private JTextField  fieldServer;
00053     private JLabel      labelFrom;
00054     private JTextField  fieldFrom;
00055     private JLabel      labelTo;
00056     private JTextField  fieldTo;
00057     private JLabel      labelSubject;
00058     private JTextField  fieldSubject;
00059     private JScrollPane messageScrollPane;
00060     private JTextArea   messageContents;
00061     
00062     private JTabbedPane tabbedPane;
00063     
00064     private JScrollPane logPane;
00065     private JTextArea   logArea;
00066     
00067     /**
00068      *  Instance of the current mail transport channel.
00069      */
00070     private MailTransport mailTransport = null;
00071 
00072     /**
00073      *  Creates an instance of the send mail application GUI.
00074      */
00075     public SendMailApp ()
00076     {
00077         super( appTitle + ", idle" );
00078             
00079         setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
00080         
00081         /////////////////////////////////////////////////////// GUI COMPONENTS ///////////
00082         
00083         addWindowListener( new java.awt.event.WindowAdapter () {
00084             public void windowClosing( java.awt.event.WindowEvent evt ) {
00085                 formWindowClosing( evt );
00086             }
00087         });
00088 
00089         Font btnFont  = new Font( Font.SANS_SERIF, Font.BOLD,  12 );
00090         Font textFont = new Font( Font.SANS_SERIF, Font.PLAIN, 15 );
00091         Font logFont  = new Font( Font.MONOSPACED, Font.PLAIN, 14 );
00092         
00093         buttonEnqueue    = new JButton ();
00094         buttonSend       = new JButton ();
00095         labelServer      = new JLabel ();
00096         fieldServer       = new JTextField ();
00097         labelFrom        = new JLabel ();
00098         fieldFrom         = new JTextField ();
00099         labelTo          = new JLabel ();
00100         fieldTo           = new JTextField ();
00101         labelSubject     = new JLabel ();
00102         fieldSubject      = new JTextField ();
00103 
00104         labelServer.setText( "STMP Server:" );
00105         labelFrom.setText( "From:" );
00106         labelTo.setText( "To:" );
00107         labelSubject.setText( "Subject:" );
00108         
00109         fieldServer.setColumns( 40 );
00110         fieldFrom.setColumns( 40 );
00111         fieldTo.setColumns( 40 );
00112         fieldSubject.setColumns( 40 );
00113 
00114         buttonEnqueue.setFont( btnFont );
00115         buttonSend.setFont( btnFont );
00116         labelServer.setFont( textFont );
00117         labelFrom.setFont( textFont );
00118         labelTo.setFont( textFont );
00119         labelSubject.setFont( textFont );
00120         fieldServer.setFont( textFont );
00121         fieldFrom.setFont( textFont );
00122         fieldTo.setFont( textFont );
00123         fieldSubject.setFont( textFont );
00124 
00125         messageContents = new JTextArea ();
00126         messageContents.setLineWrap( true );
00127         messageContents.setWrapStyleWord( true );
00128         messageContents.setEditable( true );
00129         messageContents.setFont( textFont );
00130 
00131         messageScrollPane = new JScrollPane ();
00132         messageScrollPane.setViewportView( messageContents );
00133         
00134         logArea = new JTextArea ();
00135         logArea.setLineWrap( true );
00136         logArea.setWrapStyleWord( true );
00137         logArea.setEditable( false );
00138         logArea.setFont( logFont );
00139         logArea.setBackground( new Color( 255, 255, 240 ) );
00140         logArea.setForeground( Color.BLACK );
00141         logArea.setWrapStyleWord( true );
00142         
00143         logPane = new JScrollPane ();
00144         logPane.setViewportView( logArea );
00145 
00146         buttonEnqueue.setText( "Enqueue Message" );
00147         buttonEnqueue.addActionListener( this );
00148 
00149         buttonSend.setText( "Send Immediatelly" );
00150         buttonSend.addActionListener( this );
00151 
00152         /////////////////////////////////////////////////////// COMPONENTS LAYOUT ////////
00153 
00154         JPanel sendMailPane = new JPanel (); 
00155         sendMailPane.setBorder( new MetalBorders.Flush3DBorder() );
00156         
00157         GroupLayout layout = new GroupLayout( sendMailPane );
00158         sendMailPane.setLayout( layout );
00159         layout.setAutoCreateContainerGaps( true );
00160         layout.setAutoCreateGaps( true );
00161         
00162         layout.setHorizontalGroup
00163         (
00164             layout
00165             .createParallelGroup( GroupLayout.Alignment.LEADING )
00166             .addGroup
00167             (
00168                 layout
00169                 .createSequentialGroup ()
00170                 .addGroup
00171                 (
00172                     layout
00173                     .createParallelGroup( GroupLayout.Alignment.TRAILING )
00174                     .addComponent( messageScrollPane )
00175                     .addGroup
00176                     (
00177                         GroupLayout.Alignment.LEADING, 
00178                         layout
00179                         .createSequentialGroup ()
00180                         .addContainerGap( 10, 10 )
00181                         .addGroup
00182                         (
00183                             layout
00184                             .createParallelGroup( GroupLayout.Alignment.LEADING )
00185                             .addComponent( labelServer )
00186                             .addComponent( labelFrom )
00187                             .addComponent( labelTo )
00188                             .addComponent( labelSubject )
00189                         )
00190                         .addGroup
00191                         (
00192                             layout
00193                             .createParallelGroup( GroupLayout.Alignment.LEADING, false )
00194                             .addComponent( fieldServer )
00195                             .addComponent( fieldFrom )
00196                             .addComponent( fieldTo )
00197                             .addComponent( fieldSubject )
00198                         )
00199                     )
00200                     .addGroup
00201                     (
00202                         GroupLayout.Alignment.LEADING,
00203                         layout
00204                         .createSequentialGroup ()
00205                         .addContainerGap( 10, 10 )
00206                         .addGroup
00207                         (
00208                             layout
00209                             .createParallelGroup( GroupLayout.Alignment.LEADING, false )
00210                             .addComponent( buttonEnqueue )
00211                         )
00212                         .addGroup
00213                         (
00214                             layout
00215                             .createParallelGroup( GroupLayout.Alignment.LEADING, false )
00216                             .addComponent( buttonSend )
00217                         )
00218                     )
00219                 )
00220             )
00221         );
00222         
00223         layout.setVerticalGroup
00224         (
00225             layout
00226             .createParallelGroup( GroupLayout.Alignment.LEADING )
00227             .addGroup
00228             (
00229                 layout
00230                 .createSequentialGroup ()
00231                 .addGroup
00232                 (
00233                     layout
00234                     .createParallelGroup( GroupLayout.Alignment.BASELINE )
00235                     .addComponent( labelServer )
00236                     .addComponent( fieldServer )
00237                 )
00238                 .addGroup
00239                 (
00240                     layout
00241                     .createParallelGroup( GroupLayout.Alignment.BASELINE )
00242                     .addComponent( labelFrom )
00243                     .addComponent( fieldFrom )
00244                 )
00245                 .addGroup
00246                 (
00247                     layout
00248                     .createParallelGroup( GroupLayout.Alignment.BASELINE )
00249                     .addComponent( labelTo )
00250                     .addComponent( fieldTo )
00251                 )
00252                 .addGroup
00253                 (
00254                     layout.createParallelGroup( GroupLayout.Alignment.BASELINE )
00255                     .addComponent( labelSubject )
00256                     .addComponent( fieldSubject )
00257                 )
00258                 .addGroup
00259                 (
00260                     layout.createParallelGroup( GroupLayout.Alignment.BASELINE )
00261                     .addComponent( buttonEnqueue )
00262                     .addComponent( buttonSend )
00263                 )
00264                 .addComponent( messageScrollPane )
00265             )
00266         );
00267 
00268         pack ();
00269 
00270         /////////////////////////////////////////////////////// TABBED PANES /////////////
00271         
00272         tabbedPane = new JTabbedPane ();
00273         getContentPane().add( tabbedPane );
00274         tabbedPane.addTab( "Compose Message", sendMailPane );
00275         tabbedPane.addTab( "MTA: Idle", logPane );
00276 
00277         /////////////////////////////////////////////////////// WINDOW PLACEMENT /////////
00278         
00279         /* Adjust window dimensions not to exceed screen dimensions ...
00280          */
00281         Dimension win = new Dimension( 695, 590 );
00282         Dimension scsz = Toolkit.getDefaultToolkit().getScreenSize();
00283         win.width  = Math.min( win.width, scsz.width );
00284         win.height = Math.min( win.height, scsz.height - 40 );
00285         setMinimumSize( win );
00286         setSize( win );
00287         
00288         /* ... then center window on the screen.
00289          */
00290         setLocation( ( scsz.width - win.width )/2, ( scsz.height - 40 - win.height )/2 );
00291         
00292         /* Ready for user to type in...
00293          */
00294         fieldServer.requestFocus ();
00295     }
00296 
00297     /**
00298      *  Enqueues message and optionally flushes the queue. It creates new instance of the
00299      *  mail transport channel (if there is no any and also keeps GUI elements 
00300      *  synchronized with the current state of the mail transport instance.  
00301      */
00302     private void enqueueMessage( boolean sendImmediately )
00303     {
00304         try 
00305         {
00306             /* Create new instance of mail transport (if there is no any) and lock the 
00307              * server input field so the user cannot change server name 
00308              * until the queue is flushed (because all subsequent messages
00309              * will be enqueued in the queue of the currently created MailTransport
00310              * instance). 
00311              */
00312             synchronized( this ) 
00313             {
00314                 if ( mailTransport == null ) {
00315                     mailTransport = new MailTransport( this, fieldServer.getText(), 25 );
00316                     fieldServer.setEnabled( false );
00317                 }
00318             }
00319 
00320             /* Now, create and put the message into sending queue of the mail transport...
00321              */
00322             String   from       = fieldFrom.getText().trim(); 
00323             String[] recipients = fieldTo.getText().trim().split(",");
00324             String   subject    = fieldSubject.getText().trim();
00325             String   contents   = messageContents.getText().trim();
00326            
00327             /* Enqueue message only if there is recipient specified
00328              */
00329             if ( recipients.length > 0 && ! recipients[0].isEmpty () )
00330             {
00331                 mailTransport.enqueueMessage( from, recipients, subject, contents );
00332 
00333                 int msgCount = mailTransport.getQueueSize ();
00334                 assert msgCount > 0 
00335                     : "Ouch!. We have enqueued message, but the queue is still empty?";
00336                 if ( msgCount == 1 ) {
00337                     setTitle( appTitle + ", 1 message waiting to be sent..." );
00338                 } else {
00339                     setTitle( appTitle + ", " + msgCount 
00340                             + " messages waiting to be sent..." );
00341                 }
00342                 
00343                 /* Keep "From:" field and clear other variable fields
00344                  */
00345                 fieldTo.setText( "" );
00346                 fieldSubject.setText( "" );
00347                 messageContents.setText( "" );
00348             }
00349             
00350             /* If user wants to flush the queue, then start the worker thread
00351              * and indicate that we have no more messages to send, then release
00352              * mailTransport agent.
00353              */
00354             if ( sendImmediately && mailTransport.getQueueSize () > 0 )
00355             {
00356                 println( "------------------------------------------------------------" );
00357 
00358                 tabbedPane.setForegroundAt( 1, Color.BLUE );
00359                 tabbedPane.setTitleAt( 1, "MTA: Sending..." );
00360                 tabbedPane.setSelectedIndex( 1 );
00361                 setTitle( appTitle + ", Sending messages..." );
00362                 
00363                 mailTransport.noMoreMessages ();
00364                 mailTransport.startSending ();
00365                 
00366                 /* Release mailTransport agent and unlock the server field
00367                  */
00368                 mailTransport = null;
00369                 fieldServer.setEnabled( true );
00370             }
00371             else if ( mailTransport.getQueueSize () == 0 )
00372             {
00373                 tabbedPane.setForegroundAt( 1, Color.BLACK );
00374                 tabbedPane.setTitleAt( 1, "MTA: Idle" );
00375                 setTitle( appTitle + ", idle" );
00376                 
00377                 /* Release mailTransport agent and unlock the server field
00378                  */
00379                 mailTransport = null;
00380                 fieldServer.setEnabled( true );
00381             }
00382             else
00383             {
00384                 tabbedPane.setForegroundAt( 1, Color.BLACK );
00385                 tabbedPane.setTitleAt( 1, "MTA: Idle" );
00386             }
00387         }
00388         catch( MessagingException e )
00389         {
00390             JOptionPane.showMessageDialog( this, 
00391                     "Failed to put e-mail message into the queue\n" + e.toString (), 
00392                     "Error while enqueing the message...", JOptionPane.ERROR_MESSAGE );
00393         }
00394     }
00395     
00396     /**
00397      *  Clears the log
00398      */
00399     public void clearLog ()
00400     {
00401         synchronized( logArea )
00402         {
00403             logArea.setText( "" );
00404             logArea.setRows( 0 );
00405             logArea.setCaretPosition( logArea.getText().length () );
00406         }
00407     }
00408 
00409     /**
00410      *  Gets current time stamp
00411      *  
00412      *  @return time in ISO format 
00413      */
00414     private static String now ()
00415     {
00416         Calendar cal = Calendar.getInstance ();
00417         SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
00418         return sdf.format( cal.getTime() );
00419     }
00420 
00421     /**
00422      *  Logs message terminated with new line
00423      *  
00424      *  @param str    message that will be logged
00425      */
00426     @Override
00427     public void println( String str )
00428     {
00429         synchronized( logArea )
00430         {
00431             logArea.append( now () + "  " + str + "\n" );
00432             logArea.setRows( logArea.getRows () + 1 );
00433             logArea.setCaretPosition( logArea.getText().length () );
00434         }
00435     }
00436     
00437     /**
00438      *  On send completed call-back
00439      *  
00440      *  @param errorMessage    contains an error message if not null, otherwise success
00441      */
00442     public void onSendCompleted( String errorMessage )
00443     {
00444         synchronized ( this )
00445         {
00446             int msgCount = mailTransport == null ? 0 : mailTransport.getQueueSize ();
00447             if ( msgCount == 0 ) {
00448                 setTitle( appTitle + ", idle" );
00449             } else if ( msgCount == 1 ) {
00450                 setTitle( appTitle + ", 1 message waiting to be sent..." );
00451             } else {
00452                 setTitle( appTitle + ", " + msgCount 
00453                         + " messages waiting to be sent..." );
00454             }
00455         }
00456 
00457         if ( errorMessage != null ) {
00458             // tabbedPane.setSelectedIndex( 1 );
00459             tabbedPane.setForegroundAt( 1, Color.RED );
00460             tabbedPane.setTitleAt( 1, "MTA: Error!" );
00461 
00462             /* Commented because we don't want to disturb user...
00463              * 
00464             JOptionPane.showMessageDialog( this, 
00465                     "Failed to send e-mail messages from queue!\n"
00466                     + "Please, check the log for more details...\n"
00467                     + errorMessage,
00468                     "Error while flushing the queue...", 
00469                     JOptionPane.ERROR_MESSAGE );
00470             */
00471         } else {
00472             tabbedPane.setForegroundAt( 1, new Color( 0, 128, 0 ) ); // dark green
00473             tabbedPane.setTitleAt( 1, "MTA: OK" );
00474         }
00475     }
00476     
00477     /**
00478      *  Closes application gracefully
00479      * 
00480      *  @param evt
00481      */
00482     private void formWindowClosing( WindowEvent evt )
00483     {
00484         /* Signal to mail transport's worker thread to flush the queue before exit
00485          */
00486         synchronized( this ) 
00487         {
00488             if ( mailTransport != null ) {
00489                 mailTransport.noMoreMessages ();
00490                 mailTransport = null;
00491             }
00492         }
00493 
00494         System.exit( 0 );
00495     }
00496 
00497     /**
00498      *  Handles events from 'enqueue' and 'send immediately' buttons.
00499      */
00500     public void actionPerformed( ActionEvent evt )
00501     {
00502         boolean sendImmediately = ( evt.getSource () == buttonSend );
00503         
00504         enqueueMessage( sendImmediately );
00505     }
00506 
00507     /**
00508      *  Main entry point. Creates instance of <code>SendMailApp</code> application.
00509      *  
00510      *  @param args the command line arguments
00511      */
00512     public static void main( String args[] ) 
00513     {
00514         java.awt.EventQueue.invokeLater( 
00515                 new Runnable() {
00516                     public void run() {
00517                         new SendMailApp ().setVisible( true );
00518                     }
00519                 }
00520             );
00521     }
00522 }
00523 
00524 /*! 
00525  *  \mainpage Simple SMTP Client
00526  *
00527  *  \section s_intro Introduction
00528  *  
00529  *  The package implements solution to \ref p_task as a part of 
00530  *  the <a href="http://dsv.su.se/utbildning/distans/ip1" target="_blank"><b>SU/IP1 
00531  *  course</b></a>.
00532  *  
00533  *  \image html sendMailApp.png
00534  *  
00535  *  \section s_desc Description
00536  *
00537  *  The application is the simple SMTP client GUI that demonstrates usage of the 
00538  *  MailTransport class built on the top of 
00539  *  <a href="http://www.oracle.com/technetwork/java/index-jsp-139225.html" target="_blank">
00540  *  <b>Javamail</b></a> extension to JDK.
00541  *  
00542  *  The user has possibility to either compose one by one textual message and 
00543  *  send them immediately or compose several textual messages in a raw and 
00544  *  send them together.
00545  *  
00546  *  After the first message is put into outgoing queue, application does not allow user
00547  *  to change selected server (until the queue is released with <i>Send Immediatelly</i>
00548  *  button).
00549  *   
00550  *  \subsection s_mta The Mail Transport Client
00551  *
00552  *  The MailTransport class encapsulates mail transport agent with FIFO queue and 
00553  *  non-blocking send capabilities. Instances of this class may be used in two different
00554  *  scenarios.
00555  *  (Note the position of MailTransport.startSending() method and the usage of 
00556  *  MailTransport.noMoreMessages() bellow.)
00557  *  
00558  *  <hr><div style='color:darkred;font-weight:bold'>
00559  *  Scenario 1: Sends one or more messages at once.</div>
00560  *  
00561  *  Usage:
00562  *        - create instance using constructor MailTransport.MailTransport() 
00563  *          (with SMTP server as parameter)
00564  *        - call MailTransport.enqueueMessage()
00565  *        - call MailTransport.enqueueMessage()
00566  *        - ...
00567  *        - call MailTransport.noMoreMessages() to terminate worker thread
00568  *        - call MailTransport.startSending()
00569  *        
00570  *  <hr><div style='color:darkred;font-weight:bold'>
00571  *  Scenario 2. Works in background as relay client to SMTP server.</div>
00572  *
00573  *  Usage:
00574  *        - create instance using constructor MailTransport.MailTransport() 
00575  *          (with SMTP server as parameters)
00576  *        - call MailTransport.startSending()
00577  *        - call MailTransport.enqueueMessage()
00578  *        - call MailTransport.enqueueMessage()
00579  *        - ...
00580  *
00581  *  <hr>
00582  *  \section s_jar Executable
00583  *  
00584  *  The jar file of the package can be found 
00585  *  <a href="../sendMail.jar"><b>here</b></a>.
00586  *  
00587  *  The jar also includes repacked <code>mail.jar</code> retrieved from 
00588  *  <a href="http://www.oracle.com/technetwork/java/index-138643.html" target="_blank">
00589  *  JavaMail 1.4.3</a>.
00590  *  
00591  *  \section s_src Sources
00592  *  
00593  *  Source files:
00594  *   - \ref MailTransport.java
00595  *   - \ref SendMailApp.java
00596  */
00597 /*! \page p_task IP1-6.1 Uppgift
00598  *  
00599  *  Gör ett fristående program med ett grafiskt användargränssnitt som med hjälp av 
00600  *  JDK-extensionen Javamail kan sända e-post. Användaren ska kunna skriva in följande:
00601  *  
00602  *   - Mail-server
00603  *   - Från
00604  *   - Till
00605  *   - Ämne
00606  *   - Meddelande 
00607  *
00608  */

Generated on Thu Dec 16 2010 12:56:05 for Send Mail Client by  doxygen 1.7.2