Sei sulla pagina 1di 266

1

LESSON 1: JAVA COMPONENTS


Contents
Aims and Objectives
Introduction to Java Programming
Applets
Applications
Abstract Windowing Toolkit (AWT)
Buttons
Choices
Labels
Pannels
Scrollbars
Text area And Text field
Let us Sum Up
Lesson end Activities
Points for Discussion
References

AIMS AND OBJECTIVES


At the end of this Lesson, you will be able to:
Understand the Concepts of Java Programming
Understand the functionality of various Java Components
Write code to create those components
Introduction to Java Programming
Java programs fall into two main groups:
Applets and
Applications.
Applets
Applets, are Java programs that are developed over the World Wide Web and
executed by a Web browser on the readers machine. Applets depend on a Java-capable
browser in order to run.
Creating a Java Applet:
Creating applets is different from creating a simple application, because Java
applet rules for how they behave. Because of these special rules for applets in many cases
(particularly the simple ones), creating an applet may be more complex than creating an
application. For example, to do a simple Hello World applet, instead of merely being able
to print a message, you have to create an applet to make space for your message and then
use graphics operations to paint the message to the screen.

In the next example, you create that simple Hello World applet, place it inside a
Web page, and view the result. First, you set up on environment so that your Java-capable
browser can find your HTML files and your applets. Much of the time, youll keep your
HTML files and your applet code in the same directory.
Program:
import java.awt.Graphics;
public class HelloWorldApplet extends
java.applet.Applet
{
public void paint(Graphics g)
{
g.drawString(Hello World!, 5, 25);
}
}

Save the file just like with Java applications, give your file a name that has the
same name as the class. In this case, the filename would be HelloWorldApplet.java.
Features of Applets:
The import line at the top of the file is somewhat analogous to an #include
statement in C; it enables this applet to get access to the JDk classes for creating
applets and for drawing graphics on the screen.
The paint() method displays the content of the applet onto the screen. Here, the
string Hello World gets drawn. Applets use several standard methods to take the
place of main(), which include init() to initialize the applet, start(0 to start it
running , and paint() to display it to the screen.
Now, compile the applet just as you did the application, using javac, the Java
compiler.
javac HelloWorldApplet.java

Again, just as for application, you should now have a file called
HelloWorldApplet.class in your directory.
To include an applet in a Web page, you refer to that applet in the HTML code for
that Web page. Here, you create a very simple HTML file in the directory.
<HTML>
<HEAD>
<TITLE>
Hello to Everyone!
</TITLE>
</HEAD>
<BODY>
<P> My Java applet says:
<APPLET CODE=HelloWorldApplet.class WIDTH = 150 HEIGHT = 25>
</APPLET>
</BODY>
</HTML>

Java Applications
Java applications are more general programs written in the Java language. Java
applications dont require a browser to run, and in fact, Java can be used to create all the
kinds of applications that you would normally use a more conventional programming
language to create. HotJava itself is a Java application.
Creating a Java Application:
As with all programming languages, your Java source files are created in a plain
text editor, or in an editor that can save files in plain ASCII without any formatting
characters. On UNIX, emacs, pico, or vi will work; on Windows, Notepad or DOS Edit
are both text editors.
class HelloWorld
{
public static void main(String args[])
{
System.out.println(Hello World!);
}
}

This program has two main parts:


All the program is enclose in a class definition here, a class called
HelloWorld.
The body of the program is continued in a method(function) called main().
In Java applications, as in a C or C++ program, main() is the first method
(function) that runs when the program is executed.
Once you finish typing the program, save the file. Most of the time, Java source
files are named the same name as the class they define, with an extension of .java. This
file should therefore be called HelloWorld.java. now, lets compile the source file using
the Java compiler. In suns JDK, the Java compiler is called javac. To compile your Java
program, make sure the javac program is in your execution path and type javac followed
by the name of your source file: javac HelloWorld.java.
The compiler should compile the file without any errors. If you get errors, go back
and make sure that youve typed the program exactly. When the program compiles
without errors, you end up with a file called HelloWorld.class, in the same directory as
your source file. This is your Java bytecode file. You can then run that bytecode file
using the Java interpreter. This is you rJava interpretor is called simply java. Make sure
the kjava program is in your path and type java followed by the name of ht efile without
the .class extension: java HelloWorld
If your program was typed and compiled correctly, you should get the string
Hello World! printed to your screen as a response.

1.2. ABSTRACT WINDOWING TOOLKIT (AWT)


The AWT was designed from the start to have a platform-independent API and
yet to preserve each platform's look and feel. For example, the AWT has just one API for
buttons (provided by the Button class), but a button looks different on a Macintosh than
on a PC running Windows 95.
The AWT achieves its seemingly contradictory goals by providing classes
(components) that provide a platform-independent API but that make use of platformspecific implementations (peers). To be specific, every AWT component class
(Component, MenuComponent, and their subclasses) has an equivalent peer class, and
every component object has a peer object that controls the object's look and feel.
Below is a figure that illustrates how a typical AWT component (a Button) is
mapped to a peer. Button peers are implemented in platform-specific classes that
implement the java.awt.peer ButtonPeer interface. The java.awt Toolkit class defines
methods that choose exactly which class to use for the peer implementation.

Hierarchy of AWT Components


The following diagram shows the hierarchy of awt components.

AWT Components
Component are javas building blocks for creating graphical user interface. Some
component types, such as buttons and scroll bars, are used directly for GUI control. Other
components provide spatial organization. GUI are an important part of any program.
Javas Abstract Windowing Toolkit provides extensive functionality.
Some of the important components are
1.
2.
3.
4.
5.
6.
7.

Buttons.
Checkboxes
Choices
Labels
Panels
Scrollbars
Textarea And Textfield

Javas components are implemenrted by many sybclasses of the java.awt.Component


class and java.awt.MenuComponent class. There are 19 non-super class components in
all. Let us look at the basic if these components.
Components can be broudly classified as:
Visual Component (Button, CheckBox etc)
Container Components (Frame, Panel, Applet etc)
Menu Component (Menu, MenuItem, MenuBar etc)

Let us now look at some of the basic components in detail and also learn how to use
them.
Buttons
A Button is a simple control that generates an action event when the user clicks it.
The onscreen appearance of Buttons depends on the platform they're running on and on
whether the Button is enabled. If you want your program's Buttons to look the same for
every platform or to otherwise have a special look, you should create a Canvas subclass
to implement this look; you can't change the look using a Button subclass. The only
facets of a Button's appearance that you can change without creating your own class are
the font and text it displays, its foreground and background colors, and (by enabling or
disabling the button) whether the Button looks enabled or disabled.
Example of buttons
The following figure shows a few Buttons used with FlowLayout( explained later)

Below is the code that creates the buttons.


import java.awt.*;
//The following class demonstrate use of Button
public class ButtonDemo extends Frame
{
Button b1 = new Button("Left Button"),
b2 = new Button("Middle button"),
b3 = new Button("Right button");
public ButtonDemo()
{
setLayout(new FlowLayout());
add(b1);
add(b2);
add(b3);
}

public static void main(String[] args)


{
ButtonDemo bdemo = new ButtonDemo();
bdemo.setSize(400,300);
bdemo.setVisible(true);
}

The above code sample shows how to use all but one of the commonly used
Button methods. In addition, Button defines a getLabel() method, which lets you find
out what text is displayed on a particular Button.

Checkboxes
When the user clicks a checkbox, the Checkbox State changes and it generates an
action event. Other ways of providing groups of items the user can select are choices,
lists, and menus.
If you want a group of checkboxes in which only one checkbox at a time can be
"on", you can add a CheckboxGroup object to oversee the state of the checkboxes.
(You call this element as a radio button.)
Below is an example that has two columns of checkboxes. On the left are three
independent checkboxes. You can select all three of the checkboxes, if you like. On
the right are three checkboxes that are coordinated by a CheckboxGroup object. The
CheckboxGroup ensures that no more than one of its checkboxes is selected at a time.
To be specific, a checkbox group can come up with no checkboxes selected, but once
the user selects a checkbox, exactly one of the checkboxes will be selected forever
after.
Following is the code that creates both groups of checkboxes. Note that only the
second, mutually exclusive group of checkboxes is controlled by a CheckboxGroup.
import java.awt.*;
public class CheckBoxDemo extends Frame
{
Panel p1, p2;
Checkbox cb1, cb2, cb3; //These are independent checkboxes.
Checkbox cb4, cb5, cb6; //These checkboxes are part of a group.
CheckboxGroup cbg;
public CheckBoxDemo()
{
cb1 = new Checkbox();
//Default state is "off"
(false).
cb1.setLabel("Checkbox 1");
cb2 = new Checkbox("Checkbox 2");
cb3 = new Checkbox("Checkbox 3");
cb3.setState(true);
//Set state to "on" (true).
cbg = new CheckboxGroup();
cb4 = new Checkbox("Checkbox 4", cbg, false); //initial
state: off
state: off
state: off

cb5 = new Checkbox("Checkbox 5", cbg, false); //initial


cb6 = new Checkbox("Checkbox 6", cbg, false); //initial
setLayout(new GridLayout(3,2));
add(cb1);add(cb4);
add(cb2);add(cb5);
add(cb3);add(cb6);

9
}

public static void main(String[] args)


{
CheckBoxDemo cb = new CheckBoxDemo();
cb.setSize(250,250);
cb.setVisible(true);
}

Besides the Checkbox methods shown above, Checkbox has two additional
methods you might want to use: getCheckboxGroup() and setCheckboxGroup().
Besides the single CheckboxGroup constructor used in the code example,
CheckboxGroup also defines the following methods: getCurrent() and
setCurrent(). These methods get and set (respectively) the current selected
Checkbox.
Note: CheckboxGroup is only a helper class, it is not a component by itself. Its basic
use is to generate RadioButtons.
The program in a gridlayout would look similar to this:

Choices

10

The Choice class provides a menu-like list of choices, accessed by a


distinctive button. The user presses the button to bring up the "menu", and then
chooses one of the items. When the user chooses an item, the Choice generates an
action event.
Choices are useful when you need to display a number of alternatives in a
limited amount of space, and the user doesn't need to see all the alternatives all the
time. Another name you might know for this UI element is pop-up list. Other ways of
providing multiple alternatives are checkboxes, lists, and menus.
Following is an example of a Choice and a Label.

Below is the code that creates the above output.


import java.awt.*;
public class ChoiceDemo extends Frame
{
Choice ch = new Choice();
public ChoiceDemo()
{
setTitle("This shows use of Choice component");
setSize(200,100);
setLayout(new FlowLayout());
ch.addItem("India");
ch.addItem("Pakistan");
ch.addItem("Bangladesh");
ch.addItem("Nepal");
ch.addItem("Bhutan");
add(ch);
}
public static void main(String[] args)
{
ChoiceDemo cd = new ChoiceDemo();
cd.show();
}

11
}

Besides the methods used above, the Choice class defines these other useful
methods:
int countItems()

Returns the number of items in the choice.

String getItem(int)

Returns the String displayed by the item at the specified index.

void select(int)

Selects the item at the specified index.

void select(String)

Selects the item that's displaying the specified String.

Labels
The Label class provides an easy way of putting unselectable text in your program's
GUI. Labels are aligned to the left of their drawing area, by default. You can specify that
they be centered or right-aligned by specifying Label.CENTER or Label.RIGHT either to
the Label constructor or to the setAlignment() method. As with every Component,
you can also specify the font and color of a Label.
Label Example
There are three labels, each one with a different alignment. If each label's display
area were equal to the width of the text the label displayed, you wouldn't see any
difference in the alignment of the labels. Each label's text would simply be displayed
using all the available space.

12

Below is the code that the program uses to create the labels and set their alignment.
import java.awt.*;
import java.awt.event.*;
public class LabelDemo extends Frame
{
Label l1 = new Label("Left");
Label l2 = new Label("Center");
Label l3 = new Label("Right");
public LabelDemo()
{
setTitle("This shows use of Label component");
setSize(200,100);
setLayout(new GridLayout(3,1));
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent we)
{
dispose();
System.exit(0);
}
});
l1.setAlignment(l1.LEFT);
l2.setAlignment(l2.CENTER);
l3.setAlignment(l3.RIGHT);
add(l1);
add(l2);
add(l3);
}

13

public static void main(String s[])


{
LabelDemo ld = new LabelDemo();
ld.setSize(200,200);
ld.show();
}

Besides the constructor, setText(), and setAlignment() methods


used above, the Label class also provides getText() and getAlignment()
methods

Panels
The Panel class is a general-purpose Container subclass. You can use it as-is to
hold Components, or you can define a subclass to perform special functionality, such as
event handling for the objects the Panel contains.
The Applet class is a Panel subclass with special hooks to run in a browser or other applet
viewer. Whenever you see a program that can run both as an applet and as an application,
chances are that it defines an Applet subclass but doesn't use any of the special Applet
capabilities, relying instead on the methods it inherits from the Panel class.
Here's an example of using a Panel instance to hold some Components:
Panel p1 =
p1.add(new
p1.add(new
p1.add(new

new Panel();
Button("Button 1"));
Button("Button 2"));
Button("Button 3"));

Here's an example of a Panel subclass that draws a frame around its contents..

14
class FramedArea extends Panel {
public FramedArea(CoordinatesDemo controller) {
...//Set the layout manager.
//Add any Components this Panel contains...
}
//Ensure that no Component is placed on top of the frame.
//The inset values were determined by trial and error.
public Insets insets() {
return new Insets(4,4,5,5);
}
//Draw the frame at this Panel's edges.
public void paint(Graphics g) {
Dimension d = size();
Color bg = getBackground();

g.setColor(bg);
g.draw3DRect(0, 0, d.width - 1, d.height - 1, true);
g.draw3DRect(3, 3, d.width - 7, d.height - 7, false);

Scrollbars

Scrollbars have two uses:

As shown above, a scrollbar can act as a slider that the user manipulates to set a
value.
As controls for scroll panes. The ScrollPane class, which was introduced in
1.1, lets you display part of a component that's too large for the available display
area. Scrollbars in scroll panes let the user choose exactly which part of the region
is visible. To customize scrolling behavior, you sometimes need to invoke
methods on a ScrollPane's scrollbars.

To create a scrollbar, you need to create an instance of the Scrollbar


class. You must also initialize the following values, either by specifying them to a
Scrollbar constructor or by calling the setValues() method before the scrollbar
is visible.

15

Scrollbar Properties.
int orientation

Indicates whether the scrollbar should be horizontal or vertical. Specified with


either Scrollbar.HORIZONTAL or Scrollbar.VERTICAL.
int value

The initial value of the scrollbar. For scrollbars that control a scrollable area, this
usually means the x value (for horizontal scrollbars) or y value (for vertical scrollbars) of
the part of the area that's visible when the user first sees the scrollable area. For example,
when the applet above starts up, both the horizontal and vertical scrollbars' values are 0,
and the image portion that's displayed starts at (0,0).
int visible

The size in pixels of the visible portion of the scrollable area. This value, if set
before the scrollbar is visible, determines how many pixels a click in the scrollbar (but
not on the knob) causes the display area to shift. Setting this value after the scrollbar is
visible has no effect. After the scrollbar is visible, you should use the
setPageIncrement() method to get the same effect.
int minimum

The minimum value the scrollbar can have. For scrollbars controlling scrollable
areas, this value is usually 0 (the left/upper part of the area).
int maximum

The maximum value the scrollbar can have. For scrollbars controlling scrollable
areas, this value is usually: (total width/height, in pixels, of the component that's being
partially displayed) - (currently visible width/height of the scrollable area).

Textarea and Textfield


The TextArea and TextField classes display selectable text and, optionally, allow
the user to edit the text. You can subclass TextArea and TextField to perform such tasks
as checking for errors in the input. As with any Component, you can specify the
background and foreground colors and font used by TextAreas and TextFields. You can't,
however, change their basic appearance.
Both TextArea and TextField are subclasses of TextComponent. From
TextComponent they inherit methods that allow them to set and get the current selection,
enable and disable editing, get the currently selected text (or all the text), and set the text.

16

Following

figure

displays

first

TextField

and

then

TextArea.

Here's the program. Here's just its code that creates, initializes, and handles events
in the TextArea and TextField:
//Where instance variables are defined:
TextField textField;
TextArea textArea;
public void init() {
textField = new TextField(20);
textArea = new TextArea(5, 20);
...//Add the two components to the panel.
}

The TextComponent superclass of TextArea and TextField supplies the


and selectAll() methods used in the above
code example. It also supplies the following useful methods: getSelectedText(),
isEditable(), getSelectionStart(), and getSelectionEnd(). It also provides a
select() method that lets you select text between beginning and end positions that you
specify.
getText(), setText(), setEditable(),

int getColumns()

17

Returns the number the columns in the text field.


setEchoChar()
Sets the echo character, which is useful for password fields.
char getEchoChar() boolean echoCharIsSet()
These methods let you ask about the echo character.
Like the TextField class, the TextArea class also has four constructors: TextArea(),
TextArea(int, int), TextArea(String), and TextArea(String, int,
int). The integer arguments specify the number of rows and columns (respectively) in
the text area. The String argument specifies the text initially displayed in the text area.
The TextArea class supplies the appendText() method used in the code example
above. It also supplies these methods:
int getRows(), int getColumns()
Return the number of rows or columns in the text area.
void insertText(String, int)
Inserts the specified text at the specified position.
void replaceText(String, int, int)
Replaces text from the indicated start position (the first integer) to the indicated end
position.
There are various other components available, each having its own methods and
behaviour. They are usually found in java.awt. package. If we want to know more about a
particular Component say about Frame then type the following command on a command
prompt.
javap java.awt.Frame | more
This command gives all the methods, constructors and static variables in that class. Most
of the method names are quite meaningful and we can easily figure out what that method
does.

LET US SUM UP
In the above lesson we discussed about the two different types of Java programs
(Applets and Applications). AWT components such as Buttons, Checkboxes, Choices,
Labels, Panels, Scrollbars, Textarea And Textfield were discussed with examples.

LESSON END ACTIVITIES

Write an application interface that asks for a user name and a password. The interface
should have two text fields and two buttons.
Write an interface to a calculator application. (hint: you may have to use GridLayout)
Write an application that diaplays an image.
Write a small note pad application. The application should be able to open and save a
file (ASCII).

18

POINTS FOR DISCUSSION


What are the features of Java language?

REFERENCES
Campione, Walrath and Huml, The Java Tutorial, Addison Wesley 1999
Cays, Horstmann & Gary Gornell, core Java 2 Vol-1 Fundamentals, Pearson Education
Asia, 2001

19

LESSON 2: EVENT HANDLING


Contents
Aims and Objectives
Introduction
Making windows and applets with the AWT
Check boxes and Radio Buttons
Drop-Down Lists
Lists
Menus
Dialog Boxes
File Dialogs
Let us Sum up
Lesson-End Activities
Points for Discussion
References

AIMS AND OBJECTIVES


At the end of this Lesson, you will be able to:
Understand the Concepts of Event Handing in Java
Understand the functionality of various Events
Create Windows and Applets using Events

INTRODUCTION
Events are signals which are fired when the state of a component is changed (eg:
when a button is pressed, when a menu is pressed etc.). In the event of a signal firing it is
necessary for us to handle the event based on our requirements. For example you would
want to open a new window or close it when a button is pressed, or you would want to
list a menu when a menu box is activated (pressed).
Sources:
The previous paragraph only gives you a gist of what happens when a
component is activated. Actually when the internal state of the component is modified a
source is generated. This is nothing but a source to the event.
Listeners:
A single component can take events from different sources. For Example an
applet can have sources from the keyboard or from the mouse. So you should make the
applet be ready to receive the events from the different sources. This is done by the
Listeners which are nothing but interfaces with abstract methods which could be
implemented on generation of the corresponding event.

20

Event Handling:
The actions that have to be performed on the component listening to an event like
a mouse clicked on an applet are specified. This is called Event Handling .
Component type
Adjustable
Applet
Button
Canvas
Checkbox
CheckboxMenuItem
Choice
Component
Container
Dialog
FileDialog
Frame
Label
List
Menu
MenuItem
Panel
PopupMenu
Scrollbar
ScrollPane
TextArea
TextComponent
TextField
Window

Events supported by this component


AdjustmentEvent
ContainerEvent, FocusEvent, KeyEvent, MouseEvent,
ComponentEvent
KeyEvent,
MouseEvent,
ActionEvent,
FocusEvent,
ComponentEvent
FocusEvent, KeyEvent, MouseEvent, ComponentEvent
KeyEvent,
MouseEvent,
ItemEvent,
FocusEvent,
ComponentEvent
ActionEvent, ItemEvent
KeyEvent,
MouseEvent,
ItemEvent,
FocusEvent,
ComponentEvent
FocusEvent, KeyEvent, MouseEvent, ComponentEvent
ContainerEvent, FocusEvent, KeyEvent, MouseEvent,
ComponentEvent
ContainerEvent, WindowEvent, FocusEvent, KeyEvent,
MouseEvent, ComponentEvent
ContainerEvent, WindowEvent, FocusEvent, KeyEvent,
MouseEvent, ComponentEvent
ContainerEvent, WindowEvent, FocusEvent, KeyEvent,
MouseEvent, ComponentEvent
FocusEvent, KeyEvent, MouseEvent, ComponentEvent
KeyEvent,
MouseEvent,
ActionEvent,
FocusEvent,
ItemEvent, ComponentEvent
ActionEvent
ActionEvent
ContainerEvent, FocusEvent, KeyEvent, MouseEvent,
ComponentEvent
ActionEvent
AdjustmentEvent, FocusEvent, KeyEvent, MouseEvent,
ComponentEvent
ContainerEvent, FocusEvent, KeyEvent, MouseEvent,
ComponentEvent
KeyEvent,
MouseEvent,
TextEvent,
FocusEvent,
ComponentEvent
KeyEvent,
MouseEvent,
TextEvent,
FocusEvent,
ComponentEvent
FocusEvent,
KeyEvent,
ActionEvent,
TextEvent,
MouseEvent, ComponentEvent
ContainerEvent, WindowEvent, FocusEvent, KeyEvent,
MouseEvent, ComponentEvent

21

Once you know which events a particular component supports, you dont need to
look anything up to react to that event. You simply:
Take the name of the event class and remove the word Event. Add the word
Listener to what remains. This is the listener interface you need to implement in your
inner class.
Implement the interface above and write out the methods for the events you want
to capture. For example, you might be looking for mouse movements, so you write code
for the mouseMoved( ) method of the MouseMotionListener interface. (You must
implement the other methods, of course, but theres a shortcut for that which youll see
soon.)
Create an object of the listener class in step 2. Register it with your component
with the method produced by prefixing add to your listener name. For example,
addMouseMotionListener( ).
To finish what you need to know, here are the listener interfaces:
Listener Interface Window Adapter
ActionListener
AdjustmentListener
ComponentListener
ComponentAdapter
ContainerListener
ContainerAdapter
FocusListener
FocusAdapter
KeyListener
KeyAdapter
MouseListener
MouseAdapter

MouseMotionListener
MouseMotionAdapter
WindowListener
WindowAdapter

Methods in interface
actionPerformed(ActionEvent)
AdjustmentValueChanged
(AdjustmentEvent)
componentHidden(ComponentEvent)
componentShown(ComponentEvent)
componentMoved(ComponentEvent)
componentResized(ComponentEvent)
componentAdded(ContainerEvent)
componentRemoved(ContainerEvent)
focusGained(FocusEvent)
focusLost(FocusEvent)
keyPressed(KeyEvent)
keyReleased(KeyEvent)
keyTyped(KeyEvent)
mouseClicked(MouseEvent)
mouseEntered(MouseEvent)
mouseExited(MouseEvent)
mousePressed(MouseEvent)
mouseReleased(MouseEvent)
mouseDragged(MouseEvent)
mouseMoved(MouseEvent)
windowOpened(WindowEvent)
windowClosing(WindowEvent)
windowClosed(WindowEvent)
windowActivated(WindowEvent)

22

ItemListener
TextListener

windowDeactivated(WindowEvent)
windowIconified(WindowEvent)
windowDeiconified(WindowEvent)
itemStateChanged(ItemEvent)
textValueChanged(TextEvent)

A simple example will make this clear.


//: Button2New.java
// Capturing button presses
import java.awt.*;
import java.awt.event.*; // Must add this
import java.applet.*;
public class Button2New extends Applet {
Button
b1 = new Button("Button 1"),
b2 = new Button("Button 2");
public void init() {
b1.addActionListener(new B1());
b2.addActionListener(new B2());
add(b1);
add(b2);
}
class B1 implements ActionListener {
public void actionPerformed(ActionEvent e)
{ getAppletContext().showStatus("Button
1");
}
}
class B2 implements ActionListener {
public void actionPerformed(ActionEvent e)
{ getAppletContext().showStatus("Button
2");
}
}

The output would like something similar to this:

23

Using listener adapters for simplicity


In the previous table, you can see that some listener interfaces have only one
method. These are trivial to implement since youll implement them only when you want
to write that particular method. However, the listener interfaces that have multiple
methods could be less pleasant to use. For example, something you must always do when
creating an application is provide a WindowListener to the Frame so that when you get
the windowClosing( ) event you can call System.exit(0) to exit the application. But since
WindowListener is an interface, you must implement all of the other methods even if
they dont do anything. This can be annoying.
To solve the problem, each of the listener interfaces that have more than one
method are provided with adapters, the names of which you can see in the table above.
Each adapter provides default methods for each of the interface methods. (Alas,
WindowAdapter does not have a default windowClosing( ) that calls System.exit(0).)
Then all you need to do is inherit from the adapter and override only the methods you
need to change. For example, the typical WindowListener youll use looks like this:
class MyWindowListener extends WindowAdapter
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
}

The whole point of the adapters is to make the creation of listener classes easy.
There is a downside to adapters, however, in the form of a pitfall. Suppose you
write a WindowAdapter like the one above:
class MyWindowListener extends WindowAdapter

24
{

public void WindowClosing(WindowEvent e)


{
System.exit(0);
}

This doesnt work, but it will drive you crazy trying to figure out why, since
everything will compile and run fine except that closing the window wont exit the
program. Can you see the problem? Its in the name of the method: WindowClosing( )
instead of windowClosing( ). A simple slip in capitalization results in the addition of a
completely new method. However, this is not the method thats called when the window
is closing, so you dont get the desired results.

MAKING WINDOWS AND APPLETS WITH THE AWT


Often youll want to be able to create a class that can be invoked as either a
window or an applet. To accomplish this, you simply add a main( ) to your applet that
builds an instance of the applet inside a Frame. As a simple example, lets look at
Button2New.java modified to work as both an application and an applet:
//: Button2NewB.java
// An application and an applet
import java.awt.*;
import java.awt.event.*; // Must add this
import java.applet.*;
public class Button2NewB extends Applet
{
Button
b1 = new Button("Button 1"),
b2 = new Button("Button 2");
TextField t = new TextField(20);
public void init()
{
b1.addActionListener(new B1());
b2.addActionListener(new B2());
add(b1);
add(b2);
add(t);
}
class B1 implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
t.setText("Button 1");
}
}

25
class B2 implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
t.setText("Button 2");
}
}
// To close the application:
static class WL extends WindowAdapter
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
}
// A main() for the application:
public static void main(String[] args)
{
Button2NewB applet = new Button2NewB();
Frame aFrame = new Frame("Button2NewB");
aFrame.addWindowListener(new WL());
aFrame.add(applet, BorderLayout.CENTER);
/* Layouts will be discussed in the later chapters in detail*/
aFrame.setSize(300,200);
applet.init();
applet.start();
aFrame.setVisible(true);
}
} ///:~

The output would look something similar to this

The inner class WL and the main( ) are the only two elements added to the applet,
and the rest of the applet is untouched. In fact, you can usually copy and paste the WL
class and main( ) into your own applets with little modification. The WL class is static so

26

it can be easily created in main( ). (Remember that an inner class normally needs an outer
class handle when its created. Making it static eliminates this need.) You can see that in
main( ), the applet is explicitly initialized and started since in this case the browser isnt
available to do it for you. Of course, this doesnt provide the full behavior of the browser,
which also calls stop( ) and destroy( ), but for most situations its acceptable. If its a
problem, you can:
Make the handle applet a static member of the class (instead of a local variable of
main( )), and then:
Call applet.stop( ) and applet.destroy( ) inside WindowAdapter.windowClosing( )
before you call System.exit( ).
Making the window listener an anonymous class

Any of the listener classes could be implemented as anonymous classes, but


theres always a chance that you might want to use their functionality elsewhere.
However, the window listener is used here only to close the applications window so you
can safely make it an anonymous class. Then, in main( ), the line:
aFrame.addWindowListener(new WL());
will become:
aFrame.addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});

This has the advantage that it doesnt require yet another class name. You must
decide for yourself whether it makes the code easier to understand or more difficult.
However, for the remainder of the book an anonymous inner class will usually be used
for the window listener.
Text fields

This is similar to TextField1.java, but it adds significant extra behavior:


//: TextNew.java
// Text fields with Java 1.1 events
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class TextNew extends Applet {
Button
b1 = new Button("Get Text"),
b2 = new Button("Set Text");
TextField

27
t1 = new TextField(30),
t2 = new TextField(30),
t3 = new TextField(30);
String s = new String();
public void init() {
b1.addActionListener(new B1());
b2.addActionListener(new B2());
t1.addTextListener(new T1());
t1.addActionListener(new T1A());
t1.addKeyListener(new T1K());
add(b1);
add(b2);
add(t1);
add(t2);
add(t3);
}
class T1 implements TextListener {
public void textValueChanged(TextEvent e) {
t2.setText(t1.getText());
}
}
class T1A implements ActionListener {
private int count = 0;
public void actionPerformed(ActionEvent e)
{ t3.setText("t1 Action Event " + count+
+);
}
}
class T1K extends KeyAdapter {
public void keyTyped(KeyEvent e) {
String ts = t1.getText();
if(e.getKeyChar() ==KeyEvent.VK_BACK_SPACE) {
// Ensure it's not empty:
if( ts.length() > 0) {
ts = ts.substring(0, ts.length() - 1);
t1.setText(ts);
}
}
else
t1.setText(t1.getText()
+Character.toUpperCase(e.getKeyChar()));
t1.setCaretPosition(t1.getText().length());
// Stop regular character from appearing:
e.consume();
}
}
class B1 implements ActionListener {
public void actionPerformed(ActionEvent e) {
s = t1.getSelectedText();
if(s.length() == 0) s = t1.getText();
t1.setEditable(true);
}
}
class B2 implements ActionListener {
public void actionPerformed(ActionEvent e) {

28
t1.setText("Inserted by Button 2: " + s);
t1.setEditable(false);
}
}
public static void main(String[] args)
{ TextNew applet = new TextNew();
Frame aFrame = new Frame("TextNew");
aFrame.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
aFrame.add(applet, BorderLayout.CENTER);
aFrame.setSize(300,200);
applet.init();
applet.start();
aFrame.setVisible(true);
}
} ///:~

The output would look like this


The TextField t3 is included as a place to report when the action listener for the
TextField t1 is fired. Youll see that the action listener for a TextField is fired only when
you press the enter key.
The TextField t1 has several listeners attached to it. The T1 listener copies all text
from t1 into t2 and the T1K listener forces all characters to upper case. Youll notice that
the two work together, and if you add the T1K listener after you add the T1 listener, it

29

doesnt matter: all characters will still be forced to upper case in both text fields. It would
seem that keyboard events are always fired before TextComponent events, and if you
want the characters in t2 to retain the original case that was typed in, you must do some
extra work.
T1K has some other activities of interest. You must detect a backspace (since
youre controlling everything now) and perform the deletion. The caret must be explicitly
set to the end of the field; otherwise it wont behave as you expect. Finally, to prevent the
original character from being handled by the default mechanism, the event must be
consumed using the consume( ) method that exists for event objects. This tells the
system to stop firing the rest of the event handlers for this particular event.
This example also quietly demonstrates one of the benefits of the design of inner
classes. Note that in the inner class:
class T1 implements TextListener {
public void textValueChanged(TextEvent e)
{ t2.setText(t1.getText());
}
}
t1 and t2 are not members of T1, and yet theyre accessible without any special
qualification. This is because an object of an inner class automatically captures a handle
to the outer object that created it, so you can treat members and methods of the enclosing
class object as if theyre yours. As you can see, this is quite convenient.

TextAreas

The most significant change to text areas in Java 1.1 concerns scroll bars. With
the TextArea constructor, you can now control whether a TextArea will have scroll bars:
vertical, horizontal, both, or neither. This example show the Java scrollbar constructors:
//: TextAreaNew.java
// Controlling scrollbars with the TextArea
// component in Java 1.1
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class TextAreaNew extends Applet
{ Button b1 = new Button("Text Area 1");
Button b2 = new Button("Text Area 2");
Button b3 = new Button("Replace Text");
Button b4 = new Button("Insert Text");
TextArea t1 = new TextArea("t1", 1, 30);
TextArea t2 = new TextArea("t2", 4, 30);
TextArea t3 = new TextArea("t3", 1, 30,
TextArea.SCROLLBARS_NONE);
TextArea t4 = new TextArea("t4", 10, 10,

30
TextArea.SCROLLBARS_VERTICAL_ONLY);
TextArea t5 = new TextArea("t5", 4, 30,
TextArea.SCROLLBARS_HORIZONTAL_ONLY);
TextArea t6 = new TextArea("t6", 10, 10,
TextArea.SCROLLBARS_BOTH);
public void init()
{ b1.addActionListener(new
B1L()); add(b1);
add(t1);
b2.addActionListener(new B2L());
add(b2);
add(t2);
b3.addActionListener(new B3L());
add(b3);
b4.addActionListener(new B4L());
add(b4);
add(t3);
add(t4);
add(t5);
add(t6);
}
class B1L implements ActionListener {
public void actionPerformed(ActionEvent e) {
t5.append(t1.getText() + "\n");
}
}
class B2L implements ActionListener {
public void actionPerformed(ActionEvent e) {
t2.setText("Inserted by Button 2");
t2.append(": " + t1.getText());
t5.append(t2.getText() + "\n");
}
}
class B3L implements ActionListener {
public void actionPerformed(ActionEvent e) {
String s = " Replacement ";
t2.replaceRange(s, 3, 3 + s.length());
}
}
class B4L implements ActionListener {
public void actionPerformed(ActionEvent e) {
t2.insert(" Inserted ", 10);
}
}
public static void main(String[] args)
{ TextAreaNew applet = new
TextAreaNew(); Frame aFrame = new
Frame("TextAreaNew");
aFrame.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
aFrame.add(applet, BorderLayout.CENTER);
aFrame.setSize(300,725);

31
applet.start();
aFrame.setVisible(true);
}
} ///:~

The output would be something like

Youll notice that you can control the scrollbars only at the time of construction of
the TextArea. Also, even if a TextArea doesnt have a scrollbar, you can move the cursor
such that scrolling will be forced. (You can see this behavior by playing with the
example.)

CHECK BOXES AND RADIO BUTTONS


As noted previously, check boxes and radio buttons are both created with the
same class, Checkbox, but radio buttons are Checkboxes placed into a CheckboxGroup.
In either case, the interesting event is ItemEvent, for which you create an ItemListener.
When dealing with a group of check boxes or radio buttons, you have a choice.
You can either create a new inner class to handle the event for each different Checkbox
or you can create one inner class that determines which Checkbox was clicked and
register a single object of that inner class with each Checkbox object. The following
example shows both approaches:

32

//: RadioCheckNew.java
// Radio buttons and Check Boxes in Java 1.1
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class RadioCheckNew extends Applet {
TextField t = new TextField(30);
Checkbox[] cb = {
new Checkbox("Check Box 1"),
new Checkbox("Check Box 2"),
new Checkbox("Check Box 3") };
CheckboxGroup g = new CheckboxGroup();
Checkbox
cb4 = new Checkbox("four", g, false),
cb5 = new Checkbox("five", g, true),
cb6 = new Checkbox("six", g, false);
public void init() {
t.setEditable(false);
add(t);
ILCheck il = new ILCheck();
for(int i = 0; i < cb.length; i++) {
cb[i].addItemListener(il);
add(cb[i]);
}
cb4.addItemListener(new IL4());
cb5.addItemListener(new IL5());
cb6.addItemListener(new IL6());
add(cb4); add(cb5); add(cb6);
}
// Checking the source:
class ILCheck implements ItemListener {
public void itemStateChanged(ItemEvent e) {
for(int i = 0; i < cb.length; i++) {
if(e.getSource().equals(cb[i]))
{ t.setText("Check box " + (i +
1)); return;
}
}
}
}
// vs. an individual class for each item:
class IL4 implements ItemListener {
public void itemStateChanged(ItemEvent e) {
t.setText("Radio button four");
}
}
class IL5 implements ItemListener {
public void itemStateChanged(ItemEvent e) {
t.setText("Radio button five");
}
}
class IL6 implements ItemListener {
public void itemStateChanged(ItemEvent e) {
t.setText("Radio button six");

33
}
}
public static void main(String[] args)
{ RadioCheckNew applet = new
RadioCheckNew(); Frame aFrame = new
Frame("RadioCheckNew");
aFrame.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
aFrame.add(applet, BorderLayout.CENTER);
aFrame.setSize(300,200);
applet.init();
applet.start();
aFrame.setVisible(true);
}
} ///:~
The
output would look like:

ILCheck has the advantage that it automatically adapts when you add or subtract
Checkboxes. Of course, you can use this with radio buttons as well. It should be used,
however, only when your logic is general enough to support this approach. Otherwise
youll end up with a cascaded if statement, a sure sign that you should revert to using
independent listener classes.

DROP-DOWN LISTS
Drop-down lists (Choice) since Java 1.1 also use ItemListeners to notify you
when a choice has changed:
//: ChoiceNew.java
// Drop-down lists with Java
import java.awt.*;

34
import java.awt.event.*;
import java.applet.*;
public class ChoiceNew extends Applet
{ String[] description = { "Aptech",
"NIIT", "Tulech", "Bitech", "CSC",
"Infotech", "ICOM", "Radiant" };
TextField t = new TextField(100);
Choice c = new Choice();
Button b = new Button("Add items");
int count = 0;
public void init()
{ t.setEditable(false);
for(int i = 0; i < 4; i++)
c.addItem(description[count++]);
add(t);
add(c);
add(b);
c.addItemListener(new CL());
b.addActionListener(new BL());
}
class CL implements ItemListener {
public void itemStateChanged(ItemEvent e)
{ t.setText("index: " +
c.getSelectedIndex()
+ "
" + e.toString());
}
}
class BL implements ActionListener {
public void actionPerformed(ActionEvent e) {
if(count < description.length)
c.addItem(description[count++]);
}
}
public static void main(String[] args)
{ ChoiceNew applet = new ChoiceNew();
Frame aFrame = new Frame("ChoiceNew");
aFrame.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
aFrame.add(applet, BorderLayout.CENTER);
aFrame.setSize(750,100);
applet.init();
applet.start();

35
aFrame.setVisible(true);

}} ///:~

Nothing else here is particularly new (except that Java 1.1 has significantly fewer bugs in
the UI classes).

LISTS
Youll recall that one of the problems with the Java 1.0 List design is that it took
extra work to make it do what youd expect: react to a single click on one of the list
elements. Java 1.1 has solved this problem:
//: ListNew.java
// Java 1.1 Lists are easier to use
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
public class ListNew extends Applet {
String[] flavors = { "Chocolate", "Strawberry",
"Vanilla Fudge Swirl", "Mint Chip",
"Mocha Almond Fudge", "Rum Raisin",
"Praline Cream", "Mud Pie" };
// Show 6 items, allow multiple selection:
List lst = new List(6, true);
TextArea t = new TextArea(flavors.length, 30);
Button b = new Button("test");
int count = 0;
public void init() {
t.setEditable(false);
for(int i = 0; i < 4; i++)
lst.addItem(flavors[count++]);
add(t);
add(lst);
add(b);
lst.addItemListener(new LL());
b.addActionListener(new BL());

36
}
class LL implements ItemListener {
public void itemStateChanged(ItemEvent e) {
t.setText("");
String[] items = lst.getSelectedItems();
for(int i = 0; i < items.length; i++)
t.append(items[i] + "\n");
}
}
class BL implements ActionListener {
public void actionPerformed(ActionEvent e) {
if(count < flavors.length)
lst.addItem(flavors[count++], 0);
}
}
public static void main(String[] args)
{ ListNew applet = new ListNew();
Frame aFrame = new Frame("ListNew");
aFrame.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
aFrame.add(applet, BorderLayout.CENTER);
aFrame.setSize(300,200);
applet.init();
applet.start();
aFrame.setVisible(true);
}
} ///:~

The output of the above program will be similar to this

37

You can see that no extra logic is required to support a single click on a list item. You
just attach a listener like you do everywhere else.

MENUS
The event handling for menus does seem to benefit from the Java 1.1 event
model, but Javas approach to menus is still messy and requires a lot of hand coding. The
right medium for a menu seems to be a resource rather than a lot of code. Keep in mind
that program-building tools will generally handle the creation of menus for you, so that
will reduce the pain somewhat (as long as they will also handle the maintenance!).
In addition, youll find the events for menus are inconsistent and can lead to
confusion: MenuItems use ActionListeners, but CheckboxMenuItems use ItemListeners.
The Menu objects can also support ActionListeners, but thats not usually helpful. In
general, youll attach listeners to each MenuItem or CheckboxMenuItem, but the
following example (revised from the earlier version) also shows ways to combine the
capture of multiple menu components into a single listener class. As youll see, its
probably not worth the hassle to do this.
//: MenuNew.java
import java.awt.*;
import java.awt.event.*;
public class MenuNew extends Frame {
String[] flavors = {
"Chocolate", "Strawberry",
"Vanilla Fudge Swirl", "Mint Chip",
"Mocha Almond Fudge", "Rum Raisin",
"Praline Cream", "Mud Pie"
};
TextField t = new TextField("No flavor", 30);
MenuBar mb1 = new MenuBar();
Menu f = new Menu("File");
Menu m = new Menu("Flavors");
Menu s = new Menu("Safety");
// Alternative approach:
CheckboxMenuItem[] safety = {
new CheckboxMenuItem("Guard"),
new CheckboxMenuItem("Hide")
};
MenuItem[] file = {
// No menu shortcut:
new MenuItem("Open"),
// Adding a menu shortcut is very simple:
new MenuItem("Exit",
new MenuShortcut(KeyEvent.VK_E))
};
// A second menu bar to swap to:
MenuBar mb2 = new MenuBar();
Menu fooBar = new Menu("fooBar");
MenuItem[] other = {
new MenuItem("Foo"),

38
new MenuItem("Bar"),
new MenuItem("Baz"),
};
// Initialization code:
{
ML ml = new ML();
CMIL cmil = new CMIL();
safety[0].setActionCommand("Guard");
safety[0].addItemListener(cmil);
safety[1].setActionCommand("Hide");
safety[1].addItemListener(cmil);
file[0].setActionCommand("Open");
file[0].addActionListener(ml);
file[1].setActionCommand("Exit");
file[1].addActionListener(ml);
other[0].addActionListener(new FooL());
other[1].addActionListener(new BarL());
other[2].addActionListener(new BazL());
}
Button b = new Button("Swap Menus");
public MenuNew() {
FL fl = new FL();
for(int i = 0; i < flavors.length; i++)
{ MenuItem mi = new
MenuItem(flavors[i]);
mi.addActionListener(fl);
m.add(mi);
// Add separators at intervals:
if((i+1) % 3 == 0)
m.addSeparator();
}
for(int i = 0; i < safety.length; i++)
s.add(safety[i]);
f.add(s);
for(int i = 0; i < file.length; i++)
f.add(file[i]);
mb1.add(f);
mb1.add(m);
setMenuBar(mb1);
t.setEditable(false);
add(t, BorderLayout.CENTER);
// Set up the system for swapping menus:
b.addActionListener(new BL());
add(b, BorderLayout.NORTH);
for(int i = 0; i < other.length; i++)
fooBar.add(other[i]);
mb2.add(fooBar);
}
class BL implements ActionListener {
public void actionPerformed(ActionEvent e) {
MenuBar m = getMenuBar();
if(m == mb1) setMenuBar(mb2);
else if (m == mb2) setMenuBar(mb1);
}
}
class ML implements ActionListener {
public void actionPerformed(ActionEvent e) {

39
MenuItem target = (MenuItem)e.getSource();
String actionCommand =
target.getActionCommand();
if(actionCommand.equals("Open")) {
String s = t.getText();
boolean chosen = false;
for(int i = 0; i < flavors.length; i++)
if(s.equals(flavors[i])) chosen = true;
if(!chosen)
t.setText("Choose a flavor first!");
else
t.setText("Opening "+ s +". Mmm, mm!");
}
else if(actionCommand.equals("Exit")) {
dispatchEvent(
new WindowEvent(MenuNew.this,
WindowEvent.WINDOW_CLOSING));
}

}
}
class FL implements ActionListener {
public void actionPerformed(ActionEvent e)
{ MenuItem target =
(MenuItem)e.getSource();
t.setText(target.getLabel());
}
}
// Alternatively, you can create a different
// class for each different MenuItem. Then you
// Don't have to figure out which one it is:
class FooL implements ActionListener {
public void actionPerformed(ActionEvent e) {
t.setText("Foo selected");
}
}
class BarL implements ActionListener {
public void actionPerformed(ActionEvent e) {
t.setText("Bar selected");
}
}
class BazL implements ActionListener {
public void actionPerformed(ActionEvent e) {
t.setText("Baz selected");
}
}
class CMIL implements ItemListener {
public void itemStateChanged(ItemEvent e) {
CheckboxMenuItem target =
(CheckboxMenuItem)e.getSource();
String actionCommand =
target.getActionCommand();
if(actionCommand.equals("Guard"))
t.setText("Guard the Ice Cream! " +
"Guarding is " + target.getState());
else if(actionCommand.equals("Hide"))
t.setText("Hide the Ice Cream! " +

40
}
}
public static void main(String[] args) {
MenuNew f = new MenuNew();
f.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.setSize(300,200);
f.setVisible(true);
}
} ///:~

The output will be similar to this

This code is similar to the Java 1.0 version, until you get to the initialization
section (marked by the opening brace right after the comment Initialization code:).
Here you can see the ItemListeners and ActionListeners attached to the various menu
components.
Java 1.1 and later versions support menu shortcuts, so you can select a menu
item using the keyboard instead of the mouse. These are quite simple; you just use the
overloaded MenuItem constructor that takes as a second argument a MenuShortcut
object. The constructor for MenuShortcut takes the key of interest, which magically
appears on the menu item when it drops down. The example above adds Control-E to the
Exit menu item.
You can also see the use of setActionCommand( ). This seems a bit strange
because in each case the action command is exactly the same as the label on the menu
component. Why not just use the label instead of this alternative string? The problem is
internationalization. If you retarget this program to another language, you want to change
only the label in the menu, and not go through the code changing all the logic that will no
doubt introduce new errors. So to make this easy for code that checks the text string

41

associated with a menu component, the action command can be immutable while the
menu label can change. All the code works with the action command, so its unaffected
by changes to the menu labels. Note that in this program, not all the menu components
are examined for their action commands, so those that arent dont have their action
command set.
Much of the constructor is the same as before, with the exception of a couple of calls to add listeners. The bulk of the work
happens in the listeners. In BL, the MenuBar swapping happens as in the previous example. In ML, the figure out who rang
approach is taken by getting the source of the ActionEvent and casting it to a MenuItem, then getting the action command string
to pass it through a cascaded if statement. Much of this is the same as before, but notice that if Exit is chosen, a new
WindowEvent is created, passing in the handle of the enclosing class object ( MenuNew.this) and creating a
WINDOW_CLOSING event. This is handed to the dispatchEvent( ) method of the enclosing class object, which then ends up
calling windowClosing( ) inside the window listener for the Frame (this listener is created as an anonymous inner class, inside
main( )), just as if the message had been generated the normal way. Through this mechanism, you can dispatch any message
you want in any circumstances, so its quite powerful.

The FL listener is simple even though its handling all the different flavors in the
flavor menu. This approach is useful if you have enough simplicity in your logic, but in
general, youll want to take the approach used with FooL, BarL, and BazL, in which they
are each attached to only a single menu component so no extra detection logic is
necessary and you know exactly who called the listener. Even with the profusion of
classes generated this way, the code inside tends to be smaller and the process is more
foolproof.

DIALOG BOXES
This is a direct rewrite of the earlier ToeTest.java. In this version, however,
everything is placed inside an inner class. Although this completely eliminates the need
to keep track of the object that spawned any class, as was the case in ToeTest.java, it
could be taking the concept of inner classes a bit too far. At one point, the inner classes
are nested four deep. This is the kind of design in which you need to decide whether the
benefit of inner classes is worth the increased complexity. In addition, when you create a
non- static inner class youre tying that class to its surrounding class. Sometimes a
standalone class can more easily be reused.
//: ToeTestNew.java
// Demonstration of dialog boxes
// and creating your own components
import java.awt.*;
import java.awt.event.*;
public class ToeTestNew extends Frame
{ TextField rows = new
TextField("3"); TextField cols = new
TextField("3"); public ToeTestNew()
{
setTitle("Toe Test");
Panel p = new Panel();
p.setLayout(new GridLayout(2,2));
p.add(new Label("Rows", Label.CENTER));
p.add(rows);

42
p.add(new Label("Columns", Label.CENTER));
p.add(cols);
add(p, BorderLayout.NORTH);
Button b = new Button("go");
b.addActionListener(new BL());
add(b, BorderLayout.SOUTH);
}
static final int BLANK = 0;
static final int XX = 1;
static final int OO = 2;
class ToeDialog extends Dialog {
// w = number of cells wide
// h = number of cells high
int turn = XX; // Start with x's turn
public ToeDialog(int w, int h) {
super(ToeTestNew.this, "The game itself", false);
setLayout(new GridLayout(w, h));
for(int i = 0; i < w * h; i++)
add(new ToeButton());
setSize(w * 50, h * 50);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e){
dispose();
}
});
}
class ToeButton extends Canvas {
int state = BLANK;
ToeButton() {
addMouseListener(new ML());
}
public void paint(Graphics g) {
int x1 = 0;
int y1 = 0;
int x2 = getSize().width - 1;
int y2 = getSize().height - 1;
g.drawRect(x1, y1, x2, y2);
x1 = x2/4;
y1 = y2/4;
int wide = x2/2;
int high = y2/2;
if(state == XX) {
g.drawLine(x1, y1,x1 + wide, y1 + high);
g.drawLine(x1, y1 + high,x1 + wide, y1);
}
if(state == OO) {
g.drawOval(x1, y1,x1 + wide/2, y1 +
high/2);
}
}
class ML extends MouseAdapter {
public void mousePressed(MouseEvent e) {
if(state == BLANK) {
state = turn;
turn = (turn == XX ? OO : XX);
}

43
else
state = (state == XX ? OO : XX);
repaint();
}

}
}
class BL implements ActionListener {
public void actionPerformed(ActionEvent e) {
Dialog d = new
ToeDialog( Integer.parseInt(rows.getTe
xt()),
Integer.parseInt(cols.getText()));
d.show();
}
}
public static void main(String[] args) {
Frame f = new ToeTestNew();
f.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.setSize(200,100);
f.setVisible(true);
}
} ///:~

Because statics can be at only the outer level of the class, inner classes cannot
have static data or static inner classes.

FILE DIALOGS

44

Converting from FileDialogTest.java to the new event model is straightforward:


//: FileDialogNew.java
// Demonstration of File dialog boxes
import java.awt.*;
import java.awt.event.*;
public class FileDialogNew extends Frame
{ TextField filename = new
TextField(); TextField directory = new
TextField(); Button open = new
Button("Open"); Button save = new
Button("Save"); public FileDialogNew()
{
setTitle("File Dialog Test");
Panel p = new Panel();
p.setLayout(new FlowLayout());
open.addActionListener(new OpenL());
p.add(open);
save.addActionListener(new SaveL());
p.add(save);
add(p, BorderLayout.SOUTH);
directory.setEditable(false);
filename.setEditable(false);
p = new Panel();
p.setLayout(new GridLayout(2,1));
p.add(filename);
p.add(directory);
add(p, BorderLayout.NORTH);
}
class OpenL implements ActionListener {
public void actionPerformed(ActionEvent e) {
// Two arguments, defaults to open file:
FileDialog d = new
FileDialog( FileDialogNew.this,
"What file do you want to open?");
d.setFile("*.java");
d.setDirectory("."); // Current directory
d.show();
String yourFile = "*.*";
if((yourFile = d.getFile()) != null)
{ filename.setText(yourFile);
directory.setText(d.getDirectory());
}
else {
filename.setText("You pressed cancel");
directory.setText("");
}
}
}
class SaveL implements ActionListener {
public void actionPerformed(ActionEvent e) {
FileDialog d = new
FileDialog( FileDialogNew.this,
"What file do you want to save?",
FileDialog.SAVE);
d.setFile("*.java");

45
d.setDirectory(".");
d.show();
String saveFile;
if((saveFile = d.getFile()) != null)
{ filename.setText(saveFile);
directory.setText(d.getDirectory());
}
else {
filename.setText("You pressed cancel");
directory.setText("");
}

}
}
public static void main(String[] args) {
Frame f = new FileDialogNew();
f.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.setSize(250,110);
f.setVisible(true);
}
} ///:~

The Output will be similar to this:

It would be nice if all the conversions were this easy, but theyre usually easy enough, and your code benefits from the improved
readability.

LET US SUM UP
An event is an object describes some state change in a source. It can generate
when a user presses a button, drags a mouse or performs some similar action. A set of
classes are provided in java.awt package to represent the various types of events.
The primary event classes and the situations in which their objects are generated
are summarized below:
Name of Event
class
ActionEvent
AdjustmentEvent

Situations in which an event object is created


When a button is pressed, a list item is double-clicked, or a menu
item is selected.
When a scroll bar is manipulated.

46

ComponentEvent
ContainerEvent
FocusEvent
InputEvent
ItemEvent
KeyEvent
MouseEvent
TextEvent
WindowEvent

When a component is hidden, moved, resized, or becomes visible.


When a component is added to or removed from a container.
When a component gains or loses keyboard focus.
When a mouse or key event occurs.
When a check box or list item is clicked, a choice selection is made,
or a checkable menu item is selected or disselected.
When the input is received from the keyboard.
When the mouse is dragged or moved, clicked, pressed, released,
the mouse enters or exits a component.
When the value of a text area or text field is changed.
When a window is activated, closed, deactivated, deiconified,
iconified, opened, or quit.

LESSON-END ACTIVITIES
1. Create a paint brush like application. Buttons need not have icons
2. Create a text field, get input from the user and check whether its a prime number.
Without using buttons.
3. Create three text fields and a button, concatenate the text from the two fields and put
it into the third text field.
4. Create a list and a choice which listens to item listener. Such that when the user
selects an item from the list it should get added in the choice
5. Redo the above program but this time an item should be added to the list when the
user selects an item from the choice

POINTS FOR DISCUSSION


Discuss the Advantages of Event Driven Programming over Traditional Programming
Techniques

47

REFERENCES
Campione, Walrath and Huml, The Java Tutorial, Addison Wesley 1999
Ken Arnold, James Gosling, David Holmes, The Java Programming Language, 3ed,
Addision Wesley, 2000.

48

LESSON 3: THREADING CONCEPTS


Contents
Aims and Objectives
Introduction
Multi-Thread Application
Inter Thread Communication
Thread Priorities
Let us Sum up
Lesson-End Activities
Points for Discussion
Model Answers to Check Your Progress
Suggested Readings/References/Sources

AIMS AND OBJECTIVES


At the end of this Lesson, you will be able to:
Understand the Concepts of Thread
Implement Threading concept in Java
Understand about Applications of Multi Threading

INTRODUCTION
Most computer games use graphics and sound. Have you noticed that the
graphics, the score and the music run simultaneously. Imagine a situation where you see
the screen changing first, your score getting updated next, and then finally you hear the
sound. A single game has all these elements being processed at the same time. In other
words, the program has been divided into three sub-units, each unit being handled by a
thread.
Threads are very useful when you have large computations that take several
seconds to complete and you dont want the user to perceive the delay. Animation is also
an area where threads are used.
A thread--sometimes called an execution context or a lightweight process--is a
single sequential flow of control within a program. You use threads to isolate tasks. Each
thread is a sequential flow of control within the same program (the browser). A thread is
similar to the sequential programs described previously. A single thread also has a
beginning, a sequence, and an end and at any given time during the runtime of the thread,
there is a single point of execution. However, a thread itself is not a program; it cannot
run on its own. Rather, it runs within a program. Every program has at least one thread
and it is called the primary thread. More threads can be created whenever necessary.

49

Definition: A thread is a single sequential flow of control within a program.


There is nothing new in the concept of a single thread. The real hoopla
surrounding threads is not about a single sequential thread. Rather, it's about the use of
multiple threads in a single program, running at the same time and performing different
tasks.
The HotJava Web browser is an example of a multithreaded application. Within
the HotJava browser you can scroll a page while it's downloading an applet or image,
play animation and sound concurrently, print a page in the background while you
download a new page, or watch three sorting algorithms race to the finish. You are used
to life operating in a concurrent fashion...so why not your browser?
Some texts use the name lightweight process instead of thread. A thread is similar
to a real process in that a thread and a running program are both a single sequential flow
of control. However, a thread is considered lightweight because it runs within the context
of a full-blown program and takes advantage of the resources allocated for that program
and the program's environment.
As a sequential flow of control, a thread must carve out some of its own resources
within a running program. (It must have its own execution stack and program counter for
example.) The code running within the thread works only within that context. Thus, some
other texts use execution context as a synonym for thread.
Single-Threaded and Multithreaded Applications
A process that is made up only one thread is called single-threaded. A single
threaded application can perform one application at a time. You have to wait for one task

to be completed before another can start.


A process having more than one thread is called multithreaded. Multiple threads in a
process run at the same time, perform different tasks, and interact with one another.

50

Difference between multithreading and multitasking is that multitasking is with


respect to operating system. Single program which has several tasks (and running
simultaneously) within itself is reffered as multithreading.

Life Cycle Of A Thread


The following diagram illustrates the life cycle of a thread:

The figure depicts the following states:


New thread
Runnable
Not runnable
Dead
The New Thread State
When an instance of the Thread class is created, the thread enters the new thread
state. The following code segment illustrates the instantiation of the Thread class
// this keyword signifies that the run() method needs to be invoked from the
// current object
Thread newThread = new Thread(this)
The above code creates a new thread and, as of now, no resources are allocated for it. It is
an empty object. You have to invoke the start() method to start the thread.
newThread.start() ;

51

The Runnable Thread State


When the start() method of a thread is invoked, the thread enters the runnable
state. Since a single processor cannot execute more than one thread at a time, the
processor maintains a thread queue. Once started, a thread is queued up for the processor
and waits for its turn to be executed. Therefore at any given point of time, a thread maybe
waiting for the attention of the processor. This is why the state of the thread is said to be
runnable and not running.
The Not Runnable Thread state
A thread is said to be in the not runnable state if it is:
Sleeping
Waiting
Being blocked by another thread
A thread is put in the sleeping mode with the sleep() method. A sleeping thread
enters the runnable state after the specified time of sleep has elapsed. Until the specified
time has elapsed the thread will not execute.
A thread can be made to wait on a conditional variable until a condition is
satisfied. A thread can be notified of the condition by invoking the notify() method of the
Thread Class.When the thread is blocked by an input-output operation, it enters the not
runnable state although it might otherwise qualify as runnable.
The Dead Thread State
A thread can either die or be naturally killed. A thread dies a natural death when
the loop in the run() method is complete. For example if the loop in the run() method has
a hundred iterations, the life of the thread is a hundred iterations of the loop. Assigning
null to a thread object kills a thread. The isAlive() method of the Thread class is used to
determine whether the thread has been started.

Single Thread
Every program has at least one thread. This thread can be accessed using the
currentThread() method of the Thread class. This method is a static method and hence
you do not have to create an object of the Thread class to invoke the method. The code
below uses the currentThread method.
public class CurrentThread
{
public static void main(String args[])
{
Thread thisThread = Thread.currentThread();
try
{
int i;
for( i = 0; i <10 ; i += 2 )

52
{

System.out.println(i);
Thread.sleep(1000);

}
}
catch (InterruptedException e)
{
System.out.println(I was interrupted);
}

The output is
0
2
3
6
8

In the application above, the current thread is obtained using the currentThread()
method. Everytime the thread prints the value of i , the thread is put to sleep for 1000
milliseconds. The thread might throw an exception if another thread interrupts the
sleeping one. Therefore the sleep() method is guarded by the try block
Check your Progress 1
Explain the life cycle of a thread
Note: Write your answer in the space given below:
Check your answer with one given at the end of this Lesson

MULTI-THREADED APPLICATION
Multiple threads are created in a program using any of the two methods below:
Subclassing the Thread class
Using the Runnable interface

53

Subclassing the Thread Class


The java.lang.Thread is used to construct and access individual threads in a multithreaded application. It supports many methods that obtain information about the
activities of a thread, set and check the properties of a thread, and cause a thread to wait,
be interrupted or be destroyed. You can make your applications and classes run in
separate threads by extending the Thread class.
The first way to customize what a thread does when it is running is to subclass
Thread (itself a Runnable object) and override its empty run method so that it
does something. Let's look at the SimpleThread class, the first of two classes in this
example, which does just that:
public class SimpleThread extends Thread
{
public SimpleThread(String str)
{
super(str);
}
public void run()
{
for (int i = 0; i < 10; i++)
{
System.out.println(i + " " + getName());
try
{
sleep((int)(Math.random()
*
1000));
}
catch (InterruptedException e) {}
}
System.out.println("DONE! " + getName());
}
}

The first method in the SimpleThread class is a constructor that takes a


String as its only argument. This constructor is implemented by calling a superclass
constructor and is interesting to us only because it sets the Thread's name, which is used
later in the program.
The next method in the SimpleThread class is the run() method. The run()
method is the heart of any Thread and where the action of the Thread takes place. The
run() method of the SimpleThread class contains a for loop that iterates ten times. In
each iteration the method displays the iteration number and the name of the Thread, then
sleeps for a random interval of up to 1 second. After the loop has finished, the run
method prints DONE! along with the name of the thread. That's it for the SimpleThread
class.

54

The TwoThreadsTest class provides a main method that creates two


SimpleThread threads: one is named "Ooty" and the other is named "Kodai". (If you
can't decide on where to go for vacation you can use this program to help you decide--go
to the island whose thread prints "DONE!" first.)
public class TwoThreadsTest
{
public static void main (String[] args)
{
new SimpleThread("Ooty").start();
new SimpleThread("Kodai").start();
}
}

Output of the above Program


0 Ooty
0 Kodai
1 Kodai
1 Ooty
2 Ooty
2 Kodai
3 Kodai
3 Ooty
4 Ooty
4 Kodai
5 Ooty
5 Kodai
6 Kodai
6 Ooty
7 Ooty
7 Kodai
8 Kodai
9 Kodai
8 Ooty
DONE! Kodai
9 Ooty
DONE! Ooty
(Looks like we are going to Kodai!!) Notice how the output from each thread is
intermingled with the output from the other. This is because both SimpleThread threads
are running concurrently. Thus, both run methods are running at the same time and each
thread is displaying its output at the same time as the other.
The Runnable Interface
Applets extend from the Applet class. Since Java doesnt support multiple
inheritance, a class cannot be inherited from the Applet class as well as the Thread class.

55

Java provides the Runnable interface to solve this problem. The Runnable interface
consists of a single method, run(), which is executed when the thread is activated. Hence
we can extend from the Applet class, implement the Runnable interface and code the
run() method. With applications, you have a choice of extending from the Thread class.
In other words, when a program needs to inherit from a class apart from the Thread class,
you need to implement the Runnable interface.
Example:
public class ClockThread extends Applet implements Runnable
{
----------------}

NOTE: When the Runnable interface is used, the thread becomes a part of the
Applet class and hence can grant full access to the data members and methods. A subclass
of the Thread class is limited to only the public components of the class. Therefore, when
the thread depends strongly on the components of the Applet class, use the Runnable
interface.
The start() Method
The start() method of the Thread class is responsible for starting the thread. It
allocates the system resources that are necessary for the thread, schedules the thread to
run, and calls the run() method of the thread.
Example:
public class Myclock extends Applet implements Runnable
{
Thread clockThread;
public void start() ;
// Method of the applet
{
if (ClockThread == null)
//Checks if the
is created
`
{
ClockThread = Thread(this);
ClockThread.start();
//Invokes
the
method of thread
}
}
}

thread

start

The Runnable Thread


Once started, the thread enters the runnable state. All the activities of a thread
take place in the body of the thread, which is defined by the run() method. After a thread
is created and initialized, the run() method is called. The run() method usually contains a
loop.
public void run()

56
{

while (ClockThread != null)


{
-----------}

The Not Runnable Thread


The thread is put into a sleeping mode with the sleep() method. When the thread is
sleeping, other threads in the queue are executed.
Syntax
static void sleep(long no_of_milliseconds);
no_of_milliseconds is the time in milliseconds for which the thread is inactive.
sleep is a static method because it operates on the current thread.
Example:
public void run()
{
while (ClockThread != null)
{
repaint();
try
{
ClockThread.sleep(1000);
}
catch (InterruptedException e)
{
System.out.println(I
was
Sleep interrupted
}
}
}

interrupted);

//

public void paint(Graphics g)


{
String strTime;
Date time = new Date();
GregorianCalendar calendar = new GregorianCalendar();
Calendar.setTime(time);
StrTime =
calendar.get(Calendar.HOUR) + : +
calendar.get(Calendar.MINUTE) + : +
calendar.get(Calendar.SECOND) ;
g.drawString(strTime,5,10);
}

The above code continuously updates the time on the screen. This is achieved by
using a thread. The method repaints the screen after every 100 milliseconds. The paint()

method uses the java.util.Date, java.util.Calendar, java.util.GregorianCalendar classes


to obtain the current time, extracts the hours, minutes, and seconds, converts them into a
string, and displays the string on the screen.
Stopping a Thread
A thread dies a natural death when the loop in the run() method is complete. A thread can
be killed using the stop() method.
public void stop()
{
clockThread = null;
}

The stop() method of the applet releases the memory allocated to the thread, and thereby
stops it when page on which the applet runs is left. This method sets clockThread to null
and causes the loop in the run() method to terminate. If the page is revisited, the start()
method is called again and a new thread is started.
Hence the Clock Applet is as given:
public class Clock extends java.applet.Applet implements Runnable
{
private Thread clockThread = null;
public void start()
{
if (clockThread == null)
{
clockThread = new Thread(this, "Clock");
clockThread.start();
}
}
public void run()
{
Thread myThread = Thread.currentThread();
while (clockThread == myThread)
{
repaint();
try
{
Thread.sleep(1000);
}
catch (InterruptedException e){ }
}
}
public void paint(Graphics g)
{
Calendar cal = Calendar.getInstance();
Date date = cal.getTime();
DateFormat dateFormatter =
DateFormat.getTimeInstance();

g.drawString(dateFormatter.format(date), 5, 10);

public void stop()


{
clockThread = null;
}

The output of the above program is

INTER THREAD COMMUNICATION


The power of threads can be unleashed by making them communicate with one another.
Consider this analogy: A family of four members is served a bowl of soup but only one
spoon. All the four are very hungry. They have now two options.
Option1: The first member of the family uses the spoon to have his soup first, passes it
onto the second member and so on. The last member waits for everyone else to finish,
and by then his soup is cold and very little of it is left.
Option2: Each member has one spoonful of soup each and passes the spoon around to
the next member. This will ensure that every member gets an equal share and nobody is
kept waiting.

Which option would you prefer if you were the last member?
When two threads need to share data, it must be ensured that one thread doesnot
change the data used by the other thread. Java enables you to co-ordinate the actions of
multiple threads using synchronized methods or synchronized statements.
Synchronizing Threads
So far, this lesson has contained examples with independent, asynchronous
threads. That is, each thread contained all of the data and methods required for its
execution and didn't require any outside resources or methods. In addition, the threads in
those examples ran at their own pace without concern over the state or activities of any
other concurrently running threads.
An object for which access is to be coordinated is accessed by using the methods
declared within the synchronized keyword. At any given point of time, only one
synchronized method can be invoked, thus preventing conflicts between synchronized
methods in multiple threads.
All objects and classes are associated with a monitor. The monitor controls
the way in which synchronized methods access an object or class. It ensures that
only one thread has access to the resource at any given point of time. A
synchronized method acquires the monitor of an object when it is invoked for that
object. During the execution of a synchronized method, the object is locked so that
no other synchronized method can be invoked. The monitor is automatically
released as soon as the method completes its execution. The monitor may also be
released when the synchronized method executes certain methods like the wait()
method. The thread associated with the synchronized method becomes not runnable
until the wait condition is satisfied. When the wait condition is satisfied, the thread
has to acquire the monitor of the object to become runnable.
The following code shows how synchronized methods and object monitors are
used to co-ordinate access to a common object by multiple threads.
class MyThread extends Thread
{
static String
message[]={I,love,Object,Oriented,Programs,in,java.
};
public MyThread(String id)
{
}

super(id);

public void run()


{

60
Sync.displayList(getName(), message);
}
void waiting()
{
try
{
sleep(1000);
}
catch (InterruptedException e)
{
System.out.println(I was interrupted); //
Sleep interrupted
}
}
}
class Sync
{
public static synchronized void displayList(String name,
String list[])
{
int i;
for ( i = 0; i < list.length; i++)
{
MyThread thread =
(MyThread)Thread.currentThread();
thread.waiting();
System.out.println(name + list[i]);
}
}
}
class ThreadSync
{
public static void main
{
MyThread threadA
MyThread threadB
threadA.start();
threadB.start();
}
}

Output
Thread
Thread
Thread
Thread
Thread
Thread
Thread
Thread
Thread
Thread
Thread

A: I
A: love
A: Object
A: Oriented
A: Programs
A: in
A: java.
B: I
B: love
B: Object
B: Oriented

(String args[])
= new MyThread(Thread A: );
= new MyThread(Thread B: );
//starts first thread
//starts second thread

61
Thread B: Programs
Thread B: in
Thread B: java.

However, there are many interesting situations where separate, concurrently


running threads do share data and must consider the state and activities of other threads.
One such set of programming situations are known as producer/consumer scenarios
where the producer generates a stream of data, which then is consumed by a consumer.
For example, imagine a Java application where one thread (the producer) writes
data to a file while a second thread (the consumer) reads data from the same file. Or, as
you type characters on the keyboard, the producer thread places key events in an event
queue and the consumer thread reads the events from the same queue. Both of these
examples use concurrent threads that share a common resource: the first shares a file, the
second shares an event queue. Because the threads share a common resource, they must
be synchronized in some way.
Consider this example in which the data produced by threadA is consumed by
threadB. Here threadA is the producer and threadB is the consumer. The consumer has to
check every now and then if it has the data to act upon or not. This is a huge wastage of
CPU time as the consumer occupies CPU time to check whether or not the producer is
ready with the data.
What is the producer could communicate to the consumer once it has finished
producing the required data? The consumer would then not use up CPU cycles just to
check whether the producer has done its job. This communication between threads is
called inter-thread communication. Inter-thread communication is achieved using four
methods, wait(), notify(), notifyAll(), and yield(). All these methods are declared final in
the Object class. They can only be called from synchronized methods.
The wait() method
The wait() method tells the current thread to give up the monitor and sleep until
another thread calls to notify() method. Wait() method can also be used to synchronize
threads.
Syntax
public final void wait() throws InterruptedException;
The wait() method makes the current thread wait until another thread invokes the
notify() or notifyAll() method of the current object. It is necessary for the current thread to
own the monitor of the object.
The notify() method
The notify() method wakes up a single thread that is waiting for the current
monitor of the object. If multiple threads are waiting, one of them is chosen arbitrarily.

62

The awakened thread is not able to proceed until the current thread releases the lock from
the monitor. A thread that is the owner of the monitor of the object should call this
method.
A thread becomes the owner of the monitor of an object in one of the three ways
By executing a synchronized instance method of that object
By executing the body of a synchronized statement that synchronizes the object
By executing a synchronized static method of a class (for objects of type Class)
Only one thread can own the monitor of an object at any time.
Syntax
public final void notify();
The method notifyAll() is used to wake up all the threads that are waiting for the monitor
of the object. To call notify() or notifyAll() method, the thread must own the monitor of
the object.
The yield() Method
The yield() method causes the runtime system to put the current thread to sleep and
execute the next thread in the queue. The yield method can be used to ensure that the low
priority threads also get processor time
Syntax
public void static yield();
Example:
Consider an employment agency. As new job openings arise, they are made
available to the candidates. This has to be done carefully since the candidates cannot take
up more jobs than those that are available. The agency hence puts up one notice at a time
and wait for a candidate to take up the job. Hence, until the first job offer is filled, the
second is not put up. At the same time, only one candidate can be selected for a particular
job.
The problem is solved below using the wait() and notify() methods.

class JobOpening
{
int count;
boolean valueSet = false;
synchronized int get()

63
{

if (!valueSet)
{
try
{
wait();
}
catch(InterruptedException e) {}
}
System.out.println("Got: " +count); // Job Secured
valueSet = false;
// No more jobs available
notify();
return count;

synchronized void put (int counter)


{
if (valueSet)
{
try
{
wait();
}
catch(InterruptedException e) {}
}
this.count = counter;
valueSet = true;
System.out.println("Put: " +count); //
notify();
//notify the job opening
}

class MyThreadA implements Runnable


{
JobOpening job;
public MyThreadA(JobOpening job)
{
this.job = job;
// Create a thread that produces job openings
new Thread (this, "JobProducer").start();
}

opening
}

public void run()


{
int i = 0;
while(true)
{
job.put(++i);
}

// add another job

64
class MyThreadB implements Runnable
{
JobOpening job;
public MyThreadB(JobOpening job)
{
this.job = job;
// Create a thread that consumes job openings
new Thread (this, "JobConsumer").start();
}
public void run()
{
int i = 0;
while(true)
{
job.get();
}
}

// go for the job

public static void main (String args[])


{
JobOpening job = new JobOpening();
new MyThreadA(job);
new MyThreadB(job);
}

/*Output would be
Put: 1
Got: 1
Put: 2
Got: 2
Put: 3
Got: 3
Put: 4
Got: 4
Put: 5
Got: 5
Put: 6
Got: 6
Put: 7
Got: 7
Put: 8
Got: 8
Put: 9
Got: 9
Put: 10
Got: 10
... It goes on infinitely
*/

65

THREAD PRIORITIES
The Java Run Time Environment executes threads based on their priority. A CPU
can execute only one thread at a time. Therefore the threads that are ready for execution
queue up for processor time. Each thread is given a slice of time after which it goes back
into the thread queue.
Execution of multiple threads on a single CPU, in some order, is called
scheduling. The Java runtime supports a very simple, deterministic scheduling algorithm
known as fixed priority scheduling. This algorithm schedules threads based on their
priority relative to other runnable threads.
When a Java thread is created, it inherits its priority from the thread that created
it. You can also modify a thread's priority at any time after its creation using the
setPriority method. The default property for uer is NORMAL_PROPETIES or 5.
Thread priorities are integers ranging between MIN_PRIORITY or 0 and MAX_PRIORITY
or 10(constants defined in the Thread class). The higher the integer, the higher the
priority. At any given time, when multiple threads are ready to be executed, the runtime
system chooses the runnable thread with the highest priority for execution. Only when
that thread stops, yields, or becomes not runnable for some reason will a lower priority
thread start executing. If two threads of the same priority are waiting for the CPU, the
scheduler chooses one of them to run in a round-robin fashion. The chosen thread will run
until one of the following conditions is true:

A higher priority thread becomes runnable.


It yields, or its run method exits.
On systems that support time-slicing, its time allotment has expired.

Thread Priority Table


Thread.MIN_PRIORITY
Thread.NORMAL_PRIORITY
Thread.MAX_PRIORITY

1
5
10

Then the second thread is given a chance to run, and so on, until the interpreter
exits. The Java runtime system's thread scheduling algorithm is also preemptive. If at any
time a thread with a higher priority than all other runnable threads becomes runnable, the
runtime system chooses the new higher priority thread for execution. The new higher
priority thread is said to preempt the other threads.
Note: At any given time, the highest priority thread is running. However, this is not
guaranteed. The thread scheduler may choose to run a lower priority thread to avoid
starvation. For this reason, use priority only to affect scheduling policy for efficiency
purposes. Do not rely on thread priority for algorithm correctness.

66

Syntax:
Public final void setPriority(int newPriority)
Example:
The 400,000 Micron Thread Race Applet
This given program implements an applet that animates a race between two
"runner" threads with different priorities. When you click the mouse down over the
applet, it starts the two runners. The top runner, labelled "2", has a priority of 2. The
second runner, labelled "3", has a priority of 3.
import
import
import
import
import

java.applet.*;
java.util.*;
java.awt.*;
java.text.*;
java.awt.event.*;

public class RaceApplet extends Applet implements Runnable


{
private final static int NUMRUNNERS = 2;
private final static int SPACING = 20;
private Runner[] runners = new Runner[NUMRUNNERS];
private Thread updateThread = null;
public void init()
{
String raceType = "unfair";
for (int i = 0; i < NUMRUNNERS; i++)
{
runners[i] = new Runner();
if (raceType.compareTo("unfair") == 0)
runners[i].setPriority(i+2);
else
}

Race");

if (updateThread == null)
{
updateThread = new Thread(this, "Thread

}
}

runners[i].setPriority(2);

updateThread.setPriority(NUMRUNNERS+2);
addMouseListener(new MyAdapter());

67

class MyAdapter extends MouseAdapter


{
public void mouseClicked(MouseEvent evt)
{
if (!updateThread.isAlive())
updateThread.start();
for (int i = 0; i < NUMRUNNERS; i++)
{
if (!runners[i].isAlive())
runners[i].start();
}
}
}
public void paint(Graphics g)
{
g.setColor(Color.lightGray);
g.fillRect(0, 0, getSize().width, getSize().height);
g.setColor(Color.black);
for (int i = 0; i < NUMRUNNERS; i++)
{
int pri = runners[i].getPriority();
g.drawString(new Integer(pri).toString(), 0,
(i+1)*SPACING);
}
update(g);
}
public void update(Graphics g)
{
for (int i = 0; i < NUMRUNNERS; i++)
{
g.drawLine(SPACING, (i+1)*SPACING,
SPACING + (runners[i].tick)/1000, (i+1)*SPACING);
}
}

public void run()


{
Thread myThread = Thread.currentThread();
while (updateThread == myThread)
{
repaint();
try
{
Thread.sleep(10);
}
catch (InterruptedException e) { }
}
}
public void stop()
{

68
for (int i = 0; i < NUMRUNNERS; i++)
{
if (runners[i].isAlive())
runners[i] = null;
}
if (updateThread.isAlive())
updateThread = null;
}

//Code for Runner Class (Sould be in a separate file)


public class Runner extends Thread
{
public int tick = 1;
public void run()
{
while (tick < 400000)
tick++;
}
}

The output would be (for a unfair race)

69

LET US SUM UP
Java was designed to meet the real-world requirements of creating interactive, networked
programs. To achieve this, Java supports multithreaded programming, which allows the
user to write programs that performs many functions simultaneously. The Java run-time
system enables the user to construct smoothly running interactive systems. Javas easyto-use approach to multithreading allows the user to think about the specific behaviour of
his/her own program, not the multitasking subsystem.
Every time you start a program, thread is automatically started. This is the main thread,
which starts as soon the execution of the program starts,
from which are other threads can be spawned and
which stops when the program is terminated.
Threads can be created in two ways. They are:
By extending the Thread class
By implementing the Runnable interface

LESSON END ACTIVITIES


Write three separate files by extending thread class and call them in another separate class.
Write a program to print simultaneously the table of three and five.
Write a class called A which has a static int x . now write two threads ThreadA and ThreadB

which tries to access the variable A.x. The ThreadA should print 3x and ThreadB should print 4x.

Redo problem three with variable x under a synchronized code


Write a console clock program using threads

POINTS FOR DISCUSSION


Difference between Multi threading and Time sharing are given below, Illustrate
these differences with some practical examples
Multi Threading

Time Sharing

1. Threads are a popular way to improve


application performance through parallelism.

In Traditional Time sharing OS the basic unit of CPU


utilization is a process.

2. Here the basic unit of CPU utilization is


thread which consist of single address space
and one or more threads of control.

Each process has its own program counter, its own


register status, its own stack, and its own address
space.

3. Each thread of a process has its own


program counter, its own register status, and
its own stack, but all these share a same
address space and same global variables.

In time sharing each and every process use same


program counter, register and stack but they have their
own address space and use local variables.

4. Due to sharing of a same address space

Since time sharing uses there own address space, it is

70
protection is a problem.

been protected.

5. Protection between multiple threads of a


process is not necessary because process is
always owned by a single user.

Protection between processes is needed because


different processes may belong to different users.

6. The overheads involved in creating a new


process is less.

The overheads involved in creating a process are


more.

7. Resource sharing can be achieved more


efficiently and naturally.

Resource sharing can


programming effort.

8. This is referred to as light weight processes.

This is referred as heavy weight processes.

be

done

with

some

MODEL ANSWERS TO CHECK YOUR PROGRESS


Solution 1
A thread is a line of execution. It is the smallest unit of code that is dispatched by the scheduler.

States of a Thread:
There are four states associated with a thread namely

new
runnable
dead

and

blocked

New:
When a thread is created, it is new state. New implies that the thread object has
been created but it has not started running. It requires the start() method to start it.
Runnable:
A thread is said to be in runnable state, when it is executing a set of instructions. The run() method
contains the set of instructions. This method is called automatically after start() method.

Dead:

71
The normal way for a thread to die is by returning its run() method. We can also call stop(), but
this throws an exception thats a subclass of Error (which means we normally do not catch it). Remember
that throwing an exception should be a special event and not part of normal program execution; thus the use
of stop() is discouraged. There is also a destroy() method (which is never been implemented) that should
never be called if we can avoid it, since it is drastic and does not release object locks.

Blocked:
The thread could be run but there is something that prevents it. While thread is in the blocked state
the scheduler will simply skip over it and not give it any CPU time. Until a thread re-enters the runnable
state it will not perform any operations.

Common Thread Methods:


start():

The start method starts execution of the invoking object. It canthrow an


IllegalThreadStateException if the thread was already started.
stop():

This method terminates the invoking object.


suspend():

This method suspends the invoking object. The thread will become runnable again
if it gets the resume() method.
sleep():
This sleep method suspends execution thread for the specified number of milliseconds. It can
throw an InterruptedException.

Syntax:
public static void sleep(long ms)
The following statement can suspend execution of the executing thread for the specified number of
milliseconds plus nanoseconds.

public static void sleep(long ms, int ns)


resume():
The resume() method restarts the suspended thread at the point at which it was halted. The
resume() method is called by some thread outside the suspended one, there is a separate class called
Resumer which does just that. Each of the classes demonstrating suspend/resume has an associated
resumer.

3.8. REFERENCES
th

Herbert Schidt, The Complete Reference Java 2, 5 Ed., TMH, 2002


Jane Jawroski, Java Unleashed, SAMS Techmedia Publications, 1999

72

LESSON 5: DATA STRUCTURES IN JAVA


Contents
Aims and Objectives
Introduction
Collection Interfaces
List Interfaces
Set Interface
Interator
Vector
Ordered Structures
Linked List
Sorting
Selection Sort
Heap Sort
Trees
Complete Binary Tree
Binary Search Tree
Let us Sum UP
Lesson-End Activities
Points for Discussion
References

AIMS AND OBJECTIVES


At the end of this Lesson, you will be able to:
Understand the Implementation of Data Structure in Java
Understand Collection Interfaces
Use Interator and Vector

INTRODUCTION
A collection is an object that contains a group of objects within it. These objects
are called the elements of the collection. The elements of a collection usually descend
from a common parent type. Java supports collection classes like Vector, Bits, Stack,
Hashtable and Linkedlist. Collections hold references to objects of type Object. These
new enhancements to the Java language are part of the java.util package.
In addition to the collections, the collection framework also defines several map
interfaces and classes. Maps store key/value pairs. Although maps are not collections in
the true sense of the word, they are fully integrated with collections.

COLLECTION INTERFACES
The collection API typically consists of interfaces that are used to maintain
objects. These provide different implementations of the standard interfaces. These are the
Collection, List and Set interfaces.
The objects in a Collection interface are not ordered. It enables one to work with
a group of objects, and is at the top of the collections hierarchy.
The core collection interfaces encapsulate different types of collections, which are shown
in the figure below. These interfaces allow collections to be manipulated independently
of the details of their representation. Core collection interfaces are the foundation of the
Java Collections Framework. As you can see in the following figure, the core collection
interfaces form a hierarchy.

The core collection interfaces.


A Set is a special kind of Collection, a SortedSet is a special kind of Set, and
so forth. Note also that the hierarchy consists of two distinct trees a Map is not a true
Collection.
A List interface is a group of objects where duplication is permitted. It extends collection
to handle sequences (list of objects).
A Set interface extends collection to handle sets, i.e a group of objects with no
duplication.
A Sorted set interface extends Set to handle sorted sets.
The Collection interface
The Collection interface is the foundation upon which the collection framework is built.
It declares the core methods that all collections must have. These methods are given
below:

Method
boolean add(Object obj)

boolean addAll(Collection c)
void clear()
boolean contains(Object obj)
boolean containsAll(Collection c)
boolean equals(Object obj)
int hashCode()
boolean isEmpty()
Iterator iterator()
boolean remove(object Obj)
boolean removeAll(Collection c)

boolean retainAll(Collection c)

int size()
Object[] to Array()
Object[] to Array(Object array[])

Description
Adds obj to the invoking collection. Returns true
if obj was added to the collection. Returns false if
obj is already a member, and no duplication is
allowed.
Adds all the elements of c to the invoking
collection. Returns true if the operation succeeded
(i.e the elements were added). Else returns false.
Removes all elements from the invoking collection
Returns true if obj is an element of the invoking
collection. Else returns false
Returns true if the invoking collection contains all
elements of c. Otherwise it returns false.
Returns true if the invoking collection and object
obj are equal. Otherwise returns false.
Returns the hash code for the invoking collection
Returns true if the invoking collection is empty.
Otherwise returns false
Returns an iterator for the invoking collection
Removes one instance of obj from the invoking
collection. Returns true if the element was
removed. Otherwise returns false
Removes all elements of c from the invoking
collection. Returns true if the collection changed,
(i.e elements were removed). Otherwise returns
false
Removes all elements from the invoking collection
except those in c. Returns true if the collection
changed, (i.e elements were removed). Otherwise
returns false
Returns the number of elements contained in the
invoking collection.
Returns an array that contains all the elements
stored in the invoking collection. The array
elements are copies of the collection elements
Returns an array containing only those collection
elements whose type matches that of array. The
array elements are copies of the collection
elements.

LIST INTERFACE
The List interface extends the Collection interface and declares the behavior of a
collection that stores a sequence of elements. Elements can be inserted or accessed by
their position in the list, using a zero-based index. A list may contain duplicate elements.

In addition to the methods defined by Collection, List defines its own methods. They are
given below:
Method
void add(int index, Object obj)

boolean addAll(int index, Collection c)

Object get(int index)


int indexOf(Object obj)
int lastIndexOf(Object obj)
ListIterator Listiterator()
ListIterator Listiterator(int index)
Object remove(int index)

Object set(int index, Object obj)


List subList(int start, int end)

Description
Inserts obj into the invoking list at the index
passed in index. Any pre-existing elements at
or beyond the point of insertion are shifted up.
No elements are overwritten
Inserts all elements of c into the invoking list at
the index passed in index. Any pre-existing
elements at or beyond the point of insertion are
shifted up. No elements are overwritten.
Returns true if the invoking list changes.
Otherwise returns false.
Returns the object stored at the specified index
within the invoking collection
Returns the index of the first instance of obj in
the invoking list. If obj is not an element in the
list, -1 is returned.
Returns the index of the last instance of obj in
the invoking list. If obj is not an element in the
list, -1 is returned.
Returns an iterator to the start of the invoking
list.
Returns an iterator to the invoking list that
begins at the specified index.
Removes the element at position index from
the invoking list and returns the deleted
element. The resulting list is compacted. That
is, the indexes of the subsequent elements are
decremented by one
Assigns obj to the location specified by index
within the invoking list.
Returns a list that includes elements from start
to end 1 in the invoking list. Elements in the
returned list are also referenced by the
invoking object.

SET INTERFACE
The Set interface defines a set. It extends Collection and declares the behavior of
a collection that does not allow duplicate elements. It does not define any additional
methods of its own. The add() method returns false if an attempt is made to add duplicate
elements to the set.

The SortedSet Interface


The SortedSet interface extends Set and declares the behavior of a set sorted in
ascending order. In addition to those methods defined in Set, the SortedSet defines
declares the methods given below:
Method
Comparator comparator()
Object first()
Object last()
SortedSet headset(Object end)

SortedSet subSet(Object start, Object end)

SortedSet tailSet(Object start)

Description
Returns the invoking sorted sets
comparator. If natural ordering is used, it
returns null.
Returns the first element in the invoking
sorted set.
Returns the last element in the invoking
sorted set.
Returns a SortedSet containing those
elements less than end that are contained in
the invoking sorted set. Elements in the
returned sorted set are also referenced by
the invoking sorted set.
Returns a SortedSet that includes those
elements between start and end -1.
Elements in the returned set are also
referenced by the invoking object.
Returns a SortedSet that contains those
elements greater than or equal to start that
are contained in the sorted set. Elements in
the returned set are also referenced by the
invoking object.

The Collection Classes


There are a number of standard classes that are used to implement the interfaces
described above. Some of the classes provide full implementations that can be used as
they are. Others are abstract, providing skeletal implementations that are used as starting
points for creating concrete collections.
The standard collection classes are summarized below:
Class
AbstractCollection
AbstractList
LinkedList

Description
Implements most of the Collection
interface
Extends AbstractCollection and
implements most of the List interface
Implements a linked list by extending
AbstractSequentialList

ArrayList

Implements a dynamic array by extending


AbstractList
Extends AbstractCollection and
implements most of the Set interface.
Extends AbstractSet for use with a hash
table
Implements a set stored in a tree. Extends
AbstractSet.

AbstractSet
HashSet
TreeSet

The ArrayList Class


The ArrayList class extends AbstractList and implements the List interface.
ArrayList supports dynamic arrays that can grow as needed. In essence ArrayList is a
variable length array of object references. Dynamic arrays are also supported by the
legacy class Vector, which has been re-engineered to support collections.
ArrayList has the constructors shown here:
ArrayList()
This builds an empty array list.
ArrayList(Collection c)
This builds an array list that is initialized with the elements of the collection c.
ArrayList(int capacity)
This builds an array list that has the specified initial capacity capacity.
The following program shows a simple use of ArrayList.
//Demonstrate ArrayList
import java.util.*;
class ArrayListDemonstration
{
public static void main(String args[])
{
// Create an array list
ArrayList arr = new ArrayList();
System.out.println(initial size of arr: + arr.size());
// Add elements to the array list
arr.add(A);
arr.add(B);
arr.add(C);
arr.add(D);
arr.add(E);
arr.add(F);
arr.add(1 , ZZ);

System.out.println(Size of arr after insertions: +


arr.size());
//Display the array list
System.out.println(Contents of arr: + arr);
//Remove elements from the array list
arr.remove(F);
arr.remove(2);
System.out.println(Size of arr after deletions: +

arr.size());

System.out.println(Contents of arr: + arr);

The output from this program is given below:


Initial size of arr: 0
Size of arr after insertions: 7
Contents of arr: [A, ZZ, B, C, D, E, F]
Size of arr after deletions: 5
Contents of arr: [A, ZZ, C, D, E]
Converting ArrayList into an Array
Sometimes there is a need to obtain an actual array that contains the contents of the array
list. The following program illustrates how to do so:
//Convert array list to an array
import java.util.*;
class ArrayListtoArray
{
public static void main(String args[])
{
// Create an array list
ArrayList arr = new ArrayList();
System.out.println(initial size of arr: + arr.size());
// Add elements to the array list
arr.add(new Integer(1));
arr.add(new Integer(2));
arr.add(new Integer(3));
arr.add(new Integer(4));
arr.add(new Integer(5));
//Display the array list
System.out.println(Contents of arr: + arr);

//get the array


Object iarr[] = arr.toArray();
//Find the sum of array elements
int sum=0;
for ( int j = 0; j < iarr.length; j++ )
sum+=((Integer) iarr[j]).intValue();
System.out.println(Sum of elements is: + sum);
}
}

Output from the program is:


Contents of arr: [1, 2, 3, 4, 5]
Sum of elements is: 15
The LinkedList Class
The LinkedList class extends AbstractSequentialList and implements the List
interface. It provides a linked-list data structure. It has the two constructors below:
LinkedList()
This builds an empty linked list.
LinkedList(Collection c)
This builds linked list that is initialized with the elements of the collection c.
In addition to the methods that it inherits, the LinkedList class defines some useful
methods of its own. They are:
addFirst()
This method helps us to add elements to the start of the list.
Syntax:
void addFirst(Object obj)
addLast()
This method helps us to add elements to the end of the list.
Syntax:
void addLast(Object obj)
getFirst()
This method helps us obtain the first element of the list.

80

Syntax:
Object getFirst()
getLast()
This method helps us to retrieve the last element of the list.
Syntax:
Object getLast()
removeFirst()
This method helps us remove the first element of the list.
Syntax:
Object removeFirst()
removeLast()
This method helps us to remove the last element of the list.
Syntax:
Object removeLast()
Example:
// Demonstrate LinkedList
import java.util.* ;
class LinkedListDemo
{
public static void main (String args[])
{
//Create a linked list
LinkedList llist = new LinkedList();
//Add elements
llist.add(A);
llist.add(B);
llist.add(C);
llist.add(D);
llist.add(E);
llist.addFirst(F);
llist.addLast(Z);
llist.add(1,ZZ);
System.out.println(Initial contents of llist : + llist);
//remove elements from linked list
llist.remove(F);
llist.remove(2);

81

llist);

System.out.println(Contents of llist after deletion : +


//remove first and last elements
llist.removeFirst();
llist.removeLast();

System.out.println(Contents after removing first and last


: + llist);
//get and set a value
Object val = llist.get(2);
llist.set(2, (string) val + Changed);
System.out.println(llist after change : + llist);
}
}

The output is as follows:


Initial contents of llist : [F, ZZ, A, B, C, D, E, Z]
Contents of llist after deletion : [ZZ, B, C, D, E, Z]
Contents of llist after deleting first and last : [B, C, D, E]
llist after change : [B, C, D Changed, E]
The HashSet Class
HashSet extends AbstractSet and implements the Set interface. It creates a
collection that uses a Hashtable for storage. A Hashtable stores information by using a
mechanism called hashing. In hashing the informational content of a key is used to
determine a unique value called its hash code. The hash code is then used as the index at
which the data associated with the key is stored. The transformation of the key into his
hash code is performed automatically you never see the hash code itself.
The following constructors are defined:
HashSet()
This constructs a default hash set.
HashSet( Collection c)
This initializes the hash set using the elements of c
HashSet( int capacity)
This initializes the capacity of the hash set to capacity
HashSet(int capacity, float fillRatio)
This initializes both the capacity and the fill ratio (load capacity) of the hash set from its arguments.
The fill ratio must be between 0.0 and 1.0

82

Example
//Demonstrate HashSet
import

java.util.*

class HashSetDemonstration
{
public static void main (String args[])
{
//Create a HashSet
HashSet hset = new HashSet();
//Add elements to the hash set
hset.add(B);
hset.add(A);
hset.add(D);
hset.add(E);
hset.add(C);
hset.add(F);

System.out.println(The HashSet is: + hset);

Output:
The HashSet is: [F, E, D, C, B, A]
The TreeSet Class
TreeSet provides an implementation of the Set interface that uses a tree for
storage. Objects are stored in sorted, ascending order. Aceess and retrieval times are quite
fast, which makes TreeSet an excellent choice when storing large amounts of sorted
information that must be found quickly.
The constructors are:
TreeSet()
This constructs an empty tree set that will be sotred in ascending order according
to the natural order of its elements.
TreeSet(Collection c)
This builds a tree set that contains the elements of c.
TreeSet(Comparator comp)
This constructs an empty tree set that will be sorted according to the comparator
specified by comp.
TreeSet(SortedSet ss)

83

This builds a tree that contains the elements of ss


Example
//Demonstrate TreeSet.
import java.util.* ;
class TreeSetDemonstration
{
public static void main (String args[])
{
//Create a tree set
TreeSet tset = new TreeSet();
//Add elements to the tree set
tset.add(E);
tset.add(A);
tset.add(B);
tset.add(D);
tset.add(A);
tset.add(C);
tset.add(F);
}

System.out.println(The TreeSet is: + tset);

Output:
The TreeSet is: [A, B, C, D, E, F]

ITERATOR
An Iterator provides the easiest way to cycle through the elements of the collection. It enables
cycling through a collection, obtaining or removing elements. ListIterator extends Iterator to allow bidirectional traversal of a list.
Using an Iterator
Each of the collection classes provides an iterator() method that returns an iterator to the start of
the collection. The following steps are followed:
1.
2.

Obtain an iterator to the start of the collection by calling the collections iterator() method.
Set up a loop that makes a call to hasNext(), Have the loop iterate as long as hasNext()
returns True.

84
3.

Within the loop obtain each element by calling next().

Example
//Demonstrate iterators
import java.util.*;
public class iteratorDemonstration
{
public static void main(String args[])
{
// Create an array list
ArrayList arr = new ArrayList();
// Add elements to the array list
arr.add("A");
arr.add("B");
arr.add("C");
arr.add("D");
arr.add("E");
arr.add("F");
//Display the array list using iterator
System.out.print("Original Contents of arr:");
Iterator itr = arr.iterator();
while (itr.hasNext())
{
Object element = itr.next();
System.out.print(element + " ");
}
System.out.println();
//Modify objects iterated
ListIterator litr = arr.listIterator();
while (litr.hasNext())
{
Object element = litr.next();
litr.set(element + " +");
}
System.out.print("Modified Contents of arr:");
itr = arr.iterator();
while (itr.hasNext())
{
Object element = itr.next();
System.out.print(element + " ");
}
System.out.println();
//Now display the list backwards
System.out.print("Modified list backwards: ");
while (litr.hasPrevious())
{
Object element = litr.previous();
System.out.print(element + " ");
}

85
System.out.println();
}

Output from the program is:


Original Contents of arr:A B C D E F
Modified Contents of arr:A + B + C + D + E + F +
Modified list backwards: F + E + D + C + B + A +
Map Classes And Interfaces
A map is an object that stores associations between keys and values, or key/value pairs. Given a
key, you can find its value. Both keys and values are objects. The keys must be unique, but values may be
duplicated. Some maps even accept null key and null values.

Map Interfaces
Interface
Map
Map.Entry

Description
Maps unique keys to values
Describes an element (a key/value pair) in a map. This is an inner class
of Map
Extends Map so that the keys are maintained in an ascending order.

SortedMap

The Map Interface


The Map interface maps unique keys to values. A key is an object that can be
used to retrieve a value at a later date. Given a key and a value, the value can be stored in
a Map object After storing the value, it can be retrieved using its key. The methods used
by Map are:
Method
void clear()
Boolean containsKey(Object k)
Boolean containsValue(Object v)
Set entrySet()
Boolean equals(Object obj)
Object get(Object k)
int hashCode()
Boolean isEmpty()

Description
Removes all key/value pairs from the invoking map
Returns true if the invoking map contains k as a key.
Otherwise returns false.
Returns true if the map contains v as a value.
Otherwise returns false.
Returns a Set that contains the entries in the map.
The set contains objects of type Map.Entry. This
method provides a set-view of the invoking map
Returns true if obj is a Map and contains the same
entries. Otherwise returns false.
Returns the value associated with the key k
Returns the hash code for the invoking map
Returns true if the invoking map is empty.
Otherwise returns false.

86

Set keySet

Returns a Set that contains the keys in the invoking


map.
Puts an entry in the invoking map, overwriting any
previous value associated with the key. The key and
value are k and v, respectively. Returns null if the
key didnt exist already. Otherwise the previous
value linked to the key is returned.
Puts all entries from m into this map
Removes the entry whose key equals k
Returns the number of key/value pairs in the map
Returns a collection containing the values in the
map. This method provides a collection-view of
values in the map.

Object put(Object k, Object v)

void putAll(Map m)
Object remove (Object k)
int size()
Collection values()

The MapEntry Interface


This helps in working with a map entry. Recall from above that the entrySet()
method declared by the Map interface returns a Set containing the map entries. Each of
these entries is a Map.Entry object. The methods for the Map.Entry interface is given
below:
Method
Boolean equals(Object obj)
Object getKey()
Object getValue
Int hashCode
Object setValue(Object v)

Description
Returns true if obj is a Map.Entry whose key and value
are equal to that of the invoking object.
Returns the key for this map entry
Returns the hash code for this map entry
Returns the hash code for this map entry
Sets the value for this map entry to v

The SortedMap Interface


The SortedMap interface extends Map. It ensures that the entries are maintained
in the ascending order. The methods are given below:
Method
Comparator comparator()

Object firstKey()
SortedMap headMap(Object end)
Object lastKey()
SortedMap subMap(Object start, Object end)

Description
Returns the invoking sorted maps
comparator. If the natural ordering is
used for the invoking map, null is
returned.
Returns the first key in the invoking map
Returns a sorted map for those map
entries whose keys are less than end
Returns the last key in the invoking map.
Returns a map containing those entries
with keys that are greater than or equal to

87

SortedMap subMap(Object start)

start and less than end


Returns a map containing those entries
with keys that are greater than or equal to
start.

The Map Classes


Several classes provide implementations of the map interfaces. The classes that are used
for maps are given below:
Class
AbstractMap
HashMap
TreeMap
WeakHashMap

Description
Implements most of the Map interface
Extends AbstractMap to use a hash table
Extends AbstractMap to use a tree
Extends AbstractMap to use a hash table with weak keys

AbstractMap is a superclass for the three concrete map implementations.


WeakHashMap implements a map that uses weak keys, which allows an element in a
map to be garbage-collected when its key is unused.
The HashMap Class
The HashMap class uses a hash table to implement the Map interface. The constructors
are:
HashMap()
This constructs a default hash map
HashMap(Map m)
This initializes the hash map by using the elements of m
HashMap(int capacity)
This initializes the capacity of the hash map to capacity
HashMap(int capacity, float fillRatio)
This initializes both the capacity and the fill ratio (load capacity) of the hash map from its arguments.
The fill ratio must be between 0.0 and 1.0
The HashMap implements Map and extends AbstractMap. It does not add any methods of its own.
Example
//Demonstrate Hash Map Class
import java.util.* ;
class HashMapDemonstration
{
public static void main (String args[])
{
//Create a Hash Map

88
HashMap hmap = new HashMap();
// Add elements to the map
hmap.put(Ram Gopal, new Double(1234.56));
hmap.put(Mohan Shankar, new Double(6543.21));
hmap.put(Abdul Gafoor, new Double(4321.65));
hmap.put(Thomas Mathew, new Double(3421.56));
hmap.put(Ayesha Kannan, new Double(5612.34));
hmap.put(Suhasini Akbar, new Double(2345.61));
//Get a set of the entries
Set set = hmap.entrySet();
//Get an iterator
Iterator i = set.iterator();
//Display elements
while (i.hasNext())
{
Map.Entry men = (Map.Entry)i.next();
System.out.print(men.getKey() + : );
System.out.println(men.getValue());
}
System.out.println();
//Put 1000 into Ram Gopals account
double bal =
((Double)hmap.get(Ram
Gopal)).doubleValue();
hmap.put(Ram Gopal, new Double(bal+1000));
System.out.println(Ram Gopals New balance: +
hmap.get(Ram Gopal));
}
}

Output
Thomas Mathew: 3421.56
Ram Gopal: 1234.56
Ayesha Kannan: 5612.34
Suhasini Akbar: 2345.61
Mohan Shankar: 6543.21
Abdul Gafoor: 4321.65
Ram Gopal's New balance: 2234.56
The TreeMap Class
The TreeMap class implements the Map interface by using a tree. A TreeMap
provides an efficient means of storing key/value pairs in a sorted order, and allows rapid
retrieval. The constructors are as follows:
TreeMap()

89

This constructs an empty tree map that will be sorted according to the natural
order of its keys.
TreeMap(Comparator comp)
This constructs an empty tree-based map that will be sorted according to the
comparator specified by comp.
TreeMap(Map m)
This builds a tree map that contains the entries of m.
TreeMap(SortedMap sm)
This builds a tree map that contains the entries of sm, which will be sorted in the
same order an sm
The TreeMap implements SortedMap and extends AbstractMap. It does not add any methods of its own.
Example

//Demonstrate Tree Map Class


import java.util.* ;
class TreeMapDemonstration
{
public static void main (String args[])
{
//Create a Tree Map
TreeMap tmap = new TreeMap();
// Add elements to the map
tmap.put(Ram Gopal, new Double(1234.56));
tmap.put(Mohan Shankar, new Double(6543.21));
tmap.put(Abdul Gafoor, new Double(4321.65));
tmap.put(Thomas Mathew, new Double(3421.56));
tmap.put(Ayesha Kannan, new Double(5612.34));
tmap.put(Suhasini Akbar, new Double(2345.61));
//Get a set of the entries
Set set = tmap.entrySet();
//Get an iterator
Iterator i = set.iterator();
//Display elements
while (i.hasNext())
{
Map.Entry men = (Map.Entry)i.next();
System.out.print(men.getKey() + : );
System.out.println(men.getValue());
}
System.out.println();
//Put 1000 into Ram Gopals account
double bal =
((Double)tmap.get(Ram
Gopal)).doubleValue();
tmap.put(Ram Gopal, new Double(bal+1000));
System.out.println(Ram Gopals New balance: +

90

tmap.get(Ram Gopal));

Output
Abdul Gafoor : 4321.65
Ayesha Kannan : 5612.34
Mohan Shankar : 6543.21
Ram Gopal : 1234.56
Suhasini Akbar : 2345.61
Thomas Mathew : 3421.56
RamGopals New balance : 2234.56
The above are sorted according to the first names. Using a comparator however one can
change the behavior of sorting.

The Enumeration Interface


The enumeration interface defines the methods by which you can enumerate
(obtain one at a time) the elements in a collection of objects)
It has the following methods
Boolean hasMoreElements ();
Object nextElement ()
The function hasMoreElements () returns true if there are still more elements to extract and
false when all the elements have been enumerated.

The function nextElement () returns the next object in the enumeration as a


generic object reference.

VECTOR
Vector implements a dynamic array. It is similar to an array list but with two
differences. All vectors are synchronized and contain many methods that are not part of
the collection framework.
All vectors start with an initial capacity. After this initial capacity is reached the
next time you attempt to store an object the vector automatically allocates space for
that object.
Vector defines the following protected data members
Int capacityIncrement;

91

Int elementCount;
Object elementData [];
Example of Enumeration using Vector
//enumeration example using vector
import java.io.*;
import java.util.*;
class VectorDemo
{
public static void main(String s[])
{
Vector v = new Vector(3,2); //initial size = 3 increments
by 2
System.out.println("Inital Size
" + v.size());
System.out.println("Inital Capacity " + v.capacity());
v.addElement(new
v.addElement(new
v.addElement(new
v.addElement(new

Integer(1));
Integer(2));
Integer(3));
Integer(4));

System.out.println("Vector Capacity After Addition " +


v.capacity());
v.addElement(new Double(5.45));
System.out.println("Current Capacity"+v.capacity());
v.addElement(new Double(6.08));
v.addElement(new Integer(7));
System.out.println("Currnent Capacity "+v.capacity());
v.addElement(new Float(2.4));
v.addElement(new Integer(8));
System.out.println("Current Capacity"+ v.capacity());
System.out.println("First Element " +
(Integer)v.firstElement());
System.out.println("Last
(Integer)v.lastElement());

Element " +

if(v.contains(new Integer(3)))
System.out.println("Vector Contains 3");
Enumeration venum = (Enumeration) v.elements();
System.out.println("\n Elements In Vector ");

92

while(venum.hasMoreElements())
{
System.out.println(venum.nextElement()+"");
}
System.out.println(" ");

/* The output is:


Inital Size
0
Inital Capacity 3
Vector Capacity After Addition 5
Current Capacity5
Currnent Capacity 7
Current Capacity9
First Element 1
Last Element 8
Vector Contains 3
Elements In Vector
1
2
3
4
5.45
6.08
7
2.4
8
*/

ORDERED STRUCTURES
Many data structures provide sorting and searching routines. The idea of sorting
presupposes that the data items are ordered in some way. Searching does not presuppose
an order, but it is quicker to search for an item if the items have previously been sorted.
Many data types have an intrinsic ordering. This is obvious for the primitive numeric
types. Characters are also ordered by their ASCII or Unicode values. This is the same as
the usual alphabetic ordering for letters of the alphabet. The ordering of characters can be
extended to the usual lexicographic ordering for strings.
When writing a sorting or searching algorithm, the nature of the elements sorted is
usually unimportant. It is only necessary to refer to their ordering relation.

Linked List
Class LinkedList
java.lang.Object
|

93
+--DataStructures.LinkedList
public class LinkedList
extends java.lang.Object

A simple implementation of singly linked lists.


Lists are created empty, for example:
LinkedList list = new LinkedList();

after which items can be inserted at the front of the list by


list.addFirst(item)

where item is any Object.


Items can be removed from the front of the list by
list.removeFirst();

which removes the first item from the list. Lists can be traversed using an iterator, for
example:
for (Iterator i = list.iterator(); i.hasNext();) {
System.out.println(e.next());
{
**
* Class:
* Purpose:
*/

LinkedListDemo
To demonstrate the use of a single linked list

import DataStructures.LinkedList;
import java.util.*;
public class LinkedListDemo {
public static void main(String[] args) {
LinkedList list = new LinkedList();
Random r = new Random();
Iterator i;
for (int count = 0; count < 9; count++)
{ list.addFirst(new
Integer(r.nextInt(100)));
}
System.out.println("list = " + list);
System.out.println("size = " + list.size());
System.out.print("enumeration:");
for (i = list.iterator(); i.hasNext();) {
System.out.print(" " + i.next());
}
System.out.println();
System.out.println("removing first element: " +
list.firstItem());

94
list.removeFirst();
System.out.println("list = " + list);
System.out.println("size = " + list.size());
System.out.print("removing odd numbers:");
i = list.iterator();
while (i.hasNext()) {
int n = ((Integer) i.next()).intValue();
if (n % 2 == 1) {
System.out.print(" " + n);
i.remove();
}
}
System.out.println();
System.out.println("list = " + list);
System.out.println("size = " + list.size());
list.reverse();
System.out.println("reversed list = " + list);
System.out.println("removing all elements");
i = list.iterator();
while (i.hasNext()) {
i.next();
i.remove();
}
System.out.println("list = " + list);
System.out.println("size = " + list.size());
}

SORTING
Sorting data (i.e., placing the data into some particular order, such as ascending or
descending) is one of the most important computing applications. A bank sorts all checks
by account number so that it can prepare individual bank statements at the end of each
month. Telephone companies sort their lists of accounts by last name and, further, by first
name to make it easy to find phone numbers. Virtually every organization must sort
some data, and often, massive amounts of it. Sorting data is an intriguing, computerintensive problem that has attracted intense research efforts.
An important item to understand about sorting is that the end result-the sorted
array-will be the same no matter which algorithm you use to sort the array. The choice of
algorithm affects only the run time and memory use of the program.
Selection Sort
Selection sort is a simple, but inefficient, sorting algorithm. The first iteration of the
algorithm selects the smallest element in the array and swaps it with the first element.
The second iteration selects the second-smallest item (which is the smallest item of the
remaining elements) and swaps it with the second element the algorithm continues until
the last iteration selects the second-largest element and swaps it with the second-to last

95

index, leaving the largest element in the last index. After the ith iteration, the smallest i
items of the array will be sorted into increasing order in the first I elements of the array.
The following declares the StringOrdering class. This demonstrates the selection sort for
given strings.
class StringOrdering
{
static String name[] = {"Ambika", "Ramya",
"Suresh", "Akaash"};
public static void main(String args[])
{
int size = name.length;
String temp = null;
for (int i=0; i<size; i++)
{
for(int j = i+1; j<size; j++)
{
if(name[j].compareTo(name[i]) < 0)
{
temp = name[i];
name[i] = name[j];
name[j] = temp;
}
}
}
for(int i = 0; i<size; i++)
{
System.out.println(name[i]);
}
}
}
Output:

"Kamala",

96

Heap Sort
Array sorting is a fundamental operation in many applications. The requirement is to sort
n elements of an array
a[0], ..., a[n-1]

into increasing order. For this to make sense, the elements must be comparable with
respect to order. So we assume that array elements implement the Comparable interface.
Note that the array itself may be of length greater than n. The specification only requires
that the first n elements should be sorted.
There are a number of efficient algorithms which run in
time on average.
Binary heaps provide such an algorithm, and one which has a number of attractive
features. A simple implementation would be to insert the array elements, one by one, into
a priority queue, implemented by a binary heap, and then to remove them one by one. It
is true they would then come out in reverse order, but it would be simple to revise the
binary heap code to implement an ``inverse priority'' queue in which the smallest element
emerges first.
There are, however, two related ways in which we can improve on this simple algorithm:
1. The simple algorithm requires auxiliary storage for the heap. In fact it is possible
to use the original array itself as the heap. This would provide a genuinely ``inplace'' sorting routine.
2. Insertion of the array elements one by one, and restoring the heap order property
after each insertion, is not the most efficient way of building the heap. That was
necessary for the priority queue implementation, since the next method to be
called might be the remove method, so the heap had to be properly ordered at all
times. In our case we only want to remove elements after all of them have been
inserted. In that case, it turns out there is a more efficient way of building the
heap.
Sorting by removal
Now we have converted the original array to a heap, it is simple to order it by repeatedly
applying the heap removal algorithm.
When implementing priority queues, using binary heaps, the remove method returned
the maximum element. Instead of returning it, we now just move it to the appropriate
place at the end of the array. The reason we can do this, is that the heap is smaller by one
when we remove an element, so another place is always freed up at the end each time.
Consider where we have got to as a result of heapifying the array. This was
which we can picture as

97

Now when we remove the maximum element, which is always the first, the remove
algorithm tells us to put the last element in the first position, and then demote it until we
reestablish heap order. We can do both relocations at once by swapping the first and last
element. This gives

where the thick line indicates that we are now only concerned with the first four
elements. The segment of the array after the thick line is the sorted array that we are
building up.
Now the first four elements are not in heap order. So we need to apply the demote
method, with size reduced by 1, beginning with the root node as parent. This is easily
seen to produce the array

Repeating the same procedure, of swapping the first and last elements of the heap
(ignoring the 42 which is no longer part of the heap), we obtain

which again needs to be restored to heap order. Repeating this routine until the heap is
empty, will provide us with a sorted array. The code for this part of the routine is simple:
for (int i = n - 1; i > 0; i--) {
swap(a, i, 0);
demote(a, i, 0);
}

This assumes that the array is originally in heap order. The index i begins with the last
element of the array which is at n-1. This is swapped with the first element, which is at
0, and then demote is called with i as the current size of the array, and with the root 0 as
parent. The swap routine simply exchanges the contents of a[i] and a[0].
The final code for the heapSort routine is shown below:
public class Sort
{ private Sort()
{}

98

public static final void heapSort(Comparable[] a, int n) {


if (n < 2) {
return;
}
for (int i = (n / 2) - 1; i >= 0; i--) {
demote(a, n, i);
}
for (int i = n - 1; i > 0; i--) {
swap(a, i, 0);
demote(a, i, 0);
}
}
private static void swap(Object[] a, int i, int j) {
Object tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
{

private static void demote(Comparable[] heap, int size, int parent)

Comparable item = heap[parent];


int child;
while ((child = (2 * parent) + 1) < size) {
if (child + 1 < size && heap[child].compareTo(heap[child +
1]) < 0) {
++child;
}
if (item.compareTo(heap[child]) < 0) {
heap[parent] = heap[child];
parent = child;
} else break;
}
heap[parent] = item;
}
}
Figure : A class providing the heap sort method.

The code has been placed in a Sort class which might include other sorting routines such
as quickSort, mergeSort, shellSort etc. One advantage of heapSort is that it is a genuinely
in-place routine requiring no auxiliary storage. Another is that it is an
not only on average, but also in its worst case performance.
/**
* Class:
* Purpose:
*/

HeapSortDemo
To demonstrate the use of heap sort

import DataStructures.*;
import java.util.*;
public class HeapSortDemo {

process,

static final int max = 24;


public static void main(String[] args) {
Random r = new Random();
Comparable[] array = new Comparable[max];
int n = max / 2;
for (int i = 0; i < n; i++) {
array[i] = new Integer(r.nextInt(1000));
}
System.out.print("random:");
for (int i = 0; i < n; i++) {
System.out.print(" " + array[i]);
}
System.out.println();
long t1 = System.currentTimeMillis();
Sort.heapSort(array, n);
long t2 = System.currentTimeMillis();
System.out.print("sorted:");
for (int i = 0; i < n; i++) {
System.out.print(" " + array[i]);
}
System.out.println();
System.out.println();
System.out.println("That took " + (t2-t1) + " milliseconds");
}

TREES
Linked lists, stacks and queues are linear data structures (i.e., sequences). A tree is
a non linear, two-dimensional data structure with special properties. Tree nodes contain
two or more links. This section discusses binary trees whose nodes each contain two
links (one or both of which may be null). The root node is the first node in a tree. Each
link in the root node refers to a child. The left child is the first node in the left subtree
(also known as the root node of the left subtree), and the right child is the first node in the
right subtree (also know as the root note of the right subtree). The children of a specific
node are called siblings. A node with no children is called a leaf node. Computer
scientists normally draw trees from the root node down-exactly the opposite of the way
most trees grow in nature.
Complete Binary Trees
Trees satisfying property (H) are particularly useful if they are well balanced, in
the sense of having short path lengths from root to leaves. They don't have to be quite as
well balanced as the tree above. All we require is that the path lengths are as short as
possible. For example, we could have

100

or

or even

But we don't want are trees like

in which there are paths from some leaf to the root whose lengths differ by more than 1.
We want trees in which every level is fully occupied except, possibly, for the bottom
level.
It is also very convenient, as you will see, if the bottom level is filled from left to right. (It
could alternatively be filled from right to left, but we need to agree on one or the other.)
Binary trees of this type are called complete. They are defined as being completely filled,
except possibly for the bottom level, which is filled from left to right. A complete binary
tree which also satisfies the ordering property (H) is called a binary heap.
Arrays as complete binary trees
Suppose the array to be sorted is [31, 35, 40, 10, 42]. Let us picture this as

101

where the empty spaces marked indicate that we are not concerned with these extra
entries or, indeed, how many there are of them. Now there is nothing to prevent us from
thinking of this as the array representation of the complete binary tree

Evidently any array can be pictured in this way as a complete binary tree. The problem is
that it is not a heap, as it stands, since it fails to satisfy the heap order property.
Fortunately there is an efficient algorithm for restoring heap order, which we can apply to
the original array. The original array will then play the part of our working binary heap,
without the need for auxiliary storage.
Binary Search Trees
An important linked data structure is the binary tree. This has the following
property
(B) A binary tree is either empty, or else consists of some data item together with
a left and right descendant binary tree.
One of the most useful types of binary tree is a binary search tree, for example

(S)A binary search tree is a binary tree in which the value stored at each node of the tree
is greater than the values stored in its left subtree and less than the values stored in its
right subtree.
Binary search trees can be constructed with other types of data. All that matters is that the
data items can be compared with regard to order.
If we want to find out whether a given object is present in a binary search tree, we can
proceed as follows. Suppose the item is the number 39. Beginning at the root of the tree,
we see that 39 is greater than 21, so that if 39 is present in the tree, it must occur in the
right hand sub-tree because of the (S) property. Since 39 is less than 40, it must occur in
the left-hand sub-tree of the tree rooted at 40. We next compare 39 with 31, move to the
right and finally compare 39 with 35. Since 39 is greater than 35, it must occur in the
right hand sub-tree of the tree rooted at 35, if it occurs at all. But the right-hand sub-tree
at 35 is empty, and nothing occurs in the empty tree. We have therefore established that
39 is not present in the tree.

102

Note that all the comparisons made occurred on a path through the tree, beginning at the
root and ending at one of the leaves. For efficiency, binary search trees are much more
useful if they are balanced. This means that the path lengths from the root node to each of
the leaf nodes are roughly the same. The tree shown above is not as well balanced as it
could be. The same data could just as well be stored in the balanced tree

There are several algorithms for re-balancing binary search trees. These will be discussed
in a later course.
/**
* Class:
* Purpose:
*/

SearchTreeDemo
To demonstrate the use of a binary search tree

import DataStructures.*;
import java.util.*;
public class SearchTreeDemo {
public static void main(String[] args) {
SearchTree t = SearchTree.empty();
Random r = new Random();
System.out.println("tree = " + t);
for (int count = 0; count < 10; count++) {
int item = r.nextInt(100);
System.out.println("adding " + item);
t = t.add(new Integer(item));
System.out.println("tree = " + t);
}

System.out.println("tree in order:");
for (Enumeration e = t.elementsInOrder(); e.hasMoreElements();)
System.out.print(" " + e.nextElement());
}
System.out.println();

System.out.println("tree in level order:");


for (Enumeration e = t.elementsLevelOrder();
e.hasMoreElements();) {
System.out.print(" " + e.nextElement());
}
System.out.println();
while (!t.isEmpty()) {

103

}
}

int item = r.nextInt(100);


if (t.contains(new Integer(item)))
{ System.out.println("removing " +
item); t = t.remove(new Integer(item));
System.out.println("tree = " + t);
}

LET US SUM UP
A Collection represents a group of objects known as its elements. The
Collection interface is used to pass around collections of objects where maximum
generality is desired. For example, by convention all general-purpose collection
implementations have a constructor that takes a Collection argument. This
constructor, known as a conversion constructor, initializes the new collection to contain
all of the elements in the specified collection, whatever the given collection's subinterface
or implementation type. In other words, it allows you to convert the collection's type.

LESSON END ACTIVITIES


1. Write a class that holds a number (long) and its factors. The factors should be stored
in a Vector. A member function should take in the number from the user and find its
factors and put it in a Vector.
2. Redo the above problem but this time with ArrayList. A member function in that
class should check if the number is a perfect number or not (A perfect number is the
one whose sum of all its factors except itself sums upto itself).
3. Write a class that holds two numbers and their factor. This time there should be
function that should check if the numbers are amicable numbers. (Two numbers are
said to be amicable if one numbers factors sum upto the other and vice-versa)
4. In the above problem try to use TreeMap to give a structure to the factors of the two
numbers.

POINTS FOR DISCUSSION


1. This lesson mentions three ways to traverse a List. Describe them,
and note the limitations of each.
2. Consider the four core interfaces, Set, List, Queue, and Map. For each
of the following four assignments, specify which of the four core
interfaces is best suited, and explain how to use it to implement the
assignment.

104

Welldone Project Management Consultants (WPMC) needs to


record the names of all its employees. Every month, an
employee will be chosen at random from these records to receive
a free toy.
WPMC has decided that each new product will be named after an
employee but only first names will be used, and each name will
be used only once. Prepare a list of unique first names.
WPMC decides that it only wants to use the most popular names for
its toys. Count the number of employees who have each first name.
WPMC acquires season tickets for the local lacrosse team, to be
shared by employees. Create a waiting list for this popular sport.
3. The following program is supposed to print the string "Blue". Instead, it
throws an error. Why?
import java.util.*;
public class SortMe {
public static void main(String args[]) {
SortedSet<StringBuffer> s = new
TreeSet<StringBuffer>();
s.add(new StringBuffer("Red"));
s.add(new StringBuffer("White"));
s.add(new StringBuffer("Blue"));
System.out.println(s.first());
}
}

REFERENCES
Jane Jawroski, Java Unleashed, SAMS Techmedia Publications, 1999
Campione, Walrath and Huml, The Java Tutorial, Addison Wesley 1999

105

LESSON 6: ADVANCED NETWORKING IN JAVA


Contents
Aims and Objectives
Introduction
Protocol Overview
TCP
UDP
Understanding Ports
Networking Classes in the JDK
Working with URLs
Parsing a URL
Reading Directly from a URL
Connecting to URL
Writing to a URL Connection
Sockets
Supporting Multiple Clients
Let us Sum UP
Lesson-End Activities
Points for Discussion
Suggested Readings/References/Sources

AIMS AND OBJECTIVES


At the end of this Lesson, you will be able to:
Understand the Implementation of Advanced Networking in Java
Understand Various Protocols
Understand Socket Programming
INTRODUCTION
The Java platform is highly regarded in part because of its suitability for writing
programs that use and interact with the resources on the Internet and the World Wide
Web. In fact, Java-compatible browsers use this ability of the Java platform to the
extreme to transport and run applets over the Internet. Java provides java.net package,
which provides support for networking.
What makes Java a good language for networking are the classes defined in the
java.net package. These networking classes encapsulate the socket paradigm pioneered at
the Berkeley Software Distribution from the university of California at Berkeley.
Loading Applets from the Network

106

The applets that you have run are referenced by a special tag in an HTML file, the
<APPLET> tag. Applets can be located anywhere, whether on your local machine or
somewhere out on the Internet. The location of the applet is completely invisible to you,
the user. However, the location of the applet is encoded within the <APPLET> tag. The
browser decodes this information, locates the applet, and runs it. If the applet is on some
machine other than your own, the browser must download the applet before it can be run.
This is the highest level of access that you have to the Internet from the Java
development environment. It is the browser that does all of the work of connecting to the
network and getting data from it, thereby enabling you to run applets from anywhere in
the world.
Loading images from URLs
One particular class in the java.net package called URL represents a Uniform
Resource Locator and is the address of some resource on the network. Your applets and
applications can use a URL to reference and even connect to resources out on the
network. For example, to load an image from the network, your Java program must first
create a URL that contains the address to the image.
This is the next highest level of interaction you can have with the Internet--your
Java program gets an address of something it wants, creates a URL for it, and then uses
some existing function in the Java development environment that does the grunt work of
connecting to the network and retrieving the resource.

PROTOCOL OVERVIEW
A protocol is a standard by which computers running on the Internet communicate
to each other. The two most popular protocols are the Transport Control Protocol (TCP)
and the User Datagram Protocol (UDP), as this diagram illustrates:

When you write Java programs that communicate over the network, you are
programming at the application layer. Typically, you don't need to concern yourself with
the TCP and UDP layers. Instead, you can use the classes in the java.net package.

107

These classes provide system-independent network communication. However, to decide


which Java classes your programs should use, you do need to understand how TCP and
UDP differ.
TCP
Definition: TCP (Transport Control Protocol) is a connection-based protocol that
provides a reliable flow of data between two computers.
When two applications want to communicate to each other reliably, they establish
a connection and send data back and forth over that connection. This is analogous to
making a telephone call. If you want to speak to Aishwarya Rai in Mumbai, a connection
is established when you dial her phone number and she answers. You send data back and
forth over the connection by speaking to one another over the phone lines. Like the phone
company, TCP guarantees that data sent from one end of the connection actually gets to
the other end and in the same order it was sent. Otherwise, an error is reported.
TCP provides a point-to-point channel for applications that require reliable
communications. The Hypertext Transfer Protocol (HTTP), File Transfer Protocol (FTP),
and Telnet are all examples of applications that require a reliable communication
channel. The order in which the data is sent and received over the network is critical to
the success of these applications. When HTTP is used to read from a URL, the data must
be received in the order in which it was sent. Otherwise, you end up with a jumbled
HTML file, a corrupt zip file, or some other invalid information.
Example Of TCP/IP
import java.net.*;
class InetAddressTest
{
public static void main(String s[])
{
try
{
InetAddress Address = InetAddress.getLocalHost();
System.out.println(Address);
Address = InetAddress.getByName("yahoo.com");
System.out.println(Address);
InetAddress SW[] =
InetAddress.getAllByName("www.indya.com");
for(int i =0;i < SW.length;i++)
{
System.out.println(SW[i]);
}

Net");

}
catch(Exception e)
{
System.out.println("You Are Not Connected To The
}

108

/* Output:
pc1/202.202.202.1
www.yahoo.com/216.115.108.243
www.indya.com/64.41.181.230
*/

UDP
Definition: UDP (User Datagram Protocol) is a protocol that sends independent packets
of data, called datagrams, from one computer to another with no guarantees about arrival.
UDP is not connection-based like TCP.
The UDP protocol provides for communication that is not guaranteed between
two applications on the network. UDP is not connection-based like TCP. Rather, it sends
independent packets of data, called datagrams, from one application to another. Sending
datagrams is much like sending a letter through the postal service: The order of delivery
is not important and is not guaranteed, and each message is independent of any other.
For many applications, the guarantee of reliability is critical to the success of the
transfer of information from one end of the connection to the other. However, other forms
of communication don't require such strict standards. In fact, they may be slowed down
by the extra overhead or the reliable connection may invalidate the service altogether.
Consider, for example, a clock server that sends the current time to its client when
requested to do so. If the client misses a packet, it doesn't really make sense to resend it
because the time will be correct when the client receives it on the second try. If the client
makes two requests and receives packets from the server out of order, it doesn't really
matter because the client can figure out that the packets are out of order and make another
request. The reliability of TCP is unnecessary in this instance because it causes
performance degradation and may hinder the usefulness of the service.
Another example of a service that doesn't need the guarantee of a reliable channel
is the ping command. The purpose of the ping command is to test the communication
between two programs over the network. In fact, ping needs to know about dropped or
out-of-order packets to determine how good or bad the connection is. A reliable channel
would invalidate this service altogether.
The UDP protocol provides for communication that is not guaranteed between
two applications on the network. UDP is not connection-based like TCP. Rather, it sends
independent packets of data from one application to another. Sending datagrams is much
like sending a letter through the mail service: The order of delivery is not important and
is not guaranteed, and each message is independent of any others.

109

Example of an UDP program


import java.net.*;
class MainServer
{
public static
public static
public static
public static
public static

int serverport = 666;


int clientport = 999;
int buffer_size = 1024;
DatagramSocket ds;
byte buffer[] = new byte[buffer_size];

public static void TheServer() throws Exception


{
int pos = 0;
while(true)
{
int c = System.in.read();
switch(c)
{
case -1:
System.out.println("Server Down");
return;
case '\r':
break;
case '\n':
ds.send(new
DatagramPacket(buffer,pos,InetAddress.getLocalHost(),clientport));
pos = 0;
break;
default:
buffer[pos++] = (byte)c;

public static void TheClient() throws Exception


{
while(true)
{
DatagramPacket p = new
DatagramPacket(buffer,buffer.length);
ds.receive(p);
System.out.println(new
String(p.getData(),0,p.getLength()));
}
}
public static void main(String s[]) throws Exception
{
if(s.length == 1)
{
ds = new DatagramSocket(serverport);
System.out.println("Server Started");

110

}
else
{

TheServer();

ds = new DatagramSocket(clientport);
TheClient();

}
}

/*
The above example implements a simple networked communications client and server.
message are typed into the window at the server and written across to the client window
where they are displayed
to use this program first compile it then type
java MainSever
in one window. this is the client
Then open another window and type
java MainServer 1
This is the server.Anything that is typed at the server will be written to the client window
*/
The Output is is similar to this

111

Understanding Ports
Definition: The TCP and UDP protocols use ports to map incoming data to a particular
process running on a computer.
Generally speaking, a computer has a single physical connection to the network.
All data destined for a particular computer arrives through that connection. However, the
data may be intended for different applications running on the computer. So how does the
computer know to which application to forward the data? Through the use of ports.
Data transmitted over the Internet is accompanied by addressing information that
identifies the computer and the port for which it is destined. The computer is identified by
its 32-bit IP address, which IP uses to deliver data to the right computer on the network.
Ports are identified by a 16-bit number, which TCP and UDP use to deliver the data to the
right application.
In connection-based communication such as TCP, a server application binds a
socket to a specific port number. This has the effect of registering the server with the
system to receive all data destined for that port. A client can then rendezvous with the
server at the server's port. This is illustrated in the given diagram:

112

In datagram-based communication such as UDP, the datagram packet contains the


port number of its destination and UDP routes the packet to the appropriate application,
as illistrated below.

Port numbers range from 0 to 65,535 because ports are represented by 16-bit
numbers. The port numbers ranging from 0 - 1023 are restricted; they are reserved for use
by well-known services such as HTTP and FTP and other system services. These ports
are called well-known ports. Your applications should not attempt to bind to them.

NETWORKING CLASSES IN THE JDK


Through the classes in java.net, Java programs can use TCP or UDP to
communicate over the Internet. The URL, URLConnection, Socket, and
ServerSocket classes all use TCP to communicate over the network. The
DatagramPacket, DatagramSocket, and MulticastSocket classes are for
use with UDP.
Working with URLs
URL is the acronym for Uniform Resource Locator. It is a reference (an address)
to a resource on the Internet. You provide URLs to your favorite Web browser so that it
can locate files on the Internet in the same way that you provide addresses on letters so
that the post office can locate your correspondents.
Java programs that interact with the Internet also may use URLs to find the
resources on the Internet they wish to access. Java programs can use a class called URL in
the java.net package to represent a URL address.
The term URL can be ambiguous. It can refer to an Internet address or a URL
object in a Java program. Where the meaning of URL needs to be specific, we use "URL

113

address" to mean an Internet address and "URL object" to refer to an instance of the URL
class in a program.
What Is a URL?
A URL takes the form of a string that describes how to find a resource on the
Internet. URLs have two main components: the protocol needed to access the resource
and the location of the resource.
If you've been surfing the Web, you have undoubtedly heard the term URL and
have used URLs to access HTML pages from the Web.
It's often easiest, although not entirely accurate, to think of a URL as the name of a file
on the World Wide Web because most URLs refer to a file on some machine on the
network. However, remember that URLs also can point to other resources on the
network, such as database queries and command output.
The following is an example of a URL which accesses the msn India homepage
http://www.msn.co.in/
As seen above, a URL has two main components:
Protocol identifier
Resource name
Note that the protocol identifier and the resource name are separated by a colon
and two forward slashes. The protocol identifier indicates the name of the protocol to be
used to fetch the resource. The example uses the Hypertext Transfer Protocol (HTTP),
which is typically used to serve up hypertext documents. HTTP is just one of many
different protocols used to access different types of resources on the net. Other protocols
include File Transfer Protocol (FTP), Gopher, File, and News.
The resource name is the complete address to the resource. The format of the
resource name depends entirely on the protocol used, but for many protocols, including
HTTP, the resource name contains one or more of the components listed in the following
list:
host name
the name of the machine the resource lives on
filename
the pathname to the file on the machine
port number
the port number to connect to (this is typically optional)
reference
a reference to a named anchor within a resource; usually identifies a specific
location within a file (this is typically optional)

114

For many protocols, the host name and the filename are required, while the port
number and reference are optional. For example, the resource name for an HTTP URL
must specify a server on the network (Host Name) and the path to the document on that
machine (Filename); it also can specify a port number and a reference. In the URL for
theMSN Web site www.msn.co.in is the host name and the trailing slash is shorthand for
the file named /default.asp.
Creating a URL
The easiest way to create a URL object is from a String that represents the
human-readable form of the URL address. This is typically the form that another person
will use for a URL. For example, the URL for the yahoo site takes the form:
http://www.yahoo.com/
In your Java program, you can use a String containing this text to create a URL
object: URL yahoo = new URL("http://www.yahoo.com/");
The URL object created above represents an absolute URL. An absolute URL
contains all of the information necessary to reach the resource in question. You can also
create URL objects from a relative URL address.
Parsing a URL
The URL class provides several methods that let you query URL objects. You can get
the protocol, host name, port number, and filename from a URL using these accessor
methods:
getProtocol
Returns the protocol identifier component of the URL.
getHost
Returns the host name component of the URL.
getPort
Returns the port number component of the URL. The getPort method returns
an integer that is the port number. If the port is not set, getPort returns -1.
getFile
Returns the filename component of the URL.
getRef
Returns the reference component of the URL.
Not all URL addresses contain these components. The URL class provides these
methods because HTTP URLs do contain these components and are perhaps the most
commonly used URLs. The URL class is somewhat HTTP-centric.
You can use these getXXX methods to get information about the URL regardless
of the constructor that you used to create the URL object.

115

The URL class, along with these accessor methods, frees you from ever having to
parse URLs again! Given any string specification of a URL, just create a new URL object
and call any of the accessor methods for the information you need. This small example
program creates a URL from a string specification and then uses the URL object's
accessor methods to parse the URL:
import java.net.*;
import java.io.*;
public class ParseURL {
public static void main(String[] args) throws Exception {
URL aURL = new
URL("http://java.sun.com:80/docs/books/tutorial/intro.html#DOWNLOADING"
);
System.out.println("protocol = " + aURL.getProtocol());
System.out.println("host = " + aURL.getHost());
System.out.println("filename = " + aURL.getFile());
System.out.println("port = " + aURL.getPort());
System.out.println("ref = " + aURL.getRef());
}
}

Output for the above program


protocol = http
host = java.sun.com
filename = /docs/books/tutorial/intro.html
port = 80
ref = DOWNLOADING
Reading Directly from a URL
After the successful creation of a URL, you can call the URL's openStream()
method to get a stream from which you can read the contents of the URL. The
openStream() method returns a java.io.InputStream object, so reading from
a URL is as easy as reading from an input stream.
The following small Java program uses openStream() to get an input stream on
the URL http://www.hotmail.com/. It then opens a BufferedReader on the input
stream and reads from the BufferedReader thereby reading from the URL. Everything
read is copied to the standard output stream:
import java.net.*;
import java.io.*;

116
public class URLReader {
public static void main(String[] args) throws Exception {
URL hotmail = new URL("http://www.hotmail.com/");
BufferedReader in = new BufferedReader(
new
InputStreamReader( hotm
ail.openStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);

in.close();

When you run the program, you should see, scrolling by in your command
window, the HTML commands and textual content from the HTML file located at
http://www.hotmail.com/.
Alternatively, the program might hang or you might see an exception stack trace.
If either of the latter two events occurs, you may have to set the proxy host so that the
program can find the Hotmail server.
Connecting to a URL
After you've successfully created a URL object, you can call the URL object's
openConnection method to connect to it. When you connect to a URL, you are
initializing a communication link between your Java program and the URL over the
network. For example, you can open a connection to the Hotmail site with the following
code:
try
{

URL hotmail = new URL("http://www.hotmail.com/");


hotmail.openConnection();
} catch (MalformedURLException e)
{
// new URL() failed
. . .
}
catch (IOException e)
{
// openConnection() failed
. . .
}

If possible, the openConnection method creates a new URLConnection


(if an appropriate one does not already exist), initializes it, connects to the URL, and
returns the URLConnection object. If something goes wrong--for example, the
Hotmail server is down--then the openConnection method throws an IOException.

117

Now that you've successfully connected to your URL, you can use the
URLConnection object to perform actions such as reading from or writing to the
connection. The next section shows you how.
Reading from and Writing to a URLConnection
If you've successfully used openConnection to initiate communications with
a URL, then you have a reference to a URLConnection object. The
URLConnection class contains many methods that let you communicate with the
URL over the network. URLConnection is an HTTP-centric class; that is, many of its
methods are useful only when you are working with HTTP URLs. However, most URL
protocols allow you to read from and write to the connection. This section describes both
functions.
Reading from a URLConnection
The following program performs the same function as the URLReader program
shown in Reading Directly from a URL.
However, rather than getting an input stream directly from the URL, this program
explicitly opens a connection to a URL and gets an input stream from the connection.
Then, like URLReader, this program creates a BufferedReader on the input stream and
reads from it. The bold statements highlight the differences between this example and the
previous
import java.net.*;
import java.io.*;
public class URLConnectionReader {
public static void main(String[] args) throws Exception {
URL hotmail = new URL("http://www.hotmail.com/");
URLConnection yc = hotmail.openConnection();
BufferedReader in = new BufferedReader(
new InputStreamReader(
yc.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}

The output from this program is identical to the output from the program that
opens a stream directly from the URL. You can use either way to read from a URL.
However, reading from a URLConnection instead of reading directly from a URL
might be more useful. This is because you can use the URLConnection object for
other tasks (like writing to the URL) at the same time.

118

Again, if the program hangs or you see an error message, you may have to set the
proxy host so that the program can find the Hotmail server.
Writing to a URLConnection
Many HTML pages contain forms-- text fields and other GUI objects that let you
enter data to send to the server. After you type in the required information and initiate the
query by clicking a button, your Web browser writes the data to the URL over the
network. At the other end, a cgi-bin script (usually) on the server receives the data,
processes it, and then sends you a response, usually in the form of a new HTML page.
Many cgi-bin scripts use the POST METHOD for reading the data from the
client. Thus writing to a URL is often called posting to a URL. Server-side scripts use the
POST METHOD to read from their standard input.
A Java program can interact with cgi-bin scripts also on the server side. It
simply must be able to write to a URL, thus providing data to the server. It can do this by
following these steps:
1.
2.
3.
4.

Create a URL.
Open a connection to the URL.
Set output capability on the URLConnection.
Get an output stream from the connection. This output stream is connected to the
standard input stream of the cgi-bin script on the server.
5. Write to the output stream.
6. Close the output stream.
Hassan Schroeder, a member of the Java development team, wrote a small cgibin script named backwards and made it available at the Java Web site,
http://java.sun.com/cgi-bin/backwards. You can use this script to test the
following example program. You can also put the script on your network, name it
backwards, and test the program locally.
The script at our Web site reads a string from its standard input, reverses the
string, and writes the result to its standard output. The script requires input of the form
string=string_to_reverse, where string_to_reverse is the string whose characters
you want displayed in reverse order.
Here's an example program that runs the backwards script over the network
through a URLConnection:
import java.io.*;
import java.net.*;
public class Reverse {

119
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.err.println("Usage:
string_to_reverse");
System.exit(1);
}

java Reverse

String stringToReverse = URLEncoder.encode(args[0]);


URL url = new URL("http://java.sun.com/cgi-bin/backwards");
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
PrintWriter out = new PrintWriter(connection.getOutputStream());
out.println("string=" + stringToReverse);
out.close();
BufferedReader in = new BufferedReader(
new
InputStreamReader( connection.
getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();
}

Let's examine the program and see how it works. First, the program processes its
command-line arguments:
if (args.length != 1)
{ System.err.println("Usage:
java Reverse
" +
"string_to_reverse");
System.exit(-1);
}
String stringToReverse = URLEncoder.encode(args[0]);

These statements ensure that the user provides one and only one command-line
argument to the program, and then encodes it. The command-line argument is the string
that will be reversed by the cgi-bin script backwards. It may contain spaces or
other non-alphanumeric characters. These characters must be encoded because the string
is processed on its way to the server. The URLEncoder class methods encode the
characters.
Next, the program creates the URL object--the URL for the backwards script on
java.sun.com--opens a URLConnection, and sets the connection so that it can write to it:
URL url = new URL("http://java.sun.com/cgi-bin/backwards");
URLConnection c = url.openConnection();

120
c.setDoOutput(true);

The program then creates an output stream on the connection and opens a
PrintWriter on it:
PrintWriter out = new PrintWriter(c.getOutputStream());

If the URL does not support output, getOutputStream method throws an


UnknownServiceException. If the URL does support output, then this method
returns an output stream that is connected to the standard input stream of the URL on the
server side--the client's output is the server's input.
Next, the program writes the required information to the output stream and closes the
stream:
out.println("string=" + stringToReverse);
out.close();

This code writes to the output stream using the println method. So you can
see that writing data to a URL is as easy as writing data to a stream. The data written to
the output stream on the client side is the input for the backwards script on the server
side. The Reverse program constructs the input in the form required by the script by
concatenating string= to the encoded string to be reversed.
Often, when you are writing to a URL, you are passing information to a cgi-bin
script, as in this example. This script reads the information you write, performs some
action, and then sends information back to you via the same URL. So it's likely that you
will want to read from the URL after you've written to it. The Reverse program does
this:
BufferReader in = new BufferedReader(
new InputStreamReader(c.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
System.out.println(inputLine);
in.close();

When you run the Reverse program using "Reverse Me" as an argument, you should
see this output:
Reverse Me
reversed is:
eM esreveR

121

SOCKETS
URLs and URLConnections provide a relatively high-level mechanism for
accessing resources on the Internet. Sometimes your programs require lower-level
network communication, for example, when you want to write a client-server application.
In client-server applications, the server provides some service, such as processing
database queries or sending out current stock prices. The client uses the service provided
by the server, either displaying database query results to the user or making stock
purchase recommendations to an investor. The communication that occurs between the
client and the server must be reliable. That is, no data can be dropped and it must arrive
on the client side in the same order in which the server sent it.
TCP provides a reliable, point-to-point communication channel that client-server
applications on the Internet use to communicate with each other. To communicate over
TCP, a client program and a server program establish a connection to one another. Each
program binds a socket to its end of the connection. To communicate, the client and the
server each reads from and writes to the socket bound to the connection.
Description of a Socket
Definition: A socket is one endpoint of a two-way communication link between two
programs running on the network. A socket is bound to a port number so that the TCP
layer can identify the application that data is destined to be sent.
Normally, a server runs on a specific computer and has a socket that is bound to a
specific port number. The server just waits, listening to the socket for a client to make a
connection request.
On the client-side: The client knows the hostname of the machine on which the
server is running and the port number to which the server is connected. To make a
connection request, the client tries to rendezvous with the server on the server's machine
and port.
If everything goes well, the server accepts the connection. Upon acceptance, the
server gets a new socket bound to a different port. It needs a new socket (and
consequently a different port number) so that it can continue to listen to the original
socket for connection requests while tending to the needs of the connected client.
On the client side, if the connection is accepted, a socket is successfully created
and the client can use the socket to communicate with the server. Note that the socket on
the client side is not bound to the port number used to rendezvous with the server. Rather,
the client is assigned a port number local to the machine on which the client is running.
The client and server can now communicate by writing to or reading from their
sockets.

122

The java.net package in the Java platform provides a class, Socket, that
implements one side of a two-way connection between your Java program and another
program on the network. The Socket class sits on top of a platform-dependent
implementation, hiding the details of any particular system from your Java program. By
using the java.net.Socket class instead of relying on native code, your Java programs
can communicate over the network in a platform-independent fashion.
Additionally, java.net includes the ServerSocket class, which implements a
socket that servers can use to listen for and accept connections to clients.
Reading from and Writing to a Socket
Given below is a simple example that illustrates how a program can establish a
connection to a server program using the Socket class and then, how the client can
send data to and receive data from the server through the socket.
The example program implements a client, EchoClient, that connects to the Echo
server. The Echo server simply receives data from its client and echoes it back. The Echo
server is a well-known service that clients can rendezvous with on port 7.
EchoClient creates a socket thereby getting a connection to the Echo server. It
reads input from the user on the standard input stream, and then forwards that text to the
Echo server by writing the text to the socket. The server echoes the input back through
the socket to the client. The client program reads and displays the data passed back to it
from the server:
import java.io.*;
import java.net.*;
public class EchoClient {
public static void main(String[] args) throws IOException {
Socket echoSocket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
echoSocket = new Socket("campione", 7);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new
InputStreamReader(echoSocket.getInputStream()));
} catch (UnknownHostException e)
{ System.err.println("Don't know about host:
vanavil."); System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to:
vanavil.");
System.exit(1);
}

123

BufferedReader stdIn = new BufferedReader(new


InputStreamReader(System.in));
String userInput;
while ((userInput = stdIn.readLine()) != null)
{ out.println(userInput);
System.out.println("echo: " + in.readLine());
}
out.close();
in.close();
stdIn.close();
echoSocket.close();
}

Note that EchoClient both writes to and reads from its socket, thereby sending data
to and receiving data from the Echo server.
Analyzing the program
The three statements in the try block of the main method are critical. These
lines establish the socket connection between the client and the server and open a
PrintWriter and a BufferedReader on the socket:
echoSocket = new Socket("vanavil", 7);
out = new PrintWriter(echoSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(
echoSocket.getInputStream()));

The first statement in this sequence creates a new Socket object and names it
echoSocket. The Socket constructor used here requires the name of the machine
and the port number to which you want to connect. The example program uses the host
name vanavil. This is the name of a hypothetical machine on our local network. When
you type in and run this program on your machine, change the host name to the name of a
machine on your network. Make sure that the name you use is the fully qualified IP name
of the machine to which you want to connect. The second argument is the port number.
Port number 7 is the port on which the Echo server listens. PrintWriter on it.
Similarly, the third statement gets the socket's input stream and opens a
BufferedReader on it. The example uses readers and writers so that it can write
Unicode characters over the socket.
To send data through the socket to the server, EchoClient simply needs to write
to the PrintWriter. To get the server's response, EchoClient reads from the
BufferedReader. The rest of the program achieves this.

124

The next interesting part of the program is the while loop. The loop reads a line at a time
from the standard input stream and immediately sends it to the server by writing it to the
PrintWriter connected to the socket:
String userInput;
while ((userInput = stdIn.readLine()) != null)
{ out.println(userInput);
System.out.println("echo: " + in.readLine());
}

The last statement in the while loop reads a line of information from the
BufferedReader connected to the socket. The readLine method waits until the
server echoes the information back to EchoClient. When readline returns,
EchoClient prints the information to the standard output.
The while loop continues until the user types an end-of-input character. That is,
EchoClient reads input from the user, sends it to the Echo server, gets a response from
the server, and displays it, until it reaches the end-of-input. The while loop then
terminates and the program continues, executing the next four lines of code:
out.close();
in.close();
stdIn.close();
echoSocket.close();

These lines of code fall into the category of housekeeping. A well-behaved


program always cleans up after itself, and this program is well-behaved. These statements
close the readers and writers connected to the socket and to the standard input stream, and
close the socket connection to the server. The order here is important. You should close
any streams connected to a socket before you close the socket itself.
This client program is straightforward and simple because the Echo server
implements a simple protocol. The client sends text to the server, and the server echoes it
back. When your client programs are talking to a more complicated server such as an
HTTP server, your client program will also be more complicated. However, the basics are
much the same as they are in this program:
1.
2.
3.
4.
5.

Open a socket.
Open an input stream and output stream to the socket.
Read from and write to the stream according to the server's protocol.
Close the streams.
Close the socket.

Only step 3 differs from client to client, depending on the server. The other steps remain
largely the same.

125

Writing a Client/Server Pair


This section shows you how to write a server and the client that goes with it. The server
in the client/server pair serves up Knock Knock jokes. Knock Knock jokes are favored by
children and are usually vehicles for bad puns. They go like this:
Server: "Knock
knock!" Client: "Who's
there?" Server: "A
Mos" Client: "A Mos
who?" Server: "A Mosquito" Client: "Groan."
The example consists of two independently running Java programs: the client
program and the server program. The client program is implemented by a single class,
KnockKnockClient, and is very similar to the EchoClient example from the previous
section. The server program is implemented by two classes: KnockKnockServer and
KnockKnockProtocol, KnockKnockServer contains the main method for the server
program and performs the work of listening to the port, establishing connections, and
reading from and writing to the socket. KnockKnockProtocol serves up the jokes. It
keeps track of the current joke, the current state (sent knock knock, sent clue, and so on),
and returns the various text pieces of the joke depending on the current state. This object
implements the protocol-the language that the client and server have agreed to use to
communicate.
The following section looks in detail at each class in both the client and the server and
then shows you how to run them.
The Knock Knock Server
This section walks through the code that implements the Knock Knock server program.
The complete source for the KnockKnockServer class is given below:
import java.net.*;
import java.io.*;
public class KnockKnockServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(3333);
} catch (IOException e) {
System.err.println("Could not listen on port: 3333.");
System.exit(1);
}
Socket clientSocket = null;
try {
clientSocket = serverSocket.accept();

126
} catch (IOException e)
{ System.err.println("Accept
failed."); System.exit(1);
}
PrintWriter out = new
PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
String inputLine, outputLine;
KnockKnockProtocol kkp = new KnockKnockProtocol();
outputLine = kkp.processInput(null);
out.println(outputLine);
while ((inputLine = in.readLine()) != null)
{ outputLine =
kkp.processInput(inputLine);
out.println(outputLine);
if (outputLine.equals("Bye."))
break;
}
out.close();
in.close();
clientSocket.close();
serverSocket.close();
}

The server program begins by creating a new ServerSocket object to listen on a


specific port (see the statement in bold in the following code segment). When writing a
server, choose a port that is not already dedicated to some other service. Let the
KnockKnockServer listen on port 3333.
try {
serverSocket = new ServerSocket(3333);
} catch (IOException e) {
System.out.println("Could not listen on port: 3333");
System.exit(-1);
}

ServerSocket is a java.net class that provides a system-independent


implementation of the server side of a client/server socket connection. The constructor
for ServerSocket throws an exception if it can't listen on the specified port (for
example, the port is already being used). In this case, the KnockKnockServer has
no choice but to exit.
If the server successfully connects to its port, then the ServerSocket object is
successfully created and the server continues to the next step--accepting a connection
from a client (shown in bold):
Socket clientSocket = null;
try {

127
clientSocket = serverSocket.accept();
} catch (IOException e)
{ System.out.println("Accept failed:
3333"); System.exit(-1);
}

The accept method waits until a client starts up and requests a connection on the host
and port of this server (in this example, the server is running on a hypothetical machine
on port 3333). When a connection is requested and successfully established, the accept
method returns a new Socket object which is bound to a new port. The server can
communicate with the client over this new Socket and continue to listen for client
connection requests on the ServerSocket bound to the original, predetermined port.
This particular version of the program doesn't listen for more client connection requests.
After the server successfully establishes a connection with a client, it communicates with
the client using this code:
PrintWriter out = new PrintWriter(
clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new BufferedOutputStream(
clientSocket.getInputStream())),
String inputLine, outputLine;
// initiate conversation with client
KnockKnockProtocol kkp = new KnockKnockProtocol();
outputLine = kkp.processInput(null);
out.println(outputLine);
while ((inputLine - in.readLine()) != null) {
outputLine = kkp.processInput(inputLine);
out.println(outputLine);
if outputLine.equals("Bye."))
break;
}

Features of this code:


1. It gets the socket's input and output stream and opens readers and writers on them.
2. It Initiates communication with the client by writing to the socket (shown in bold).
3. It Communicates with the client by reading from and writing to the socket (the
while
loop).
Step 1 is already familiar. Step 2 is shown in bold and is worth a few comments. The bold
statements in the code segment above initiate the conversation with the client. The code
creates a KnockKnockProtocol object-the object that keeps track of the current joke,
the current state within the joke, and so on.

128

After the KnockKnockProtocol is created, the code calls KnockKnockProtocol's


processInput method to get the first message that the server sends to the client. For
this example, the first thing that the server says is "Knock! Knock!" Next, the server
writes the information to the PrintWriter connected to the client socket, thereby
sending the message to the client.
Step 3 is encoded in the while loop. As long as the client and server still have something
to say to each other, the server reads from and writes to the socket, sending messages
back and forth between the client and the server.
The server initiated the conversation with a "Knock! Knock!" so afterwards the server
must wait for the client to say "Who's there?" As a result, the while loop iterates on a read
from the input stream. The readLine method waits until the client responds by writing
something to its output stream (the server's input stream). When the client responds, the
server passes the client's response to the KnockKnockProtocol object and asks the
KnockKnockProtocol object for a suitable reply. The server immediately sends the reply
to the client via the output stream connected to the socket, using a call to println. If the
server's response generated from the KnockKnockServer object is "Bye." this indicates
that the client doesn't want any more jokes and the loop quits.
The KnockKnockServer class is a well-behaved server, so the last several lines of this
section of KnockKnockServer clean up by closing all of the input and output streams,
the client socket, and the server socket:
out.close();
in.close();
clientSocket.close();
serverSocket.close();

The Knock Knock Protocol


The KnockKnockProtocol class implements the protocol that the client and server
use to
communicate. This class keeps track of where the client and the server are in their
conversation and serves up the server's response to the client's statements. The
KnockKnockServer object contains the text of all the jokes and makes sure that
the client gives the proper response to the server's statements. It wouldn't do to have the
client say "Turnip who?" when the server says "Knock! Knock!"
All client/server pairs must have some protocol by which they speak to each other;
otherwise, the data that passes back and forth would be meaningless. The protocol that
your own clients and servers use depends entirely on the communication required by
them to accomplish the task.

129

Source code for the KnockKnockProtocol


import java.net.*;
import java.io.*;
public class KnockKnockProtocol
{ private static final int WAITING =
0;
private static final int SENTKNOCKKNOCK = 1;
private static final int SENTCLUE = 2;
private static final int ANOTHER = 3;
private static final int NUMJOKES = 5;
private int state = WAITING;
private int currentJoke = 0;
private String[] clues = { "Turnip", "Little Old Lady", "Atch",
"Who", "Who" };
private String[] answers = { "Turnip the heat, it's cold in here!",
"I didn't know you could yodel!",
"Bless you!",
"Is there an owl in here?",
"Is there an echo in here?" };
public String processInput(String theInput) {
String theOutput = null;

if (state == WAITING)
{ theOutput = "Knock!
Knock!"; state =
SENTKNOCKKNOCK;
} else if (state == SENTKNOCKKNOCK) {
if (theInput.equalsIgnoreCase("Who's there?")) {
theOutput = clues[currentJoke];
state = SENTCLUE;
} else {
theOutput = "You're supposed to say \"Who's there?\"! "

"Try again. Knock! Knock!";


}
} else if (state == SENTCLUE) {
if (theInput.equalsIgnoreCase(clues[currentJoke] + "
who?")) {
theOutput = answers[currentJoke] + " Want another?
(y/n)";
state = ANOTHER;
} else {
theOutput = "You're supposed to say \"" +
clues[currentJoke] +
" who?\"" +
"! Try again. Knock! Knock!";
state = SENTKNOCKKNOCK;
}
} else if (state == ANOTHER) {
if (theInput.equalsIgnoreCase("y")) {
theOutput = "Knock! Knock!";
if (currentJoke == (NUMJOKES - 1))

130
currentJoke = 0;

else

currentJoke++;
state = SENTKNOCKKNOCK;
} else {
theOutput = "Bye.";
state = WAITING;
}

}
return theOutput;

The Knock Knock Client


The KnockKnockClient class implements the client program that speaks to the
KnockKnockServer. KnockKnockClient is based on the EchoClient
program in the previous section. We'll go over the program and look at what's happening
in the client in the context of what's going on in the server.
When you start the client program, the server should already be running and listening to
the port, waiting for a client to request a connection. So, the first thing the client program
does is to open a socket that is connected to the server running on the hostname and port
specified:
kkSocket = new Socket("vanavil", 3333);
out = new PrintWriter(kkSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(
kkSocket.getInputStream()));

When creating its socket, KnockKnockClient uses the host name vanavil, the
name of a hypothetical machine on our network. When you type in and run this program,
change the host name to the name of a machine on your network. This is the machine on
which you will run the KnockKnockServer.
The KnockKnockClient program also specifies the port number 3333 when creating its
socket. This is a remote port number--the number of a port on the server machine--and is
the port to which KnockKnockServer is listening. The client's socket is bound to any
available local port--a port on the client machine. Remember that the server gets a new
socket as well. That socket is bound to a local port number (not port 3333) on its
machine. The server's socket and the client's socket are connected.
Next comes the while loop that implements the communication between the client and
the server. The server speaks first, so the client must listen first. The client does this by
reading from the input stream attached to the socket. If the server does speak, it says
"Bye." and the client exits the loop. Otherwise, the client displays the text to the standard
output and then reads the response from the user, who types into the standard input. After

131

the user types a carriage return, the client sends the text to the server through the output
stream attached to the socket.
while ((fromServer = in.readLine()) != null)
{ System.out.println("Server: " +
fromServer); if (fromServer.equals("Bye."))
break;
fromUser = stdIn.readLine();
if (fromUser != null) {
System.out.println("Client: " + fromUser);
out.println(fromUser);
}
}

The communication ends when the server asks if the client wishes to hear another joke,
the client says no, and the server says "Bye."
In the interest of good housekeeping, the client closes its input and output streams and the
socket:
out.close();
in.close();
stdIn.close();
kkSocket.close();

Source Code for the KnockKnockClient class


import java.io.*;
import java.net.*;
public class KnockKnockClient {
public static void main(String[] args) throws IOException {
Socket kkSocket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
kkSocket = new Socket("campione", 4444);
out = new PrintWriter(kkSocket.getOutputStream(), true);
in = new BufferedReader(new
InputStreamReader(kkSocket.getInputStream()));
} catch (UnknownHostException e)
{ System.err.println("Don't know about host:
taranis."); System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to:
taranis.");
System.exit(1);
}
BufferedReader stdIn = new BufferedReader(new
InputStreamReader(System.in));

132
String fromServer;
String fromUser;
while ((fromServer = in.readLine()) != null)
{ System.out.println("Server: " +
fromServer); if (fromServer.equals("Bye."))
break;

fromUser = stdIn.readLine();
if (fromUser != null) {
System.out.println("Client: " + fromUser);
out.println(fromUser);
}

out.close();
in.close();
stdIn.close();
kkSocket.close();
}

Running the Programs


You must start the server program first. To do this, run the server program using the Java
interpreter, just as you would any other Java application. Remember to run the server on
the machine that the client program specifies when it creates the socket.
Next, run the client program. Note that you can run the client on any machine on your
network; it does not have to run on the same machine as the server.
If you are too quick, you might start the client before the server has a chance to initialize
itself and begin listening on the port. If this happens, you will see a stack trace from the
client. If this happens, just restart the client.
If you forget to change the host name in the source code for the KnockKnockClient
program, you will see the following error message:
Don't know about host: vanavil
To fix this, modify the KnockKnockClient program and provide a valid host name
for your network. Recompile the client program and try again.
If you try to start a second client while the first client is connected to the server, the
second client just hangs. The next section on Supporting Multiple Clients, talks about
supporting multiple clients.
When you successfully get a connection between the client and server, you will see the
following text displayed on your screen:

133

Server: Knock! Knock!


Now, you must respond with:
Who's there?
The client echoes what you type and sends the text to the server. The server responds
with the first line of one of the many Knock Knock jokes in its repertoire. Now your
screen should contain this (the text you typed is in bold):
Server: Knock! Knock!
Who's there?
Client: Who's there?
Server: Doctor
Now, you respond with:
Doctor who?"
Again, the client echoes what you type and sends the text to the server. The server
responds with the punch line. Now your screen should contain this:
Server: Knock! Knock!
Who's there?
Client: Who's there?
Server: Doctor
Doctor who?
Client: Doctor who?
Server: How did you guess my name? Want another? (y/n)
If you want to hear another joke, type y; if not, type n. If you type y, the server begins
again with "Knock! Knock!" If you type n, the server says "Bye." thus causing both the
client and the server to exit.
If at any point you make a typing mistake, the KnockKnockServer object catches it and
the server responds with a message similar to this:
Server: You're supposed to say "Who's there?"!
The server then starts the joke over again:
Server: Try again. Knock! Knock!
Note that the KnockKnockProtocol object is particular about spelling
and punctuation but not about capitalization.

134

SUPPORTING MULTIPLE CLIENTS


To keep the KnockKnockServer example simple, we designed it to listen for and
handle a single connection request. However, multiple client requests can come into the
same port and, consequently, into the same ServerSocket. Client connection requests
are queued at the port, so the server must accept the connections sequentially. However,
the server can service them simultaneously through the use of threads - one thread per
each client connection.
The basic flow of logic in such a server is this:
while (true) {
accept a connection ;
create a thread to deal with the client ;
end while

The thread reads from and writes to the client connection as necessary.

LET US SUM UP
Java provides several useful classes for simplifying internet and socket
programming. These include InetAddress for obtaining IP addresses from domain names,
URL and URLConnection classes for communicating with web servers, and Socket and
ServerSocket classes for creating general client server programs.
A Socket is a handle to a communication link over the network with another
application. A TCP Socket uses the TCP Protocol, inherting the behavior of that
transparent protocol. Four pieces of information are needed to create a TCP socket.
The local system is IP address.
The TCP Port number the local application is using.
The remote systems IP address.
The TCP Port number to which the remote application is responding.

LESSON END ACTIVITIES


1. Write a program which takes an website address from the user and prints the
webservers InetAddress.
2. Write a program which redirects the user to the server specified by him.
3. Write a program to create a client server communication that is what ever is typed
at the server should be displayed at the client window and vise-versa

135

POINTS FOR DISCUSSION


Discuss about the various classes of sockets that can be created in Java with some
examples

REFERENCES
Jane Jawroski, Java Unleashed, SAMS Techmedia Publications, 1999
Campione, Walrath and Huml, The Java Tutorial, Addison Wesley 1999

136

LESSON 7: REMOTE METHOD INVOCATION (RMI)


Contents
Aims and Objectives
Introduction
Remote Interfaces
Using the Remote Object
Alternatives to RMI
Let us Sum Up
Lesson-End Activities
Points for Discussion
References

AIMS AND OBJECTIVES


At the end of this Lesson, you will be able to:
Understand the need for Distributed Applicaitons
Understand the use of RMI
Write Java programs using RMI

INTRODUCTION
Traditional approaches to executing code on other machines across a network
have been confusing as well as tedious and error-prone to implement. The nicest way to
think about this problem is that some object happens to live on another machine, and you
can send a message to that object and get a result as if the object lived on your local
machine. This simplification is exactly what Java Remote Method Invocation (RMI)
allows you to do. This section walks you through the steps necessary to create your own
RMI objects.

REMOTE INTERFACES
RMI makes heavy use of interfaces. When you want to create a remote object,
you mask the underlying implementation by passing around an interface. Thus, when the
client gets a handle to a remote object, what they really get is an interface handle, which
happens to connect to some local stub code that talks across the network. But you dont
think about this, you just send messages via your interface handle.
When you create a remote interface, you must follow these guidelines:
1. The remote interface must be public (it cannot have package access, that is, it
cannot be friendly). Otherwise, a client will get an error when attempting to
load a remote object that implements the remote interface.
2. The remote interface must extend the interface java.rmi.Remote.

137

3. Each method in the remote interface must declare java.rmi.RemoteException in


its throws clause in addition to any application-specific exceptions.
4. A remote object passed as an argument or return value (either directly or
embedded within a local object) must be declared as the remote interface, not the
implementation class.
Heres a simple remote interface that represents an accurate time service:
//: PerfectTimeI.java
// The PerfectTime remote interface
package c15.ptime;
import java.rmi.*;
interface PerfectTimeI extends Remote {
long getPerfectTime() throws RemoteException;
} ///:~
It looks like any other interface except that it extends Remote and all of its methods
throw RemoteException. Remember that an interface and all of its methods are
automatically public.

Implementing the remote interface


The server must contain a class that extends UnicastRemoteObject and
implements the remote interface. This class can also have additional methods, but only
the methods in the remote interface will be available to the client, of course, since the
client will get only a handle to the interface, not the class that implements it.
You must explicitly define the constructor for the remote object even if youre
only defining a default constructor that calls the base-class constructor. You must write it
out since it must throw RemoteException.
Heres the implementation of the remote interface PerfectTimeI:
//: PerfectTime.java
// The implementation of the PerfectTime
// remote object
package c15.ptime;
import java.rmi.*;
import java.rmi.server.*;
import java.rmi.registry.*;
import java.net.*;
public class PerfectTime
extends UnicastRemoteObject
implements PerfectTimeI {
// Implementation of the interface:
public long getPerfectTime()
throws RemoteException {
return System.currentTimeMillis();
}
// Must implement constructor to throw
// RemoteException:

138
public PerfectTime() throws RemoteException {
// super(); // Called automatically
}
// Registration for RMI serving:
public static void main(String[] args) {
System.setSecurityManager(
new RMISecurityManager());
try {
PerfectTime pt = new PerfectTime();
Naming.bind(
"//colossus:2005/PerfectTime", pt);
System.out.println("Ready to do time");
} catch(Exception e) {
e.printStackTrace();
}
}
} ///:~

Here, main( ) handles all the details of setting up the server. When youre serving RMI
objects, at some point in your program you must:
1. Create and install a security manager that supports RMI. The only one available
for RMI as part of the Java distribution is RMISecurityManager.
2. Create one or more instances of a remote object. Here, you can see the creation of
the PerfectTime object.
3. Register at least one of the remote objects with the RMI remote object registry for
bootstrapping purposes. One remote object can have methods that produce
handles to other remote objects. This allows you to set it up so the client must go
to the registry only once, to
4. get the first remote object.
Setting up the registry
Here, you see a call to the static method Naming.bind( ). However, this call
requires that the registry be running as a separate process on the computer. The name of
the registry server is rmiregistry, and under 32-bit Windows you say:
start rmiregistry
to start it in the background. On Unix, it is:
rmiregistry &
Like many network programs, the rmiregistry is located at the IP address of
whatever machine started it up, but it must also be listening at a port. If you invoke the
rmiregistry as above, with no argument, the registrys port will default to 1099. If you
want it to be at some other port, you add an argument on the command line to specify the
port. For this example, the port will be located at 2005, so the rmiregistry should be
started like this under 32-bit Windows:

139

start rmiregistry 2005


or for Unix:
rmiregistry 2005 &
The information about the port must also be given to the bind( ) command, as
well as the IP address of the machine where the registry is located. But this brings up
what can be a frustrating problem if youre expecting to test RMI programs locally the
way the network programs have been tested so far in this chapter.
The name for the service is arbitrary; it happens to be PerfectTime here, just like
the name of the class, but you could call it anything you want. The important thing is that
its a unique name in the registry that the client knows to look for to procure the remote
object. If the name is already in the registry, youll get an AlreadyBoundException. To
prevent this, you can always use rebind( ) instead of bind( ), since rebind( ) either adds
a new entry or replaces the one thats already there.
Even though main( ) exits, your object has been created and registered so its kept
alive by the registry, waiting for a client to come along and request it. As long as the
rmiregistry is running and you dont call Naming.unbind( ) on your name, the object
will be there. For this reason, when youre developing your code you need to shut down
the rmiregistry and restart it when you compile a new version of your remote object.
You arent forced to start up rmiregistry as an external process. If you know that
your application is the only one thats going to use the registry, you can start it up inside
your program with the line:
LocateRegistry.createRegistry(1785);
1785 is the port number we happen to be using in this example. This is the
equivalent of running rmiregistry 1785 from a command line, but it can often be more
convenient when youre developing RMI code since it eliminates the extra steps of
starting and stopping the registry. Once youve executed this code, you can bind( ) using
Naming as before.
Creating stubs and skeletons
If you compile and run PerfectTime.java, it wont work even if you have the
rmiregistry running correctly. Thats because the framework for RMI isnt all there yet.
You must first create the stubs and skeletons that provide the network connection
operations and allow you to pretend that the remote object is just another local object on
your machine.
Whats going on behind the scenes is complex. Any objects that you pass into or
return from a remote object must implement Serializable (if you want to pass remote

140

references instead of the entire objects, the object arguments can implement Remote ),
so you can imagine that the stubs and skeletons are automatically performing serialization
and deserialization as they marshal all of the arguments across the network and return
the result. Fortunately, you dont have to know any of this, but you do have to create the
stubs and skeletons. This is a simple process: you invoke the rmic tool on your compiled
code, and it creates the necessary files. So the only requirement is that another step be
added to your compilation process.
The rmic tool is particular about packages and classpaths, however.
PerfectTime.java is in the package c15.Ptime, and even if you invoke rmic in the same
directory in which PerfectTime.class is located, rmic wont find the file, since it
searches the classpath. So you must specify the location off the class path, like so:
rmic c15.PTime.PerfectTime
You dont have to be in the directory containing PerfectTime.class when you
execute this command, but the results will be placed in the current directory.
When rmic runs successfully, youll have two new classes in the directory:
PerfectTime_Stub.class
PerfectTime_Skel.class
corresponding to the stub and skeleton. Now youre ready to get the server and client to
talk to each other.

USING THE REMOTE OBJECT


The whole point of RMI is to make the use of remote objects simple. The only
extra thing that you must do in your client program is to look up and fetch the remote
interface from the server. From then on, its just regular Java programming: sending
messages to objects. Heres the program that uses PerfectTime:
//: DisplayPerfectTime.java
// Uses remote object PerfectTime
package c15.ptime;
import java.rmi.*;
import java.rmi.registry.*;
public class DisplayPerfectTime {
public static void main(String[] args) {
System.setSecurityManager(
new RMISecurityManager());
try {
PerfectTimeI t =
(PerfectTimeI)Naming.lookup(
"//colossus:2005/PerfectTime");
for(int i = 0; i < 10; i++)
System.out.println("Perfect time = " +

141
t.getPerfectTime());
} catch(Exception e) {
e.printStackTrace();
}

}
} ///:~

The ID string is the same as the one used to register the object with Naming, and
the first part represents the URL and port number. Since youre using a URL, you can
also specify a machine on the Internet.
What comes back from Naming.lookup( ) must be cast to the remote interface, not to the
class. If you use the class instead, youll get an exception.
You can see in the method call
etPerfectTime( )
that once you have a handle to the remote object, programming with it is
indistinguishable from programming with a local object (with one difference: remote
methods throw RemoteException).

Using RMI with applets


There are a number of special concerns when running RMI with applets. Applets
have their own security manager since they run inside a browser. Thus, they do not use
the RMISecurityManager on the client side.
We must take care where to place the stub and server files. Consider a browser
that opens a web page with an APPLET tag. The browser loads the class file referenced in
the tag and all other class files as they are needed during execution. The classes are
loaded from the same hostthat contains the web page. Because of applet security
restrictions, the applet can make network connections only to its originating host.
Therefore, the server objects must reside on the same host as the web page. That is the
same server must store
Web pages
Applet code
Stub classes
Server objects
The RMI registry Examples
to illustrate use of RMI

142

Example 1
import java.rmi.*;
import java.awt.*;
public interface Product
extends Remote
{ String getDescription()
throws RemoteException;

static final int MALE = 1;


static final int FEMALE = 2;
static final int BOTH = MALE + FEMALE;

Example 2
import java.rmi.*;
import java.util.*;
public interface Warehouse
extends Remote
{ public Vector find(Customer c)
throws RemoteException;
}

Example 3
import java.rmi.*;
import java.rmi.server.*;
import java.awt.*;
public class ProductImpl
extends UnicastRemoteObject
implements Product
{ public ProductImpl(String n, int s, int age1, int age2,
String h)
throws RemoteException
{ name = n;
ageLow = age1;
ageHigh = age2;
sex = s;
hobby = h;
}
public boolean match(Customer c) // local method
{ if (c.getAge() < ageLow || c.getAge() > ageHigh)
return false;
if (!c.hasHobby(hobby)) return false;
if ((sex & c.getSex()) == 0) return false;
return true;
}
public String getDescription()

143

{
}

throws RemoteException
return "I am a " + name + ". Buy me!";

private
private
private
private
private

String name;
int ageLow;
int ageHigh;
int sex;
String hobby;

Example 4
import java.io.*;
public class Customer implements Serializable
{ public Customer(int theAge, int theSex, String[] theHobbies)
{ age = theAge;
sex = theSex;
hobbies = theHobbies;
}
public int getAge() { return age; }
public int getSex() { return sex; }
public boolean hasHobby(String aHobby)
{ if (aHobby == "") return true;
for (int i = 0; i < hobbies.length; i++)
if (hobbies[i].equals(aHobby)) return true;
}

return false;

public void reset()


{ age = 0;
sex = 0;
hobbies = null;
}
public String toString()
{ String result = "Age: " + age + ", Sex: ";
if (sex == Product.MALE) result += "Male";
else if (sex == Product.FEMALE) result += "Female";
else result += "Male or Female";
result += ", Hobbies:";
for (int i = 0; i < hobbies.length; i++)
result += " " + hobbies[i];
return result;
}
private int age;

144
private int sex;
private String[] hobbies;
}

Example 5
Import java.rmi.*;
import java.util.*;
public interface Warehouse
extends Remote
{ public Vector find(Customer c)
throws RemoteException;
}

Example 6
import java.rmi.*;
import java.util.*;
import java.rmi.server.*;
public class WarehouseImpl
extends UnicastRemoteObject
implements Warehouse
{ public WarehouseImpl()
throws RemoteException
{ products = new Vector();
}
public synchronized void add(ProductImpl p) // local method
{ products.add(p);
}
public synchronized Vector find(Customer c)
throws RemoteException
{ Vector result = new Vector();
for (int i = 0; i < products.size(); i++)
{ ProductImpl p = (ProductImpl)products.get(i);
if (p.match(c)) result.add(p);
}
result.add(new ProductImpl("Core Java Book",
0, 200, Product.BOTH, ""));
c.reset();
return result;
}
}

private Vector products;

Example 7
import java.rmi.*;
import java.rmi.server.*;

145

public class WarehouseServer


{

public static void main(String[] args)


{ try
{ System.out.println
("Constructing server implementations...");
WarehouseImpl w = new WarehouseImpl();
fillWarehouse(w);
System.out.println
("Binding server implementations to registry...");
Naming.rebind("central_warehouse", w);
System.out.println
("Waiting for invocations from clients...");

}
catch(Exception e)
{ System.out.println("Error: " + e);
}

public static void fillWarehouse(WarehouseImpl w)


throws RemoteException
{ w.add(new ProductImpl("Blackwell Toaster",
Product.BOTH, 18, 200, "Household"));
w.add(new ProductImpl("ZapXpress Microwave Oven",
Product.BOTH, 18, 200, "Household"));
w.add(new ProductImpl("Jimbo After Shave",
Product.MALE, 18, 200, "Beauty"));
w.add(new ProductImpl("Handy Hand Grenade",
Product.MALE, 20, 60, "Gardening"));
w.add(new ProductImpl("DirtDigger Steam Shovel",
Product.MALE, 20, 60, "Gardening"));
w.add(new ProductImpl("U238 Weed Killer",
Product.BOTH, 20, 200, "Gardening"));
w.add(new ProductImpl("Van Hope Cosmetic Set",
Product.FEMALE, 15, 45, "Beauty"));
w.add(new ProductImpl("Persistent Java Fragrance",
Product.FEMALE, 15, 45, "Beauty"));
w.add(new ProductImpl("Rabid Rodent Computer Mouse",
Product.BOTH, 6, 40, "Computers"));
w.add(new ProductImpl
("Learn Bad Java Habits in 21 Days Book",
Product.BOTH, 20, 200, "Computers"));
w.add(new ProductImpl("My first Espresso Maker",
Product.FEMALE, 6, 10, "Household"));
w.add(new ProductImpl("JavaJungle Eau de Cologne",
Product.FEMALE, 20, 200, "Beauty"));
w.add(new ProductImpl("Fast/Wide SCSI Coffee Maker",
Product.MALE, 20, 50, "Computers"));
w.add(new ProductImpl("ClueLess Network Computer",
Product.BOTH,6, 200, "Computers"));
} }

146

Example 8
import
import
import
import
import
import
import

java.awt.*;
java.awt.event.*;
java.io.*;
java.rmi.*;
java.rmi.server.*;
java.util.*;
javax.swing.*;

public class WarehouseClient


{ public static void main(String[] args)
{ JFrame frame = new WarehouseClientFrame();
frame.show();
}
}
class WarehouseClientFrame extends JFrame
implements ActionListener
{ public WarehouseClientFrame()
{ initUI();
System.setSecurityManager(new RMISecurityManager());
try
{ Properties props = new Properties();
String fileName = "WarehouseClient.properties";
FileInputStream in = new FileInputStream(fileName);
props.load(in);
String url = props.getProperty("warehouse.url");
if (url == null)
url = "rmi://localhost/central_warehouse";
centralWarehouse = (Warehouse)Naming.lookup(url);
}
catch(Exception e)
{ System.out.println("Error: Can't connect to warehouse.
" + e);
}
}
private void callWarehouse(Customer c)
{ try
{ Vector recommendations = centralWarehouse.find(c);
result.setText(c + "\n");
for (int i = 0; i < recommendations.size(); i++)
{ Product p = (Product)recommendations.get(i);
String t = p.getDescription() + "\n";
result.append(t);
}
}
catch(Exception e)
{ result.setText("Error: " + e);
}
}

147

public void actionPerformed(ActionEvent evt)


{ Object[] hobbyObjects = hobbies.getSelectedValues();
String[] hobbyStrings = new String[hobbyObjects.length];
System.arraycopy(hobbyObjects, 0, hobbyStrings, 0,
hobbyObjects.length);
Customer c = new Customer(Integer.parseInt(age.getText()),
(male.isSelected() ? Product.MALE : 0)
+ (female.isSelected() ? Product.FEMALE : 0),
hobbyStrings);
callWarehouse(c);
}
private void initUI()
{ setTitle("WarehouseClient");
setSize(300, 300);
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent e)
{ System.exit(0);
}
} );
getContentPane().setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 100;
gbc.weighty = 0;
add(new JLabel("Age:"), gbc, 0, 0, 1, 1);
age = new JTextField(4);
age.setText("20");
add(age, gbc, 1, 0, 1, 1);
male = new JCheckBox("Male", true);
female = new JCheckBox("Female", true);
add(male, gbc, 0, 1, 1, 1);
add(female, gbc, 1, 1, 1, 1);
gbc.weighty = 100;
add(new JLabel("Hobbies"), gbc, 0, 2, 1, 1);
String[] choices = { "Gardening", "Beauty",
"Computers", "Household", "Sports" };
gbc.fill = GridBagConstraints.BOTH;
hobbies = new JList(choices);
add(new JScrollPane(hobbies), gbc, 1, 2, 1, 1);
gbc.weighty = 0;
gbc.fill = GridBagConstraints.NONE;
JButton submitButton = new JButton("Submit");
add(submitButton, gbc, 0, 3, 2, 1);
submitButton.addActionListener(this);
gbc.weighty = 100;
gbc.fill = GridBagConstraints.BOTH;
result = new JTextArea(4, 40);

148
result.setEditable(false);
add(result, gbc, 0, 4, 2, 1);
}
private void add(Component c, GridBagConstraints gbc,
int x, int y, int w, int h)
{ gbc.gridx = x;
gbc.gridy = y;
gbc.gridwidth = w;
gbc.gridheight = h;
getContentPane().add(c, gbc);
}
private
private
private
private
private
private

Warehouse centralWarehouse;
JTextField age;
JCheckBox male;
JCheckBox female;
JList hobbies;
JTextArea result;

Example for using RMI with JDBC (Example no: 9)


/* The objective of the following code is to obtain some details
about a person (whose entry is in a data base in a remote
server), using RMI */
// RemoteInterface
import java.rmi.*;
import java.sql.*;
public interface RMIInterfaceForDB extends Remote
{
String[] fetchResults(String name) throws RemoteException;
}
// Server Implementation
/*Note that the following program assumes that you have already
created a data source name called ContactsDB with user name as
user and passowrd as user. Also the DSN has a table called
CONT which has the following 4 fields:
NAME
ADDRESS
EMAIL
AGE
The name of the database used here was contacts.mdb (MS Access
was used)
*/

149

import java.rmi.*;
import java.rmi.server.*;
import java.io.*;
import java.sql.*;
public class DBFetcher extends UnicastRemoteObject
implements RMIInterfaceForDB
{
public DBFetcher() throws RemoteException
{
super();
}
public String[] fetchResults(String x) throws
RemoteException
{
try
{
String[] s = new String[4];
for(int i = 0;i<4;i++) s[i] = new String();
String query = "SELECT * FROM CONT WHERE NAME
LIKE '"+x+"'";
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection con = DriverManager.getConnection(
"jdbc:odbc:ContactsDB","user","user");
Statement smt = con.createStatement();
ResultSet rs = smt.executeQuery(query);
while(rs.next()){
s[0] = rs.getString("NAME");
s[1] = rs.getString("ADDRESS");
s[2] = rs.getString("EMAIL");
s[3] = new
Integer(rs.getInt("AGE")).toString();
}
return s;
}
catch(Exception e)
{
e.printStackTrace();
System.out.println("Client request could not be
processed");
return null;
}
}
public static void main(String args[])
{
DBFetcher ms;
try
{
ms = new DBFetcher();

150

Naming.rebind("rmi://202.202.202.11/rmiindb",ms);
System.out.println("I am registered with RMI!
Please do not disturb me");
}
catch(Exception e){System.out.println(e);}
}//end of main
}
/* Cient Program contacts the rmiregistry and looks for an
Object named rmiindb from which it takes the method called
fetchResults(String name ) and gives the results
*/
import java.sql.*;
import java.rmi.*;
public class ClientProgram
{
public static void main(String[] args)
{
RMIInterfaceForDB r;
try
{
ResultSet rs;
r = (RMIInterfaceForDB)
Naming.lookup("rmi://202.202.202.11/rmiindb");
String[] s = new String[4];
for(int i = 0;i<4;i++) s[i] = new String();
s = r.fetchResults("Contact3");
System.out.println("Name :"+s[0]+
"\nAddress :"+s[1]+
"\nemail :"+s[2]+
"\nage :"+s[3]+"\n");
}

}catch(Exception e){e.printStackTrace();}

}
/*
The output is
Name :Contact3
Address :Prince Pettai
email :itoodontknowmyname@yahoo.com
age :16
*/

151

Explanation to the above programs:


Example 1:This program is simple application that lets the user shop for a
gift. On the client, The user runs the program that gathers information about the gift
recipient, in this case, age, sex, hobbies. An object of type Customer is then sent to the
RMI server. Since Customer is not a remote Object, a copy of the object is made on the
server. The server program sends back a vector of products. The vector contains those
products that match the customer profile. Vector is not a remote class so vector is copied
from the server back to its client. The recipient gets the copy of the Vector, filled with
stub objects to the products on the srever.
Example 2: self explanatory
Example 3 shows the implementation for the product service. Products store a
description, an age range, the gender targeted (male, female or both), and the matching
hobby. Note that this class implements the get Description method advertised in the
Product interface. The match method is an example of local method, a method that can
be called only from the program, not remotely. Since the match method is local, it need
not be prepared to throw a Remote Exception.
Example 4 contains the code for the Customer class-none of its methods can be
executed remotely. However the class is serializable. Therefore, objects of this class can
be transported from one machine to another.
Example 5 shows the implementation for the warehouse service. This class has
local and remote methods. The add; it is used by the server to add products to the
warehouse. The find method is remote; it is used to find items in the warehouse. The find
method is remote; it is used to find items in the warehouse.
To illustrate that the Costumer object is actually copied, the find method of the
warehouseImpl class clears the costumer object it receives. When the remote method
returns, the WarehouseClient displays the costumer object that it sent to the server. As
you will see, that object has not changed. The server cleared only its copy. In this case,
the clear operation serves no useful purpose except to demonstrate that local objects are
copied when they are passed as parameters.
Example 6 shows the server program that creates a warehouse object and
registers it with the bootstrap registry service.
Example 7 shows the code for the client. When the user clicks on the Submit
button, a new costumer object is generated and passed to the remote find method. Then,
the costumer record is displayed in the text area ( to prove that the clear call in the server
did not effect it ). Finally , the product descriptions of the return products in the vector
are added to the text area. Note that each getDescription is again a remote method
invocation.

152

ALTERNATIVES TO RMI
RMI is just one way to create objects that can be distributed across a network. It
has the advantage of being a pure Java solution, but if you have a lot of code written in
some other language, it might not meet your needs. The two most compelling alternatives
are Microsofts DCOM (which, according to Microsofts plan, will eventually be hosted
on platforms other than Windows) and CORBA, which is supported in Java 1.1 and was
designed from the start to be cross-platform.

LET US SUM UP
In the above Lesson we discussed the need of distributed applications using RMI.
Usage of remote objects and object serialization has been discussed in detail

LESSON END ACTIVITIES


1) Write a remote method that computes weather a given year is leap year or not and
return just a boolean value. Write both client side and the server side programs as
well as the interfaces required.
2) Write two interfaces (Remote) and give one abstract methods each, and try to access
these methods. (e.g one interface could be taken from the previous example. The
other could be a method that returns a string say hello world?)
3) Write a RMI program that connects to the database server and retrievs some
information from the data base. (Please note the java.sql.ResultSet is not Serializable)

POINTS FOR DISCUSSION


Execute those Examples given in this lesson and try to make some changes and
record the output

REFERENCES
Jane Jawroski, Java Unleashed, SAMS Techmedia Publications, 1999
Campione, Walrath and Huml, The Java Tutorial, Addison Wesley 1999

153

LESSON 8: JAVA BEANS


Contents
8.0 Aims and Objectives
8.1. Introduction
8.2.The BeanBox Utility
8.3.Packaging a Bean
8.4.Bean Persistence
Object Serialization
Serialization
Classes that are Serializable
Controlling Serialization
Default Serialization: The Serializable Interface
Selective Serialization Using the transient Keyword
Selective Serialization: writeObject and readObject
The Externalizable Interface
8.5.Long Term Persistence
8.6.Let us Sum UP
8.7.Lesson-End Activities
8.8.Points for Discussion
Model Answers to Check Your Progress
Suggested Readings/References/Sources

AIMS AND OBJECTIVES


At the end of this Lesson, you will be able to understand:
JavaBeans Concepts which describes the basic notion of JavaBeans and
what makes a bean.
Using the NetBeans GUI Builder which describes the NetBeans GUI
Builder within the scope of operating with bean objects.
Writing a Simple Bean walks you through creating a rudimentary bean,
saving the bean, adding the bean to the Palette of the NetBeans GUI Builder
and inspecting the bean's properties and events.
Bean Properties which explains how to give your beans properties: bean
appearance and behavior characteristics that are customizable at design time.
Manipulating Events which describes the JavaBeans event manipulating
capabilities. If you are not familiar with event handling, you might want to
read up on Writing Event Listeners to prepare for this material.
Bean Persistence which explains how to save and restore beans to their
customized state.
Long Term Persistence which explains how to save and load your beans in
the XML format using the XMLDecoder and XMLEncoder classes.

154

Introspection which describes how methods, properties, and events are


discovered in the beans that you write.
Bean Customization which introduces you to property editors, and the
Customizer interface.

INTRODUCTION
JavaBeans is a portable, platform-independent component model written in the
Java programming language. The JavaBeans architecture was built through a
collaborative industry effort and enables developers to write reusable components in
the Java programming language.
With the JavaBeans API you can create reuseable, platform-independent components.
Using JavaBeans-compliant application builder tools, you can combine these
components into applets, applications, or composite components.
JavaBean components are known as beans. Beans are dynamic in that they can be
changed or customized. Through the design mode of a builder tool, you use the
property sheet or bean customizer to customize the bean and then save (persist) your
customized beans.
In many application programs, we require components that do exactly what we need.
Wed like to drop these parts into our design like the electronic engineer puts together
chips on a circuit board. It seems, too, that there should be some way to accelerate this
modular assembly style of programming.
Visual programming first became successful very successful with
Microsofts Visual Basic (VB), followed by a second-generation design in Borlands
Delphi (the primary inspiration for the Java Beans design). With these programming tools
the components are represented visually, which makes sense since they usually display
some kind of visual component such as a button or a text field. The visual representation,
in fact, is often exactly the way the component will look in the running program. So part
of the process of visual programming involves dragging a component from a pallet and
dropping it onto your form. The application builder tool writes code as you do this, and
that code will cause the component to be created in the running program.
However, simply dropping the component onto a form is usually not enough to
complete the program. Often, you must change the characteristics of a component, such
as what color it is, what text is on it, what database its connected to, etc. Characteristics
that can be modified at design time are referred to as properties. You can manipulate the
properties of your component inside the application builder tool, and when you create the
program this configuration data is saved so that it can be rejuvenated when the program is
started.
The characteristics alone do not describe an object completely. An object also has a
set of behaviors. At design-time, the behaviors of a visual component are partially

155

represented by events, meaning Heres something that can happen to the component.
Ordinarily, you decide what you want to happen when an event occurs by tying code to
that event.
This is not all. The application builder tool is able to dynamically interrogate (using
reflection) the component to find out which properties and events the component
supports. Once it knows what they are, it can display the properties and allow you to
change those (saving the state when you build the program), and also display the events.
In general, you do something like double clicking on an event and the application builder
tool creates a code body and ties it to that particular event. All you have to do at that
point is write the code that executes when the event occurs.
All this adds up to a lot of work thats done for you by the application builder tool.
As a result you can focus on what the program looks like and what it is supposed to do,
and rely on the application builder tool to manage the connection details for you. The
reason that visual programming tools have been so successful is that they dramatically
speed up the process of building an application certainly the user interface, but often
other portions of the application as well.
Viewed subjectively, a component is after all really just a block of code, typically
embodied in a class. The key issue is the ability for the application builder tool to
discover the properties and events for that component. To create a VB component, the
programmer had to write a fairly complicated piece of code following certain conventions
to expose the properties and events. Delphi was a second-generation visual programming
tool and the language was actively designed around visual programming so it is much
easier to create a visual component. However, Java has brought the creation of visual
components to its most advanced state with Java Beans, because a Bean is just a class.
You dont have to write any extra code or use special language extensions in order to
make something a Bean. The only thing you need to do, in fact, is slightly modify the
way that you name your methods. It is the method name that tells the application builder
tool whether this is a property, an event, or just an ordinary method.

THE BEANBOX UTILITY


Starting and Using the BeanBox
This section gives you a brief, introductory look at the BeanBox and it's basic
operation. The beans/beanbox directory contains Windows (run.bat) and Unix
(run.sh) scripts that start the BeanBox.
When started, the BeanBox displays three windows: The ToolBox, the BeanBox
window, and the Properties sheet.

156

Here are brief descriptions of each window.

The ToolBox contains the Beans available for use by the BeanBox. To work
on a Bean, you choose it from the ToolBox and drop it on the BeanBox
window.

The BeanBox window is the area where you visually wire Beans together,
defining how Beans appear, and interact with other Beans. The BeanBox
window is itself an instance of a BeanBox Bean. The above screenshot shows
the BeanBox window with a Juggler Bean instance dropped in it. Later
you'll see how to wire the Juggler to two button Beans that start and stop
him juggling.
You select among Beans in the BeanBox window simply by clicking on the
Bean. The selected Bean will have a hatced border, as the Juggler Bean does
in the above screenshot. Which Bean is selected has significance for the
Properties sheet.

The Properties sheet displays the properties for the Bean currently selected
within the BeanBox window. In the above screenshot, the Properties sheet
displays the Juggler Bean's properties. If you drop another Bean in the
BeanBox window, the properties sheet will display that Bean's properties.

157

Adding a Bean to the ToolBox


When the BeanBox is started, it automatically loads the ToolBox with all the
Beans it finds within the JAR files contained in the beans/jars directory.
Move your JAR files into that directory to have them automatically loaded at
BeanBox startup. You can load Beans from JAR files located elsewhere by
using the File|LoadJar... BeanBox menu item.
Dropping a Bean on the BeanBox
Clicking on a Bean name within the ToolBox chooses that Bean for
placement within the BeanBox. To drop a JellyBean instance onto the
BeanBox
1. Click on the word JellyBean in the ToolBox. The cursor will
change to a crosshair when flying over the BeanBox windows.
2. Click within the BeanBox. The JellyBean instance will appear,
and will be selected.
Note the change in the Properties sheet when you put the JellyBean in the
BeanBox. Before you placed the JellyBean in the BeanBox, the BeanBox's
properties were displayed. After placing the JellyBean in the BeanBox, the
JellyBean properties are displayed. If you missed the change, click within
the BeanBox, away from the JellyBean. This will select the BeanBox rather
than the JellyBean. The Properties sheet will then display the BeanBox's
properties.
After dropping a JellyBean instance on the BeanBox, the Properties sheet
displays the JellyBean properties: color, foreground, priceInCents,
background, and font.
Editing Bean Properties
The Properties sheet displays each property's name and its current value.
Values are displayed in an editable text field (strings and numbers), a choice
menu (booleans), or as painted values (colors and fonts). Each property has
an associated property editor. Clicking on a property within the Properties
sheet activates the property's editor. Properties displayed in text fields or
choice menus are edited within the Properties sheet. Because editing their
values requires a more sophisticated user interface, Color and Font
property types use a custom property editor. When you click on a color or
font property a separate panel will pop up to do the editing. Try clicking on
each of the JellyBean properties.
Saving and Restoring Beans
You can save the state of a Bean that your are customizing, and restore the
Bean and its saved state at a later time. The BeanBox uses Java Object
Serialization to save and restore Beans and their state. The following steps
demonstrate how to save and restore a Bean:
1. Drop a JellyBean on the BeanBox.

158

2. Change the color property to anything you want.


3. Select the File|Save menu item. A file browser will pop up; use it to
save the Bean to a file.
4. Select the File|Clear menu item.
5. Select the File|Load menu item. The file browser will again pop up;
use it to retrieve the serialized Bean. The JellyBean will be the
color you chose.
The BeanBox

Making beans
Making beans requires just a naming convention and its fairly simple:
1. For a property named xxx, you typically create two methods: getXxx( ) and
setXxx( ). Note that the first letter after get or set is automatically lowercased to
produce the property name. The type produced by the get method is the same as the
type of the argument to the set method. The name of the property and the type for
the get and set are not related.
2. For a boolean property, you can use the get and set approach above, but you
can also use is instead of get.
3. Ordinary methods of the Bean dont conform to the above naming convention, but
theyre public.
4. For events, you use the listener approach. Its exactly the same as youve been
seeing:
addFooBarListener(FooBarListener)
and
removeFooBarListener(FooBarListener) to handle a FooBarEvent. Most of the

159

time the built-in events and listeners will satisfy your needs, but you can also create
your own events and listener interfaces.
Now you can see that most of those changes had to do with adapting to the get
and set naming conventions in order to make that particular component into a Bean.
We can use these guidelines to create a simple Bean:
Example1
import java.awt.*;
import java.io.*;
import javax.swing.*;
public class ImageViewerBean extends JPanel
implements Serializable
{ public void setFileName(String f)
{ fileName = f;
image = Toolkit.getDefaultToolkit().getImage(fileName);
MediaTracker tracker = new MediaTracker(this);
tracker.addImage(image, 0);
try { tracker.waitForID(0); }
catch (InterruptedException e) {}
repaint();
}
public String getFileName()
{ return fileName;
}
public void paint(Graphics g)
{ if (image == null)
{ g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
}
else
g.drawImage(image, 0, 0, this);
}
public Dimension getPreferredSize()
{ if (image == null)
return new Dimension(MINSIZE, MINSIZE);
return new Dimension(image.getWidth(null),
image.getHeight(null));
}

private static final int MINSIZE = 50;


private Image image = null;
private String fileName = "";

When you look at this code, notice that it really doesnt look any different from
any other JAVA class. For example, all accessor methods begin with get; all mutator
programs begin with set. As we have seen earlier, builder tools use this standard
naming convention to discover properties. For example, fileName is a property of this

160

bean because it has get and set methods. In this particular example, the filename
property is stored in an instance variable that is also called filename. However, a
property doesnt have to be stored in an instance variable- the get method can compute
it some other way.
Getting the Bean Information using the Introspector
One of the most critical parts of the Bean scheme occurs when you drag a
Bean off a palette and plop it down on a form. The application builder tool must be
able to create the Bean (which it can do if theres a default constructor) and then,
without access to the Beans source code, extract all the necessary information to
create the property sheet and event handlers.
One good way to do this would be reflection, which allows all the methods of an
anonymous class to be discovered. This is perfect for solving the Bean problem
without requiring you to use any extra language keywords like those required in other
visual programming languages. In fact, one of the prime reasons that reflection was
added to Java 1.1 was to support Beans (although reflection also supports object
serialization and remote method invocation). So you might expect that the creator of
the application builder tool would have to reflect each Bean and hunt through its
methods to find the properties and events for that Bean.
This is certainly possible, but the Java designers wanted to provide a standard
interface for everyone to use, not only to make Beans simpler to use but also to
provide a standard gateway to the creation of more complex Beans. This interface is
the Introspector class, and the most important method in this class is the static
getBeanInfo( ). You pass a Class handle to this method and it fully interrogates that
class and returns a BeanInfo object that you can then dissect to find properties,
methods, and events.
The example given below shows how we can get a beans properties using bean
descriptor.
import java.beans.*;
import java.lang.reflect.*;
public class BeanDumper
{
public static void dump(Class bean)
{
BeanInfo bi = null;
try
{
bi = Introspector.getBeanInfo(bean,
java.lang.Object.class);
} catch(IntrospectionException ex)
{
System.out.println("Couldn't introspect " +
bean.getName());
System.exit(1);
}

161
PropertyDescriptor[] properties =
bi.getPropertyDescriptors();
for(int i = 0; i < properties.length; i++)
{
Class p = properties[i].getPropertyType();
System.out.println("Property type:\n " +
p.getName());
System.out.println("Property name:\n " +
Method readMethod =
properties[i].getReadMethod();
if(readMethod != null)
System.out.println("Read method:\n " +
readMethod.toString());
Method writeMethod =
properties[i].getWriteMethod();
if(writeMethod != null)
System.out.println("Write method:\n " +
writeMethod.toString());
System.out.println("====================");
}
System.out.println("Public methods:");
MethodDescriptor[] methods =bi.getMethodDescriptors();
for(int i = 0; i < methods.length; i++)
System.out.println(methods[i].getMethod().toString());
System.out.println("======================");
System.out.println("Event support:");
EventSetDescriptor[] events =
bi.getEventSetDescriptors();
for(int i = 0; i < events.length; i++) {
System.out.println("Listener type: " +
events[i].getListenerType().getName());
Method[] lm = events[i].getListenerMethods();
for(int j = 0; j < lm.length; j++)
System.out.println("Listener method:\n "
+lm[j].getName());
MethodDescriptor[] lmd =
events[i].getListenerMethodDescriptors();
for(int j = 0; j < lmd.length; j++)
System.out.println("Method descriptor:\n " +
lmd[j].getMethod().toString());
Method addListener = events[i].getAddListenerMethod();
System.out.println("Add Listener Method:\n " +
addListener.toString());
Method removeListener =
events[i].getRemoveListenerMethod();
System.out.println("Remove Listener Method:\n "
+removeListener.toString());
System.out.println("====================");
}
// Dump the class of your choice:
public static void main(String[] args)
{
if(args.length < 1)
{

System.err.println("usage: \n" +"BeanDumper


fully.qualified.class");
System.exit(0);
}
Class c = null;
try
{
c = Class.forName(args[0]);
} catch(ClassNotFoundException ex)
{
System.err.println("Couldn't find " + args[0]);
System.exit(0);
}
dump(c);
}
}

BeanDumper.dump( ) is the method that does all the work. First it tries to create
a BeanInfo object, and if successful calls the methods of BeanInfo that produce
information about properties, methods, and events. In Introspector.getBeanInfo( ),
youll see there is a second argument. This tells the Introspector where to stop in the
inheritance hierarchy. Here, it stops before it parses all the methods from Object,
since were not interested in seeing those.
For properties, getPropertyDescriptors( ) returns an array of
PropertyDescriptors. For each PropertyDescriptor
you
can
call
getPropertyType( ) to find the class of object that is passed in and out via the
property methods. Then, for each property you can get its pseudonym (extracted from
the method names) with getName( ), the method for reading with getReadMethod( ),
and the method for writing with getWriteMethod( ). These last two methods return a
Method object that can actually be used to invoke the corresponding method on the
object (this is part of reflection).
For the public methods (including the property
methods),
getMethodDescriptors( ) returns an array of MethodDescriptors. For each one you
can get the associated Method object and print out its name.
For the events, getEventSetDescriptors( ) returns an array of (what else?)
EventSetDescriptors. Each of these can be queried to find out the class of the
listener, the methods of that listener class, and the add- and remove-listener methods.
The BeanDumper program prints out all of this information.

A more sophisticated Bean


This next example is slightly more sophisticated, albeit frivolous. Its a canvas
that draws a little circle around the mouse whenever the mouse is moved. When you
press the mouse, the word Bang! appears in the middle of the screen, and an action
listener is fired.

The properties you can change are the size of the circle as well as the color, size,
and text of the word that is displayed when you press the mouse. A BangBean also
has its own addActionListener( ) and removeActionListener( ) so you can attach
your own listener that will be fired when the user clicks on the BangBean. You should
be able to recognize the property and event support:
Example 2
package bangbean;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
public class BangBean extends Canvas
implements Serializable {
protected int xm, ym;
protected int cSize = 20; // Circle size
protected String text = "Bang!";
protected int fontSize = 48;
protected Color tColor = Color.red;
protected ActionListener actionListener;
public BangBean() {
addMouseListener(new ML());
addMouseMotionListener(new MML());
}
public int getCircleSize() { return cSize; }
public void setCircleSize(int newSize) {
cSize = newSize;
}
public String getBangText() { return text; }
public void setBangText(String newText) {
text = newText;
}
public int getFontSize() { return fontSize; }
public void setFontSize(int newSize) {
fontSize = newSize;
}
public Color getTextColor() { return tColor; }
public void setTextColor(Color newColor) {
tColor = newColor;
}
public void paint(Graphics g)
{ g.setColor(Color.black);
g.drawOval(xm - cSize/2, ym - cSize/2,
cSize, cSize);
}
// This is a unicast listener, which is
// the simplest form of listener management:
public void addActionListener (
ActionListener l)
throws TooManyListenersException {
if(actionListener != null)
throw new TooManyListenersException();
actionListener = l;

}
public void removeActionListener(
ActionListener l) {
actionListener = null;
}
class ML extends MouseAdapter {
public void mousePressed(MouseEvent e) {
Graphics g = getGraphics();
g.setColor(tColor);
g.setFont(
new Font(
"TimesRoman", Font.BOLD, fontSize));
int width =
g.getFontMetrics().stringWidth(text);
g.drawString(text,
(getSize().width - width) /2,
getSize().height/2);
g.dispose();
// Call the listener's method:
if(actionListener != null)
actionListener.actionPerformed(
new ActionEvent(BangBean.this,
ActionEvent.ACTION_PERFORMED, null));
}
}
class MML extends MouseMotionAdapter
{ public void mouseMoved(MouseEvent e)
{
xm = e.getX();
ym = e.getY();
repaint();
}
}
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
// Testing the BangBean:
public static void main(String[] args) {
BangBean bb = new BangBean();
try {
bb.addActionListener(new BBL());
} catch(TooManyListenersException e) {}
Frame aFrame = new Frame("BangBean Test");
aFrame.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
aFrame.add(bb, BorderLayout.CENTER);
aFrame.setSize(300,300);
aFrame.setVisible(true);
}
// During testing, send action information
// to the console:
static class BBL implements ActionListener

System.out.println("BangBean action");
}
}

The first thing youll notice is that BangBean implements the Serializable interface.
This means that the application builder tool can pickle all the information for the
BangBean using serialization after the program designer has adjusted the values of the
properties. When the Bean is created as part of the running application, these
pickled properties are restored so that you get exactly what you designed.
You can see that all the fields are private, which is what youll usually do with a
Bean allow access only through methods, usually using the property scheme.
When you press the mouse, the text is put in the middle of the BangBean, and if
the actionListener field is not null, its actionPerformed( ) is called, creating a new
ActionEvent object in the process. Whenever the mouse is moved, its new
coordinates are captured and the canvas is repainted (erasing any text thats on the
canvas, as youll see).
The main( ) is added to allow you to test the program from the command line.
When a Bean is in a development environment, main( ) will not be used, but its
helpful to have a main( ) in each of your Beans because it provides for rapid testing.
main( ) creates a Frame and places a BangBean within it, attaching a simple
ActionListener to the BangBean to print to the console whenever an ActionEvent
occurs. Usually, of course, the application builder tool would create most of the code
that uses the Bean.
When you run the BangBean through BeanDumper or put the BangBean inside a
Bean-enabled development environment, youll notice that there are many more
properties and actions than are evident from the above code. Thats because
BangBean is inherited from Canvas, and Canvas is a Bean, so youre seeing its
properties and events as well.

PACKAGING A BEAN
Before you can bring a Bean into a Bean-enabled visual builder tool, it must be put
into the standard Bean container, which is a JAR (Java ARchive) file that includes all the
Bean classes as well as a manifest file that says This is a Bean. A manifest file is
simply a text file that follows a particular form. For the BangBean, the manifest file
looks like this:
Manifest-Version: 1.0
Name: bangbean/BangBean.class
Java-Bean: True

The first line indicates the version of the manifest scheme, which until further notice
from Sun is 1.0. The second line (empty lines are ignored) names the BangBean.class
file, and the third says, Its a Bean. Without the third line, the program builder tool will
not recognize the class as a Bean.
The only tricky part is that you must make sure that you get the proper path in the
Name: field. If you look back at BangBean.java, youll see its in package bangbean
(and thus in a subdirectory called bangbean thats off of the classpath), and the name in
the manifest file must include this package information. In addition, you must place the
manifest file in the directory above the root of your package path, which in this case
means placing the file in the directory above the bangbean subdirectory. Then you must
invoke jar from the same directory as the manifest file, as follows:
jar cfm BangBean.jar BangBean.mf bangbean
This assumes that you want the resulting JAR file to be named BangBean.jar and
that youve put the manifest in a file called BangBean.mf.
You might wonder What about all the other classes that were generated when I compiled
BangBean.java? Well, they all ended up inside the bangbean subdirectory, and youll
see that the last argument for the above jar command line is the bangbean subdirectory.
When you give jar the name of a subdirectory, it packages that entire subdirectory into
the jar file (including, in this case, the original BangBean.java source-code file you
might not choose to include the source with your own Beans). In addition, if you turn
around and unpack the JAR file youve just created, youll discover that your manifest
file isnt inside, but that jar has created its own manifest file (based partly on yours)
called MANIFEST.MF and placed it inside the subdirectory META-INF (for metainformation). If you open this manifest file youll also notice that digital signature
information has been added by jar for each file, of the form:
Digest-Algorithms: SHA MD5
SHA-Digest: pDpEAG9NaeCx8aFtqPI4udSX/O0=
MD5-Digest: O4NcS1hE3Smnzlp2hj6qeg==
In general, you dont need to worry about any of this, and if you make changes you
can just modify your original manifest file and re-invoke jar to create a new JAR file for
your Bean. You can also add other Beans to the JAR file simply by adding their
information to your manifest.
One thing to notice is that youll probably want to put each Bean in its own
subdirectory, since when you create a JAR file you hand the jar utility the name of a
subdirectory and it puts everything in that subdirectory into the JAR file. Once you have
your Bean properly inside a JAR file you can bring it into a Beans-enabled programbuilder environment. The way you do this varies from one tool to the next, but Sun
provides a freely-available test bed for Java Beans in their Beans Development Kit
(BDK) called the beanbox.. To place your Bean in the beanbox, copy the JAR file into

the

BDKs

jars

subdirectory

before

you

start

up

the beanbox.

More complex Bean support


It has been seen here that it would be very easy to write beans. However real world
beans are much more elaborate and tedious to code than the examples we have seen
here, for two reasons.
1. Beans need to be usable by less-than-expert programmers. Such people will access
most of the functionality of your bean with a visual design tool that uses essentially no
programming. You need to expose lots of properties to make it easy to customize bean
behavior.
2. The same bean needs to be used in a wide variety of contexts. A bean that is too
simplistic to be usable in the real world wont get much respect.
So it would be instructive to see where a bean can get complicated. One place where
you can add sophistication is with properties. The examples above have shown only
single properties, but its also possible to represent multiple properties in an array. This is
called an indexed property . You simply provide the appropriate methods (again
following a naming convention for the method names) and the Introspector recognizes
an indexed property so your application builder tool can respond appropriately.
Properties can be bound, which means that they will notify other objects via a
PropertyChangeEvent. The other objects can then choose to change themselves based
on the change to the Bean.
Properties can be constrained, which means that other objects can veto a change to
that property if it is unacceptable. The other objects are notified using a
PropertyChangeEvent, and they can throw a ProptertyVetoException to prevent the
change from happening and to restore the old values.
You can also change the way your Bean is represented at design time:
1. You can provide a custom property sheet for your particular Bean. The ordinary
property sheet will be used for all other Beans, but yours is automatically invoked when
your Bean is selected.
2. You can create a custom editor for a particular property, so the ordinary property
sheet is used, but when your special property is being edited, your editor will
automatically be invoked.
3. You can provide a custom BeanInfo class for your Bean that produces information
thats different from the default created by the Introspector.
4. Its also possible to turn expert mode on and off in all FeatureDescriptors to
distinguish between basic features and more complicated ones.

BEAN PERSISTENCE
A bean has the property of persistence when its properties, fields, and state information
are saved to and retrieved from storage. Component models provide a mechanism for

persistence that enables the state of components to be stored in a non-volatile place for
later retrieval.
Object serialization
Serialization is a process of reading or writing an object. It is a process of saving an
objects state to a sequence of bytes, as well as a process of rebuilding those bytes back
into a live object at some future time. An object is marked serializable by implementing
the java.io.Serializable interface, which is only a marker interfaceit simply allows the
serialization mechanism to verify that the class can be persisted.
Serialization has a number of advantages. It provides:

a simple and robust way to make objects persistent


a method of issuing remote procedure calls
a method for distributing objects, especially in software componentry such as
COM, CORBA, etc.

For some of these features to be useful, architecture independence must be maintained.


For example, for maximal use of distribution, a computer running on a different hardware
architecture should be able to reliably reconstruct a serialized data stream. This means
that the simpler and faster procedure of directly copying the memory layout of the data
structure cannot work reliably for all architectures. Serializing the data structure in an
architecture independent format means that we do not suffer from the problems of byte
ordering, memory layout, or simply different ways of representing data structures in
different programming languages.
Serializing Objects : An object is serialization only if its implements the Serializable
interface. The class must implement the Serializable interface. Serializable is an emplty
interface. It doesn't contain any method declaration. Its purpose is simply to identify
classes whose objects are serializable.
Implementing the Serializable Interface:
package java.io;
public interface Serializable
{
}
Making instances of the classes serializable is easy. Just add the implements Serializable
clause to your class declaration
public class MySerialClass implements Serializable
{
}
Serialization has the disadvantage that because the encoding of the data is serial, merely
extracting one part of the data structure that is serialized means that the entire object must
be reconstructed or read before this can be done.
Serialization
The mechanism that makes persistence possible is called serialization. Object
serialization means converting an object into a data stream and writing it to storage. Any

applet, application, or tool that uses that bean can then "reconstitute" it by deserialization.
The object is then restored to its original state.
For example, a Java application can serialize a Frame window on a Microsoft Windows
machine, the serialized file can be sent with e-mail to a Solaris machine, and then a Java
application can restore the Frame window to the exact state which existed on the
Microsoft Windows machine.
Any applet, application, or tool that uses that bean can then "reconstitute" it
deserialization.

by

All beans must persist. To persist, your beans must support serialization by implementing
either the java.io.Serializable(in the API reference documentation) interface, or the
java.io.Externalizable(in the API reference documentation) interface. These
interfaces offer you the choices of automatic serialization and customized serialization. If
any class in a class's inheritance hierarchy implements Serializable or
Externalizable, then that class is serializable.
Classes that are Serializable
Any class is serializable as long as that class or a parent class implements the
java.io.Serializable interface. Examples of serializable classes include
Component, String, Date, Vector, and Hashtable. Thus, any subclass of the
Component class, including Applet, can be serialized. Notable classes not supporting
serialization include Image, Thread, Socket, and InputStream. Attempting to
serialize objects of these types will result in an NotSerializableException.
The Java Object Serialization API automatically serializes most fields of a Serializable
object to the storage stream. This includes primitive types, arrays,and strings. The API
does not serialize or deserialize fields that are marked transient or static.
Controlling Serialization
You can control the level of serialization that your beans undergo. Three ways
to control serilization are:
Automatic serialization, implemented by the Serializable interface. The
Java serialization software serializes the entire object, except transient and static
fields.
Customized serialization. Selectively exclude fields you do not want serialized by
marking with the transient (or static) modifier.
Customized file format, implemented by the Externalizable interface and
its two methods. Beans are written in a specific file format.
Default Serialization: The Serializable Interface
The Serializable interface provides automatic serialization by using the Java Object
Serialization tools. Serializable declares no methods; it acts as a marker, telling the
Object Serialization tools that your bean class is serializable. Marking your class
Serializable means you are telling the Java Virtual Machine (JVM) that you have

170

made sure your class will work with default serialization. Here are some important points
about working with the Serializable interface:
Classes that implement Serializable must have an access to a noargument constructor of supertype. This constructor will be called when an
object is "reconstituted" from a .ser file.
You don't need to implement Serializable in your class if it is
already implemented in a superclass.
All fields except static and transient fields are serialized. Use the transient
modifier to specify fields you do not want serialized, and to specify classes that are
not serializable.
Selective Serialization Using the transient Keyword
To exclude fields from serialization in a Serializable object from serialization, mark
the fields with the transient modifier.
transient int status;
Default serialization will not serialize transient and static fields.
Selective Serialization: writeObject and readObject
If your serializable class contains either of the following two methods (the signatures
must be exact), then the default serialization will not take place.
private void writeObject(java.io.ObjectOutputStream out)
throws IOException;
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;

You can control how more complex objects are serialized, by writing your own
implementations of the writeObject and readObject methods. Implement
writeObject when you need to exercise greater control over what gets serialized when
you need to serialize objects that default serialization cannot handle, or when you need to
add data to the serialization stream that is not an object data member. Implement
readObject to reconstruct the data stream you wrote with writeObject.
The Externalizable Interface
Use the Externalizable interface when you need complete control over your bean's
serialization (for example, when writing and reading a specific file format). To use the
Externalizable interface you need to implement two methods: readExternal and
writeExternal. Classes that implement Externalizable must have a no-argument
constructor.
Check you Progress
How implement Persistent Objects?
Note: Write your answer in the space given below:
Check your answer with one given at the end of this Lesson

171

LONG TERM PERSISTENCE


Long-term persistence is a model that enables beans to be saved in XML format.
Information on the XML format and on how to implement long-term persistence for nonbeans can be found in XML Schema and Using XMLEncoder .
Encoder and Decoder
The XMLEncoder class is assigned to write output files for textual
representation of Serializable objects. The following code fragment is an
example of writing a Java bean and its properties in XML format:
XMLEncoder encoder = new XMLEncoder(
new BufferedOutputStream(
new FileOutputStream( "Beanarchive.xml"
) ) );
encoder.writeObject( object );
encoder.close();
The XMLDecoder class reads an XML document that was created with XMLEncoder:

) );

XML

XMLDecoder decoder = new XMLDecoder(


new BufferedInputStream(
new FileInputStream( "Beanarchive.xml" )
Object object = decoder.readObject();
decoder.close();

An XML bean archive has its own specific syntax, which includes the following
tags to represent each bean element:
an XML preamble to describe a version of XML and type of encoding
a <java> tag to embody all object elements of the bean
an <object> tag to represent a set of method calls needed to reconstruct an object
from its serialized form

<object class="javax.swing.JButton"
method="new">
<string>Ok</string>
</object>
or statements
<object class="javax.swing.JButton">
<void method="setText">
<string>Cancel</string>
</void>
</object>

tags to define appropriate primitive types:


o <boolean>
o <byte>
o <char>
o <short>
o <int>
o <long>
o <float>
o <double>

<int>5555</int>

a <class> tag to represent an instance of Class.

<class>java.swing.JFrame</class>

an <array> tag to define an array

<array class="java.lang.String" length="5">

</array>

The following code represents an XML archive that will be generated for the
SimpleBean component:
<?xml version="1.0" encoding="UTF-8" ?>
<java>
<object class="javax.swing.JFrame">
<void method="add">
<object class="java.awt.BorderLayout" field="CENTER"/>
<object class="SimpleBean"/>
</void>
<void property="defaultCloseOperation">
<object class="javax.swing.WindowConstants"
field="DISPOSE_ON_CLOSE"/>
</void>
<void method="pack"/>
<void property="visible">
<boolean>true</boolean>
</void>

</object>
</java>

LET US SUM UP
JavaBeans are classes written in the Java programming language conforming to a
particular convention. They are used to encapsulate many objects into a single object (the
bean), so that the bean can be passed around rather than the individual objects.
The specification by Sun Microsystems defines them as "reusable software components
that can be manipulated visually in a builder tool".

LESSON END ACTIVITY


1. Write a program to create a new component date field. Make this component by
deriving it from the textfield. This component accepts only dates in the format
dd/mm/yy. It does not allow the user to enter any other type of data into it.
Make a JAVA bean for this component.
2. Write a bean to implement a password field. The letters typed must not be
displayed. Instead * must be displayed.
3. Write a bean to implement a clock component. The component can inherit from
either a tect field or a label. It must display the time at every instant [ Hint : Make
use of threading concept for keeping time.
4. Make a graphical user interface, consisting of a frame. Put the components
created in the previous three exercise on this frame. Let there also be two buttons
OK and Cancel. Use a suitable layout to organize these components neatly.
The graphical user interface must requests the user to type his date of birth in the
date field, then type the password in the password field and then press the OK
button. The program must display a message box based on this input. If the
password is correct and the data is in the right format, the message box must
display Welcome user . If the date is not in right format the message will be
Please enter birthday properly. If password is wrong, message will be Invalid
password. The program must also keep track of time. If the user takes more than
one minute to give his response message will be Sorry! Your times up.
5. Convert the graphical user interface for calculator, created in the chapter on
Swing into a bean.

POINTS TO DISCUSSION
Discuss the following:

BeanInfo
Bean
Properties
Methods

Event Sources

MODEL ANSWERS TO CHECK YOUR PROGRESS


Solution:
Java code should be made that implements object methods to actual SQL statements
however there is several already usable Persistence libraries. One is WebApp Framework
created by Peter Robach and Hendrik Schreiber. This library is has very high
performance and features but with high cost. Another is included in Oracle distribution
named Business Object for Java. This library is huge with lot of features, but
unfortunately this library has little performance and errors. But it is easy and not requires
mach of effort to implement such library, what is done with help of people in my
previous projects. Persistence library named INetForms originally meant to be for
MySQL database, but later expanded with support for Oracle and functionality not
related to persistence.

REFERENCES
Jane Jawroski, Java Unleashed, SAMS Techmedia Publications, 1999
Campione, Walrath and Huml, The Java Tutorial, Addison Wesley 1999
http://java.sun.com/docs/books/tutorial/javabeans/whatis/index.html

LESSON 9: JAVA DATABASE CONNECTIVITY (JDBC)


Contents
9.0 Aims and Objectives
Introduction
JDBC Architecture
Driver Architecture
Structured Query Language
Executing queries
Creating Multimedia Databases
9.6.Let us Sum up
9.7.Lesson-End Activities
9.8.Points for Discussion
9.9.Suggested Readings/References/Sources

AIMS AND OBJECTIVES


After the end of this lesson you can able to understand

Understand JDBC
Architecture of JDBC
SQL commands in JDBC

INTRODUCTION
In the summer of 1996,Sun released the first version of the JDBC (Java database
connectivity) kit. This package lets the user connect to a database, query it, or update it,
using SQL (Structured query language). This is one of the most important developments
in programming for JAVA platform. It is not just that databases are among the most
common use of hardware and software today. The more important reason that Java and
JDBC have an essential advantage over other database programming environments is
this:

Programs developed with the JAVA programming language and JDBC are
platform independent and vendor independent.

The same database program written in the JAVA programming language can
run on a NT box, a Solaris server, or a database appliance powered by the JAVA
platform. You can move your data from one database to another, for example, from
Microsoft SQL Server to Oracle, or even a tiny database embedded in a device, and
the same program can still read your data. This is in sharp contrast to traditional
database programming. It is all too common that one writes database

applications in a propriety database language, using a database management system


that is available from only a single vendor. The result is that you can run the
resulting applications only on one or two platforms.

9.2. JDBC ARCHITECTURE


Two-tier and Three-tier Processing Models
The JDBC API supports both two-tier and three-tier processing models for database
access.
Figure 9.1: Two-tier Architecture for Data Access.

In the two-tier model, a Java applet or application talks directly to the data source. This
requires a JDBC driver that can communicate with the particular data source being
accessed. A user's commands are delivered to the database or other data source, and the
results of those statements are sent back to the user. The data source may be located on
another machine to which the user is connected via a network. This is referred to as a
client/server configuration, with the user's machine as the client, and the machine housing
the data source as the server. The network can be an intranet, which, for example,
connects employees within a corporation, or it can be the Internet.
In the three-tier model, commands are sent to a "middle tier" of services, which then
sends the commands to the data source. The data source processes the commands and
sends the results back to the middle tier, which then sends them to the user. MIS directors
find the three-tier model very attractive because the middle tier makes it possible to
maintain control over access and the kinds of updates that can be made to corporate data.
Another advantage is that it simplifies the deployment of applications. Finally, in many
cases, the three-tier architecture can provide performance advantages.

Figure 2: Three-tier Architecture for Data Access.

Until recently, the middle tier has often been written in languages such as C or C++,
which offer fast performance. However, with the introduction of optimizing compilers
that translate Java bytecode into efficient machine-specific code and technologies such as
Enterprise JavaBeans, the Java platform is fast becoming the standard platform for
middle-tier development. This is a big plus, making it possible to take advantage of Java's
robustness, multithreading, and security features.
With enterprises increasingly using the Java programming language for writing server
code, the JDBC API is being used more and more in the middle tier of a three-tier
architecture. Some of the features that make JDBC a server technology are its support for
connection pooling, distributed transactions, and disconnected rowsets. The JDBC API is
also what allows access to a data source from a Java middle tier.

DRIVER ARCHITECTURE
From the start, the developers of the Java technology at Sun were aware of
the potential Java showed for wording with databases. Starting in 1995, they began
working on extending the standard java library to deal with SQL access to
databases. What they first hoped to do was to extend Java so that it could talk to
any random database, using only pure Java. it didnt take them very long to
realize that this is impossible task: there are simply too many databases out there,
using too many protocols. Moreover, while database vendors were all in favor of Sun
providing a standard network protocol for database access, they were only in favor
of it if Sun decided to use their network protocol.
What all the database vendors and tool vendors did agree on was that it would be
useful if Sun provided a pure Java API for SQL access along with a driver manager to
allow third-party drivers to connect to specific database. database vendors could provide
their own drivers to plug into the driver manager. There would then be a simple
mechanism for registering third-party drivers with the driver manager-the point being that
all the drivers needed to do was follow the requirements laid out in the driver manager
API.

After a fairly long period of public discussion, the API or database access became
the JDBC API, and the rules for writing drivers were encapsulated in the JDBC driver
API. (the JDBC driver API is of interest only to database vendors and database tool
providers; we dont cover it here.)
This protocol follows the very successful model of Microsofts ODBC, which
provided a C programming language interface for database access. Both JDBC and
ODBC are based on the same idea: Programs written according to the JDBC API would
talk to the JDBC driver manager, which, in turn, would use the drivers that were plugged
into it at that moment to talk to the actual database.
JDBC/ODBC
Bridge

Java application

JDBC Driver Manager

Database

ODBC
driver

VendorSupplied
JDBC driver

Database

JDBC-to-database communication path

More precisely, the JDBC consists of three layers. The top layer is the JDBC
API. This API communicates with the JDBC manager driver API, sending it the various
SQL statements. The manager should (transparently to the programmer) communicate
with the various third-party drivers that actually connect to the database and return the
information from the query or perform the action specified by the query.
All this means the Java/JDBC layer is all that most programmers will ever have to deal
with.
JDBC drivers are classified into the following types:

A type 1 driver translates JDBC to ODBC and relies on an ODBC driver to


communicate with the database. Sun includes one such driver, the JDBC/ODBC
bridge, with the JDK. However, the bridge does not support JDBC, and it requires
deployment and proper configuration of an ODBC driver. The bridge is handy for
testing, but we dont recommend it for production use.
A type 2 driver is a driver, written partly in the Java programming language and
partly in native code, that communicates with the client API of a data-base. When
you use such a driver, you must install some platform specific code in addition
to a Java library.

A type 3 driver is a pure Java client library that uses a database-independent


protocol to communicate database requests to a server component, which then
translates the requests into a database-specific protocol. The client library is
independent of the actual database, thus simplifying deployment.
A type 4 driver is a pure Java library that translates JDBC requests directly to a
database-specific protocol.

Most database vendors supply either a type 3 or a type 4 driver with their
database. Furthermore, a number of third party companies specialize in producing drivers
with better standards conformance, support for more platforms, or in some cases, simply
better reliability than the drivers that are provided by database vendors.
In summary, the ultimate goal of JDBC is to make possible the following:

Programmers can write applications in the JAVA programming language to


access any database, using standard SQL statements-or even specialized
extensions of SQL_while still following JAVA language conventions.
Database vendors and database tool vendors can supply the low_level
drivers.Thus they can optimize their drivers for their specific products.

Connecting and interacting with the database:


One of the most important steps in the design of a database program, is that of
establishing connectivity between the front end and the back end. Here the front end is
JAVA. The back end can be SQL Server, Oracle, Access, FoxPro or any other such
database manipulation language. This consists of a set of routine steps that are same for
all programs. Nevertheless, it will be worth wile to study, in detail, the steps involved and
the significance of each step, in order to get a better insight about how JDBC actually
works.
To allow platform independence, JDBC provides a driver manager that
dynamically maintains all the driver objects that your database queries will need. So if
you have three different kinds of vendor databases to connect to, youll need three
different driver objects. The driver objects register themselves with the driver manager at
the time of loading, and you can force the loading using Class.forName( ).
To open a database, you must create a database URL that specifies:
1. That youre using JDBC with jdbc
2. The subprotocol: the name of the driver or the name of a database connectivity
mechanism. Since the design of JDBC was inspired by ODBC, the first
subprotocol available is the jdbc-odbc bridge, specified by odbc
3. The database identifier. This varies with the database driver used, but it generally
provides a logical name that is mapped by the database administration software to

180

a physical directory where the database tables are located. For your database
identifier to have any meaning, you must register the name using your database
administration software. (The process of registration varies from platform to
platform.)
All this information is combined into one string, the database URL. For
example, to connect through the ODBC subprotocol to a database identified as people,
the database URL could be:
String dbUrl = "jdbc:odbc:people";
If youre connecting across a network, the database URL will also contain the
information identifying the remote machine.
When youre ready to connect to the database, you call the static method
DriverManager.getConnection( ), passing it the database URL, the user name, and a
password to get into the database. You get back a Connection object that you can then
use to query and manipulate the database.
The following example opens a database of contact information and looks for a
persons last name as given on the command line. It selects only the names of people that
have email addresses, then prints out all the ones that match the given last name:
//: Lookup.java
// Looks up email addresses in a
// local database using JDBC
import java.sql.*;
public class Lookup
{
public static void main(String[] args)
{
String dbUrl = "jdbc:odbc:people";
String user = "";
String password = "";
try
{
// Load the driver (registers itself)
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection
c
=
DriverManager.getConnection(dbUrl,
user, password);
Statement s = c.createStatement();
// SQL code:
ResultSet r =
s.executeQuery( "SELECT FIRST,
LAST, EMAIL " +
"FROM people.csv people " +
"WHERE " +
"(LAST='" + args[0] + "') " +
" AND (EMAIL Is Not Null) " +
"ORDER BY FIRST");
while(r.next())
{

181
// Capitalization doesn't matter:
System.out.println(
r.getString("Last") + ", "
+ r.getString("fIRST")
+ ": " + r.getString("EMAIL") );

}
s.close(); // Also closes ResultSet
} catch(Exception e) {e.printStackTrace();}

You can see the creation of the database URL as previously described. In this
example, there is no password protection on the database so the user name and password
are empty strings.
Once the connection is made with DriverManager.getConnection( ), you can
use the resulting Connection object to create a Statement object using the
createStatement( ) method. With the resulting Statement,
you
can
call
executeQuery( ), passing in a string containing an SQL-92 standard SQL statement.
(Youll see shortly how you can generate this statement automatically, so you dont have
to know much about SQL.)
The executeQuery( ) method returns a ResultSet object, which is quite a bit like
an iterator: the next( ) method moves the iterator to the next record in the statement, or
returns null if the end of the result set has been reached. Youll always get a ResultSet
object back from executeQuery( ) even if a query results in an empty set (that is, an
exception is not thrown). Note that you must call next( ) once before trying to read any
record data. If the result set is empty, this first call to next( ) will return false. For each
record in the result set, you can select the fields using (among other approaches) the field
name as a string. Also note that the capitalization of the field name is ignored it doesnt
matter with an SQL database. You determine the type youll get back by calling getInt( ),
getString( ), getFloat( ), etc. At this point, youve got your database data in Java native
format and can do whatever you want with it using ordinary Java code.
Getting the example to work
With JDBC, understanding the code is relatively simple. The confusing part is
making it work on your particular system. The reason this is confusing is that it requires
you to figure out how to get your JDBC driver to load properly, and how to set up a
database using your database administration software.
Of course, this process can vary radically from machine to machine, but the
process I used to make it work under 32-bit Windows might give you clues to help you
attack your own situation.

182

Step 1: Find the JDBC Driver


The program above contains the statement:
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
This implies a directory structure, which is deceiving. With this particular
installation of JDK 1.1, there was no file called JdbcOdbcDriver.class, so if you looked
at this example and went searching for it youd be frustrated. Other published examples
use a pseudo name, such as myDriver.ClassName, which is less than helpful. In fact,
the load statement above for the jdbc-odbc driver (the only one that actually comes with
JDK 1.1) appears in only a few places in the online documentation (in particular, a page
labeled JDBC-ODBC Bridge Driver). If the load statement above doesnt work, then
the name might have been changed as part of a Java version change, so you should hunt
through the documentation again.
If the load statement is wrong, youll get an exception at this point. To test
whether your driver load statement is working correctly, comment out the code after the
statement and up to the catch clause; if the program throws no exceptions it means that
the driver is loading properly.
Step 2: Configure the database
Again, this is specific to 32-bit Windows; you might need to do some research to
figure it out for your own platform.
First, open the control panel. You might find two icons that say ODBC. You
must use the one that says 32bit ODBC, since the other one is for backwards
compatibility with 16-bit ODBC software and will produce no results for JDBC. When
you open the 32bit ODBC icon, youll see a tabbed dialog with a number of tabs,
including User DSN, System DSN, File DSN, etc., in which DSN means Data
Source Name. It turns out that for the JDBC-ODBC bridge, the only place where its
important to set up your database is System DSN, but youll also want to test your
configuration and create queries, and for that youll also need to set up your database in
File DSN. This will allow the Microsoft Query tool (that comes with Microsoft Office)
to find the database. Note that other query tools are also available from other vendors.
The most interesting database is one that youre already using. Standard ODBC
supports a number of different file formats including such venerable workhorses as
DBase. However, it also includes the simple comma-separated ASCII format, which
virtually every data tool has the ability to write. In my case, I just took my people
database that Ive been maintaining for years using various contact-management tools
and exported it as a comma-separated ASCII file (these typically have an extension of
.csv). In the File DSN section I chose Add, chose the text driver to handle my

183

comma-separated ASCII file, and then un-checked use current directory to allow me to
specify the directory where I exported the data file.
Youll notice when you do this that you dont actually specify a file, only a
directory. Thats because a database is typically represented as a collection of files under
a single directory (although it could be represented in other forms as well). Each file
usually contains a single table, and the SQL statements can produce results that are culled
from multiple tables in the database (this is called a join). A database that contains only a
single table (like this one) is usually called a flat-file database . Most problems that go
beyond the simple storage and retrieval of data generally require multiple tables that must
be related by joins to produce the desired results, and these are called relational
databases.
Step 3: Test the configuration
To test the configuration youll need a way to discover whether the database is
visible from a program that queries it. Of course, you can simply run the JDBC program
example above up to and including the statement:
Connection
password);

DriverManager.getConnection(

dbUrl,

user,

If an exception is thrown, your configuration was incorrect. However, its useful


to get a query-generation tool involved at this point. Well use Microsoft Query that
comes with Microsoft Office( Of course this is not the only choice we have) . The query
tool must know where the database is, and Microsoft Query requires that we go to the
ODBC Administrators File DSN tab and add a new entry there, again specifying the
text driver and the directory where my database lives. You can name the entry anything
you want, but its helpful to use the same name you used in System DSN.
Once weve done this, we will see that your database is available when you create
a new query using your query tool.
Step 4: Generate your SQL query
Well write a query that would search for records that had the last name that was
typed on the command line when starting the Java program. So as a starting point, well
search for a specific last name, Shankar. Well also try to display only those names that
had email addresses associated with them. The steps to create this query are:
1. Start a new query and use the Query Wizard. Select the people database. (This
is the equivalent of opening the database connection using the appropriate
database URL.)
2. Select the people table within the database. From within the table, choose the
columns FIRST, LAST, and EMAIL.

184

3. Under Filter Data, choose LAST and select equals with an argument of
Shankar. Click the And radio button.
4. Choose EMAIL and select Is not Null.
5. Under Sort By, choose FIRST.
The result of this query will show you whether youre getting what you want. Now you
can press the SQL button and without any research on your part, up will pop the correct
SQL code, ready for you to cut and paste. For this query, it would look like this:
SELECT people.FIRST, people.LAST, people.EMAIL
FROM people.csv people
WHERE (people.LAST='Shankar') AND
(people.EMAIL Is Not Null)
ORDER BY people.FIRST
With more complicated queries its easy to get things wrong, but with a query tool
you can interactively test your queries and automatically generate the correct code. Its
hard to argue the case for doing this by hand.
Step 5: Modify and paste in your query
Youll notice that the code above looks different from whats used in the program.
Thats because the query tool uses full qualification for all of the names, even when
theres only one table involved. (When more than one table is involved, the qualification
prevents collisions between columns from different tables that have the same names.)
Since this query involves only one table, you can optionally remove the people
qualifier from most of the names, like this:
SELECT FIRST, LAST, EMAIL
FROM people.csv people
WHERE (LAST='Shankar') AND
(EMAIL Is Not Null)
ORDER BY FIRST
In addition, you dont want this program to be hard coded to look for only one
name. Instead, it should hunt for the name given as the command-line argument. Making
these changes and turning the SQL statement into a dynamically-created String
produces:
"SELECT FIRST, LAST, EMAIL " +
"FROM people.csv people " +
"WHERE " +
"(LAST='" + args[0] + "') " +
" AND (EMAIL Is Not Null) " +
"ORDER BY FIRST");

185

SQL has another way to insert names into a query called stored procedures , which is
used for speed. But for much of your database experimentation and for your first cut,
building your own query strings in Java is fine.
You can see from this example that by using the tools currently available in particular
the query-building tool database programming with SQL and JDBC can be quite
straightforward.

STRUCTURED QUERY LANGUAGE


From the previous example, it is evident that, in order to write a database
program, we have to have at least a basic knowledge of the SQL commands. Though, it is
possible to create a query without having knowledge of SQL, as illustrated in the
previous section, using Microsoft Query, it is helpful to have at least an elementary
knowledge of SQL.This enables us to perform custom retrievals, which may not be
possible using the Wizard. A complete study of Structured query language would be part
of the study of a database management language. So we will not attempt to go into the
depths of SQL here. We shall, however take a look at the syntax and function of some of
the most commonly used SQL commands.
The SQL statements can be classified broadly into three types, namely :

Data retrieval
Data manipulation language
Data definition language

We shall deal with the most commonly used statements, belonging to each one of these
three types.
Data retrieval:
These statements are generally known as queries. They start with the word select. The
syntax is as follows
SELECT [(column_name [,column_name])] FROM table_name
condition(s)]

[WHERE

column_name refers to the columns of the table, whose data we desire to see
table_name is the table from which we want data
condition(s) refers to the conditions we may set to restrict the records retrieved
The result of this query will be obtained by assigning it to a ResultSet, about which we
dealt in the previous section. From the ResultSet, we can recover the required data in
appropriate form.

186

Data manipulation:
Insertion, updating and deletion are the operations carried out by data manipulation
language. The syntax of each of them is given below.
INSERT INTO table_name [(column_name [, column_name])] VALUES (value [,
value])
UPDATE table_name
SET column_name = VALUE [, column = value]
[WHERE condition]
DELETE [FROM] table_name
[WHERE condition]
Here also the notations are almost similar to the last case. The notation value refers to the
value will be setting to the fields in the record we are inserting or updating.
Data definition:
These statements help in creating, deleting or renaming a table during runtime. They also
help in modifying a table. The syntaxes of some of these statements are given below.
CREATE TABLE table_name (column_name datatype [DEFAULT expr])
ALTER TABLE table_name
ADD (column_name datatype [DEFAULT expr] [,datatype])
ALTER TABLE table_name
MODIFY (column_name datatype [DEFAULT expr] [,datatype])
DROP TABLE table_name
Here also column and datatype mean the same as in earlier cases. datatype refers to
the datatype of the column in the table. expr refers to the expression that will be used to
compute default values for a column, in case values are not set for that particular field.
Application of JDBC:
Usually JDBC is useful in creating user friendly applications with a graphical user interface. To do this, it is used along with Swing
features to make some applications that require access to a database. Here we shall see a few simple examples, in which the JDBC
concepts are made use of.

Populating a database:

187

The first thing we must have, in order to write a JDBC program is a database. So
we shall first write a program for creating a database. Then we shall write other programs
that run using this database that we create. Here data is provided to the program as text
files. It is very easy to create these text files. The format in which the data must exist in
the text file will be given. So one can use his own set of data and make these text files.
Four text files have to be made. The first file is authors . The fields in it are Author_Id
char(4), Name char(25), URL char(80).Let this be the first line in the text file. The
program turns the first line into a CREATE TABLE statement such as CREATE
TABLE Authors(Author_Id char(4), Name char(25), URL char(80)).The data starts from
the next line onwards. Here is a sample data
'ARON', 'Aronson, Larry', 'www.interport.net/~laronson/Homepage.html'
Data, in similar form should be given, one set of data on each line.
Similarly, we have Books with fields Title char(60), ISBN char(13), Publisher_Id
char(5), URL char(80), Price double , BooksAuthors with fields ISBN char(13),
Author_Id char(4), Seq_No int, Publishers with fields Publisher_Id char(5), Name
char(30), URL char(80).
The program will turn all the lines of the text files, excepting the first line into statements,
such as Insert into Publishers values('01262', 'Academic Press', 'www.apnet.com/'). We
have to run the program as follows to create tables from each of the above mentioned text
files.
Java makeDB Books
Java makeDB Authors
Java makeDB Publishers
Java makeDB BooksAuthors
There is one more thing to be done for making the program run. There has to be a file
MakeDb.properties that looks like this jdbc.drivers=com.pointbase.jdbc.jdbcDriver
jdbc.url=jdbc:pointbase:corejava
jdbc.username=PUBLIC
jdbc.password=PUBLIC
These values work for PointBase database. They must be changed if some other database
is being used.
The following steps provide an overview of the MakeDB program.
1. Connect to the database.The getConnection method reads the properties in the file
MakeDB.properties and add the jdbc.drivers property to the system properties.
The driver manager uses the jdbc.drivers property to load the appropriate database

188

driver. The getConnection method uses the jdbc.url, jdbc.username, and the
jdbc.password properties to open the database connection.
2. Obtain the filename from the table name by appending the extension .dat
3. Read in the column names and types and construct a CREATE TABLE
command. Then execute that command:
String line = in.readLine();
String command = "CREATE TABLE " + tableName
+ "(" + line + ")";
stmt.executeUpdate(command);
Here we use executeUpdate, not execute query, because this statement has no
result.
4. For each line in the input file, execute an INSERT statement:
command = "INSERT INTO " + tableName
+ " VALUES (" + line + ")";
stmt.executeUpdate(command);
5. After all these elements have been inserted, run a SELECT * FROM table
name query, using the show table method to show the result. This method shows
that the data has been successfully inserted. To find the number of columns in the
result set, we need the get column count method of the result set metadata class.
The code for the program is given below:import
import
import
import

java.net.*;
java.sql.*;
java.io.*;
java.util.*;

public class MakeDB


{
public static void main (String args[])
{
try
{
Connection con = getConnection();
Statement stmt = con.createStatement();
String tableName = "";
if (args.length > 0)
tableName = args[0];
else
{
System.out.println("Usage: MakeDB TableName");
System.exit(0);
}
BufferedReader in = new BufferedReader(new
FileReader(tableName + ".dat"));
createTable(tableName, in, stmt);
showTable(tableName, stmt);

189

in.close();
stmt.close();
con.close();
}catch (SQLException ex)
{
System.out.println ("SQLException:");
while (ex != null)
{
System.out.println
("SQLState:
ex.getSQLState());
System.out.println
("Message:
ex.getMessage());
System.out.println
("Vendor:
ex.getErrorCode());
ex = ex.getNextException();
System.out.println ("");
}
}
catch (IOException ex)
{
System.out.println("Exception: " + ex);
ex.printStackTrace ();
}
} //end of main

"+

"+
"+

static
Connection
getConnection()
throws
SQLException,
public
IOException
{
Properties props = new Properties();
String fileName = "MakeDB.properties";
FileInputStream in = new FileInputStream(fileName);
props.load(in);
String drivers = props.getProperty("jdbc.drivers");
if (drivers != null)
System.setProperty("jdbc.drivers", drivers);
String url = props.getProperty("jdbc.url");
String username = props.getProperty("jdbc.username");
String password = props.getProperty("jdbc.password");
}

return

DriverManager.getConnection(url, username, password);

public static void createTable(String tableName,BufferedReader


Statement stmt)
throws SQLException, IOException
{

String line = in.readLine();


String command = "CREATE TABLE " + tableName
+ "(" + line + ")";
stmt.executeUpdate(command);

in,

190

while ((line = in.readLine()) != null)


{
command = "INSERT INTO " + tableName
+ " VALUES (" + line + ")";
stmt.executeUpdate(command);
}
}
public static void showTable(String tableName,Statement stmt) throws
SQLException
{
String query = "SELECT * FROM " + tableName;
ResultSet rs = stmt.executeQuery(query);
ResultSetMetaData rsmd = rs.getMetaData();
int columnCount = rsmd.getColumnCount();
while (rs.next())
{
for (int i = 1; i <= columnCount; i++)
{
if (i > 1) System.out.print(", ");
System.out.print(rs.getString(i));
}

}
}

System.out.println();

rs.close();

Executing queries
We shall now have a look at a program that executes queries against the database we
created in the preceding section. A graphical user interface has been implemented using
Swing. The application consists of two combo boxes, two buttons, a text field and a text
box. One combo box contains the names of the authors and another one contains the
name of the books. The two buttons are Query and Change Price. The user can choose
an author from the combo box and choose any in publisher. Then if he presses the query
button, the names of all books published by the author are displayed in the text box. On
the converse, if he chooses a publisher and choose any for author, all books published by
him will be displayed. There is one more thing, which the user can do. He can type the
name of a book in the text box and the change in its price in the text field. Then, if he
presses the Change Price button, the price of the book gets changed by the amount

191

entered, in the database. Thus, in this program, we perform both data retrieval and data
updation.
The following steps provide an overview of the program
1. Arrange the components in the frame, using a grid bag lay out.
2. Populate the author and publisher textboxes by running two queries that
return all author and publisher name in the database.
3. When the user selects query, find which of the four query types need to be
executed. If this is the first time this query type is executed, then the prepared
statement is null, and the prepared statement is constructed. Then, the values
are bound to the query and the query is executed.
4. The results of the query are displayed in the result textbox.
5. When the user selects change price, then the update query is constructed
and executed. The query is quite complex because the where clause of the
update statement needs the publisher code and we need know only the
publisher name. This problem is solved with a nested subquery:
UPDATE Books " +
"SET Price = Price + " + priceChange.getText() +
" WHERE Books.Publisher_Id = " +
"(SELECT Publisher_Id FROM Publishers WHERE Name = '" +
publisher + "')
6. We initialize the connection and statement objects in the constructer. We
hang on to them for the life of the program. Just before the program exits, we
call the dispose method and these objects are closed.
The entire code is listed below.
import
import
import
import
import
import
import

java.net.*;
java.sql.*;
java.awt.*;
java.awt.event.*;
java.io.*;
java.util.*;
javax.swing.*;

public class QueryDB


{ public static void main(String[] args)
{ JFrame frame = new QueryDBFrame();
frame.show();
}
}
class QueryDBFrame extends JFrame
implements ActionListener
{
private JComboBox authors;
private JComboBox publishers;
private JTextField priceChange;
private JTextArea result;
private Connection con;
private Statement stmt;
private PreparedStatement authorQueryStmt;
private PreparedStatement authorPublisherQueryStmt;

192
private PreparedStatement publisherQueryStmt;
private PreparedStatement allQueryStmt;
public QueryDBFrame()
{
setTitle("QueryDB");
setSize(400, 300);
addWindowListener(new WindowAdapter()
{ public void windowClosing(WindowEvent e)
{ System.exit(0);
}
} );
getContentPane().setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
authors = new JComboBox();
authors.setEditable(false);
authors.addItem("Any");
publishers = new JComboBox();
publishers.setEditable(false);
publishers.addItem("Any");
result = new JTextArea(4, 50);
result.setEditable(false);
priceChange = new JTextField(8);
priceChange.setText("-5.00");
try
{

con = getConnection();
stmt = con.createStatement();
String query = "SELECT Name FROM Authors";
ResultSet rs = stmt.executeQuery(query);
while (rs.next())
authors.addItem(rs.getString(1));
query = "SELECT Name FROM Publishers";
rs = stmt.executeQuery(query);
while (rs.next())
publishers.addItem(rs.getString(1));
}
catch(Exception e)
{
result.setText("Error " + e);
}
gbc.fill = GridBagConstraints.NONE;
gbc.weightx = 100;
gbc.weighty = 100;
add(authors, gbc, 0, 0, 2, 1);
add(publishers, gbc, 2, 0, 2, 1);

193

gbc.fill = GridBagConstraints.NONE;
JButton queryButton = new JButton("Query");
queryButton.addActionListener(this);
add(queryButton, gbc, 0, 1, 1, 1);
JButton changeButton = new JButton("Change prices");
changeButton.addActionListener(this);
add(changeButton, gbc, 2, 1, 1, 1);
gbc.fill = GridBagConstraints.HORIZONTAL;
add(priceChange, gbc, 3, 1, 1, 1);
gbc.fill = GridBagConstraints.BOTH;
add(result, gbc, 0, 2, 4, 1);
}
public static Connection getConnection()
throws SQLException, IOException
{
Properties props = new Properties();
String fileName = "QueryDB.properties";
FileInputStream in = new FileInputStream(fileName);
props.load(in);
String drivers = props.getProperty("jdbc.drivers");
if (drivers != null)
System.setProperty("jdbc.drivers", drivers);
String url = props.getProperty("jdbc.url");
String username = props.getProperty("jdbc.username");
String password = props.getProperty("jdbc.password");
returnDriverManager.getConnection(url, username,
password);
}
private void add(Component c, GridBagConstraints gbc,int x, int
y, int w, int h)
{
gbc.gridx = x;
gbc.gridy = y;
gbc.gridwidth = w;
gbc.gridheight = h;
getContentPane().add(c, gbc);
}
public void actionPerformed(ActionEvent evt)
{
String arg = evt.getActionCommand();
if (arg.equals("Query"))
{
ResultSet rs = null;
try
{
String author=
(String)authors.getSelectedItem();

194
String publisher=
(String)publishers.getSelectedItem();
if (!author.equals("Any")&&
!publisher.equals("Any"))
{
if (authorPublisherQueryStmt == null)
{
String authorPublisherQuery =
"SELECT Books.Price, Books.Title "
+
"FROM Books, BooksAuthors,
Authors, Publishers " +
"WHERE Authors.Author_Id =
BooksAuthors.Author_Id AND " +
"BooksAuthors.ISBN = Books.ISBN
AND " +
"Books.Publisher_Id =
Publishers.Publisher_Id AND " +
"Authors.Name = ? AND " +
"Publishers.Name = ?";
authorPublisherQueryStmt
=
con.prepareStatement(authorPublisherQuery);
}
authorPublisherQueryStmt.setString(1,

author);

authorPublisherQueryStmt.setString(2,publisher);
rs =
authorPublisherQueryStmt.executeQuery();
}
publisher.equals("Any"))

else if (!author.equals("Any")&&
{

if (authorQueryStmt == null)
{
String authorQuery =
"SELECT Books.Price, Books.Title "
"FROM Books, BooksAuthors, Authors

" +

"WHERE Authors.Author_Id =

BooksAuthors.Author_Id AND " +

"BooksAuthors.ISBN = Books.ISBN

AND " +

"Authors.Name = ?";

con.prepareStatement(authorQuery);
}

authorQueryStmt=

authorQueryStmt.setString(1, author);
rs = authorQueryStmt.executeQuery();

195
}
else if (author.equals("Any")&&

!publisher.equals("Any"))

if (publisherQueryStmt == null)
{
String publisherQuery =
"SELECT Books.Price, Books.Title "

"FROM Books, Publishers " +


"WHERE Books.Publisher_Id =

Publishers.Publisher_Id AND " +

"Publishers.Name = ?";
publisherQueryStmt=

con.prepareStatement(publisherQuery);
}

publisherQueryStmt.setString(1,

publisher);

rs = publisherQueryStmt.executeQuery();

}
else
{

if (allQueryStmt == null)
{
String allQuery ="SELECT
Books.Price, Books.Title FROM Books";
con.prepareStatement(allQuery);

allQueryStmt=
}

rs = allQueryStmt.executeQuery();
}
result.setText("");
while (rs.next())
result.append(rs.getString(1)
+ " | " + rs.getString(2) + "\n");
rs.close();
}
catch(Exception e)
{
result.setText("Error " + e);
}
}
else if (arg.equals("Change prices"))
{
String publisher=
(String)publishers.getSelectedItem();
if (publisher.equals("Any"))

196
result.setText("I am sorry, but I cannot do that.");
else
try
{
String updateStatement =
"UPDATE Books " +
"SET Price = Price + " + priceChange.getText()

" WHERE Books.Publisher_Id = " +


"(SELECT Publisher_Id FROM Publishers WHERE

Name = '" +

publisher + "')";
int r = stmt.executeUpdate(updateStatement);

result.setText(r + " records updated.");


}
catch(Exception e)
{
result.setText("Error " + e);
}

}
public void dispose()
{
try
{
stmt.close();
con.close();
}

catch(SQLException e) {}

The above examples would be sufficient to give one a decent exposure to JDBC. If one is
interested in knowing more, lot of books are available, dealing entirely with SQL only.
There are also a number of good books dealing with the RDBMS (Relational database
management systems) concepts. It would be highly enriching to read them. But for day
today database application programming using JAVA, the concepts covered in the above
section would suffice.

CREATING MULTIMEDIA DATABASES


Creating an Applet from an Application
In this section will discuss about various elements found in applet code that are not
present in standalone application code. Some of these elements involve advanced aspects
of the Java programming language. This section will give some rationale and some basic
explanation, but explaining them fully is beyond the scope of this Lesson. For purposes
of this sample applet, you only need to grasp the general idea, so don't worry if you don't

197

understand everything. You can use the applet code as a template, substituting your own
queries for the one in the applet.
Writing Applet Code
To begin with, applets will import classes not used by standalone applications. Our applet
imports two classes that are special to applets: the class Applet , which is part of the
java.applet package, and the class Graphics , which is part of the java.awt
package. This applet also imports the general-purpose class java.util.Vector so that
we have access to an array-like container whose size can be modified. This code uses
Vector objects to store query results so that they can be displayed later.
All applets extend the Applet class; that is, they are subclasses of Applet. Therefore,
every applet definition must contain the words extends Applet, as shown here:
public class MyAppletName extends Applet {
. . .
}

In our applet example, OutputApplet, this line also includes the words implements
Runnable, so it looks like this:
public class OutputApplet extends Applet implements Runnable {
. . .
}

is an interface that makes it possible to run more than one thread at a time. A
thread is a sequential flow of control, and it is possible for a program to be multithreaded,
that is, to have many threads doing different things concurrently. The class
OutputApplet implements the interface Runnable by defining the method run, the only
method in Runnable. In our example the run method contains the JDBC code for
opening a connection, executing a query, and getting the results from the result set. Since
database connections can be slow, and can sometimes take several seconds, it is generally
a good idea to structure an applet so that it can handle the database work in a separate
thread.
Runnable

Similar to a standalone application, which must have a main method, an applet must
implement at least one init, start, or paint method. Our example applet defines a
start method and a paint method. Every time start is invoked, it creates a new
thread (named worker) to re-evaluate the database query. Every time paint is invoked, it
displays either the query results or a string describing the current status of the applet.
As stated previously, the run method defined in OutputApplet contains the JDBC code.
When the thread worker invokes the method start, the run method is called
automatically, and it executes the JDBC code in the thread worker. The code in run is
very similar to the code you have seen in our other sample code with three exceptions.
First, it uses the class Vector to store the results of the query. Second, it does not print

198

out the results but rather adds them to the Vector results for display later. Third, it
likewise does not print out exceptions and instead records error messages for later
display.
Applets have various ways of drawing, or displaying, their content. This applet, a very
simple one that has only text, uses the method drawString (part of the Graphics class)
to display its text. The method drawString takes three arguments:
(1) the string to be displayed,
(2) the x coordinate, indicating the horizontal starting point for displaying the string,
and
(3) the y coordinate, indicating the vertical starting point for displaying the string
(which is below the text).
The method paint is what actually displays something on the screen, and in
OutputApplet.java , it is defined to contain calls to the method drawString . The
main thing drawString displays is the contents of the Vector results (the stored
query results). When there are no query results to display, drawString will display the
current contents of the String message . This string will be "Initializing" to begin with.
It gets set to "Connecting to database" when the method start is called, and the method
setError sets it to an error message when an exception is caught. Thus, if the database
connection takes much time, the person viewing this applet will see the message
"Connecting to database" because that will be the contents of message at that time. (The
method paint is called by AWT when it wants the applet to display its current state on
the screen.)
The last two methods defined in the class OutputApplet, setError and setResults
are private, which means that they can be used only by OutputApplet. These methods
both invoke the method repaint , which clears the screen and calls paint . So if
setResults calls repaint , the query results will be displayed, and if setError calls
repaint, an error message will be displayed.
A final point to be made is that all the methods defined in OutputApplet except run are
synchronized . The keyword synchronized indicates that while a method is accessing
an object, other synchronized methods are blocked from accessing that object. The
method run is not declared synchronized so that the applet can still paint itself on the
screen while the database connection is in progress. If the database access methods were
synchronized , they would prevent the applet from being repainted while they are
executing, and that could result in delays with no accompanying status message.
To summarize, in an applet, it is good programming practice to do some things you
would not need to do in a standalone application:
(1) Put your JDBC code in a separate thread
(2) Display status messages on the screen during any delays, such as when a database
connection is taking a long time

199

(3) Display error messages on the screen instead of printing them to System.out or
System.err .
Running an Applet
Before running our sample applet, you need to compile the file OutputApplet.java .
This creates the file OutputApplet.class , which is referenced by the file
OutputApplet.html.
The easiest way to run an applet is to use the appletviewer, which is included as part of
the JDK. Simply follow the instructions below for your platform to compile and run
OutputApplet.java :
UNIX
javac OutputApplet.java
appletviewer OutputApplet.html
Windows 95/NT
javac OutputApplet.java
appletviewer OutputApplet.html
Applets loaded over the network are subject to various security restrictions. Although this
can seem bothersome at times, it is absolutely necessary for network security, and
security is one of the major advantages of using the Java programming language. An
applet cannot make network connections except to the host it came from unless the
browser allows it. Whether one is able to treat locally installed applets as "trusted" also
depends on the security restrictions imposed by the browser. An applet cannot ordinarily
read or write files on the host that is executing it, and it cannot load libraries or define
native methods.
Applets can usually make network connections to the host they came from, so they can
work very well on intranets.
The JDBC-ODBC Bridge driver is a somewhat special case. It can be used quite
successfully for intranet access, but it requires that ODBC, the bridge, the bridge native
library, and JDBC be installed on every client. With this configuration, intranet access
works from Java applications and from trusted applets. However, since the bridge
requires special client configuration, it is not practical to run applets on the Internet with
the JDBC-ODBC Bridge driver. Note that this is a limitation of the JDBC-ODBC Bridge,
not of JDBC. With a pure Java JDBC driver, you do not need any special configuration to
run applets on the Internet.

LET US SUM UP
The JDBC API is a Java API that can access any kind of tabular data, especially
data stored in a Relational Database.

200

JDBC helps you to write java applications that manage these three programming
activities:

Connect to a data source, like a database


Send queries and update statements to the database
Retrieve and process the results received from the database in answer to your
query

LESSON END ACTIVITIES


1. Create a table, containing the fields Name, Id and salary. Populate it and create the
jdbc-odbc connection. Do it either manually or through a program, as shown in the
example program.
2. Create a graphical user interface consisting of three Text fields and three Labels ,
corresponding to the three fields of the table, created in the previous exercise. There
must be a button SHOW. The user must type the Id and press SHOW to display
the rest of the information. Write a program, utilizing JDBC to implement this, for the
table.
3. To the above GUI, add two more buttons ADD and DELETE. If the user enter
data into the three fields and presses ADD, the new data must be added to the table.
On the other hand, if the user enters data in one of the fields and presses DELETE,
all the records having that value for that field must be deleted from the table.
4. Now add two more buttons NEXT and PREVIOUS. By pressing these buttons the
user must be able to scroll through the records in the table, one after the other.
5. Add one more button UPDATE. When the user is scrolling through the records,
using NEXT and PREVIOUS, if the user changes the value in a particular field
and presses UPDATE, the value must get changed in the table.
Note: The programs must take care of all conditions of wrong entry of data and must display message
boxes, displaying the appropriate error messages

POINTS FOR DISCUSSION

Compare 2 Tier and 3 Tier Architecture and Discuss the limitations of 2-tier
architecture

201

REFERENCES
Jane Jawroski, Java Unleashed, SAMS Techmedia Publications, 1999
Campione, Walrath and Huml, The Java Tutorial, Addison Wesley 1999

202

LESSON 10: DATABASE FOR WEB


Contents
10.0 Aims and Objectives
10.1. Introduction to Servlet
10.2.Initializing a Servlet
The Servlet Interface
Requests and responses
Servlet Descriptions
10.6.Let us Sum up
10.7.Lesson-End Activities
10.8.Points for Discussion
10.9.Suggested Readings/References/Sources

AIMS AND OBJECTIVES


At the end of this lesson you can able to understand

Servlets
Applications of Servlets
Database support in web applications

INTRODUCTION TO SERVLETS
Servlets are the programs that execute on the server side. Servlets are modules that extend
request/response-oriented servers, such as Java-enabled web servers. For example, a servlet might be
responsible for taking data in an HTML order-entry form and applying the business logic used to
update a company's order database.

203

Servlets are to servers what applets are to browsers. Unlike applets, however, servlets
have no graphical user interface.
Servlets can be embedded in many different servers because the servlet API, which
you use to write servlets, assumes nothing about the server's environment or protocol.
Servlets have become most widely used within HTTP servers.
Use Servlets instead of CGI Scripts!
Servlets are an good replacement for CGI scripts. They provide a way to generate
dynamic documents that is both writing easily and running faster . Servlets also address
the problem of doing server-side programming with platform-specific APIs: they are
developed with the Java Servlet API, a standard Java extension.
So use servlets to handle HTTP client requests. For example, have servlets
process data POSTed via HTTPS using an HTML form, including purchase order or

204

credit card data. A servlet like this could be part of an order-entry and processing system,
working with product and inventory databases, and perhaps an on-line payment system.
Other Uses for Servlets
Here are a few more of the many applications for servlets:
Allowing collaboration between people. A servlet can handle multiple requests
concurrently, and can synchronize requests. This allows servlets to support
systems such as on-line conferencing.
Forwarding requests. Servlets can forward requests to other servers and servlets.
Thus servlets can be used to balance load among several servers that mirror the
same content, and to partition a single logical service over several servers,
according to task type or organizational boundaries.
The Life Cycle of a Servlet
Each servlet has the same life cycle:
A server loads and initializes the servlet
The servlet handles zero or more client requests
The server removes the servlet
(some servers do this step only when they shut down)

205

INITIALIZING A SERVLET
When a server loads a servlet, the server runs the servlet's init method.
Initialization completes before client requests are handled and before the servlet is
destroyed.
Even though most servlets are run in multi-threaded servers, servlets have no
concurrency issues during servlet initialization. The server calls the init method once,
when the server loads the servlet, and will not call the init method again unless the server
is reloading the servlet. The server cannot reload a servlet until after the server has
destroyed the servlet by calling the destroy method.
After initialization, the servlet is able to handle client requests.
10.2.1. Destroying a Servlet
Servlets run until the servers are destroys them, for example, at the request of a
system administrator. When a server destroys a servlet, the server runs the servlet's
destroy method. The method is run once; the server will not run that servlet again until
after the server reloads and reinitializes the servlet.

206

When the destroy method runs, another thread might be running a service
request.
The servletrunner Utility
Once you have written your servlet, you can test it in the servletrunner utility.
The servletrunner is a small, multithreaded process that handles requests for
servlets. Because servletrunner is multi-threaded, it can be used to run multiple
servlets simultaneously, or to test one servlet that calls other servlets to satisfy client
requests.
To start this utility type the following at the dos prompt
Servletrunner yourservlet
Unlike some web servers, servletrunner does not automatically reload updated
servlets. However you can stop and restart servletrunner with very little overhead to
run a new version of a servlet.
You might have to specify certain pieces of data to run a servlet. For example, if a
servlet requires initialization parameters, you must set up this data before starting
servletrunner.
After the property file is set up, you can run the servletrunner utility.
Understanding of the Servlet Package Architecture
The javax.servlet package provides interfaces and classes for writing servlets.
The architecture of the package is described in the next section.

207

THE SERVLET INTERFACE


The central abstraction in the Servlet API is the Servlet interface. All servlets
implement this interface, either directly or, more commonly, by extending a class that
implements it such as HttpServlet

The Servlet interface declares, but does not implement, methods that manage
the servlet and its communications with clients. Servlet writers provide some or all of
these methods when developing a servlet.
Client Interaction
When a servlet accepts a call from a client, it receives two objects:
A ServletRequest API, which encapsulates the communication from
the client to the server.
A ServletResponse API, which encapsulates the communication from
the servlet back to the client.
ServletRequest and ServletResponse are interfaces defined by the
javax.servlet package.
The ServletRequest Interface
The ServletRequest interface allows the servlet access to:
Information such as the names of the parameters passed in by the client, the
protocol (scheme) being used by the client, and the names of the remote host that
made the request and the server that received it.
The input stream, ServletInputStream API. Servlets use the input stream to
get data from clients that use application protocols such as the HTTP POST and
PUT methods.
Interfaces that extend ServletRequest interface allow the servlet to retrieve
more protocol-specific data. For example, the HttpServletRequest API interface
contains methods for accessing HTTP-specific header information.

208

The ServletResponse Interface


The ServletResponse interface gives the servlet methods for replying to the
client. It:
Allows the servlet to set the content length and MIME type of the reply.
Provides an output stream, ServletOutputStream API, and a Writer
through which the servlet can send the reply data.
Interfaces that extend the ServletResponse interface give the servlet more
protocol-specific capabilities. For example, the HttpServletResponse API interface
contains methods that allow the servlet to manipulate HTTP-specific header information.
Additional Capabilities of HTTP Servlets
The classes and interfaces described above make up a basic Servlet. HTTP
servlets have some additional objects that provide session-tracking capabilities. The
servlet writer can use these APIs to maintain state between the servlet and the client that
persists across multiple connections during some time period. HTTP servlets also have
objects that provide cookies. The servlet writer uses the cookie API to save data with the
client and to retrieve this data.
Example Servlet Coding
The following class completely defines servlet:
public class SimpleServlet extends HttpServlet
{
/**
* Handle the HTTP GET method by building a simple web
page.
*/
public void doGet (HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
PrintWriter
out;
String
title = "Simple Servlet Output";
// set content type and other response header fields
first
response.setContentType("text/html");
// then write the data of the response
out = response.getWriter();
out.println("<HTML><HEAD><TITLE>");
out.println(title);
out.println("</TITLE></HEAD><BODY>");
out.println("<H1>" + title + "</H1>");
out.println("<P>This is output from
SimpleServlet.");
out.println("</BODY></HTML>");
out.close();
}
}

209

Description of Example
SimpleServlet extends the HttpServlet class, which implements the
Servlet interface.
SimpleServlet overrides the doGet method in the HttpServlet
class. The doGet method is called when a client makes a GET request
(the default HTTP request method), and results in the simple HTML
page being returned to the client.
Within the doGet method,
The user's request is represented by an HttpServletRequest
object.
The response to the user is represented by an
HttpServletResponse object.
Because text data is returned to the client, the reply is sent using
the Writer object obtained from the HttpServletResponse
object.
Protocol Support
An HTTP Servlet handles client requests through its service method. The
service method supports standard HTTP client requests by dispatching each request
to a method designed to handle that request.
javax.servlet package

Classes:

ServletException,
ServletInputStream,
GenericServlet, UnavailableException.

Interfaces:

Servlet, ServletConfig, ServletContext, ServletRequest,


ServletResponse, SingleThreadModel.

ServletOutputStream,

javax.servlet.http package

Classes:
Interfaces:

Cookie, HttpUtils, HttpServlet, HttpSessionBindingEvent


HttpServletRequest, HttpServletResponse,
HttpSession, HttpSessionBindingListener,
HttpSessionContext,

REQUESTS AND RESPONSES


Now we will discusses using the objects that represent the client's request (an
HttpServletRequest object) and the servlet's response (an HttpServletResponse
object). These objects are provided to the service method and to the methods that
service calls to handle HTTP requests.
Methods in the HttpServlet class that handle client requests take two arguments:

210

1. An HttpServletRequest object, which encapsulates the data from the client


2. An HttpServletResponse object, which encapsulates the response to
the client
HttpServletRequest Objects
An HttpServletRequest object provides access to HTTP header data, such as
any cookies found in the request and the HTTP method with which the request was made.
The HttpServletRequest object also allows you to obtain the arguments that the client
sent as part of the request.
To access client data:
The getParameter method returns the value of a named parameter. If
your parameter could have more than one value, use
getParameterValues instead. The getParameterValues method
returns an array of values for the named parameter. (The method
getParameterNames provides the names of the parameters.)
For HTTP GET requests, the getQueryString method returns a String
of raw data from the client. You must parse this data yourself to obtain the
parameters and values.
For HTTP POST, PUT, and DELETE requests,
If you expect text data, the getReader method returns a
BufferedReader for you to use to read the raw data.
If you expect binary data, the getInputStream method returns a
ServletInputStream for you to use to read the raw data
Note: Use either a getParameter[Values] method or one of the
methods that allow you to parse the data yourself. They can not be used
together in a single request.
HttpServletResponse Objects
An HttpServletResponse object provides two ways of returning data to the
user:

The getWriter method returns a Writer


The getOutputStream method returns a
ServletOutputStream Use the getWriter method to return text data
to the user, and the getOutputStream method for binary data.
Closing the Writer or ServletOutputStream after you send the response
allows the server to know when the response is complete.
HTTP Header Data

211

You must set HTTP header data before you access the Writer or OutputStream.
The HttpServletResponse class provides methods to access the header data. For
example, the setContentType method sets the content type. (This header is often the
only one manually set.)
Handling GET and POST Requests
The methods to which the service method delegates HTTP requests include,

doGet,

for handling GET, conditional GET, and HEAD requests


doPost, for handling POST requests
doPut, for handling PUT requests
doDelete, for handling DELETE requests

Note that, By default, these methods return a BAD_REQUEST (400) error.


Your servlet should override the method or methods designed to handle the HTTP
interactions that it supports. This section shows you how to implement methods that
handle the most common HTTP requests: GET and POST.
The HttpServlet's service method also calls the doOptions method when the
servlet receives an OPTIONS request, and doTrace when the servlet receives a TRACE
request. The default implementation of doOptions automatically determines what HTTP
options are supported and returns that information. The default implementation of
doTrace causes a response with a message containing all of the headers sent in the trace
request. These methods are not typically overridden.
Handling GET requests
Handling GET requests involves overriding the doGet method. The following example
shows the BookDetailServlet doing this.

public class BookDetailServlet extends HttpServlet {


public void doGet (HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
...
// set content-type header before accessing the Writer
response.setContentType("text/html");
PrintWriter out = response.getWriter();
// then write the response
out.println("<html>" +
"<head><title>Book Description</title></head>" +
...);

212

//Get the identifier of the book to display


String bookId = request.getParameter("bookId");
if (bookId != null) {
// and the information about the book and print it
...
}
out.println("</body></html>");
out.close();
}

}
...

The servlet extends the HttpServlet class and overrides the doGet method.
Within the doGet method, the getParameter method gets the servlet's expected
argument.
To respond to the client, the example doGet method uses a Writer from the
HttpServletResponse object to return text data to the client. Before accessing the
writer, the example sets the content-type header. At the end of the doGet method, after
the response has been sent, the Writer is closed.
Handling POST Requests
Handling POST requests involves overriding the doPost method. The
following example shows the ReceiptServlet doing this.
public class ReceiptServlet extends HttpServlet
{ public void doPost(HttpServletRequest
request,
HttpServletResponse response)
throws ServletException, IOException
{
...
// set content type header before accessing the Writer
response.setContentType("text/html");
PrintWriter out = response.getWriter();
// then write the response
out.println("<html>" +
"<head><title> Receipt </title>" +
...);
out.println("<h3>Thank you for purchasing your books from us "

request.getParameter("cardname") +
...);

out.close();
}
...

213

The servlet extends the HttpServlet class and overrides the doPost
method.
Within the doPost method, the getParameter method gets the servlet's
expected argument.
To respond to the client, the example doPost method uses a Writer from the
HttpServletResponse object to return text data to the client. Before accessing the
writer the example sets the content-type header. At the end of the doPost method, after
the response has been set, the Writer is closed

SERVLET DESCRIPTIONS
In addition to handling HTTP client requests, servlets are also called upon to
supply descriptions of themselves. Here we will see to provide a description by
overriding the method, getServletInfo, that supplies the servlet description.
Some applications, such as the Java Web Server Administration Tool, get
descriptive information from the servlet and display it. The servlet description is a string
that can describe the purpose of the servlet, its author, its version number, or whatever the
servlet author deems important.
The method that returns this information is getServletInfo, which returns null
by default. You are not required to override this method, but applications are unable to
supply a description of your servlet unless you do.
The following example shows the description of the BookStoreServlet:

public class BookStoreServlet extends HttpServlet {


...
public String getServletInfo() {
return "The BookStore servlet returns the " +
"main web page for Duke's Bookstore.";
}
}

Generic Servlet:
So far we discuses about HTTP Servlet. Now we will get into the Generic servlet.
The Generic Servlet provides functionality that makes it easy to handle request &
response.
Consider the following example

214

public class Myservlet extends GenericServlet{


Public void service ( ServletRequest request, ServletResponse
respone )
throws
ServletException,IOException{ response.set
ContentType ( text/html ); PrintWriter
prnwrt = response.getWriter();
prnwrt.println(Its my Generic Servlet);
prnwrt.close();
}

Description
Here Myservlet defined as s subclass of genericServlet. This provides
functionality to handle the request and reponse to the Myservlet.Inside the Myservlet ,the
service() method is overridden the GenericServlet method.This method handles request
from client.
The argument ServletRequest is used to get request from the client and
ServletResponseused to formulate a response to the client.The setContentType ()calling
establishes the MIME type of the HTTP response. In this program, MIME type is text or
html type. The getWriter () obtains a PrintWriter. Anything written in this stream is sent
the client. Then, println() is used to write HTML source code as the HTTP response.

What is a session?
HTTP is a stateless protocol which means that eash request is independent of the
previous one. How ever it is necessary to save state information so that information can
be collected from several interactions between a browser and a server. Sessions provide
such a mechanism.
A session can be created via the getSession() method of the
HttpServeltRequest. An HttpSession object is returned. This object can store a set of
binding that associate names with objects. The putValue(), getValue(),
getValueNames() and removeValue() Are some of the methods used for binding. It is
important to note that sessions state is shared among all the servlets that are
associated with a particular client.

Knowing about the clients State


The Servlet API provides two ways to track client state:
Session Tracking
Session tracking is a mechanism that Servlets use to maintain state about a series
of requests from the same user (that is, requests originating from the same browser)
across some period of time.

215

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
public class CatalogServlet extends HttpServlet
{
public void doGet (HttpServletRequest
request,HttpServletResponse response)
throws ServletException, IOException
{
PrintWriter out;
// Get the user's session
//Session Object Created here

HttpSession session = request.getSession(true);


//...
out = response.getWriter();
//...

Cookies
Cookies are a mechanism that a servlet uses to have clients hold a small amount
of state-information associated with the user. Servlets can use the information in a cookie
as the user enters a site (as a low-security user sign-on, for example), as the user
navigates around a site (as a repository of user preferences for example), or both.
The Cookie class encapsulates a cookie. a cookie is stored on the client and
contains state information. cookies are valuable for tracking user activities.
A servlet can write a cookie to a users machine via a addCookie() method of the
HttpServletResponce interface. the data for thta cookie is then included in the header of
the HTTP responce that is sent to the browser.
A cookie contains the following

name
value
expiry date
domain and path

The expiry date determines whrn the cookie is deleted from the users machine.If
no expiry date is assigned then it is deleted when the current session ends
The domain and path of the cookie determines whne it is included in the header of
an HTTP request. if the user enters a URL whose domainb and path match these values
then the cookie is supplied to the web server

216

The only constructor for a cookie is


cookie(string name String value)
Example
// AddCookie.html
<html>
<body>
<center>
<form name = "form1" method = POST action =
"http://localhost:8080/servlet/AddCookieServlet">
<b>Enter The Value For The Cookie:</b>
<input type = text name = "data" value = "">
<input type = submit value = submit>
</form>
</body>
</html>
//AddCookieServlet.java
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class AddCookieServlet extends HttpServlet
{
public void doPost(HttpServletRequest req,
HttpServletResponse res) throws ServletException,
IOException
{
//get parameter from the HTTP request
String data = req.getParameter("data");
//create cookie
Cookie cookie = new Cookie("MyCookie",data);
//add cookie to HTTP response
res.addCookie(cookie);
//Write output to browser

res.setContentType("text/html");
PrintWriter pw = res.getWriter();
pw.println("<b>MyCookie has been set to ");
pw.println(data);
pw.close();
}

//GetCookieServlet.java

217
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class GetCookieServlet extends HttpServlet
{
public void doGet(HttpServletRequest req,
HttpServletResponse res) throws ServletException,
IOException
{
//get cookie from header to HTTP request
Cookie[] cookies = req.getCookies();
//displayt these cookies
res.setContentType("text/html");
PrintWriter pw = res.getWriter();
pw.println("<b>");
for(int i = 0;i<cookies.length;i++)
{
String name = cookies[i].getName();
String value = cookies[i].getValue();
pw.println("Name = "+ name + " Value "+
value);

}
pw.close();

After compiling the two java files do the following

compile the servlets

start the servletrunner

display the AddCookie.html

enter the value

submit the webpage

And then requst the following URL


http://localhost:800/servlet/GEtCookieServlet
You should be able to see the values that you typed in the HTML page
The Cookie Object can be found in the package javax.servlet.http It has
the following methods:
public class javax.servlet.http.Cookie extends
java.lang.Object implements java.
lang.Cloneable {
public
javax.servlet.http.Cookie(java.lang.String,java.lang.String
);
public void setComment(java.lang.String);

218
public
public
public
public
public
public
public
public
public
public
public
public
public
public
public

java.lang.String getComment();
void setDomain(java.lang.String);
java.lang.String getDomain();
void setMaxAge(int);
int getMaxAge();
void setPath(java.lang.String);
java.lang.String getPath();
void setSecure(boolean);
boolean getSecure();
java.lang.String getName();
void setValue(java.lang.String);
java.lang.String getValue();
int getVersion();
void setVersion(int);
java.lang.Object clone();

LET US SUM UP
In this lesson we discussed about Database search on WEB, database support in web
applications using servlet.

LESSON END ACTIVITIES


3. Get the user name and print a welcome message
4. Get the user name and password , validate with the backend and print the appropriate
message(if the username is not valid then redirect to another page).
5. Write a servlet to display the hit count
6. Write a servlet to get a users name, and email address and store it in the backend

POINTS FOR DISCUSSION


Discuss various advantages and disadvantages of cookies

REFERENCES
Jane Jawroski, Java Unleashed, SAMS Techmedia Publications, 1999
Campione, Walrath and Huml, The Java Tutorial, Addison Wesley 1999

219

LESSON 11: JAVA ARCHIVE (JAR) FILE FORMAT


Contents
11.0 Aims and Objectives
Introduction
Advantages of JAR
Using JAR Files: The Basics
Creating a JAR File
Java Internationalization
Let us Sum up
Lesson-End Activities
Points for Discussion
References

AIMS AND OBJECTIVES


This lesson shows you how to perform basic JAR-file operations, and how to run
software that is bundled in JAR files. This section also introduces you to the concept of
the JAR file's manifest, which plays important role in more advanced JAR functionality.

INTRODUCTION
The Java Archive (JAR) file format enables you to bundle multiple files into a single
archive file. Typically a JAR file will contain the class files and auxiliary resources
associated with applets and applications.

ADVANTAGES OF JAR
The JAR file format provides many benefits:

Security: You can digitally sign the contents of a JAR file. Users who recognize your signature
can then optionally grant your software security privileges it wouldn't otherwise have.
Decreased download time: If your applet is bundled in a JAR file, the applet's class files and
associated resources can be downloaded to a browser in a single HTTP transaction without the
need for opening a new connection for each file.
Compression: The JAR format allows you to compress your files for efficient storage.
Packaging for extensions (version 1.2): The extensions framework provides a means by which
you can add functionality to the Java core platform, and the JAR file format defines the
packaging for extensions. Java 3D and JavaMail are examples of extensions developed by Sun.
By using the JAR file format, you can turn your software into extensions as well.
Package Sealing (version 1.2): Packages stored in JAR files can be optionally sealed so that the
package can enforce version consistency. Sealing a package within a JAR file means that all
classes defined in that package must be found in the same JAR file.
Package Versioning (version 1.2): A JAR file can hold data about the files it contains, such as
vendor and version information.
Portability: The mechanism for handling JAR files is a standard part of the Java platform's core
API.

The JAR file format is an important part of the Java platform's extension mechanism.

220

USING JAR FILES: THE BASICS


JAR files are packaged with the ZIP file format, so you can use them for "ZIP-like" tasks
such as lossless data compression, archiving, decompression, and archive unpacking.
These are among the most common uses of JAR files, and you can realize many JAR file
benefits using only these basic features.
Even if you want to take advantage of advanced functionality provided by the JAR file
format such as electronic signing, you'll first need to become familiar with the
fundamental operations.
To perform basic tasks with JAR files, you use the Java Archive Tool provided as part of
the Java Development Kit. Because the Java Archive tool is invoked by using the jar
command, for convenience we'll call it the "Jar tool".
As a synopsis and preview of some of the topics to be covered in this lesson, the
following table summarizes common JAR-file operations:
Operation

Command

To create a JAR file

jar cf jar-file input-file(s)

To view the contents of a JAR file

jar tf jar-file

To extract the contents of a JAR file

jar xf jar-file

To extract specific files from a JAR file

jar xf jar-file archived-file(s)

To run an application packaged as a JAR file


(version 1.1)

jre -cp app.jar MainClass

To run an application packaged as a JAR file


(version 1.2 -- requires Main-Class
manifest header)

java -jar app.jar

To invoke an applet packaged as a JAR file

<applet code=AppletClassName.class
archive="JarFileName.jar"
width=width height=height>
</applet>

ations, with examples for each of the basic


features:

This
secti
on
will
sho
w
you
how
to
perf
orm
the
mos
t
com
mon
JAR
-file
oper

CREATING A JAR FILE


This section shows you how to use the Jar tool to package files and directories into a JAR
file.
Viewing the Contents of a JAR File
You can display a JAR file's table of contents to see what it contains without actually
unpacking the JAR file.
Extracting the Contents of a JAR File

You can use the Jar tool to unpack a JAR file. When extracting files, the Jar tool makes
copies of the desired files and writes them to the current directory, reproducing the
directory structure that the files have in the archive.

Modifying a Manifest File


This section shows you a couple of ways that you can modify the contents of a JAR file's
manifest. You might want to modify the manifest, for example, to enable special JAR-file
functionality.
Updating a JAR File
The Jar tool in version 1.2 of the Java Development Kit provides a new functionality for
updating the contents of an existing JAR file by modifying its manifest or by adding files.
This section shows you how use this new feature.
Running JAR-Packaged Software
This section shows you how to invoke and run applets and applications that are packaged
in JAR files.
Understanding the Manifest
Some of the more advanced features offered by the JAR file format such as package
sealing and electronic signing are made possible by the JAR file's manifest, a special file
that JAR files contain. In the final section of this lesson, you'll find basic information
about the structure and uses of the manifest file.
Creating a JAR File
The basic format of the command for creating a JAR file is:
jar cf jar-file input-file(s)
Let's look at the options and arguments used in this command:

The c option indicates that you want to create a JAR file.

The f option indicates that you want the output to go to a file rather than to stdout.

jar-file is the name that you want the resulting JAR file to have. You can use any filename for a
JAR file. By convention, JAR filenames are given a .jar extension, though this is not required.

The input-file(s) argument is a space-delimited list of one or more files that you want to be placed
in your JAR file. The input-file(s) argument can contain the wildcard * symbol. If any of the
"input-files" are directories, the contents of those directories are added to the JAR archive
recursively.

The c and f options can appear in either order, but there must not be any space between them.
This command will generate a compressed JAR file and place it in the current directory. The command will
also generate a default manifest file for the JAR archive.
You can add any of these additional options to the cf options of the basic command:
Option Description

Produces verbose output on stderr (in version 1.1) or stdout (in version 1.2) while the JAR file is
being built. The verbose output tells you the name of each file as it's added to the JAR file.

0
(zero)

Indicates that you don't want the JAR file to be compressed.

Indicates that the default manifest file should not be produced.

Used to include manifest information from an existing manifest file. The format for using this
option is:
jar cmf existing-manifest jar-file input-file(s)
See Modifying a Manifest for more information about his option.

-C

To change directories during execution of the command. Version 1.2 only. See below for an
example.

In version 1.1, the JAR-file format supports only ASCII filenames. Version 1.2 adds
support for UTF8-encoded names.
An Example
Let's look at an example. The JDK demos include a simple TicTacToe applet. This demo contains a
bytecode class file, audio files, and images all housed in a directory called TicTacToe having this structure:

The audio and images subdirectories contain sound files and GIF images used by the applet.
To package this demo into a single JAR file named TicTacToe.jar, you would run this command from
inside the TicTacToe directory:
jar cvf TicTacToe.jar TicTacToe.class audio images
The audio and images arguments represent directories, so the Jar tool will recursively place them and their
contents in the JAR file. The generated JAR file TicTacToe.jar will be placed in the current directory.
Because the command used the v option for verbose output, you'd see something similar to this output
when you run the command:
adding: TicTacToe.class
(in=3825) (out=2222) (deflated 41%)
adding: audio/ (in=0) (out=0) (stored 0%)
adding: audio/beep.au
(in=4032) (out=3572) (deflated 11%)
adding: audio/ding.au
(in=2566) (out=2055) (deflated 19%)
adding: audio/return.au
(in=6558) (out=4401) (deflated 32%)
adding: audio/yahoo1.au
(in=7834) (out=6985) (deflated 10%)
adding: audio/yahoo2.au
(in=7463) (out=4607) (deflated 38%)

adding: images/ (in=0) (out=0) (stored 0%)


adding: images/cross.gif
(in=157) (out=160) (deflated -1%)
adding: images/not.gif
(in=158) (out=161) (deflated -1%)

You can see from this output that the JAR file TicTacToe.jar is compressed. The Jar tool compresses files
by default. You can turn off the compression feature by using the 0 (zero) option, so that the command
would look like:
jar cvf0 TicTacToe.jar TicTacToe.class audio images
You might want to avoid compression, for example, to increase the speed with which a JAR file could be
loaded by a browser. Uncompressed JAR files can generally be loaded more quickly than compressed files
because the need to decompress the files during loading is eliminated. However, there's a tradeoff in that
download time over a network may be longer for larger, uncompressed files.
The Jar tool will accept arguments that use the wildcard * symbol. As long as there weren't any unwanted
files in the TicTacToe directory, you could have used this alternative command to construct the JAR file:
jar cvf TicTacToe.jar *
Though the verbose output doesn't indicate it, the Jar tool automatically adds a manifest file to the JAR
archive with pathname META-INF/MANIFEST.MF.
In the above example, the files in the archive retained their relative pathnames and directory structure. The
Jar tool in version 1.2 of the Java Development Kit provides the -C option that you can use to create a JAR
file in which the relative paths of the archived files are not preserved. It's modeled after GZIP's -C option.
As an example, suppose you wanted put audio files and gif images used by the TicTacToe demo into a JAR
file, and that you wanted all the files to be on the top level, with no directory hierarchy. You could
accomplish that by issuing this command from the parent directory of the images and audio directories:
jar cf ImageAudio.jar -C images * -C audio *
The -C images part of this command directs the Jar tool to go to the images directory, and the * following C images directs the Jar tool to archive all the contents of that directory. The -C audio * part of the
command then does the same with the audio directory. The resulting JAR file would have this table of
contents:
META-INF/MANIFEST.MF
cross.gif
not.gif
beep.au
ding.au
return.au
yahoo1.au
yahoo2.au

By contrast, suppose that you used a command that didn't employ the -C option:
jar cf ImageAudio.jar images audio
The resulting JAR file would have this table of contents:
META-INF/MANIFEST.MF
images/cross.gif

images/not.gif
audio/beep.au
audio/ding.au
audio/return.au
audio/yahoo1.au
audio/yahoo2.au

JAVA INTERNATIONALIZATION
Internationalization is the process of designing software so that it can be adapted
(localized) to various languages and regions easily, cost-effectively, and in particular
without engineering changes to the software. Localization is performed by simply adding
locale-specific components, such as translated text, data describing locale-specific
behavior, fonts, and input methods.
In the Java SE Platform, internationalization support is fully integrated into the classes
and packages that provide language- or culture-dependent functionality.
Core Java Internationalization

Core Java provides the foundation for internationalization of desktop and server
applications.
Text representation: the Java programming language is based on the Unicode character set, and
several libraries implement the Unicode standard.

Locale identification and localization: Locales in the Java SE platform are just identifiers that can

be used to request locale specific behavior in many different areas of functionality. Localization is
supported at the most basic level by the ResourceBundle class, which provides access to locale
specific objects, including strings.

Date and time handling: The Java SE platform provides various calendars, and supports
conversion to and from calendar independent Date objects. All time zones in the world are
supported.

Text processing includes character analysis and case mapping, string comparison, breaking text

into words and lines, as well as formatting numbers, dates, and time values into strings or parsing
them back from strings. Most of these functions are locale dependent.

Character encoding conversion supports converting text between Unicode and other character
encodings when reading incoming text from streams or writing outgoing text to streams.

LET US SUM UP
In this lesson we saw how to perform basic JAR-file operations, and how to run
software that is bundled in JAR files. This section also introduces you to the concept of
the JAR file's manifest, which plays important role in more advanced JAR functionality.

LESSON END ACTIVITIES


Write down various steps associated in creating JAR file format

POINTS FOR DISCUSSION


Discuss various applications of JAR file format with suitable examples.

REFERENCES
Jar tool reference for Windows platform
http://java.sun.com/products/jdk/1.2/docs/tooldocs/win32/jar.html
Jar tool reference for Solaris platform
http://java.sun.com/products/jdk/1.2/docs/tooldocs/solaris/jar.html
Java Internationalization
http://java.sun.com/javase/technologies/core/basic/intl/#mobile

LESSON 12: SWING PROGRAMMING


Contents
12.0 Aims and Objectives
Introduction
Compiling and running swing programs
Learning Swing with the Netbeans IDE
Setting up the Celsius converter project
NetBeans IDE Basics
Creating the Celsiusconverter GUI
Let us Sum up
Lesson-End Activities
Points for Discussion
Suggested Readings/References/Sources

AIMS AND OBJECTIVES


This lesson gives you a brief introduction to using the Java Foundation Classes (JFC)
and Swing. After telling you about JFC and Swing, it helps you get the necessary
software and walks you through how to compile and run a program that uses the Swing
packages.
The following lesson, Learning Swing with the NetBeans IDE, will build on these first
steps to help you create several progressively more complex examples. For now, let's
start with the basics.

INTRODUCTION
JFC is short for Java Foundation Classes, which encompass a group of features for
building graphical user interfaces (GUIs) and adding rich graphics functionality
and interactivity to Java applications. It is defined as containing the features shown
in the table below.
Feature

Swing GUI
Components

Pluggable Lookand-Feel Support

Accessibility API
Java 2D API

Features of the Java Foundation Classes


Description

Includes everything from buttons to split panes to tables. Many


components are capable of sorting, printing, and drag and drop, to
name a few of the supported features.
The look and feel of Swing applications is pluggable, allowing a
choice of look and feel. For example, the same program can use
either the Java or the Windows look and feel. Additionally, the Java
platform supports the GTK+ look and feel, which makes hundreds
of existing look and feels available to Swing programs. Many more
look-and-feel packages are available from various sources.
Enables assistive technologies, such as screen readers and Braille
displays, to get information from the user interface.
Enables developers to easily incorporate high-quality 2D graphics,
text, and images in applications and applets. Java 2D includes
extensive APIs for generating and sending high-quality output to

printing devices.

javax.accessibility

javax.swing.plaf

javax.swing.text

javax.swing

javax.swing.plaf.basic javax.swing.text.html

javax.swing.border

javax.swing.plaf.metal

javax.swing.text.html.parser javax.swing.colorchooser
javax.swing.plaf.multi javax.swing.text.rtf javax.swing.event
javax.swing.plaf.synth javax.swing.tree
javax.swing.filechooser
javax.swing.table
Allows developers
to build applicationsjavax.swing.undo
that can interact with

users
worldwide in their own languages and cultural conventions. With
Internationalization the input method framework developers can build applications that
accept text in languages that use thousands of different characters,
such as Japanese, Chinese, or Korean.

This trail concentrates on the Swing components. We help you choose the appropriate
components for your GUI, tell you how to use them, and give you the background information
you need to use them effectively. We also discuss other JFC features as they apply to Swing
components.

Which Swing Packages Should I Use?

The Swing API is powerful, flexible and immense. The Swing API has 18 public packages:

Fortunately, most programs use only a small subset of the API. This trail sorts out the
API for you, giving you examples of common code and pointing you to methods and
classes you're likely to need. Most of the code in this trail uses only one or two Swing
packages:
javax.swing
javax.swing.event (not always required)

COMPILING AND RUNNING SWING PROGRAMS


This section explains how to compile and run a Swing application from the command line. For
information on compiling and running a Swing application using NetBeans IDE. The
compilation instructions work for all Swing programs applets, as well as applications. Here
are the steps you need to follow:

Install the latest release of the Java SE platform, if you haven't already done so.
Create a program that uses Swing components.
Compile the program.
Run the program.

Install the Latest Release of the Java SE Platform


You can download the latest release of the JDK for free from
http://java.sun.com/javase/downloads.

Create a Program That Uses Swing Components


You can use a simple program we provide, called HelloWorldSwing, that
brings up the GUI shown in the figure below. The program is in a single file,
HelloWorldSwing.java. When you save this file, you must match the
spelling and capitalization of its name exactly.

Compile the Program


Your next step is to compile the program. Here's an example of compiling HelloWorldSwing.java:
javac HelloWorldSwing.java
If you can't compile, make sure you're using the compiler in a recent release of the Java platform. Once
you've updated your JDK, you should be able to use the programs in this trail without changes. Another
common mistake is installing the Java Runtime Environment (JRE) and not the full Java Development Kit
(JDK) needed to compile these programs

Run the Program


After you compile the program successfully, you can run it. For example:
java HelloWorldSwing

LEARNING SWING WITH THE NETBEANS IDE


This section provides an introduction to Graphical User Interface (GUI)
programming with Swing and the NetBeans IDE. As you learned in the "Hello
World!" lesson, the NetBeans IDE is a free, open-source, cross-platform
integrated development environment with built-in support for the Java
programming language. It offers many advantages over coding with a text
editor; we recommend its use whenever possible. If you have not yet read the
above lesson, please take a moment to do so now. It provides valuable
information about downloading and installing the JDK and NetBeans IDE.
The goal of this section is to introduce the Swing API by designing a simple
application that converts temperature from Celsius to Fahrenheit. Its GUI will
be basic, focusing on only a subset of the available Swing components. We will
use the NetBeans IDE GUI builder, which makes user interface creation a
simple matter of drag and drop. Its automatic code generation feature simplifies

the GUI development process, letting you focus on the application logic instead
of the underlying infrastructure.
Because this lesson is a step-by-step checklist of specific actions to take, we
recommend that you run the NetBeans IDE and perform each step as you read
along. This will be the quickest and easiest way to begin programming with
Swing. If you are unable to do so, simply reading along should still be useful,
since each step is illustrated with screenshots.
If you prefer the traditional approach of programming each component
manually (without the assistance of an IDE), think of this lesson as an entry
point into the lower-level discussions already provided elsewhere in the tutorial.
Hyperlinks in each discussion will take you to related lessons, should you wish
to learn such lower-level details.
The finished GUI for this application will look as follows:

The CelsiusConverter Application.

From an end-user's perspective, usage is simple: enter a temperature (in


Celsius) into the text box, click the "Convert" button, and watch the converted
temperature (in Fahrenheit) appear on screen. The minimize, maximize, and
close buttons will behave as expected, and the application will also have a title
that appears along the top of the window.
From a programmer's perspective, we will write the application in two main
stages. First, we will populate the GUI with the various Swing components and
arrange them as shown above. Then, we will add the application logic, so that
the program actually performs a conversion when the user presses the
"Convert" button.

SETTING UP THE CELSIUS CONVERTER PROJECT


If you have worked with the NetBeans IDE in the past, much of this section will look
familiar, since the initial steps are similar for most projects. Still, the following steps
describe settings that are specific to this application, so take care to follow them closely.

Step 1: Create a New Project


To create a new project, launch the NetBeans IDE and choose New Project
from the File menu:

230

Creating a New Project


Keyboard shortcuts for each command appear on the far right of each menu item. The look and
feel of the NetBeans IDE may vary across platforms, but the functionality will remain the same.

Step 2: Choose General -> Java Application


Next, select General from the Categories column, and Java Application from the Projects
column:

This figure has been reduced to fit on the page.


Click the image to view it at its natural size.

231

You may notice mention of "J2SE" in the description pane; that is the old name
for what is now known as the "Java SE" platform. Press the button labeled
"Next" to proceed.

Step 3: Set a Project Name


Now enter "CelsiusConverterProject" as the project name. You can leave the
Project Location and Project Folder fields set to their default values, or click the
Browse button to choose an alternate location on your system.

This figure has been reduced to fit on the page.


Click the image to view it at its natural size.

Make sure to deselect the "Create Main Class" checkbox; leaving this option
selected generates a new class as the main entry point for the application, but
our main GUI window (created in the next step) will serve that purpose, so
checking this box is not necessary. Click the "Finish" button when you are
done.

232

This figure has been reduced to fit on the page.


Click the image to view it at its natural size.

When the IDE finishes loading, you will see a screen similar to the above. All
panes will be empty except for the Projects pane in the upper left hand corner,
which shows the newly created project.

Step 4: Add a JFrame Form

This figure has been reduced to fit on the page.


Click the image to view it at its natural size.

Now right-click the CelsiusConverterProject name and choose New -> JFrame
Form (JFrame is the Swing class responsible for the main frame for your

233

application.) You will learn how to designate this class as the application's entry
point later in this lesson.

Step 5: Name the GUI Class


Next, type CelsiusConverterGUI as the class name, and learn as the package name.
You can actually name this package anything you want, but here we are following the tutorial
convention of naming the package after the lesson in which is resides.

This figure has been reduced to fit on the page.


Click the image to view it at its natural size.

The remainder of the fields should automatically be filled in, as shown above.
Click the Finish button when you are done.

234

This figure has been reduced to fit on the page.


Click the image to view it at its natural size.

When the IDE finishes loading, the right pane will display a design-time,
graphical view of the CelsiusConverterGUI. It is on this screen that you will
visually drag, drop, and manipulate the various Swing components.

NETBEANS IDE BASICS


It is not necessary to learn every feature of the NetBeans IDE before exploring its GUI creation
capabilities. In fact, the only features that you really need to understand are the Palette, the
Design Area, the Property Editor, and the Inspector. We will discuss these features below.

The Palette
The Palette contains all of the components offered by the Swing API. You can probably already
guess what many of these components are for, even if this is your first time using them
(JLabel is a text label, JList is a drop-down list, etc.)

This figure has been reduced to fit on the page.


Click the image to view it at its natural size.

235

From this list, our application will use only JLabel (a basic text label),
JTextField (for the user to enter the temperature), and JButton (to convert
the temperature from Celsius to Fahrenheit.)

The Design Area


The Design Area is where you will visually construct your GUI. It has two views: source view,
and design view. Design view is the default, as shown below. You can toggle between views at
any time by clicking their respective tabs.

This figure has been reduced to fit on the page.


Click the image to view it at its natural size.

The figure above shows a single JFrame object, as represented by the large
shaded rectangle with blue border. Commonly expected behavior (such as
quitting when the user clicks the "close" button) is auto-generated by the IDE
and appears in the source view between uneditable blue sections of code known
as guarded blocks.

236

This figure has been reduced to fit on the page.


Click the image to view it at its natural size.

A quick look at the source view reveals that the IDE has created a private
method named initComponents, which initializes the various components of
the GUI. It also tells the application to "exit on close", performs some layoutspecific tasks, then packs the (soon to be added) components together on screen.

The Property Editor


The Property Editor does what its name implies: it allows you to edit the properties of each
component. The Property Editor is intuitive to use; in it you will see a series of rows one row
per property that you can click and edit without entering the source code directly. The
following figure shows the Property Editor for the newly added JFrame object:

237

This figure has been reduced to fit on the page.


Click the image to view it at its natural size.
The screenshot above shows the various properties of this object, such as background color,
foreground color, font, and cursor.

The Inspector
The last component of the NetBeans IDE that we will use in this lesson is the Inspector:

The Inspector
The Inspector provides a graphical representation of your application's components. We will use
the Inspector only once, to change a few variable names to something other than their defaults.

CREATING THE CELSIUSCONVERTER GUI


This section explains how to use the NetBeans IDE to create the application's
GUI. As you drag each component from the Palette to the Design Area, the IDE
will auto-generate the appropriate source code.

238

Step 1: Set the Title


First, set the title of the application's JFrame to "Celsius Converter", by single-clicking the
JFrame in the Inspector:

Selecting the JFrame


Then, set its title with the Property Editor:

Setting the Title


You can set the title by either double-clicking the title property and entering the new text
directly, or by clicking the
button and entering the title in the provided field. Or, as a
shortcut, you could single-click the JFrame of the inspector and enter its new text directly
without using the property editor.

239

Step 2: Add a JTextField


Next, drag a JTextField from the Palette to the upper left corner of the Design Area. As you
approach the upper left corner, the GUI builder will will provide visual cues (dashed lines) that
suggest the appropriate spacing. Using these cues as a guide, drop a JTextField into the
upper left hand corner of the window as shown below:

Adding a JTextField
You may be tempted to erase the default text "JTextField1", but just leave it in place for now.
We will replace it later in this lesson as we make the final adjustments to each component.

Step 3: Add a JLabel


Next, drag a JLabel onto the Design Area. Place it to the right of the JTextField, again
watching for visual cues that suggest an appropriate amount of spacing. Make sure that text base
for this component is aligned with that of the JTextField. The visual cues provided by the
IDE should make this easy to determine.

240

Adding a JLabel

Step 4: Add a JButton


Next, drag a JButton from the Palette and position it to the left and underneath the
JTextField. Again, the visual cues will help guide it into place.

241

Adding a JButton

You may be tempted to manually adjust the width of the JButton and
JTextField, but just leave them as they are for now. You will learn how to
correctly adjust these components later in this lesson. For more information
about this component.

242

Step 5: Add a Second JLabel

Adding a Second JLabel

Finally, add a second JLabel, repeating the process in step 2. Place this second
label to the right of the JButton, as shown above.
Adjusting the CelsiusConverter GUI
With the GUI components now in place, it is time to make the final adjustments. There are a
few different ways to do this; the order suggested here is just one possible approach.

Step 1: Set the Component Text


First, double-click the JTextField and JButton to change the default text
that was inserted by the IDE. When you erase the text from the JTextField, it
will shrink in size as shown below. Change the text of the JButton from
"JButton1" to "Convert." Also change the top JLabel text to "Celsius" and the
bottom to "Fahrenheit."

243

Setting the Component Text

Step 2: Set the Component Size


Next, shift-click the JTextField and JButton components. This will
highlight each showing that they are selected. Right-click (control-click for
mac users) Same Size -> Same Width. The components will now be the same
width, as shown below. When you perform this step, make sure that JFrame
itself is not also selected. If it is, the Same Size menu will not be active.

244
Setting the JTextField and JButton Sizes

Step 3: Remove Extra Space


Finally, grab the lower right-hand corner of the JFrame and adjust its size to eliminate any
extra whitespace. Note that if you eliminate all of the extra space (as shown below) the title
(which only appears at runtime) may not show completely. The end-user is free to resize the
application as desired, but you may want to leave some extra space on the right side to make
sure that everything fits correctly. Experiment, and use the screenshot of the finished GUI as a
guide.

The Completed GUI

The GUI portion of this application is now complete! If the NetBeans IDE has done its job, you
should feel that creating this GUI was a simple, if not trivial, task. But take a minute to click on
the source tab; you might be surprised at the amount of code that has been generated.

245

This figure has been reduced to fit on the page.


Click the image to view it at its natural size.

To see the code in its entirety, scroll up and down within the IDE as necessary.
You can expand or collapse certain blocks of code (such as method bodies) by
clicking the + or - symbol on the left-hand side of the source editor.
Adding the Application Logic
It is now time to add in the application logic.

Step 1: Change the Default Variable Names


The figure below shows the default variable names as they currently appear within the
Inspector. For each component, the variable name appears first, followed by the object's type in
square brackets. For example, jTextField1 [JTextField] means that "jTextField1" is
the variable name and "JTextField" is its type.

246
Default Variable Names
The default names are not very relevant in the context of this application, so it makes sense to
change them from their defaults to something that is more meaningful. Right-click each variable
name and choose "Change variable name." When you are finished, the variable names should
appear as follows:

New Variable Names


The new variable names are "tempTextField", "celsiusLabel", "convertButton", and
"fahrenheitLabel." Each change that you make in the Inspector will automatically propagate its
way back into the source code. You can rest assured that compilation will not fail due to typos
or mistakes of that nature mistakes that are common when editing by hand.

Step 2: Register the Event Listeners


When an end-user interacts with a Swing GUI component (such as clicking the Convert button),
that component will generate a special kind of object called an event object which it will
then broadcast to any other objects that have previously registered themselves as listeners for
that event. The NetBeans IDE makes event listener registration extremely simple:

247

This figure has been reduced to fit on the page.


Click the image to view it at its natural size.

In the Design Area, click on the Convert button to select it. Make sure that only
the Convert button is selected (if the JFrame itself is also selected, this step will
not work.) Right-click the Convert button and choose Events -> Action ->
ActionPerformed. This will generate the required event-handling code, leaving
you with empty method bodies in which to add your own functionality:

This figure has been reduced to fit on the page.


Click the image to view it at its natural size.

248

There are many different event types representing the various kinds of actions
that an end-user can take (clicking the mouse triggers one type of event, typing
at the keyboard triggers another, moving the mouse yet another, and so on.) Our
application is only concerned with the ActionEvent;

Step 3: Add the Temperature Conversion Code


The final step is to simply paste the temperature conversion code into the empty method body.
The following code is all that is necessary to convert a temperature from Celsius to Fahrenheit:

//Parse degrees Celsius as a double and convert to


Fahrenheit.
int tempFahr = (int)
((Double.parseDouble(tempTextField.getText()))
* 1.8 + 32);
fahrenheitLabel.setText(tempFahr + " Fahrenheit");
Simply copy this code and paste it into the convertButtonActionPerformed method as shown
below:

This figure has been reduced to fit on the page.


Click the image to view it at its natural size.
With the conversion code in place, the application is now complete.

Step 4: Run the Application


Running the application is simply a matter of choosing Run -> Run Main Project within the
NetBeans IDE. The first time you run this application, you will be prompted with a dialog
asking to set CelsiusConverterGUI as the main class for this project. Click the OK
button, and when the program finishes compiling, you should see the application running in its
own window.

249

Congratulations! You have completed your first Swing application!

LET US SUM UP
Though very good GUI applications are possible using awt, the GUI components
still seem rather minimal, primitive, and awkward. That was why Swing came in. Swing
contains a large variety of most elegant looking components; those that you expect to see
in a modern UI, everything from buttons that contain pictures to trees and grids. Its a big
library, but its designed to have appropriate complexity for the task at hand if
something is simple, you dont have to write much code but as you try to do more your
code becomes increasingly complex. This means an easy entry point, but youve got the
power if you need it.
Swing has great depth. This section does not attempt to be comprehensive, but instead introduces
the power and simplicity of Swing to get you started using the library. Please be aware that what you see
here is intended to be simple. If you need to do more, then Swing can probably give you what you want if
youre willing to do the research by hunting through the online documentation from Sun. There are so
many components in Swing and each component has so many interfaces and functions that it is virtually
impossible to deal completely with it in a course of this sort. Moreover it would be unfair to expect one to
memorize all these things from a book. The best way to learn is by experience. However, the salient
features of some of the most important components will be dealt with here. That would be enough to make
a start. Actually excellent applications using GUI can be developed with this knowledge alone. But if one
wants to learn more, he can use this knowledge as a foundation and build up upon it by working more with
Swing and hunting through the online documentation from Sun.

LESSON END ACTIVITIES


1.

Create a graphical user interface for a calculator, using Swing components.

2.

Add a menu bar to the calculator, you created in the previous example. The menu bar must contain
menus File, Edit, View. File must contain Open and Close buttons. Edit must contain
Cut, Copy and Paste. View must contain Ordinary and Scientific. The two must be
separated by a separator. Also provide short cuts for using the menus, through the keyboard.

3.

Create an interface that looks similar to the windows explorer. Populate it fictional filenames and
directory names. Few of them will do, but see to it that there is at least one folder that contains two
levels of sub folders and one with one sub folders. All others may be folders with a few files in
them

.
[Hint: Make use of tree, scroll pane and split pane]
4.

Create a GUI, having a tabbed pane that has images in each of the panes and the title of each tab is
the name of the image. The GUI must also have four buttons TOP, BOTTOM, RIGHT,
LEFT. If the user presses the button BOTTOM, the tabs must be displayed at the bottom.
Similarly if he presses LEFT, the tabs must be displayed to the left and so on.

5.

Create a table having columns Name, Roll Number and Total Marks. Populate the table with
at least ten rows. As a further exercise, make this table editable. If time permits, create a database
table, consisting of these fields, and develop the application such that changes to the table will be
reflected in the database.

12.9. POINTS FOR DISCUSSION


Your application will be a Graphical User Interface (GUI) that looks similar to these:

250

This GUI contains several components:

a JTextArea component, in which you can type text or display content of a file.

a JMenuBar component, which contains two JMenu components


1) a JMenu component which is labeled "File". This menu contains three items:
"Open", "Save As" and "Exit".
2) a JMenu component which is labeled "Style". This menu contains two submenus: the JMenu "font-type" and the JMenu "textAreaColor". The "fonttype" menu contains three items: "Plain", "Bold" and "Italic". The
"textAreaColor" menu contains two sub-menus: the JMenu "ForegroundColor" and the JMenu "Background-Color", each contains four items
representing the color: Pink, White, Blue and Black.

You are required to achieve the following tasks with these components:
(1)
If you click File-> Open, you should be able to open a file window as below.
You can open a file by either double clicking the file name or typing in the file
name and hitting the open button, just as you normally do. The content of the
file you selected should be shown in the text area. Only the content of a plain text
file is required to be shown correctly. If the file doesnt exist (double clicking the
file name wont has this problem, but if you type into the file name, it is possible),
show a message box to indicate such an error. If you click Cancel, this window
will be closed and nothing happens.

251

HINT: Design of this open window is NOT your job; its already done in the
JFileChoose class. Go to http://java.sun.com/j2se/1.4.2/docs/api/ to check
what functions and fields this class provides. What you need to do is figuring out which
file has been selected and how to read its context into the text area. As to the message
box, refer to the JOptionPane class.
(2)

If you click File-> Save As, you should be able to open a file window as
below. After you double click a file name or type in a file name and click Save,
the text currently shown in the text area should be saved in that file. You are NOT
required to handle a double confirmation if the file has existed, so be careful that
you may override some useful files (just be careful by yourself, this lab doesnt
require you to do anything about it). If you click Cancel, this window will be
closed and nothing happens.

HINT: Same as task (1), this window is also manipulated by the JFileChoose class.
(3)

If you click File-> Exit, your text editor window will be closed and the
program stops.

(4)

You should be able to change the font style, the foreground color and the
background color of the text area.

12.10. REFERENCES
Jane Jawroski, Java Unleashed, SAMS Techmedia Publications, 1999
Campione, Walrath and Huml, The Java Tutorial, Addison Wesley 1999

252

LESSON 13: ADVANCED JAVA TECHNIQUES


Contents
Aims and Objectives
JAVA Server Pages
Overview of EJB
JINI Technology Architectural Overview
Overview of CORBA
Let us Sum UP
Lesson-End Activities
Points for Discussion
References

AIMS AND OBJECTIVES


At the end of this lesson you can able to understand

Understand JSP
Architecture of CORBA
Applications of EJB
Applications of JINI

JAVA SERVER PAGES


What Is JSP?
JavaServer Pages are all about data-- how to move it, handle it and display it. JSP lets the
programmer build dynamic web sites. For example, when you log on to your favorite on-line book store,
the web site may greet you by name and suggest new titles of specific interest to you based on your past
purchases. The web site content changes dynamically, in this example, based on who the user is. With JSP,
web site design is not only a function of how the data is presented but also what data is used (and how it is
used) based on current conditions.

Why Use JSP Instead of Pure Java?


JSP facilitates a division of labor between programmers and page designers.
As we go ahead we will see that JSP looks a lot like HTML with embedded Java. The HTML
paints the page, and the Java gets the work done, but that means the page designers and the programmers
are constantly working on the same JSP script
If you let the page designers translate their vision into the JSP's HTML and let the programmers
write their part in Java Beans that are executed from the JSP part of the script, then nobody steps on
anybody. It's a powerful division of labor, allowing each group to concentrate on doing what it does best.
Another advantage of this approach is that Java Beans are reusable, so it just makes good sense to separate
them out into database calls, business rules, and other common routines.
So Learning JSP also Means Learning HTML and Java Beans

253

Java Beans aren't all that big a deal either. If you can write an applet or a Java application, you can
write a Bean. It's just got a bit more structure. We're not going to get there for quite a while, but Bean
basics will be covered when we do.
How Does the JSP Process Work?
First we need to define a few terms that will keep popping up.
A Web Server is software that accepts a request for a web file (HTML). When it gets that file, it
sends the information back to the client machine's browser for display.
A Container is software that stores JSP files and servlets, converts JSP files into servlets,
compiles servlets, and runs servlets, creating HTML. All this stuff happens when the web server gets a
request for a file with a .jsp extension.
We'll also be talking about some software to accommodate connection pooling, but that can wait
until a subsequent lesson when we're going after real data.
The user does something to cause a request for a JSP file to be sent to the web browser. A realworld example is a HTML form that allows the user to enter something and then take an action (like
clicking a button) that fires off a request to the web server for a JSP file to be loaded into the web browser
and displayed.
The web server receives the request for a .jsp file, but it has no idea what to do with the .jsp
extension. Remember, this web server isn't all that bright. It serves up HTML, and nothing else, so it
forwards the request to the container.
The container looks for a servlet class with the requested file name in the appropriate package. If it
finds the servlet, it runs the servlet, creating HTML that is immediately sent to the web browser (so,
servlets create HTML).
Important point: a JavaServer Page is converted to a Java servlet for compiling and processing.
If the container doesn't find the servlet class, it looks for the same file name, but with a .jsp
extension. If it finds a match, the JSP is converted to a servlet by the container's JSP engine, and the servlet
is compiled. Then the container runs the servlet, creating HTML that is immediately sent to the web
browser, just like before.
The web server gets the newly-created HTML from the container and forwards it to the client's
browser for processing. The browser does its thing and the user sees the data he/she requested in the
beginning.

OVERVIEW OF ENTERPRISE JAVA BEANS


TM

Enterprise JavaBeans (EJB) technology defines a model for the development and deployment of reusable
TM
Java server components. Components are pre-developed pieces of application code that can be assembled
TM
into working application systems. Java technology currently has a component model called JavaBeans ,
which supports reusable development components. The EJB architecture logically extends the JavaBeans
component model to support server components.
Server Components
Server components are application components that run in an application server. EJB technology is part of
Sun's Enterprise Java platform, a robust Java technology environment that can support the rigorous

254
demands of large-scale, distributed, mission-critical application systems. EJB technology supports
application development based on a multitier, distributed object architecture in which most of an
application's logic is moved from the client to the server. The application logic is partitioned into one or
more business objects that are deployed in an application server.
Java Application Servers
A Java application server provides an optimized execution environment for server-side Java application
components. By combining traditional OLTP technologies with new distributed object technologies, a Java
application server delivers a high-performance, highly scalable, robust execution environment specifically
suited to support Internet-enabled application systems.
WORA
The Enterprise JavaBeans architecture defines a standard model for Java application servers to support
TM
"Write Once, Run Anywhere " (WORA) portability. WORA is one of the primary tenets of Java
technology. The Java virtual machine (JVM) allows a Java application to run on any operating system. But
server components require additional services that are not supplied directly by the JVM. These services are
supplied either by an application server or by a distributed object infrastructure, such as CORBA or
DCOM. Traditionally, each application server supplied a set of proprietary programming interfaces to
access these services, and server components have not been not portable from one application server to
another. For example, a server component designed to run in BEA Tuxedo could not execute in IBM
TXSeries without significant modification. The EJB server component model defines a set of standard
vendor-independent interfaces for all Java application servers.
Component Portability
Enterprise JavaBeans technology takes the WORA concept to a new level. Not only can these components
run on any platform, but they are also completely portable across any vendor's EJB-compliant application
server. The EJB environment automatically maps the component to the underlying vendor-specific
infrastructure services.
Enterprise JavaBeans Specification
The Enterprise JavaBeans specification defines a standard model for a Java application server that supports
complete portability. Any vendor can use the model to implement support for Enterprise JavaBeans
components. Systems, such as TP monitors, CORBA runtime systems, COM runtime systems, database
systems, Web server systems, or other server-based runtime systems can be adapted to support portable
Enterprise JavaBeans components.
Overview of Components
Components
A component is a reusable software building block: a pre-built piece of encapsulated application code that
can be combined with other components and with handwritten code to rapidly produce a custom
application.
Containers
Components execute within a construct called a container. A container provides an application context for
one or more components and provides management and control services for the components. In practical
terms, a container provides an operating system process or thread in which to execute the component.
Client components normally execute within some type of visual container, such as a form, a compound
document, or a Web page. Server components are non-visual and execute within a container that is
provided by an application server, such as a TP monitor, a Web server, or a database system.

255

Component Model
A component model defines the basic architecture of a component, specifying the structure of its interfaces
and the mechanisms by which it interacts with its container and with other components. The component
model provides guidelines to create and implement components that can work together to form a larger
application. Application builders can combine components from different developers or different vendors
to construct an application.
Granularity
Components come in a variety of shapes and sizes. A component can be very small, such as a simple GUI
widget (e.g., a button), or it can implement a complex application service, such as an account management
function.
Standard Interface
In order to qualify as a component, the application code must provide a standard interface that enables
other parts of the application to invoke its functions and to access and manipulate the data within the
component. The structure of the interface is defined by the component model.
Customization without Source Code
An application developer should be able to make full use of the component without requiring access to its
source code. Components can be customized to suit the specific requirements of an application through a
set of external property values. For example, the button component has a property that specifies the name
that should appear on the button. The account management component has a property that specifies the
location of the account database. Properties can be used to support powerful customization services. For
example, the account management component might allow a user to add a special approval process for
withdrawals over a certain dollar amount. One property would be used to indicate that special approval
functions are enabled, a second property would identify the conditions that require special approvals, and a
third property would indicate the name of the approval process component that should be called when the
condition exists.
Component Marketplace
One of the promises of component technology is a world in which customized business solutions can be
assembled from a set of off-the-shelf business objects. Software vendors could produce numerous
specialized business components, and organizations could select the appropriate components to match their
business needs. Thus far, there is a fairly rich supply of off-the-shelf, third-party, client-side development
components. For the moment, the market for server-side components is still very young. As more and more
organizations adopt the server component architecture, the market is likely to mature rapidly. Application
software companies are already beginning to implement applications using server components. Some ecommerce vendors are beginning to supply individual application functions, such as a shopping cart and a
credit validation service, as customizable components.
Server Components
Shared Servers
In order to achieve the most benefit from the multitier architecture, server components should be
implemented as shared servers. But building a shared server is harder than building a single-user
application function. Highly scalable shared servers need to support concurrent users, and they need to
efficiently share scarce system resources, such as threads, processes, memory, database connections, and
network connections. For business operations, shared servers must participate in transactions. In many
cases, a shared server needs to enforce security policies.

256

Plug-and-Play Assembly
A component builder doesn't especially want to implement multithreading, concurrency control, resourcepooling, security, and transaction management in every component. If these services were implemented in
each component, achieving true plug-and-play application assembly would be very difficult. A component
model standardizes and automates the use of these services, thereby enabling easy application development.
Container
An application server provides a container to manage the execution of a component. When a client invokes
a server component, the container automatically allocates a process thread and initiates the component. The
container manages all resources on behalf of the component and manages all interactions between the
component and the external systems.
Example Application Servers
There are many different types of application servers in common use today, and each provides a container
for some type of server-based request. For example:
A TP monitor contains transactions and manages shared resources on behalf of a transaction.
Multiple transactions can work together and rely on the TP monitor to coordinate the extended
transaction.
A database management system (DBMS) contains database requests. Multiple database clients can
submit requests to the database concurrently and rely on the DBMS to coordinate locks and
transactions.
A Web server contains Web page requests. Multiple Web clients can submit concurrent page
requests to the Web server. The Web server serves up HTML pages or invokes server extensions
or servlets in response to requests.
Portability across Containers
The operations and behaviors of a container are defined by its component model. Unfortunately, each
container implements its own set of services with its own service interfaces. As a result, components
developed for one type of environment are usually not portable to any other type of environment. The
Enterprise JavaBeans component model, however, is designed to deliver a portability layer for these
container systems.
EJB Servers
The first EJB-compliant application servers began to appear in August 1998. Products that are shipping or
in beta as of this writing include:
BEA WebLogic Tengah
Bluestone Sapphire/Web
GemStone GemStone/J
IBM WebSphere Advanced Edition
Novera jBusiness
Oracle8i
Oracle Application Server
OrchidSoft Vanda
Persistence PowerTier
Progress Apptivity
Secant Extreme
Valto Ejipt
Additional EJB-compliant application servers should be available in early 1999 from vendors, such as
Forte, Fujitsu, Haht, Inprise, Informix, Netscape, Sun, Sybase, and Vision.

257

Benefits
Component Portability
The Enterprise JavaBeans architecture provides a simple and elegant server component container model.
The model ensures that Java platform server components can be developed once and deployed anywhere, in
any vendor's container system. Even though the container systems implement their runtime services
differently, the Enterprise JavaBeans interfaces ensure that an enterprise bean can rely on the underlying
system to provide consistent lifecycle, persistence, transaction, distribution, and security services.
Architecture Independence
The Enterprise JavaBeans architecture is completely independent from any specific platform, protocol, or
middleware infrastructure. Applications that are developed for one platform can be picked up, moved, and
redeployed to another platform. EJB applications can scale from a small single-processor, Intel-based
TM
Novell environment to a large multiprocessor, UltraSPARC environment to a massive Sysplex IBM
mainframe environment-all without modification.
Developer Productivity
The Enterprise JavaBeans architecture improves the productivity of application developers. The Enterprise
JavaBeans environment automates the use of complex infrastructure services, such as transactions, thread
management, and security checking. Component developers and application builders do not need to
implement complex service functions within the application programming logic.
Highly Customizable
Enterprise JavaBeans applications are highly customizable. The underlying component model supports
customization without requiring access to source code. Application behaviors and runtime settings are
defined through a set of attributes that can be changed at deployment time.
Wrap and Embrace
The Enterprise JavaBeans architecture is an extremely compatible evolutionary environment. The
Enterprise Java services layer over existing infrastructure services. Organizations are not required to
implement yet another incompatible set of middleware technologies. Enterprise JavaBeans technology
enhances, enables, and simplifies popular systems, such as CORBA or DCOM.
Versatility and Scalability
The Enterprise JavaBeans model is based on an extremely versatile and powerful multitier, distributed
object architecture that relies on industry-standard protocols. The model is appropriate for small-scale
applications or large-scale business transactions. As application requirements grow, applications can
migrate to progressively more powerful operating environments. The environment inherently supports
Web-based applications and a variety of other Internet-enabled client devices. Additional client systems
can be added at any time without modification of the core application systems. Enterprise JavaBeans
technology provides an environment that is designed to grow with the industry to support new technologies
as they emerge.

JINI TECHNOLOGY ARCHITECTURAL OVERVIEW


A Jini system is a distributed system based on the idea of federating groups of users and the resources
required by those users. The overall goal is to turn the network into a flexible, easily administered tool on
which resources can be found by human and computational clients. Resources can be implemented as either

258
hardware devices, software programs, or a combination of the two. The focus of the system is to make the
network a more dynamic entity that better reflects the dynamic nature of the workgroup by enabling the
ability to add and delete services flexibly.
A Jini system consists of the following parts:

A set of components that provides an infrastructure for federating services in a distributed system
A programming model that supports and encourages the production of reliable distributed services
Services that can be made part of a federated Jini system and which offer functionality to any
other member of the federation

While these pieces are separable and distinct, they are interrelated, which can blur the distinction in
practice. The components that make up the Jini technology infrastructure make use of the Jini programming
model; services that reside within the infrastructure also use that model; and the programming model is
well supported by components in the infrastructure.
The end goals of the system span a number of different audiences; these goals include the following:
Enabling users to share services and resources over a network
Providing us
t-in security that allows the confidence to run code downloaded from another machine. Strong typing in the
Java application environment enables identifying the class of an object to be run on a virtual machine even
when the object did not originate on that machine. The result is a system in which the network supports a
fluid configuration of objects which can move from place to place as needed and can call any part of the
network to perform operations.
The Jini architecture exploits these characteristics of the Java application environment to simplify the
construction of a distributed system. The Jini architecture adds mechanisms that allow fluidity of all
components in a distributed system, extending the easy movement of objects to the entire networked
system.
The Jini technology infrastructure provides mechanisms for devices, services, and users to join and detach
from a network. Joining into and leaving a Jini system is an easy and natural, often automatic, occurrence.
Jini systems are far more dynamic than is currently possible in networked groups where configuring a
network is a centralized function done by hand.

How Jini Connection Technology Works


Jini connection technology consists of an infrastructure and a programming model
which address the fundamental issues of how devices connect with each other to
form an impromptu community. Based on Java technology, Jini technology uses
Java Remote Method Invocation protocols to move code around the network.
Network services run on top of the Jini software architecture.

259

Architecture of Jini Connection Technology

Devices and applications use a process known as discovery to register with the network. Once registered,
the device or application places itself in the lookup service, equivalent to a bulletin board for all services on
the network. The lookup can store not only pointers to the services on the network, but also the code for
these services.
For example, when a printer registers with the lookup, it loads its printer driver or an interface to the driver
into the lookup. When a client wants to use the printer, the driver and driver interface get downloaded from
the lookup to the client. This code mobility means that clients can take advantage of services from the
network without pre-installing or loading drivers or other software.
The printer might also load other value-added services into the lookup. For instance, the printer might store
attributes about itself, such as whether it supports the Postscript language or color printing. The printer
might also store help wizards that will run on the client to make it easier for people on the network to use
the printer's services.
To preserve the network's flexibility and resilience, Jini technology employs the concept of leasing. When a
device joins the network, it registers for a certain leased time. As the time expires, the device can
renegotiate the lease. But if the device is removed from the network before the lease expires, the device's
entry in the lookup is removed.

OVERVIEW OF CORBA
The Common Object Request Broker Architecture (CORBA) is an emerging open distributed
object computing infrastructure being standardized by the Object Management Group. CORBA automates
many common network programming tasks such as object registration, location, and activation; request
demultiplexing; framing and error-handling; parameter marshalling and demarshalling; and operation
dispatching.
The following figure illustrates the primary components in the OMG Reference Model
architecture..

Figure. OMG Reference Model Architecture


Object Services -- These are domain-independent interfaces that are used by many distributed object
programs. For example, a service providing for the discovery of otheravailable services is almost always
necessary regardless of the application domain.

Two examples of Object Services that fulfill this role are:


The Naming Service -- which allows clients to find objects based on names;
The Trading Service -- which allows clients to find objects based on their properties.
Common Facilities -- Like Object Service interfaces, these interfaces are also horizontally-oriented,
but unlike Object Services they are oriented towards end-user applications. An example of such a facility
is the Distributed Document Component Facility (DDCF), a compound document Common Facility
based on OpenDoc. DDCF allows for the presentation and interchange of objects based on a document
model, for example, facilitating the linking of a spreadsheet object into a report document.
Domain Interfaces -- These interfaces fill roles similar to Object Services and Common Facilities
but are oriented towards specific application domains. For example, one of the first OMG RFPs issued
for Domain Interfaces is for Product Data Management (PDM) Enablers for the manufacturing domain.
Other OMG RFPs will soon be issued in the telecommunications, medical, and financial domains.

Application Interfaces - These are interfaces developed specifically for a given application.

Because they are application-specific, and because the OMG does not develop applications (only
specifications), these interfaces are not standardized. However, if over time it appears that certain broadly
useful services emerge out of a particular application domain, they might become candidates for future
OMG standardization.

CORBA ORB Architecture


The following figure illustrates the primary components in the CORBA ORB architecture.
Descriptions of these components are available below the figure.

CORBA ORB Architecture


Object -- This is a CORBA programming entity that consists of an identity, an interface, and an

implementation, which is known as a Servant.


Servant -- This is an implementation programming language entity that defines the operations
that support a CORBA IDL interface. Servants can be written in a variety of languages, including
C, C++, Java, Smalltalk, and Ada.
Client -- This is the program entity that invokes an operation on an object implementation.
Accessing the services of a remote object should be transparent to the caller. Ideally, it should be
as simple as calling a method on an object, i.e., obj->op(args). The remaining
components in Figure 2 help to support this level of transparency.
Object Request Broker (ORB) -- The ORB provides a mechanism for transparently
communicating client requests to target object implementations. The ORB simplifies distributed
programming by decoupling the client from the details of the method invocations. This makes
client requests appear to be local procedure calls. When a client invokes an operation, the ORB is
responsible for finding the object implementation, transparently activating it if necessary,
delivering the request to the object, and returning any response to the caller.

ORB Interface -- An ORB is a logical entity that may be implemented in various ways (such as
one or more processes or a set of libraries). To decouple applications from implementation details,
the CORBA specification defines an abstract interface for an ORB. This interface provides various
helper functions such as converting object references to strings and vice versa, and creating
argument lists for requests made through the dynamic invocation interface described below.
CORBA IDL stubs and skeletons -- CORBA IDL stubs and skeletons serve as the ``glue''
between the client and server applications, respectively, and the ORB. The transformation between
CORBA IDL definitions and the target programming language is automated by a CORBA IDL
compiler. The use of a compiler reduces the potential for inconsistencies between client stubs and
server skeletons and increases opportunities for automated compiler optimizations.
Dynamic Invocation Interface (DII) -- This interface allows a client to directly access the
underlying request mechanisms provided by an ORB. Applications use the DII to dynamically
issue requests to objects without requiring IDL interface-specific stubs to be linked in. Unlike IDL
stubs (which only allow RPC-style requests), the DII also allows clients to make non-blocking
deferred synchronous (separate send and receive operations) and oneway (send-only) calls.
Dynamic Skeleton Interface (DSI) -- This is the server side's analogue to the client side's DII.
The DSI allows an ORB to deliver requests to an object implementation that does not have
compile-time knowledge of the type of the object it is implementing. The client making the
request has no idea whether the implementation is using the type-specific IDL skeletons or is
using the dynamic skeletons.
Object Adapter -- This assists the ORB with delivering requests to the object and with activating
the object. More importantly, an object adapter associates object implementations with the ORB.
Object adapters can be specialized to provide support for certain object implementation styles
(such as OODB object adapters for persistence and library object adapters for non-remote objects).

CORBAservices
CORBAservices add functionality to a CORBA application at the server level. They provide services to
objects that are necessary for various tasks, including event management, object lifecycle, and object
persistence. New CORBAservices are constantly being produced, but at the time of this writing, only the
following 15 services are in existence (a full list of available CORBAservices can be found on the OMG
Web site at http://www.omg.org):

Collection Service: This service provides access to a variety of data structures.

Concurrency Control Service: This service enables multiple clients to coordinate access to shared
resources. For example if two clients are attempting to withdraw funds from the same back
account, this service could be used to ensure that the two transactions do not happen at the same
time.

Event Service: This service enables event's to be delivered from multiple event sources to multiple
event listeners.

Externalization Service: This service enables an object (or objects) or a graph to be written out as
a stream of bytes. This is similar to object serialization in JDK 1.1.

Licensing Service: This service enables control over intellectual property. It


authors to ensure that their efforts are not being used by others for profit.

Life Cycle Service: This service defines conventions for creating, deleting, copying, and moving
objects.

Naming Service: This service allows objects to be tagged with a unique logical name. The service
can be told of the existence of objects and can also be queried for registered objects.

Persistent Object Service: This service enables objects to be stored in some medium. This medium
will usually be a relational or object database, but it could be virtually anything.

Property Service: This service enables name/value pairs to be associated with an object. For
example, some image file could be tagged with name/value pairs describing its content.

Query Service: This service enables queries to be performed against collections of objects.

Relationship Service: This service enables the relationship between entities to be logically
represented.

Security Service: This service enables access to objects to be restricted by user or by role.

Time Service: This service is used to obtain the current time along with the margin of error
associated with that time. In general, it's not possible to get the exact time from a service due to
various factors, including the time delta that occurs when messages are sent between server and
client.

Trader Object Service: This service allows objects to locate certain services by functionality. The
object will first discuss with the trader service whether a particular service is available; then it
negotiates access to those resources.

Transaction Service: This service manages multiple, simultaneous transactions across a variety of

allows content

8
environments.
CORBA services are always being developed by the OMG; chances are that by the time you read this list,
there will be a few more services. Already steps are being taken to finalize firewall and fault tolerance
services.

CORBA facilities
As stated earlier, CORBAfacilities add additional functionality to an application
level closer to the user. Facilities are similar to services in that they both aid a
CORBA application however CORBA facilities need not be simply targeted at a
broad audience.
CORBAfacilities are categorized into horizontal and vertical services.

Vertical CORBAfacilities
A vertical CORBAfacility has specific applications in a unique industry or domain.
Obvious parallels exist between a vertical CORBAfacility and a CORBAdomain; however,
CORBAdomains usually have much broader applications within the domain. The following list describes
the eight existing vertical CORBAfacilities:

Accounting: This facility enables commercial object transactions.

Application Development: This facility enables communication between application development


objects.

Distributed Simulation: This facility enables communication between objects used to create
simulations.

Imagery: This facility enables interoperability between imaging devices, images and image data.

Information Superhighways: This facility enables multiuser application communication across


wide area networks.

Manufacturing: This facility enables interoperability between objects used in a manufacturing


environment.

Mapping: This facility enables communication between objects used for mapping.

Oil and Gas Industry Exploitation and Production: This facility enables communication between
objects used in the petroleum market.

Horizontal CORBAfacilities
Horizontal CORBAfacilities are broad in their function and should be of use to virtually any application.
Due to their broad scope, there are four categories of horizontal CORBAfadilities. This list of categories is
not at all static and can be added to at some point in the future:

User Interface: All facilities in this category apply to the user interface of an application.

Information. Management: All facilities in this category deal with the modeling, definition,
storage, retrieval, and interchange of information.

System Management: All facilities in this category deal with management of information systems.
Facilities should be neutral in vendor support, because any system should be supported.

Task Management: All facilities in this category deal with automation of various user- or systemlevel tasks.

The User Interface common facilities apply to an application's, interface at many levels.
As shown in the following list, this includes everything from physically rendering object to the aggregation
of objects into compound documents:

Rendering Management: This facility enables the physical display of graphical


objects on any medium (screen, printer, plotter, and so forth).
Compound Presentation Management: This facility enables the aggregation of
multiple objects into a single compound document.
User Support: This facility enables online help presentation (both general and context sensitive) and data
validation.
Desktop Management: This facility supports the variety of, functions needed by the user at the desktop.
Scripting: This facility exists to support user automation scripts.
The Information Management common facilities enable the myriad functions required in a data ownership
situation. These facilities, defined in the following list, range in function from information management to
information storage:

Information Modeling: This facility supports the physical modeling of data storage systems.

Information Storage and Retrieval: This facility enables the storage and retrieval of information.

Compound Interchange: This facility enables the interchange of data contained in compound
documents.

Data Interchange: This facility enables the interchange of physical data.

Information Exchange: This facility enables the interchange of information as an entire logical
unit.

Data Encoding and Representation: This facility enables document encoding discovery and
translation.

Time Operations: This facility supports manipulation and understanding of time operations.

The System Management common facilities aid in the difficult task of managing a heterogeneous collection
of information systems. These facilities, defined in the following list, range in function from managing
resources to actually controlling their actions:

Management Tools: This facility enables the interoperation of management tools and collection
management tools.

Collection Management: This facility enables control over a collection of systems.

Control: This facility enables actual control over system resources.

10

The Task Management common facilities assist with the automation of user- and systemlevel tasks:
Workflow: This facility enables tasks that are directly part of a work process.
Agent: This facility supports manipulation and creation of software agents.
Rule Management: This facility enables objects to both acquire knowledge and to also take action based on
that knowledge.
Automation: This facility allows one object to access the key functionality of another object.

LET US SUM UP
In this lesson we discussed about various Advanced Techniques used in JAVA such as:

JSP
EJB
JINI
CORBA

LESSON END ACTIVITIES


List out the uses of JSP
Explain the Architecture of CORBA

POINTS FOR DISCUSSION


List out various Advanced Java Techniques with their specific applications

REFERENCES
Jane Jawroski, Java Unleashed, SAMS Techmedia Publications, 1999
Campione, Walrath and Huml, The Java Tutorial, Addison Wesley 1999

Potrebbero piacerti anche