Microsoft Word - Advanced Java Programming
Microsoft Word - Advanced Java Programming
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!);
}
}
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
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)
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
9
}
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
11
}
Besides the methods used above, the Choice class defines these other useful
methods:
int countItems()
String getItem(int)
void select(int)
void select(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
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
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.
15
Scrollbar Properties.
int orientation
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).
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.
}
int getColumns()
17
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.
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
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
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
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)
23
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
{
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.
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 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
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
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);
}
} ///:~
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);
}
} ///:~
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.)
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);
}
} ///:~
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);
}
} ///:~
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
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);
}
} ///:~
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
46
ComponentEvent
ContainerEvent
FocusEvent
InputEvent
ItemEvent
KeyEvent
MouseEvent
TextEvent
WindowEvent
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
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
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
50
51
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
54
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
56
{
interrupted);
//
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()
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);
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);
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.
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;
opening
}
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();
}
}
/*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:
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.*;
Race");
if (updateThread == null)
{
updateThread = new Thread(this, "Thread
}
}
runners[i].setPriority(2);
updateThread.setPriority(NUMRUNNERS+2);
addMouseListener(new MyAdapter());
67
68
for (int i = 0; i < NUMRUNNERS; i++)
{
if (runners[i].isAlive())
runners[i] = null;
}
if (updateThread.isAlive())
updateThread = null;
}
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
which tries to access the variable A.x. The ThreadA should print 3x and ThreadB should print 4x.
Time Sharing
70
protection is a problem.
been protected.
be
done
with
some
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.
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.
3.8. REFERENCES
th
72
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.
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)
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.
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.
Description
Implements most of the Collection
interface
Extends AbstractCollection and
implements most of the List interface
Implements a linked list by extending
AbstractSequentialList
ArrayList
AbstractSet
HashSet
TreeSet
arr.size());
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);
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);
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
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.
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();
}
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
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
void putAll(Map m)
Object remove (Object k)
int size()
Collection values()
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
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
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
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
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.
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));
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(" ");
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
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
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,
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
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();
103
}
}
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.
104
REFERENCES
Jane Jawroski, Java Unleashed, SAMS Techmedia Publications, 1999
Campione, Walrath and Huml, The Java Tutorial, Addison Wesley 1999
105
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
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
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
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.
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());
}
}
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
{
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
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());
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
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();
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
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();
}
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;
}
128
129
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?\"! "
130
currentJoke = 0;
else
currentJoke++;
state = SENTKNOCKKNOCK;
} else {
theOutput = "Bye.";
state = WAITING;
}
}
return theOutput;
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();
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();
}
133
134
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.
135
REFERENCES
Jane Jawroski, Java Unleashed, SAMS Techmedia Publications, 1999
Campione, Walrath and Huml, The Java Tutorial, Addison Wesley 1999
136
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
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
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.
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).
142
Example 1
import java.rmi.*;
import java.awt.*;
public interface Product
extends Remote
{ String getDescription()
throws RemoteException;
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;
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;
}
}
Example 7
import java.rmi.*;
import java.rmi.server.*;
145
}
catch(Exception e)
{ System.out.println("Error: " + e);
}
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.*;
147
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;
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
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
REFERENCES
Jane Jawroski, Java Unleashed, SAMS Techmedia Publications, 1999
Campione, Walrath and Huml, The Java Tutorial, Addison Wesley 1999
153
154
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.
156
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
158
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));
}
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)
{
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.
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.
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:
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
) );
XML
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>
<int>5555</int>
<class>java.swing.JFrame</class>
</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".
POINTS TO DISCUSSION
Discuss the following:
BeanInfo
Bean
Properties
Methods
Event Sources
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
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
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.
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
Database
ODBC
driver
VendorSupplied
JDBC driver
Database
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:
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:
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
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,
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.
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.*;
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
in,
190
}
}
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.*;
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.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 "
"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()
Name = '" +
publisher + "')";
int r = stmt.executeUpdate(updateStatement);
}
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.
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:
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
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 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
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:
ServletOutputStream,
javax.servlet.http package
Classes:
Interfaces:
210
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,
212
}
...
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:
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
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.
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
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
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();
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.
REFERENCES
Jane Jawroski, Java Unleashed, SAMS Techmedia Publications, 1999
Campione, Walrath and Huml, The Java Tutorial, Addison Wesley 1999
219
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
Command
jar tf jar-file
jar xf jar-file
<applet code=AppletClassName.class
archive="JarFileName.jar"
width=width height=height>
</applet>
This
secti
on
will
sho
w
you
how
to
perf
orm
the
mos
t
com
mon
JAR
-file
oper
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.
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)
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%)
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.
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
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
Accessibility API
Java 2D API
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.
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)
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.
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:
230
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.
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
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.
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.
The remainder of the fields should automatically be filled in, as shown above.
Click the Finish button when you are done.
234
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.
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.)
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 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
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.
237
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.
238
239
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.
240
Adding a JLabel
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
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.
243
244
Setting the JTextField and JButton Sizes
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
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.
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:
247
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:
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;
249
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.
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.
250
a JTextArea component, in which you can type text or display content of a file.
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
Understand JSP
Architecture of CORBA
Applications of EJB
Applications of JINI
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.
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.
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.
259
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..
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.
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):
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.
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:
Distributed Simulation: This facility enables communication between objects used to create
simulations.
Imagery: This facility enables interoperability between imaging devices, images and image data.
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:
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.
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.
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
REFERENCES
Jane Jawroski, Java Unleashed, SAMS Techmedia Publications, 1999
Campione, Walrath and Huml, The Java Tutorial, Addison Wesley 1999