XML and Java Tutorial, Part II-Swing

Posted by

Table of contents

About the tutorial

Overview

Step 1: Converting an XML document to a Java object model

Creating the Java object model

Step 2: Working with the Java object model

Adding new information to the AddressBook

Editing the AddressBook

Deleteing information from the AddressBook

Step 3: Generating an XML document from a Java object model

Working with Swing

Implementing the TableModel

Downloading the source code and running the program

About the tutorial

In this tutorial, we will read an XML document and map the content of the XML document to a Java object model; this model can then be view and modified using a JFC/Swing application. Also, we will generate an XML document from this Java object model.

You should use the JDOM parser to run the code.

Overview

There are three main steps we have to go through when working with XML and Java. They are: converting an XML document to an Java object model, working with the Java object model, and generating (saving) an XML document from the Java object model.

These steps are shown below:

Overview Step 1: Converting an XML document to a Java object model. This step involves using an XML parser and DOM. Using the DOM API we will create our own a Java object model. In this tutorial, an XML address book document is converted to a Java object model for an address book.

Step 2: Working with the Java object model. The contents of the address book are stored in the object model and this model is used to add, edit, or delete information (about persons).

Step 3: Generating an XML document from the Java object model. The Java object model for the address book is saved as an XML document.

Step 1: Converting an XML document to a Java object model

Please refer to Tutorial I for a detailed explanation on how to read XML documents using the Sun and IBM XML parser using the DOM API.

The DOM API is used to read in information from an XML document. DOM can also be used to change this information, but using DOM is very tedious. DOM can also be used to generate an XML document. There is an easier way of getting around using DOM for modifiying and saving the XML data; by creating a Java object model for the information in the document, you can create this object model by giving it a DOM object that holds all the XML document information. That is, the XML document should be mapped to a Jave object model.

Here is how to map the AddressBook XML document (used in tutorial one) to a set of related Java classes (or a Java object model):

Converting an XML document to a Java object model As shown above, the ADDRESSBOOK element is mapped to the AdressBook class, the PERSON element is mapped to the Person class. The AddressBook class is simply a container for Person objects.

Here is a partial code listing from AddressBook.java:

public class AddressBook {
//data members
 
 
protected java.util.List data = new ArrayList();
//METHODS
 
 
/**
  Add a person to the address book
  @param    p   a Person object
*/
  public void add(Person p){
    data.add(p);
  }//end method

The Person class maps the PERSON element to a class and is a container for the LASTNAME, FIRSTNAME, COMPANY, AND EMAIL elements. The LASTNAME, FIRSTNAME, COMPANY, AND EMAIL elements are mapped to simple Strings.

Here is a partial code listing of Person.java:

public class Person {
 //
 // Data Members
 //
 
     protected String lastName, firstName, company, email
 
 ….
 
}

Creating the Java object model

Converting AddressBook XML document to a an AddressBook object is done by the IoUtils class. The getAddressBook() method returns an AddressBook object when it is called with an XML filename and path.

Here is a partial code listing from IoUtils.java:

import com.sun.xml.tree.*;
import org.w3c.dom.*;
import java.io.*;
 
public class IoUtils {
 
//
// Data Members
//
    //xml file location - from user’s input
    public static String fileLocation;
 
    //TABLE META DATA
    public static final String ROOT_ELEMENT_TAG = “PERSON”;
 
//
// Methods
//
 
     /**
      Return AddressBook object
      @return    a AddressBook Object
     */
 
 
    public static AddressBook getAddressBook(String file){
 
         fileLocation = file;
         //instantiate AddressBook object
         AddressBook addressBook = new AddressBook();
         Person person;
 
         try {
            //convert comming file location into input stream
             InputStream is = new FileInputStream(file);
 
             //create xml document
             Document doc =
               XmlDocumentBuilder.createXmlDocument(is);
 
             //get the number of person
             int size = XmlUtils.getSize(doc , ROOT_ELEMENT_TAG );
 
             for ( int i = 0; i < size; i++ ) {
 
                 //instanticate a Person object
                 person = new Person();
 
                 //get information about a person 
                 //and set information
                 Element row =
                   XmlUtils.getElement(doc , ROOT_ELEMENT_TAG , i);
                 person.setLastName(
                   XmlUtils.getValue( row , “LASTNAME” ) );
                 person.setFirstName(
                   XmlUtils.getValue( row , “FIRSTNAME” ) );
                 person.setEmail(
                   XmlUtils.getValue( row , “EMAIL” ) );
                 person.setCompany(
                   XmlUtils.getValue( row , “COMPANY” ) );
 
                 //add a person to an address book
                 addressBook.add(person);
 
             }//end for
 
         }
 
         catch ( Exception e ) {
             System.out.println( e );
             return addressBook;
         }
 
         return addressBook;
 
     }//end method
 
 ….
 
}//end of IoUtils class

Step 2: Working with the Java object model

Now that we can change the information in the AddressBook XML document into an AddressBook object, we dont need to use DOM anymore. It is very simple to modify the AddressBook object; it is also trivial to create and modify Person objects. The AddressBook contains an ArrayList object (which holds all the Person objects).

Adding new information to the AddressBook

The following code snippet adds a Person object to an AddressBook:

AddressBook addressBook = new AddressBook();
 
Person person = new Person();
person.setLastName(“John”);
person.setFirstName(“Doe”);
person.setCompany(“Doe Enterprise, Inc.”);
person.setEmail(“john@doeenterprise.com”);
addressBook.add(person);


Editing the AddressBook

To edit the 2nd Person object in the AddressBook, we need to get a Person object in index 2 of the AddressBook object (which is a container of Person objects).

   Person person = addressBook.get( 2 );

Then with the person object reference, you can change the contents of this person object. Once you have finished your modifications, you can put the person object back in the AddressBook object by using:

   addressBook.set( 2 , person )

Deleting a person from the AddressBook

To delete the 2nd Person object from the AddressBook object, we simple tell the addressbook to remove the 2nd object it contains:

   addressBook.remove( 2 );

Step 3: Generating an XML document from a Java object model

Generating an XML document is exactly the same as writing a text file. The object model has to be manually covered to text using all the appropriate tags. DOM can generate XML text based on the intformation contained in it, but since we didn’t use DOM to allow modifications on the AddressBook, we have to manually genereate the XML ourselves. It is actually easier to do it this way, becuase DOM is very messy to manipulate.

We first need to create a new text file using FileOutputStream, we can write Strings to this file using a PrintWriter. Since we know how the Java object model is structured, we can simply add a tag before and after every element. The AddressBook object contains multiple Person objects, so we need to use loop to extract each Person object.

As you might already know, a DTD does not need to be included in XML file. In this example however the DTD is included in the XML file.

Here is an XML-generating code example:

import com.sun.xml.tree.*;
import org.w3c.dom.*;
import java.io.*;
 
public class IoUtils {
 
//
// Data Members
//
 
    //xml file location - from user’s input
    public static String fileLocation;
 
 
//
// Methods
//
 
 ….
 
 
    /**
      Generating an xml file given a Java object
 
      @param     data     the collection of Person object
      */
 
     public static void saveAddressBook(java.util.List data){
 
         Person person;
 
         try {
             FileOutputStream fo =
               new FileOutputStream(fileLocation);
             PrintWriter pw = new PrintWriter(fo);
 
             //start writing XML file
             pw.println(“<?xml version= ‘1.0′?>”);
             pw.println(“<!DOCTYPE ADDRESSBOOK [”);
             pw.println(“<!ELEMENT ADDRESSBOOK (PERSON)*>”);
             pw.println(“<!ELEMENT PERSON”+
               “(LASTNAME, FIRSTNAME, COMPANY, EMAIL)>”);
             pw.println(“<!ELEMENT LASTNAME (#PCDATA)>”);
             pw.println(“<!ELEMENT FIRSTNAME (#PCDATA)>”);
             pw.println(“<!ELEMENT COMPANY (#PCDATA)>”);
             pw.println(“<!ELEMENT EMAIL (#PCDATA)>”);
             pw.println(“]>”);
             pw.println(“<ADDRESSBOOK>”);
             pw.println(“”);
 
             int size = data.size();
             for ( int i = 0; i < size; i++ ) {
 
                 //get a person object and 
                 //write it to a file
                 person = (Person)data.get(i);
 
                 pw.println(”  <PERSON>”);
                 pw.println(”    <LASTNAME>”+
                   person.getLastName()+“</LASTNAME>”);
                 pw.println(”    <FIRSTNAME>”+
                   person.getFirstName()+“</FIRSTNAME>”);
                 pw.println(”    <COMPANY>”+
                   person.getCompany()+“</COMPANY>”);
                 pw.println(”    <EMAIL>”+
                   person.getEmail()+“</EMAIL>”);
                 pw.println(”  </PERSON>”);
                 pw.println(“”);
 
             }//end for
 
             pw.println(“</ADDRESSBOOK>”);
             pw.flush();
             pw.close();
 
         }
         catch ( Exception e ) {
             System.out.println(e);
         }
 
     }//end method
 
}//end of IoUtils class

Working with Swing

Implementing the TableModel

A TableModel is a Java interface which allows access to any kind of two-dimensional data (such as an Vector or ArrayList of object); The ArrayList contains objects which represent each row of the table, and each of these objects have data that constitutes each column of the table. The JTable accesses this data through the TableModel interface. So the TableModel interface must be implemented by the 2 dimensional data structure or object model that you are implementing.

Here is the TableModel interface:

//must implement this
 public int getRowCount();
 
//must implement this
public int getColumCount();
 
//must implement this
public String getColumnName(int columnIndex);
 
//must implement this
public Class getColumnClass(int columnIndex);
 
//must implement this
public boolean isCellEditable(int rowIndex, int columnIndex);
 
//must implement this
public Object getValueAt(int rowIndex, int columnIndex);
 
//does not need to implement this if isCellEditable 
//returns false
public void setValueAt(Object aValue,
  int rowIndex, int columnIndex);
 
//need to implement this if table content changes
public void addTableModelListener(TableModelListener l);
 
//need to implements this if table content changes
public void removeTableModelListener(TableModelListener l);

This TableModel interface is inmplemented by the AddressBook class. So not only is the AddressBook a container for address book data, it is also a TableModel, which allows the AddressBook to be accessed and modified by a JTable. The (TableModel) model is not the data in this case, but a set of interfaces which allow you to access the underlying data, which is actually stored in an ArrayList object inside the AddressBook. The TablModel is a fancy way to allow the JTable to access the information stored in the ArrayList.

The TableModel has methods to determined the structure of the underlying table data. The JTable needs to know the number of rows and columns of data, the name of each column (for column headings), and each column’s object type. JTable can display two dimensional data with above information.

isCellEditable() method is used to determined if the cells in the table can be modified; if they are not editable ( return false), the setValueAt() does need to be implemented.

The JTable also sends a TableModelEvent to all registered TableModelListeners, notifying them that the underlying data has changed (when the user modifies the data using the JTable or other user interface components). When you write your own mutator method (as it is in the AddressBook class) you must generate a TableModelEvent and send it a all registered listeners (the JTable itself is the most important registered listener). This TableModelEvent allows the data model to notify the view (or JTable) that some underlying data has changed and that the JTable should refresh its view. The view interface for a TableModel is the TableModelListener interface. The AddressBook changes its underlying data when a new person object is added, or an existing person object is edited or deleted.

If you would like to know more information on the TableModel and Model View Controller (in Swing) in general, please let us know and we will create a tutorial on it. We value your feedback for new tutorial ideas.

Here is the code to generate a TableModelEvent and notify all registered listeners:

/**
  Underlying personal information has changed
  Create a TableModel event
  Notify all registered listeners
  */
 
public void fireContentsChanged(){
 
    TableModelListener ldl; //temp var
    TableModelEvent e = new TableModelEvent(this);
 
    for(int i=0; i<tableModelListeners.size(); i++){
         ldl =(TableModelListener)tableModelListeners.get(i);
         ldl.tableChanged(e);
    }
 
}//end method

Downloading the source code and running the programs

Here is a screen shot of the program:

Screenshot of Swing program in action
The same sets of Java classes are provided for the Sun Parser and IBM Parser. Here is a description of these source code files:

Name Description
AddressBook.java Is a container for Person objects, and implements the TableModel
Person.java Stores information about a person
XmlUtils.java Needed by AddressBook.java
IoUtils.java Read from and Write to an XML document (file)
AddressBookFrame.java Displays a JTable in a JFrame
AddressBookPanel.java Needed by AddressBookFrame.java
AddressBookOpen.java Get XML file location
EditDialog.java Edit address book information
AddressBookToolBar.java Toolbar used by AddressBookFrame

To run the Swing JTable program, you can type java AddressBookFrame at the command prompt. Make sure that you have Java2 (or JDK1.2) installed on your machine because it will not work with JDK1.1.

After starting AddressBookFrame, a dialog box pop ups asking a XML file location. Simply type in the folder and file name. For example. I have a AddressBook.xml file in c:/temp. So I type in: c:/temp/AddressBook.xml

If the file name is not provided, the the program will throw an exception when it tries to generate an XML file.

Here is the source code for the Sun Parser: sunSwing.zip

I hope you enjoy this tutorial and find it to be useful. I will have more useful and interesting applications of XML and Java in Part III of the tutorial, so stay tuned and keep coming back :).

Click here to send me any feedback/comments. If any material in this tutorial does not make sense please let me know, and I will try to make it more understandable. And please let me know if there are any new topics you would like to see more tutorials on.