Creating JBiff

JBiff will not take much code, so we can define it in a single class in a single file. As we will see, that is a fib; we will need another small class to handle a mouse event on the window’s “kill” button, but more on that later. It is generally good OO style to separate the GUI from the logic, but we won’t get too hung up on that. Now, to structure the class: as with any Java class, we will have to create a constructor. The constructor creates an instance of the JBiff class and shows the basic GUI. The class’s main () method is where the action takes places; it will connect to an IMAP server, retrieve the information, and then cause it to be displayed in the GUI.

The first thing that we need to do is import references to the various Java packages that we will be using—some from JAF and the Java Mail API and others from the more mundane java.awt and java.util packages in the core. Those classes in the javax. mail package are in Java Mail API. Those in the javax.activation package are part of the JAF.

import javax.mail.*;
import javax.mail.event.*;
import javax.mail.internet.*;
import javax.activation.*;
import java.util.*;
import java.awt.*;
import java.awt.event.*;

Our class represents the JBiff GUI; all of the logic is in the main () method. To make things easy, we will have our GUI class extend Frame, which will create a frame when the class is instantiated. We will also need a label on which to write our mailbox status message. The class starts this way:

public class JBiff extends Frame  { 

  // Labels to print some info onto...
  public Label display_label;

Our constructor will do a very few things: create the GUI frame with a label in it, and create an event handler to deal with closing the window. We will give it a title of “JBiff.”

The way that we handle the window closing event is with a Java version 1.1-style “inner class,” which is essentially a class defined within another class. Although the theory behind this can be a bit daunting, inner classes in Java provide a simple clean interface to event handling. Since a discussion of inner classes and their use in Java is beyond the scope of this book, we refer you to Java in a Nutshell, 2nd edition, by David Flanagan (O’Reilly Media, 1997). For now, we will try to describe what is happening for novice Java programmers but won’t go into why this works in the language.

The addWindowListener() method takes a class of type WindowAdapter as an argument. A WindowAdapter is created anonymously as a type of inner class. A WindowAdapter is an abstract class that contains methods for each type of event relating to windows; here we override just the windowClosing() method, which is called by the Java event handler when a window is closing, or should be. We use this method to exit JBiff cleanly whenever the GUI window is destroyed.

The constructor, then, is:

/*
 * Constructor. Creates the various AWT components required
 * in the system.
 */
public JBiff() { 

  // Create the simple GUI
  display_label = new Label ("Please wait... ",Label. LEFT) ;
  add(display_label);
  pack() ;
  setSize(600,30);
  display_label.setSize(600,30);
  setTitle ("JBiff");
  setVisible(true); 
  // Create a handler to close the application
  addWindowListener(new WindowAdapter()   {

    public void windowClosing(WindowEvent w)  {

      // Time to leave
      System.exit(0);
    }

  });    // Note the odd syntax here, at the closing of an
         // inner class and the enclosing method call.

}        // End of constructor.

Every Java class that will be directly executed as an application (that is, not as an applet) must have a main() method. This method is the interface between the Java application and the command line from which it was called, so it takes a String array of command-line arguments so that they may be used by the application.

public final static void main(String[] args) throws Exception {

Just like any other command-line program with arguments, we should test to make sure that the user understands how to use the application. Therefore, if we didn’t receive the appropriate number of arguments, we’ll send back a usage message and exit.

// Check that the right number Parameters have been passed
 if (args.length != 5) { 

   System.out.println("JBiff: Monitor the state of an IMAP mailbox.");
   System.out.println("usage: java JBiff <username>
   <password> <host> <mailbox> <frequency
   (sec)>") ;
   System.exit(l);
   
 }

If we have the right number of arguments, they can be assigned to the right variables. Next, we make those assignments. We can play fast and loose with the username, password, and hostname since they are just strings that we will feed to the Mail API classes; if they are wrong, a connection will simply not be established. The frequency of refresh, however, is a number and really should be checked to ensure that it is valid. If it is not a valid number, we will set it to a default value as shown.

// Get the parameters from the command line.
String username = args[0];
String password = args[l];
String host = args[2];
String mailbox = args[3];
int frequency; 
try {

  frequency = Integer.parseInt(args[4]) * 1000;

} catch (NumberFormatException nfe){

  // bad number, just check every 5 mins.
  frequency = 300000;

  System.err.println("Your frequency value was bogus. " +
                     "Using 5 minutes instead");
}

Now that we have all of the information necessary, we are going to try to connect to the IMAP server. Before we do, though, we need to instantiate the GUI so we have a place to put the results. We do this by creating an instance of the JBiff class that makes a frame. The frame is created and shown, you may recall, when the constructor is called.

// Create the GUI
 JBiff jbiff = new JBiff(); 

The Java Mail API includes a Session object, which encapsulates the concept of a mail session. We will need to instantiate one of these objects for our use. Before we do that, however, we need to get a handle on the Java system properties. A number of system properties may be set that are used by the Java Mail API, such as mail.host. If mail. host is not set, the local machine is used as the default mail server. In our case, we will pass in an explicit hostname for the IMAP server and not use an SMTP server, so this will not come into play.

The Session object has a handy debugging facility so that you can watch the details of each connection if you desire. This can be turned on with the setDebug() method, shown commented in the code that follows:

Properties system_properties System.getProperties();

// get the default JavaMail Session instance
Session session = Session.getDefaultInstance(system-properties,null);

// switch on the session debugging to see what's happening
 // session. setDebug (true);

Connections to a remote server may fail and therefore generate an exception. In the case of the Mail API, this would be a MessagingException. We will have to place each of the method calls that might throw this exception (or any other exceptions) into a trycatch block.

We will need to use our instance of the Session object to create a Store object; this is an abstract class that models a particular message store (i.e., mailbox hierarchy) and its protocol (in this case, IMAP). Once we get an instance of a class that implements the Store abstract class, we have defined what type of mailboxes we have and which protocol we are using. We can then connect to the Store instance by the appropriate method; in this case, we pass it the IMAP server hostname, our username, and our password.

If we get a good connection to the server, we can open the mailbox that was named on the command line. This is done with the getFolder() method of the Store object. We have to check that the folder is really a mailbox and not something else, like a directory.

The catch part of the try… catch block will be shown after we have covered our entire connection to the server in the try.

try  { 

  // get the Store object for IMAP
   Store store = session.getStore("imap");

  // connect to the specified host
   store.connect (host,username,password) ;

  // get the Folder for this mailbox
   Folder folder = store.getFolder(mailbox);

  // Ensure we got an existing folder that holds messages
  // not a sub folder!
  if (folder == null || !folder.exists() ||
                folder.getType() == Folder.HOLDS_FOLDERS)  {

      System.err.println("Invalid folder, or folder does not" +
                         "exist, or folder holds other folders!");
      System.exit(1) ;
  }

If we have made a good connection to the server and successfully opened the mailbox, then we are almost home. The only thing left to do is to determine the folder’s status, display it, and loop until the user kills the process.

We will use a while loop to continually refresh the mailbox statistics. We don’t have to handle any events here in order to exit the loop because we have already created (in the constructor) an event handler that listens to any WindowClosing events. This event handle will exit cleanly when the user demands it. That event handler runs in a separate thread, so our while loop can just ignore its presence.

The Mail API allows method calls to check the status of folders without first opening them. If the folder is not already open, it will be opened before and closed after the requested operation. This is good, unless you are doing a series of operations on the same folder, in which case it becomes horribly inefficient! It is much better in our case to explicitly open the folder, perform all of our operations, and close it when we are done.

Another option is to open the folder and register a listener for a Message-CountEvent; however, this would require the folder to be held continually open in READ_WRITE mode. This could conflict with another program trying to access the folder, such as an MUA. Since we would like our monitor to avoid any read-write opening of the folder, we won’t do this.

// Loop forever until the user kills us
 while   (true)  { 

   // Open the folder, read-only
    folder.open(Folder.READ_ONLY) ; 

   // Get the current total number of messages
    int total_nr_messages = folder.getMessageCount();

   // Get the current number of unread messages
    int unread_nr_messages = folder.getUnreadMessageCount();

   // get the number of new messages
    int new_nr_messages =  folder.getNewMessageCount();

   // display a status message...
    jbiff.display_label.setText("You have" +
             new_nr_messages + " new messages, "+unread_nr_messages +
             " unread messages and " + total_nr_messages + 
             " total messages in your mailbox: " + mailbox);

   // close the folder, expunging messages is not our problem.
    folder.close(false);

   // try to sleep for a while
    try { 

      Thread.sleep(frequency);

    } catch (InterruptedException ie) {

     // just ignore and continue on...

    }

}    // End the while loop.

That is the end of the connection operations, and hence the end of the enclosing try block. The catch block, which has to catch and handle any MessagingExceptions, looks like this:

   }  catch (MessagingException me) {

      System.err.println("Error: " + me.getMessage());
      System.exit(l);

   }

 }     // End the mainO method.


}  // End the class.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.31.209