XML and Java Tutorial, Part
II-Swing
Tutorial Content Author:: Nazmul
Idris
Tutorial Code Author: Sun
Koh
Date: February 11, 1999.
Copyright The Bean Factory, LLC. 1999. All Rights
Reserved.
Index
About the
tutorial
Overview
Step 1: Converting an XML
document to a Java object model
Step 2: Working with
the Java object model
Step 3: Generating an XML
document from a Java object model
Working with Swing
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.
Two sets of source code bundles are provided,
one that uses the IBM XML Parser for Java and another that uses the Sun
ProjectX XML Parser. Both sets of source code bundles can be downloaded
as zip files (at the end of this document).
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:
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):
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:
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 IBM Parser: ibmSwing.zip
Here is the source code for the Sun Parser: sunSwing.zip
Please go to the tools
section to actually download the Parsers themselves.
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.
Nazmul Idris.
 |