A Simple Java RMI
example

There are five constructors:
However, the
Furthermore, you can append text to a
The selection is used for copy and paste and other purposes. The first character in a
The
A
For example the following
Custom canvases are added to applets just like any other component. For example,

Creating a choice menu is a little more complex than creating the other user interface components you've seen. There's an extra step, adding the menu items to the menu. That is the five steps are
These methods get or set the current selected item in the
You do not always need to do this. It is not uncommon to only check the value of a
For example, the following applet builds a

Checkboxes are often used to select from a list of possible choices when as few selections as zero or as many as everything on the list may be made. Adding a
By default check boxes are unchecked when created. If you want a
The
Every
An
For example, the following program is an applet that asks the age-old question, "What do you want on your pizza?" When an ingredient is checked the price of the pizza goes up by fifty cents. When an ingredient is unchecked fifty cents is taken off. The price is shown in a
The constructor for a
To make check boxes act like radio buttons, use this constructor for each
The label is the label for this
At any time, you can get or set the selected

The following methods add items at the end of the list:
There are three constructors:
A
Finally
A
The following program is an applet that changes the number in a

An example of text fields in Java
The following applet reads text from oneTextField
and capitalizes it in another TextField
.
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class CapitalizeApplet extends Applet {
private TextField input;
private TextField output;
public void init () {
// Construct the TextFields
this.input = new TextField(40);
this.output = new TextField(40);
this.output.setEditable(false);
Button b = new Button("Capitalize");
// add the button to the layout
this.add(input);
this.add(b);
this.add(output);
// specify that action events sent by the
// button or the input TextField should be handled
// by the same CapitalizerAction object
CapitalizerAction ca = new CapitalizerAction(input, output);
b.addActionListener(ca);
this.input.addActionListener(ca);
// notice that ActionEvents produced by output are ignored.
}
}
class CapitalizerAction implements ActionListener {
private TextField in;
private TextField out;
public CapitalizerAction(TextField in, TextField out) {
this.in = in;
this.out = out;
}
public void actionPerformed(ActionEvent ae) {
String s = in.getText();
out.setText(s.toUpperCase());
}
}
In this program, a different pattern is used for handling events. The
constructor for the CapitalizerAction
class is used to pass in references to the different components the actionPerformed()
method affects. An example of text fields in Java
An alternate pattern uses an inner class so the private fields can be accessed directly.import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class CapitalizeApplet extends Applet {
private TextField input;
private TextField output;
public void init () {
// Construct the TextFields
this.input = new TextField(40);
this.output = new TextField(40);
this.output.setEditable(false);
Button b = new Button("Capitalize");
// add the button to the layout
this.add(input);
this.add(b);
this.add(output);
// specify that action events sent by the
// button or the input TextField should be handled
// by the same CapitalizerAction object
CapitalizerAction ca = new CapitalizerAction();
b.addActionListener(ca);
this.input.addActionListener(ca);
// notice that ActionEvents produced by output are ignored.
}
class CapitalizerAction implements ActionListener {
public void actionPerformed(ActionEvent ae) {
String s = input.getText();
output.setText(s.toUpperCase());
}
}
}
TextArea
Thejava.awt.TextArea
class is a subclass of java.awt.TextComponent
that provides a widget for editing multiple lines of text. It's useful for
input and output.
There are five constructors:
public TextArea()
public TextArea(String text)
public TextArea(int rows, int columns)
public TextArea(String text, int rows, int columns)
public TextArea(String text, int rows, int columns, int scrollbars)
Because of the way Java lays out components, you should not use the noargs
constructor. Either start off with a String
or specify the number of rows and columns this area is expected to hold. For
example, TextArea address = new TextArea("Type your address here", 5, 80);
By default, TextAreas don't have scrollbars. However you can add them by
passing one of these constants to the constructor: TextArea.SCROLLBARS_BOTH
TextArea.SCROLLBARS_HORIZONTAL_ONLY
TextArea.SCROLLBARS_NONE
TextArea.SCROLLBARS_VERTICAL_ONLY
For example, TextArea instructions =
new TextArea("", 15, 70, TextArea.SCROLLBARS_VERTICAL_ONLY);
Unlike text fields, text areas do not generate action events when the user
hits return inside the area. Instead, the line is broken and the caret moves on
to the next row. However, the
getText()
method does return the contents of the TextArea
,
and the setText()
method
does change it. The setEditable()
method lets you determine whether or not, the user can modify the contents of a
TextField
. If these methods
sound familiar it's because they're both inherited from the common superclass
of TextField
and TextArea
, TextComponent
.Furthermore, you can append text to a
TextArea
with the append()
method,
insert text into the middle of a TextArea
with the insert()
method,
and replace a block of text with the replaceRange()
method:public void insert(String text, int position)
public void append(String text)
public void replaceRange(String text, int start, int end)
TextComponent
BothTextArea
and TextField
are subclasses of java.awt.TextComponent
. This class
contains methods common to both classes including several you've already seen: getText()
, setText()
, and setEditable()
.
The TextComponent
class also
defines methods for manipulating the selection and the caret and for processing
TextEvent
s. The selection is used for copy and paste and other purposes. The first character in a
TextComponent
is character 0; the second is character 1, and so on. public int getSelectionStart()
public void setSelectionStart(int selectionStart)
public int getSelectionEnd()
public void setSelectionEnd(int selectionEnd)
public void select(int selectionStart, int selectionEnd)
public void selectAll()
public String getSelectedText()
The caret is the insertion point. It's where text appears when the user
types. There are two methods to adjust it: public void setCaretPosition(int position)
public int getCaretPosition()
TextEvents
BothTextArea
and TextField
can install a TextListener
that catches TextEvent
s. TextComponent
s fire TextEvent
s every time the text of the
component changes. This is more or less every time the user hits a key in the
component. The
java.awt.event.TextListener
interface defines a single method, textValueChanged()
:public void textValueChanged(TextEvent te)
You register a TextListener
with a TextComponent
by
calling the component's addTextListener()
method. For example, TextArea password = new TextArea(24)
password.addTextListener(new PasswordChecker());
However, most of the time it's sufficient to just get and set the text as
you need it. It's really quite rare that you need to process it character by
character. A
TextListener
can be
removed by calling removeTextListener()
.public void
removeTextListener(TextListener tl)
java.awt.Canvas
Thejava.awt.Canvas
class
is a rectangular area on which you can draw using the methods of java.awt.Graphics
discussed last week.
The Canvas
class has only
three methods: public Canvas()
public void addNotify()
public void paint(Graphics g)
You generally won't instantiate a canvas directly. Instead you'll subclass
it and override the paint()
method in your subclass to draw the picture you want. For example the following
Canvas
draws a big red oval you can add to your applet.import java.awt.*;
public class RedOval extends Canvas {
public void paint(Graphics g) {
Dimension d = this.getSize();
g.setColor(Color.red);
g.fillOval(0, 0, d.width, d.height);
}
public Dimension getMinimumSize() {
return new Dimension(50, 100);
}
public Dimension getPreferredSize() {
return new Dimension(150, 300);
}
public Dimension getMaximumSize() {
return new Dimension(200, 400);
}
}
Any applet that uses components should not also override paint()
. Doing so will have unexpected
effects because of the way Java arranges components. Instead, create a Canvas
object and do your drawing in its
paint()
method.Custom canvases are added to applets just like any other component. For example,
public void init() {
this.add(new RedOval());
}
Canvases themselves do not normally fire any events. Next week, we'll see
how to change that in the subclasses. An alternate approach
import java.awt.*;
public class ColoredOval extends Canvas {
public ColoredOval() {
this(Color.RED, 100, 100);
}
public ColoredOval(Color c) {
this(c, 100, 100);
}
public ColoredOval(int width, int height) {
this(Color.RED, width, height);
}
public ColoredOval(Color c, int width, int height) {
this.setColor(c);
this.setSize(width, height);
}
public void paint(Graphics g) {
Dimension d = this.getSize();
g.fillOval(0, 0, d.width, d.height);
}
}
This is almost but not quite the same effect as the previous applet. (It's a
little less resizeable.) java.awt.Choice
Thejava.awt.Choice
class
implements a popup menu with a fixed position. (The java.awt.PopupMenu
class is a popup menu
with no fixed position. It pops up when the user clicks
and holds the right mouse button.)

Creating a choice menu is a little more complex than creating the other user interface components you've seen. There's an extra step, adding the menu items to the menu. That is the five steps are
- Declare the
Choice
- Allocate the
Choice
- Add the menu items to the
Choice
- Add the
Choice
to thelayout
- Add an
ItemListener
to theChoice
public void init() {
Choice ch;
ch = new Choice();
ch.addItem("1");
ch.addItem("2");
ch.addItem("3");
ch.addItem("4");
ch.addItem("5");
add(ch);
}
Methods of java.awt.Choice
TheChoice
class has a
number of methods to add, remove, and return different items from the list. The
list starts counting at 0. public int getItemCount()
public String getItem(int index)
public void add(String item)
public void addItem(String item)
public void insert(String item, int position)
public void remove(String item)
public void remove(int position)
public void removeAll()
However, most of the item you'll just build the Choice
when the applet starts up, and
not modify it later. These methods get or set the current selected item in the
Choice
, that is the item that's shown. public void removeAll()
public String getSelectedItem()
public Object[] getSelectedObjects()
public int getSelectedIndex()
public void select(int position)
public void select(String item)
ItemListeners
When the user changes the selected item in aChoice
, the Choice
fires two ItemListener
events, one to indicate that the original selection has been deselected and the
other to indicate that a new selection has been made. You can process these
events by registering an ItemListener
object with your Choice
. You do not always need to do this. It is not uncommon to only check the value of a
Choice
when some
other event occurs like a Button
press.For example, the following applet builds a
Choice
menu with the numbers from 1 to 5. When the user
makes a selection, the applet beeps that many times.import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class MultiBeep extends Applet {
public void init() {
Choice ch;
ch = new Choice();
ch.addItem("1");
ch.addItem("2");
ch.addItem("3");
ch.addItem("4");
ch.addItem("5");
this.add(ch);
ch.addItemListener(new BeepItem());
}
}
class BeepItem implements ItemListener {
public void itemStateChanged(ItemEvent ie) {
if (ie.getStateChange() == ItemEvent.SELECTED) {
String name = (String) ie.getItem();
Toolkit tk = Toolkit.getDefaultToolkit();
try {
int n = Integer.parseInt(name);
for (int i = 0; i < n; i++) tk.beep();
}
catch (Exception e) {
tk.beep();
}
}
}
}
The
BeepItem
class implements the ItemListener
interface. It filters out events caused by items being deselected with ItemEvent.getStateChange()
and only
beeps if an item was selected. The available convenience constants you can
check are: ItemEvent.DESELECTED
ItemEvent.ITEM_FIRST
ItemEvent.ITEM_LAST
ItemEvent.ITEM_STATE_CHANGED
ItemEvent.SELECTED
The
ItemEvent.getItem()
method is used to retrieve the actual selected item.java.awt.Checkbox
Check boxes are used to select aboolean
value. Each Checkbox
has a
label that should be used to tell the user what the Checkbox
represents. For instance a Checkbox
with the label
"Anchovies" would be checked if the user wants anchovies on their
pizza and unchecked if they don't. 
Checkboxes are often used to select from a list of possible choices when as few selections as zero or as many as everything on the list may be made. Adding a
Checkbox
to an applet is
simple. Just declare it, construct it and add it. Checkbox c c = new Checkbox("Pepperoni"));
add(c);
As usual these steps may be combined into the single line add(new
Checkbox("Pepperoni"));
By default check boxes are unchecked when created. If you want a
Checkbox
to start life checked, use the
following constructor instead:add(new Checkbox("Pepperoni",
null, true));
The
null
is a reference
to a CheckboxGroup
. Passing null
for this argument says that this Checkbox
does not belong to a CheckboxGroup
.Every
Checkbox
has a boolean
value, either true
or false
. When the Checkbox
is checked that value is true
.
When it is unchecked that value is false. You access this value using the Checkbox
's getState()
and setState(boolean
b)
methods. For example private void handleCheckbox(Checkbox c) {
if (c.getState()) price += 0.50;
else price -= 0.50;
}
Checkbox Events
When the aCheckbox
changes state, normally as a result of user action, it fires an ItemEvent
. Most of the time you ignore
this event. Instead you manually check the state of a Checkbox
when you need to know it.
However if you want to know immediately when a Checkbox
changes state, you can register an ItemListener
for the Checkbox
. An
ItemEvent
is exactly
the same as the item event fired by a Choice
.
In fact item events are used to indicate selections or deselections in any sort
of list including checkboxes, radio buttons, choices, and lists.For example, the following program is an applet that asks the age-old question, "What do you want on your pizza?" When an ingredient is checked the price of the pizza goes up by fifty cents. When an ingredient is unchecked fifty cents is taken off. The price is shown in a
TextField
.
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class Ingredients extends Applet {
private TextField display;
private double price = 7.00;
public void init() {
this.add(new Label("What do you want on your pizza?", Label.CENTER));
Pricer p = new Pricer(this);
Checkbox pepperoni = new Checkbox("Pepperoni");
this.add(pepperoni);
pepperoni.addItemListener(p);
Checkbox olives = new Checkbox("Olives");
olives.addItemListener(p);
this.add(olives);
Checkbox onions = new Checkbox("Onions");
onions.addItemListener(p);
this.add(onions);
Checkbox sausage = new Checkbox("Sausage");
sausage.addItemListener(p);
this.add(sausage);
Checkbox peppers = new Checkbox("Peppers");
peppers.addItemListener(p);
this.add(peppers);
Checkbox extraCheese = new Checkbox("Extra Cheese");
extraCheese.addItemListener(p);
this.add(extraCheese);
Checkbox ham = new Checkbox("Ham");
ham.addItemListener(p);
this.add(ham);
Checkbox pineapple = new Checkbox("Pineapple");
pineapple.addItemListener(p);
this.add(pineapplec);
Checkbox anchovies = new Checkbox("Anchovies");
anchovies.addItemListener(p);
this.add(anchovies);
this.display = new TextField(String.valueOf(price));
// so people can't change the price of the pizza
display.setEditable(false);
this.add(display);
}
public void setPrice(double price) {
this.price = price;
display.setText(String.valueOf(price));
}
public double getPrice() {
return this.price;
}
}
class Pricer implements ItemListener {
private Ingredients out;
public Pricer(Ingredients out) {
this.out = out;
}
public void itemStateChanged(ItemEvent ie) {
double price = out.getPrice();
if (ie.getStateChange() == ItemEvent.SELECTED) price += 0.50;
else price -= 0.50;
// Change the price
out.setPrice(price);
}
}
java.awt.CheckboxGroup
Checkbox groups are collections of checkboxes with the special property that no more than one checkbox in the same group can be selected at a time. The checkboxes in aCheckboxGroup
are often called radio buttons. Checkboxes that are members of the same CheckboxGroup
cannot be checked
simultaneously. When the user checks one, all others are unchecked
automatically. The constructor for a
CheckboxGroup
is trivial. No arguments are needed. You do not even need to add the CheckboxGroup
to the applet since
checkbox groups are themselves not user-interface widgets, just ways of
arranging checkboxes.CheckboxGroup cbg = new
CheckboxGroup();
To make check boxes act like radio buttons, use this constructor for each
Checkbox
in the group.public Checkbox(String label,
CheckboxGroup cbg, boolean checked)
The label is the label for this
Checkbox
.
The CheckboxGroup
is the
group you want this Checkbox
to belong to and must already exist.At any time, you can get or set the selected
Checkbox
with these two methods: public Checkbox getSelectedCheckbox()
public void setSelectedCheckbox(Checkbox box)
java.awt.CheckboxGroup example
The following program asks the customer how they're going to pay for their pizza, Visa, Mastercard, American Express, Discover, cash or check. Someone may want both anchovies and pineapple on their pizza, but they're unlikely to pay with both Visa and American Express.
import java.applet.*;
import java.awt.*;
public class PaymentMethod extends Applet {
public void init() {
this.add(new Label("How will you pay for your pizza?"));
CheckboxGroup cbg = new CheckboxGroup();
this.add(new Checkbox("Visa", cbg, false));
this.add(new Checkbox("Mastercard", cbg, false));
this.add(new Checkbox("American Express", cbg, false));
this.add(new Checkbox("Discover", cbg, false));
this.add(new Checkbox("Cash", cbg, true)); // the default
}
}
There isn't any action in this simple example applet. If you need to add
action as radio buttons are checked and unchecked, you do it just the same as
for any other Checkbox
. java.awt.List
Scrolling lists are useful for storing long lists of things one to a line. The things in the list are called items, but each one is just a String. For example,
List Methods
You create a newList
with one of these three constructors: public List()
public List(int numLines)
public List(int numLines, boolean allowMultipleSelections)
For example, List l = new List(8, true);
numLines
is the number of
items you want to be visible in the scrolling list. It is not necessarily the
same as the number of items in the list which is limited only by available
memory. allowMultipleSelections
says whether the user is allowed to select more than one item at once
(typically by Shift-clicking).The following methods add items at the end of the list:
public void add(String item)
public void addItem(String item)
These two methods add items at the specified position in the list. public void add(String item, int index)
public void addItem(String item, int index)
The following methods remove items from the List
: public void removeAll()
public void remove(String item)
public void remove(int position)
public void delItem(int position)
These methods allow you to retrive particular items from the
List
: public int getItemCount()
public String getItem(int index)
public String[] getItems()
You ran also replace a particular item: public void replaceItem(String newValue, int index)
These methods allow you to determine which item the user has selected: public int getSelectedIndex()
public int[] getSelectedIndexes()
public String getSelectedItem()
public String[] getSelectedItems()
public Object[] getSelectedObjects()
If a list allows multiple selections, you should use the plural forms of the
above methods. You can determine whether multiple selections are allowed with isMultipleMode()
and change it with setMultipleMode()
. public boolean isMultipleMode()
public void setMultipleMode(boolean b)
These methods allow you to manipulate the selection: public void select(int index)
public void deselect(int index)
public boolean isIndexSelected(int index)
These two methods determine whether an item at a particular index is
currently visible in the List box: public int getVisibleIndex()
public void makeVisible(int index)
List Events
Lists can fire two separate types of events. When a list item is selected or deselected, theList
fires
an ItemEvent
. However, when
the user double clicks on a list item, the List
fires an ActionEvent
.
Therefore, you can register both an ItemListener
to process selections and/or an ActionListener
to process double clicks. public void addItemListener(ItemListener l)
public void removeItemListener(ItemListener l)
public void addActionListener(ActionListener l)
public void removeActionListener(ActionListener l)
The action command in the ActionEvent
is the list item which was double clicked. java.awt.Scrollbar
List
s, TextArea
s, and ScrollPane
s come with ready made
scrollbars. However if you want to scroll any other object you'll have to use a
java.awt.Scrollbar
.
Scrollbars have many uses. At their most basic they're used for moving the
visible area. They can also be used to set a value between two numbers. Or they
can be used to flip through a number of screens as in a database operation that
looks at successive records. There are three constructors:
public Scrollbar()
public Scrollbar(int orientation)
public Scrollbar(int orientation, int value, int visible, int min, int max)
The orientation
argument
is one of the mnemonic constants, Scrollbar.HORIZONTAL
or Scrollbar.VERTICAL
. As
you expect this determines whether the Scrollbar
is laid out from left to right or top to bottom. A
Scrollbar
has an int
value at all times. This value will
be between the minimum
and
the maximum
value set by the
last two arguments to the constructor. When a Scrollbar
is created, its value is given by the value
argument. The default is 0.Finally
visible
represents the size of the visible portion of the scrollable area in pixels.
The Scrollbar
uses this when
moving up or down a page.A
Scrollbar
fires an
adjustment event when its value changes. You register an adjustment listener to
catch this event. This class needs an adjustmentValueChanged()
method with this signature:public void
adjustmentValueChanged(AdjustmentEvent e)
The following program is an applet that changes the number in a
TextField
between 1 and 100 based on the
position of the thumb (the movable part of the Scrollbar
). In a practical application the number would
of course mean something.
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class Scrollie extends Applet implements AdjustmentListener {
private TextField t;
private Scrollbar sb;
public void init() {
int initialValue = 1;
sb = new Scrollbar(Scrollbar.HORIZONTAL, initialValue, 100, 1, 100);
sb.addAdjustmentListener(this);
this.add(sb);
this.t = new TextField(4);
this.t.setText(String.valueOf(initialValue));
this.add(t);
}
public void adjustmentValueChanged(AdjustmentEvent e)
int val = sb.getValue();
this.t.setText(String.valueOf(val));
}
}
Peer vs. Swing Components
I'm not going to talk much about Swing in this course, but most of what I teach you about the standard AWT components carries over to their Swing equivalents with only trivial changes. For example, here's yet another way to write an applet that says "Cub Scouts!" in 24 point, SansSerif, bold and blue and with a yellow background.import java.awt.*;
import javax.swing.*;
public class SwingCubScout extends JApplet {
public void init() {
JLabel cubScouts = new JLabel("Cub Scouts!");
cubScouts.setForeground(Color.blue);
cubScouts.setBackground(Color.yellow);
cubScouts.setFont(new Font("Sans", Font.BOLD, 24));
this.getContentPane().add(cubScouts);
}
}
This is almost identical to the AWT-based Cub Scout applet, except that I've
imported the javax.swing
package and changed Label
to
JLabel
and Applet
to JApplet
. Week 6 Exercises
- Write an applet that with a 60 column by 10 row text area that allows the user to type some text. Add a button to this applet that clears the text area when it's pressed.
Don't worry excessively about making the applet
look good. Before you can do that you'll need to learn about layout managers.
- Rewrite the payroll problem from week 2 as an applet. Provide a text field for the number of hours, a text field for the pay rate, and a non-editable text field for the output. Also provide labels to identify all three text fields and a button to calculate the result.
Don't worry about minimum wage, number of hours in
the week, or other error conditions we checked before. In the event the user
enters data that cannot be interpreted as a number, don't put anything in the
output text field. In a couple of weeks, you'll learn how to bring up an error
dialog to handle these conditions.
Don't worry excessively about making the applet
look good. Before you can do that you'll need to learn about layout managers.
We'll cover them next week
Getting into more fun Graphics
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class ShowColors2 extends JFrame {
private JButton changeColorButton;
private Color color = Color.LIGHT_GRAY;
private Container container;
// set up GUI
public ShowColors2()
{
super( "Using JColorChooser" );
container = getContentPane();
container.setLayout( new FlowLayout() );
// set up changeColorButton and register its event handler
changeColorButton = new JButton( "Change Color" );
changeColorButton.addActionListener(
new ActionListener() { // anonymous inner class
// display JColorChooser when user clicks button
public void actionPerformed( ActionEvent event )
{
color = JColorChooser.showDialog(
ShowColors2.this, "Choose a color", color );
// set default color, if no color is returned
if ( color == null )
color = Color.LIGHT_GRAY;
// change content pane's background color
container.setBackground( color );
}
} // end anonymous inner class
); // end call to addActionListener
container.add( changeColorButton );
setSize( 400, 130 );
setVisible( true );
} // end ShowColor2 constructor
// execute application
public static void main( String args[] )
{
ShowColors2 application = new ShowColors2();
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
}
import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;
public class Shapes2 extends JFrame {
// set window's title bar String, background color and dimensions
public Shapes2()
{
super( "Drawing 2D Shapes" );
getContentPane().setBackground( Color.WHITE );
setSize( 400, 400 );
setVisible( true );
}
// draw general paths
public void paint( Graphics g )
{
super.paint( g ); // call superclass's paint method
int xPoints[] = { 55, 67, 109, 73, 83, 55, 27, 37, 1, 43 };
int yPoints[] = { 0, 36, 36, 54, 96, 72, 96, 54, 36, 36 };
Graphics2D g2d = ( Graphics2D ) g;
GeneralPath star = new GeneralPath(); // create GeneralPath object
// set the initial coordinate of the General Path
star.moveTo( xPoints[ 0 ], yPoints[ 0 ] );
// create the star--this does not draw the star
for ( int count = 1; count < xPoints.length; count++ )
star.lineTo( xPoints[ count ], yPoints[ count ] );
star.closePath(); // close the shape
g2d.translate( 200, 200 ); // translate the origin to (200, 200)
// rotate around origin and draw stars in random colors
for ( int count = 1; count <= 20; count++ ) {
g2d.rotate( Math.PI / 10.0 ); // rotate coordinate system
// set random drawing color
g2d.setColor( new Color( ( int ) ( Math.random() * 256 ),
( int ) ( Math.random() * 256 ),
( int ) ( Math.random() * 256 ) ) );
g2d.fill( star ); // draw filled star
}
} // end method paint
// execute application
public static void main( String args[] )
{
Shapes2 application = new Shapes2();
application.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
}
Takashi Yamanoue , yamanoue@cc.kagoshima-u.ac.jp
- The client program(RmiClient.class) sends a message to the server
program(RmiServer.class). The server program print out the message on the
console.
A Simple Java RMI
example
Takashi Yamanoue , yamanoue@cc.kagoshima-u.ac.jp
- The client program(RmiClient.class) sends a message to the server
program(RmiServer.class). The server program print out the message on the
console.

- This example consists of the following files
Ø MessageReceiverInterface.java
² This part defines the RMI interface. The method (receiveMessage) of the
server class, which implements this interface, is called from the remote
client. In the remote client program, the type of the server class (which is
the remote class in this client class) is this interface.
Ø RmiServer.java
² This is the server program(class). In this class, the method greceiveMessageh, which is
called from the remote client, is defined. This class is the implementation of
the RMI interface.
Ø RmiClient.java
² This is the client program(class). The remote method is called from this
class.
- Execution outline
1. RmiServer creates the gregistryh. This is a kind of dictionary. Its key is a name (which is the
ID of a remote object) and its content is an object. This object is looked up
from a remote program by the name. This registry is accessed from a remote object by the IP address (or host name) and the port number.
2. RmiServer binds the name grmiServerh and it-self(RmiServer.class) in the registry.

3. RmiClient looks up the remote object (RmiServer) by the name grmiServerh.

4. RmiClient calls the method greceiveMessageh of the RmiServer class.
5. The method greceiveMessageh of the RmiServer class prints out the message.

- Compile
1. javac RmiServer.java
2. rmic RmiServer
3. javac RmiClient.java
- Execution
1. (at one host,) java RmiServer
2. (at another host) java RmiClient <serverfs address> 3232
<message text>
- The source codes
ReceiveMessageInterface.java
import java.rmi.*;
public interface ReceiveMessageInterface extends
Remote
{
@@@@@@@void receiveMessage(String x)
throws RemoteException;
@@@@@@}
RmiServer.java
import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;
import java.net.*;
public class RmiServer extends
java.rmi.server.UnicastRemoteObject
implements
ReceiveMessageInterface
{
int
thisPort;
String
thisAddress;
Registry registry; // rmi registry for lookup the remote
objects.
// This method is called from the remote
client by the RMI.
// This is the implementation of the
gReceiveMessageInterfaceh.
public void receiveMessage(String x) throws
RemoteException
{
System.out.println(x);
}
public RmiServer() throws RemoteException
{
try{
// get the address of this host.
thisAddress=
(InetAddress.getLocalHost()).toString();
}
catch(Exception e){
throw new
RemoteException("can't get inet address.");
}
thisPort=3232; // this port(registryfs port)
System.out.println("this
address="+thisAddress+",port="+thisPort);
try{
// create the registry and bind the
name and object.
registry =
LocateRegistry.createRegistry( thisPort );
registry.rebind("rmiServer", this);
}
catch(RemoteException e){
throw e;
}
}
static public void main(String args[])
{
try{
RmiServer s=new
RmiServer();
}
catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
RmiClient.java
import java.rmi.*;
import java.rmi.registry.*;
import java.net.*;
public class RmiClient
{
static public void main(String args[])
{
ReceiveMessageInterface rmiServer;
Registry registry;
String serverAddress=args[0];
String serverPort=args[1];
String text=args[2];
System.out.println("sending "+text+" to "+serverAddress+":"+serverPort);
try{
// get the gregistryh
registry=LocateRegistry.getRegistry(
serverAddress,
(new Integer(serverPort)).intValue()
);
// look up the remote object
rmiServer=
(ReceiveMessageInterface)(registry.lookup("rmiServer"));
// call the remote method
rmiServer.receiveMessage(text);
}
catch(RemoteException e){
e.printStackTrace();
}
catch(NotBoundException e){
e.printStackTrace();
}
}
}
import java.rmi.registry.*;
import java.net.*;
public class RmiClient
{
static public void main(String args[])
{
ReceiveMessageInterface rmiServer;
Registry registry;
String serverAddress=args[0];
String serverPort=args[1];
String text=args[2];
System.out.println("sending "+text+" to "+serverAddress+":"+serverPort);
try{
// get the gregistryh
registry=LocateRegistry.getRegistry(
serverAddress,
(new Integer(serverPort)).intValue()
);
// look up the remote object
rmiServer=
(ReceiveMessageInterface)(registry.lookup("rmiServer"));
// call the remote method
rmiServer.receiveMessage(text);
}
catch(RemoteException e){
e.printStackTrace();
}
catch(NotBoundException e){
e.printStackTrace();
}
}
}
- This example consists of the following files
Ø MessageReceiverInterface.java
² This part defines the RMI interface. The method (receiveMessage) of the
server class, which implements this interface, is called from the remote
client. In the remote client program, the type of the server class (which is
the remote class in this client class) is this interface.
Ø RmiServer.java
² This is the server program(class). In this class, the method greceiveMessageh, which is
called from the remote client, is defined. This class is the implementation of
the RMI interface.
Ø RmiClient.java
² This is the client program(class). The remote method is called from this
class.
- Execution outline
1. RmiServer creates the gregistryh. This is a kind of dictionary. Its key is a name (which is the
ID of a remote object) and its content is an object. This object is looked up
from a remote program by the name. This registry is accessed from a remote object by the IP address (or host name) and the port number.
2. RmiServer binds the name grmiServerh and it-self(RmiServer.class) in the registry.

3. RmiClient looks up the remote object (RmiServer) by the name grmiServerh.

4. RmiClient calls the method greceiveMessageh of the RmiServer class.
5. The method greceiveMessageh of the RmiServer class prints out the message.

- Compile
1. javac RmiServer.java
2. rmic RmiServer
3. javac RmiClient.java
- Execution
1. (at one host,) java RmiServer
2. (at another host) java RmiClient <serverfs address> 3232
<message text>
- The source codes
ReceiveMessageInterface.java
import java.rmi.*;
public interface ReceiveMessageInterface extends
Remote
{
@@@@@@@void receiveMessage(String x)
throws RemoteException;
@@@@@@}
RmiServer.java
import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;
import java.net.*;
public class RmiServer extends
java.rmi.server.UnicastRemoteObject
implements
ReceiveMessageInterface
{
int
thisPort;
String
thisAddress;
Registry registry; // rmi registry for lookup the remote
objects.
// This method is called from the remote
client by the RMI.
// This is the implementation of the
gReceiveMessageInterfaceh.
public void receiveMessage(String x) throws
RemoteException
{
System.out.println(x);
}
public RmiServer() throws RemoteException
{
try{
// get the address of this host.
thisAddress=
(InetAddress.getLocalHost()).toString();
}
catch(Exception e){
throw new
RemoteException("can't get inet address.");
}
thisPort=3232; // this port(registryfs port)
System.out.println("this
address="+thisAddress+",port="+thisPort);
try{
// create the registry and bind the
name and object.
registry =
LocateRegistry.createRegistry( thisPort );
registry.rebind("rmiServer", this);
}
catch(RemoteException e){
throw e;
}
}
static public void main(String args[])
{
try{
RmiServer s=new
RmiServer();
}
catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
RmiClient.java
import java.rmi.*;
import java.rmi.registry.*;
import java.net.*;
public class RmiClient
{
static public void main(String args[])
{
ReceiveMessageInterface rmiServer;
Registry registry;
String serverAddress=args[0];
String serverPort=args[1];
String text=args[2];
System.out.println("sending "+text+" to "+serverAddress+":"+serverPort);
try{
// get the gregistryh
registry=LocateRegistry.getRegistry(
serverAddress,
(new Integer(serverPort)).intValue()
);
// look up the remote object
rmiServer=
(ReceiveMessageInterface)(registry.lookup("rmiServer"));
// call the remote method
rmiServer.receiveMessage(text);
}
catch(RemoteException e){
e.printStackTrace();
}
catch(NotBoundException e){
e.printStackTrace();
}
}
}
TagSupport
is an abstract class which is part of the JSP tag APIs Listing 3. 1 pre-sents a Java
class that implements a tag handler, but it also contains methods and objects
that are new to you unless you already have a very solid background in
serv-lets and JSPs. We mentioned earlier that tags are Java classes that
implement one of two special interfaces. These interfaces define all the
methods the JSP runtime uses to get at the tag's functionality. As with many
Java interfaces, some utility-only classes that provide basic implementations
of these interfaces are available, making development easier. In the case of
our
Aborts
the execution upon errors We
watch out for
Uses the
BodyTagSupport is an abstract class which
is part of the JSP tag APIs.
Declares that the JSP file uses
the library referenced by the URI and that the library's tags are referenced by
jspx.
Uses the lowercase tag to
change its body to lowercase.
import java.rmi.registry.*;
import java.net.*;
public class RmiClient
{
static public void main(String args[])
{
ReceiveMessageInterface rmiServer;
Registry registry;
String serverAddress=args[0];
String serverPort=args[1];
String text=args[2];
System.out.println("sending "+text+" to "+serverAddress+":"+serverPort);
try{
// get the gregistryh
registry=LocateRegistry.getRegistry(
serverAddress,
(new Integer(serverPort)).intValue()
);
// look up the remote object
rmiServer=
(ReceiveMessageInterface)(registry.lookup("rmiServer"));
// call the remote method
rmiServer.receiveMessage(text);
}
catch(RemoteException e){
e.printStackTrace();
}
catch(NotBoundException e){
e.printStackTrace();
}
}
}
What are JSP custom tags?
At
its most fundamental level, a tag is a group of characters read by a
program for the purpose of instructing the program to perform an action. In the
case of HTML tags, the program reading the tags is a Web browser, and the actions
range from painting words or objects on the screen to creating forms for data
collection. Cus-tom JSP tags are also interpreted by a program; but, unlike
HTML, JSP tags are interpreted on the server side— not client side. The program
that interprets custom JSP tags is the runtime engine in your application
server (TomCat, JRun, WebLogic, etc.). When the JSP engine encounters a custom
tag, it executes Java code that has been specified to go with that tag. Common
tasks performed by tag codes include retrieving database values, formatting
text, and returning HTML to a browser. Since a tag references some Java code to
run when it's encountered, one way to think of a tag is simply as a shorthand
notation for a block of code. Notice in figure 3.1 that when the JSP runtime
encounters the tag, it causes a block of Java code to execute and return a
message to the client's browser.
3.1.1 Anatomy of a tag
Tags
are often structured with a body and/ or attributes which are the places where
a page author (the user of the tag) can include more information about how the
tag should do its job. The following snippet shows the general structure of a
tag.
<tagname attributename=" attributevalue"
otherattributename=" otherattributevalue">
Tag's body... can contain about anything.
</ tagname>

This
syntax should look familiar, since we see it so often in HTML tags, such as:
<font face=" Tahoma" size= 3">
Tag, you're it!
</ font>
Tags
can also appear without a body, meaning that the start tag does not have a
matching end tag. These "bodyless" tags look like this:
<bodylesstagname attributename=" attributevalue"
otherattributename=" otherattributevalue"/>
You've
probably seen examples of bodyless tags in HTML, such as:
<input type=" input" name=" body">
Bodyless
tags usually represent a certain function, as in the printing of the value of a
database field onto the page. Tags often have bodies in order to perform an
opera-tion on the content in the body, such as formatting, translating, or
processing it in some way.
JSP
custom tags are merely Java classes that implement one of two special
inter-faces. Since tags are standard Java classes, they can interact with,
delegate to, or integrate with any other Java code in order to make that
functionality available through a tag. For instance, we might have a library of
utility classes we've written for composing and sending email, or for accessing
a particular database that we'd like to make available to HTML developers. We
need build only a few tags that col-lect the necessary information through
attributes and pass this information to our utility classes.
3.1.2 Using a tag in JSP
JSP
code that uses email and database tags such as those just mentioned might look
something like this:
<html>
I am sending you an email with your account information
<jspx: sendmail server=" mail. corp. com"
from=" john. doe@ corp. com"
to=" foo@ bar. com"
subject=" mail from a tag">
Look at how easy it is to send an email from a tag... here is
your status.
<jspx: dbaccess>
<jspx: wdbcon id=" con1"/>
<jspx: wjitdbquery>
select reserves from account where id= '<%= userid %> '
</ jspx: wjitdbquery>
You have <jspx: wdbshow field=" reserves "/>$ in your saving account.
</ jspx: dbaccess>
</ jspx: sendmail>
</ html>
Among
the JSP and HTML fragments are special tags prefixed with
jspx.
Even to the untrained eye, these tags appear to query a
database, present the information in the content of an email, and send the
message. Notice how the attributes help gather information such as the email
sender and subject and the field in the data-base to display. Also, note how
the
<jspx:
wjitdbquery>
tag contains a Structured Query Language (SQL)
statement within its body that it uses for the database query. This is a good
example of what a JSP using custom tags might look like. Consider how much
messier this JSP would look if we had to include all the Java code neces-sary
for creating classes, setting properties, catching exceptions, and so forth. 3.1.3 The tag library descriptor
An important step in creating tags is specifying how they
will be used by the JSP runtime that executes them. To properly work with a
tag, the runtime must know several things about it, such as what (if any)
attributes it has, and whether or not it has a body. This information is used
by the runtime to verify that the tag is properly employed by a JSP author and
to correctly execute the tag during a request. This crucial information is made
available to the runtime engine via a standard XML file called a tag library
descriptor (TLD), a key component of the JSP Specification and standard across
all products that implement it. How to create a TLD is discussed in section
3.2.4, and covered in greater detail in chapter 5 and appendix B.
Why tags?
JSP
already makes it possible to embed scriptlets (bits of Java code) and
JavaBeans in line with HTML content, so why do we need JSP tags? We need them
because tags were never intended to offer more functionality than scriptlets,
just better packag-ing. JSP tags were created to improve the separation of
program logic and presenta-tion logic; specifically, to abstract Java syntax
from HTML. Scriptlets are not a suitable solution for all web development
because most con-tent developers (art designers, HTML developers, and the like)
don't know Java and, perhaps, don't care to. Though much Java code can be
encapsulated in beans, their usage in a JSP still requires the presentation
developer to have a basic knowl-edge of Java syntax and datatypes in order to
be productive. JSP tags form a new "scriptlet-free" and even a
completely "Java-free" component model that is adapted perfectly to
the JSP environment with its different developer types. If custom tags are
properly constructed, they can be of enormous use to HTML developers, even
those who have no working knowledge of Java— they won't even have to know
they're using it. Tags can reduce or eliminate the number of scriptlets in a
JSP appli-cation in four ways:
- A tag is nothing more than a Java component that takes its arguments from attribute and body. Since tags can have attributes and body, any necessary param-eters to the tag can be passed within the tag's body or as one of its attributes. No Java code is needed to initialize or set properties on the component. .
- JSP requires a considerable quantity of scriptlets for tasks such as iteration, setting of initial values, and performing conditional HTML. All of these tasks can be cleanly abstracted in a few simple tags.
- In many cases, a JavaBean component is configured and activated using scriptlets. One can develop a set of JSP tags to perform this configuration and activation without any Java.
- Tags can implement many utility operations, such as sending email and con-necting to a database, and in this way reduce the number of utility scriptlets needed inside JSP.
The
benefits of custom tags also include the creation of a neat abstraction layer
between logic and presentation. This abstraction creates an interface that
allows Java developers to fix bugs, add features, and change implementation
without requiring any changes to the JSPs that include those tags. In short,
JSP tags help bring you one step closer to the Holy Grail of web development—
true abstraction of presentation and control. For more on the benefits of
custom tags, see chapter 15.
3. 2. 1 Comparisons of scriptlets and custom tags
- The differences between scriptlets and custom tags are fairly concrete: Custom tags have simpler syntax. Scriptlets are written in Java and require the author to be familiar with Java syntax, whereas tags are HTML-like in syn-tax and require no Java knowledge.
- Custom tags are easier to debug and are less error prone than scriptlets, since omitting a curly bracket, a semicolon, or some other minute character in a scriptlet can produce errors that are not easy to understand. Custom tag syn-tax is extraordinarily simple and, with most JSP runtime products, even the occasional typo in custom tag usage will produce meaningful error messages.
- Custom tags are easy to integrate in development environments. Since tags are a common component of many web technologies, HTML editors have support for adding tags into the development environment. This allows JSP authors to continue using their favorite integrated development environ-ment (IDE) to build tag-based JSPs. Support for JSP scriptlets syntax in development environments exists, but is only useful to JSP authors well versed in Java.
- Custom tags can eliminate the need for Java in your JSPs. By containing most of your logic within objects in your scriptlets, you can vastly reduce the amount of Java code in a JSP; however, custom tags still carry the advantage of imposing absolutely no Java syntax, something scriptlets can-not achieve.
For
small projects in which all your JSPs will be authored by developers
knowledge-able in Java, scriptlets are a fine solution. For larger projects,
where content devel-opers unfamiliar with Java will be handling most of the
presentation, JSP custom tags provide a real advantage and are a logical
choice.
3. 4 Hello World example
Our
goal in this section is to create a simple tag that may not be particularly
reus-able, but it will introduce most of the concepts needed for building
useful tags. This simplicity is necessary now, as the myriad details involved
with constructing even a Hello World tag can be daunting at first. Later
sections in this chapter will present tags that have more real-world relevance.
Our
Hello World
tag is merely
going to print "Hello JSP tag World"
out
to an HTML page. Listing 3. 1 presents the source code for the Hello
World
implementation.
Listing 3. 1 Source code for the
HelloWorldTag handler class


HelloWorldTag,
we extend
one such utility class called TagSupport.agSupport
and the interface it implements, Tag,
are
both part of the custom JSP tag API. Don't worry too much over the specifics of
this interface. For now it's important to know only that we need to implement Tag
to create a tag, and we've done so by extending TagSupport.
JSP
runtime calls
doStartTag()
to
execute the tag Here
we note that there is no explicit constructor for this tag, nor is there a main()
method for invoking the class. This is because a tag handler is
not a stand-alone class, but is instantiated by the JSP runtime that invokes
its methods. The JSP custom tags API defines a set of methods for custom tags
(which are included in the two special interfaces previously men-tioned) that
the JSP runtime calls throughout a tag's life cycle. One of these methods, doStartTag(),
can be seen in our example and is called by the JSP runtime when
it starts executing a tag (more about the Tag
methods
in chapter 4). The doStartTag()
method
is a repository for code that we wish to have executed when-ever the JSP
runtime encounters our tag within the page. 5
Tag
echoes the
hello
message to the user In our implementation of doStart-Tag(),
we
perform three operations. We print the hello
message
using an out
object that we got
from the PageContext
(in chapter
2). 
IOExceptions
that
may be thrown by the response Writer,
catch
them, and abort the tag's execution by throwing a JspTagException.
Finally, as required by the method, we return an integer value
which tells the JSP runtime how to proceed after encountering our tag. A value
of SKIP_BODY
tells the
runtime engine to simply ignore the tag's body, if there is one, and go on
evaluating the rest of the page. There are, of course, other valid return
values for doStartTag(),
which
we'll explore in future chapters.
As
listing 3.1 shows, the tag is only a few lines long and, indeed, all it does is
write out to the page, but a few details that will reappear in other tags are
already evident. Now that we have the Java source of our tag, it is time to
compile it.
3.4.1 Compiling the tag
Compiling
Java source into its class (without an IDE) requires careful setting of the
compilation
CLASSPATH
(a list
of all directories and .jar files that hold the classes ref-erenced in our
source code). Basically, the CLASSPATH
for
a tag handler must include the Servlet and JSP APIs; you should also include
any additional classes or libraries that you are using within the tag handler
(such as JavaMail and JNDI).
5 Though this would seem to imply
that the runtime evaluates a JSP each time a page is requested, we know from
JSP development that the page is only interpreted and compiled into a servlet
once. Tags are no ex-ception; this is just a convenient way to think about how
the tag will behave at runtime.
In
the case of
For
HelloWorldTag
,we
are not using any additional libraries, and can settle with the following Javac
command line (assuming that JAVA_HOME
and
TOMCAT_HOME
are both
defined and we are compiling the source file into a directory named classes): For
UNIX:
$JAVA_HOME/bin/javac
-d ../classes -classpath $TOMCAT_HOME/lib/servlet.jar
book/simpletasks/HelloWorldTag.java
For
Windows:
%JAVA_HOME%\bin\javac
-d ..\classes -classpath %TOMCAT_HOME%\lib\servlet.jar
book\simpletasks\HelloWorldTag.java
Both
command lines use the
TOMCAT_HOME
environment
variable to add the Servlet and JSP API into the CLASSPATH
,
and this is actually the only JSP-Tags-
specific
portion in the compilation command. When the compilation ends, we have our
com-piled tag handler in the classes directory and we are ready to continue to
the next step— creating the tag library descriptor (TLD).Creating a tag library descriptor (TLD)
The JSP runtime requires your
assistance if it is to understand how to use your cus-tom tag. For example, it
has to know what you want to name your tag and any tag attributes. To do this
you need to create a file called a tag library descriptor for your tag. An
in-depth explanation of the exact use of a TLD will be covered in chapter 5,
and its syntax is explained in appendix B, so we needn't go into great detail
on these now. Instead, if we look at our example for the
HelloWorldTag,
the ways
to use a TLD will emerge.
The TLD is nothing more than a
simple extended markup language (XML6 ) file, a text file
including a cluster of tags with some predefined syntax. Since the TLD is just
a text file, you can create it with your preferred editor (Emacs, VI, notepad,
etc.) as long as you keep to some rudimentary guidelines as explained in
appendix B. The TLD created for the
HelloWorld
tag is
presented in listing 3. 2.
Listing
3. 2 Tag library descriptor for the HelloWorldTag
<? xml version=" 1.0" encoding=" ISO-8859-1" ?>
<! DOCTYPE taglib
PUBLIC "-// Sun Microsystems, Inc.// DTD JSP Tag Library 1. 1// EN"
"http:// java. sun. com/ j2ee/ dtds/ web-jsptaglibrary_ 1_ 1.dtd">
<taglib>
<tlibversion> 1. 0</ tlibversion>
<jspversion> 1.1</ jspversion>
<shortname> simp</ shortname>
<uri> http:// www. manning. com/ jsptagsbook/ simple-taglib </ uri>
<info>
A simple sample tag library
</ info>
<tag>
<name> hello</ name>
<tagclass> book. simpletasks. HelloWorldTag</ tagclass>
<bodycontent> empty</ bodycontent>
<info>
Say hello.
</ info>
</ tag>
</ taglib>
Listing 3. 2 defines a tag whose
name is "hello," and whose implementing class is
HelloWorldTag
, which we just developed.
This means that whenever the JSP run-time sees the tag <hello/>
it should actually execute
the methods contained in our HelloWorldTag
.
The portion of listing 3.2 unique
to this tag is in bold face and, as it demon-strates, creating a tag library
involves many "overhead lines" that specify such infor-mation as the
desired version of JSP and the like. Normally you can just grab (and update) these
overhead lines from a pre-existing library descriptor and add your own tags
below them.
Let's assume that we saved the TLD
in a file named simpletags. tld. We now have our tag handler class and the TLD
to help the JSP runtime use it. These two files are all we need to deploy our
HelloWorldTag
and begin using it in a
JSP. Testing HelloWorldTag
Testing
HelloWorldTag
involves deploying it to a
JSP container and writing a JSP file to use the tag. To do this: - Create a web application for
your tags (in our case,
HelloWorldTag
). - Deploy your tags in the application.
- Write a JSP file that will
use
HelloWorldTag
. - Execute the JSP file created in step 3 and look at the results.
Creating a web application
What must be done to create a new web application in Tomcat? This can be accom-plished either by deploying a web application archive or creating an application directory that follows the WAR structure. We are going to create an application directory, as follows:
What must be done to create a new web application in Tomcat? This can be accom-plished either by deploying a web application archive or creating an application directory that follows the WAR structure. We are going to create an application directory, as follows:
- Make a directory named testapp in Tomcat's webapps directory.
- Under the testapp directory make another directory named WEB-INF, and inside this create directories named lib and classes.
Create a file named web. xml in the
WEB-INF directory and add the content of listing 3. 3 into it; web. xml is
going to be your web application deployment descrip-tor; and listing 3. 3
contains an "empty" deployment descriptor content.
Listing
3. 3 An empty web application deployment descriptor
<? xml version=" 1.0" encoding=" ISO-8859-1"?>
<! DOCTYPE web-app
PUBLIC "-// Sun Microsystems, Inc.// DTD Web Application 2. 2// EN"
"http:// java. sun. com/ j2ee/ dtds/ web-app_ 2. 2. dtd">
<web-app>
</ web-app>
Deploying a tag
You now have an application structure under the testapp directory into which you may deploy your tags. Tag deployment takes the following steps:
You now have an application structure under the testapp directory into which you may deploy your tags. Tag deployment takes the following steps:
· Copy your tag implementation classes or jar
files into the application direc-tory; .jar files should go into the newly
created lib directory, .class files should go into the classes directory. In
the present case, we will copy the compiled class into the classes directory
(while preserving the package directory structure).
· Copy the TLD into a location in the
application's directory structure (WEB-INF is a good location). In our example
we will copy our TLD from listing 3. 2 (simpletags. tld) into the WEB-INF
directory.
· Add a tag library reference into the web
application deployment descriptor. In our case, edit web. xml and add the
content of listing 3.4 into the
<web-app>
section (these last two steps set
up a reference to the TLD as will be explained in chapter 5).
Listing
3. 4 A TLD reference entry for the tags described in simpletags. tld
<taglib>
<taglib-uri>
http:// www. manning. com/ jsptagsbook/ simple-taglib
</ taglib-uri>
<taglib-location>
/WEB-INF/ simpletags. tld
</ taglib-location>
</ taglib>
The tag was deployed into the web
application; all we need to do now is to create a JSP that uses the tag and
verify whether it works.
Creating a JSP file to test
HelloWorldTag
Developing a JSP file to test
Developing a JSP file to test
HelloWorldTag
is a
relatively simple task. All we need to do is craft a JSP file similar to the
one presented in listing 3. 5.
Listing
3. 5 A JSP file to drive HelloWorldTag

1. Declares that the JSP file
uses the library referenced by the URI and that the library's tags are
referenced by jspx Listing 3.5 is elementary, yet it illustrates a few
impor-tant points about tags. The first is the
taglib
directive at the beginning of the JSP file. The taglib
directive is further discussed in
chapter 5, but for now we need to note that it indicates to the JSP runtime
where the tag library lives and the prefix by which we'll refer to tags in this
library. With this directive in place, the JSP runtime will recognize any usage
of our tag throughout the JSP, as long as we precede our tag name with the
prefix "jspx." 2. Uses the hello
tag through the JSP file We also see how
the custom tag can be used through the JSP file. We use the HelloWorldTag
twice, and we could, of
course, have used it as much as we wanted. All that's needed is to add it to
the JSP content. Note that our tag is bodyless, necessitating the use of the
trailing backslash.
Figure 3. 2 shows the results
achieved by executing the JSP file in listing 3. 5. Observe that wherever we
had the <hello> tag, we now have the content generated by it.
Executing HelloWorldTag
Once we've created a web application, deployed the tag, and created and deployed a JSP to use it, all that's left is to view the page in a browser.
Once we've created a web application, deployed the tag, and created and deployed a JSP to use it, all that's left is to view the page in a browser.
3.4.4 Did it work?
If your tag didn't work properly
there is always some recourse. The error messages you see will vary, depending
on which JSP runtime engine you've chosen. If, how-ever, the messages you're
seeing aren't helpful, here are a couple of suggestions:
- Make sure there are no spelling errors in the URL that you specified for the browser when asking for the JSP file (it should look like http:// www. host. name/ appname/ jspfile. jsp).
- Make sure there are no spelling errors in your TLD file and that you've spec-ified the fully qualified class name for your tag— package names and all.
- Verify that your TLD file is in a location where the JSP engine will be seeking it, such as the WEB-INF directory in your web application. .
- Make sure the
taglib
directive has been properly placed at the top of the JSP. Without this, the engine doesn't know where to find the code for your tags and will just ignore them. When that happens, you'll actually see the tag in the HTML source.
A tag with attributes
Our
HelloWorldTag
is predictable; in fact, it always does
exactly the same thing. In the dynamic world of web development, that is seldom
the case, so let's look at a tag that behaves realistically, based on some
user-specified attributes.
A web page might, for instance,
need to display the value stored in a cookie such as a user name. Rather than
forcing the page author to learn Java to access that value, we'll build a
simple tag that does this for him. The tag should be flexible enough to be used
in retrieving the value of any accessible cookie, so we'll create a tag
attribute called
cookieName
to allow this. The first step in supporting this new attribute is to modify our
tag handler class to receive and make use of this new attribute( listing 3. 6):
Listing
3. 6 Source code for the CookieValueTag handler class

The field that will get set by
the attribute.
2. Prints the value of the
cookie to the response.
Returns
SKIP_ BODY
to tell the JSP runtime
to skip the body if one exists.
Invokes the set method when the
JSP runtime encounters this attribute.
All we needed to do was add a set
method called
setCookieName()
and assign a variable within it. The value of that variable is examined within
our tag handler's doStartTag()
to decide which cookie value to return. Now we need to inform the JSP runtime
of this new tag and its attribute. Recall that the TLD is where we spec-ify
this kind of information, so we need to modify our previous TLD to support CookieValueTag
. The tag declaration in
our TLD file (listing 3.7) now looks like the following:
Listing
3. 7 The new TLD file with our CookieValueTag
<? xml version=" 1.0" encoding=" ISO-8859-1" ?>
<! DOCTYPE taglib
PUBLIC "-// Sun Microsystems, Inc.// DTD JSP Tag Library 1. 1// EN"
"http:// java. sun. com/ j2ee/ dtds/ web-jsptaglibrary_ 1_ 1.dtd">
<taglib>
<tlibversion> 1. 0</ tlibversion>
<jspversion> 1.1</ jspversion>
<shortname> simp</ shortname>
<uri> http:// www. manning. com/ jsptagsbook/ simple-taglib </ uri>
<info>
A simple sample tag library
</ info>
<tag>
<name> hello</ name>
<tagclass> book. simpletasks. HelloWorldTag</ tagclass>
<bodycontent> empty</ bodycontent>
<info>
Say hello.
</ info>
</ tag>
<tag>
<name> cookievalue</ name>
<tagclass> book. simpletasks. CookieValueTag</ tagclass>
<bodycontent> empty</ bodycontent>
<info>
Get a cookie's value.
</ info>
<attribute>
<name> cookiename</ name>
<required> true</ required>
</ attribute>
</ tag>
</ taglib>
This tag will have an attribute
called
cookiename
.
Specifies that this attribute is
always required for this tag.
The tag definition itself should
look familiar, since it is very similar to our
Hello-WorldTag
. The important difference is, of course,
the attribute we've included. Note that the name of an attribute, in our case cookiename
, is used by the JSP run-time
to find setCookieName()
to
use in the tag handler; therefore, these need to match exactly for the tag to
function.
To use this attribute within a JSP,
syntax such as in listing 3. 8 works well:
Listing
3. 8 A JSP file to drive HelloWorldTag

Declares that the JSP file uses
the library referenced by the URI and that the library's tags are referenced by
jspx.

cookeivalue
tag to retrieve a
cookie called "username".
Assuming we've used this tag in a
case where a cookie named "username" will be accessible, we'll see a
message like that shown in figure 3.3.
Adding attributes to your tags
makes them much more flexible and useful to the web pages where they are used.
We explore the use of tag attributes in further detail in chapters 4 and 6.
3.4.6 Packaging tags for shipment
Once the tags have been tested to
your satisfaction, it's time to package them in a standard deployable manner.
Packaging tags means putting the implementation classes along with the library
descriptor in a .jar file following a convention that further instructs you to:
- Put your tag class files inside the .jar archive while maintaining their package structure. .
- Put your TLD in the .jar file in a directory called META-INF.
For example, packaging our lone
HelloWorldTag
will require the following
.jar file structure: /book/ simpletasks/ HelloWorldTag. class
/META-INF/ simpletags. tld
This .jar packaging need not be
complicated; all that's required is to create the desired directory structure
on your file system and use the
jar
command (bundled with the JDK) to archive this structure into the .jar file.
The command to place our class and TLD in a jar called hello. jar looks like
this: jar cf hello. jar META-INF book
Now you can distribute your tag.
A tag with a body
Remember that tags can have a body
or be bodyless. Our
HelloWorldTag
was an example of a tag without a body, so let's see an example of a tag with
one. We create them whenever we want to take a block of content (typically
HTML) and modify it or include it in the server's response. Think back to the
HTML <font>
tag. The
body of the <font>
is
where you put text to which you wish to apply a particular font. Tags with
bodies are great for translating content (from, say, HTML to WML), applying formatting,
or indicating that a grouping of content should be treated in a special way, as
is the case with the HTML <form>
tag.
Here is an extremely simplified
example that illustrates how a tag with a body works. Suppose we need to create
a tag that will change a block of text from capital letters to lower case.
We'll be creative and call this tag
LowerCaseTag
.
Our new tag will have a lot in common with HelloWorldTag
,
but there are a few differences. The first is that LowerCaseTag
doesn't extend from TagSupport
, rather from BodyTag-Support
. The formula is
elementary: if your custom tag doesn't have a body or will include just its
body verbatim, it should either implement the Tag
interface or extend its utility class, TagSupport
. If, however, your tag will modify
or control its body, it needs to implement BodyTag
or extend its utility class called BodyTagSupport
.
We'll cover several additional examples of both types in the next chapters. 3.5.1 LowerCaseTag handler
Here is the code for our
LowerCaseTag
handler class:
Listing
3. 9 Source code for the LowerCaseTag handler class

The method
doAfterBody()
is executed by the
JSP runtime, once it has read in the tag's body. Retrieves the body that was
just read in by the JSP runtime.
Gets JspWriter to output the
lowercase content.
Writes the body out to the user
in lowercase.
Returns
SKIP_ BODY
is returned to tell the
JSP runtime to continue processing the rest of the page.
With the tag handler class written,
the next step is, once again, to create a TLD. This time our tag entry looks
like this:
Listing
3. 10 Tag entry for LowerCaseTag
<tag>
<name> lowercase</ name>
<tagclass> book. simpletasks. LowerCaseTag</ tagclass>
<bodycontent> JSP</ bodycontent>
<info>
Put body in lowercase.
</ info>
</ tag>
The only difference in this listing
is that the
<bodycontent>
field is no longer empty but now must be JSP. This is the way to indicate to
the runtime that Lower-CaseTag
will have a body, unlike our HelloWorldTag
that did not. There will be much more about bodycontent and other TLD fields in
chapters 5 and 6.
We have returned to the stage where
we need to use this new tag in a JSP file. Our JSP looks like this:
Listing
3. 11 A JSP file to drive the LowerCaseTag



Now we add our tag to our
deployment directory, pull up the JSP in our browser (figure 3. 4), and voila!
This tag doesn't do anything
especially useful, however it is always possible to modify it to do something
worthwhile with the body. Some examples might include the body as the message
of an email, translating the body from one markup lan-guage to another, or
parsing the body of XML and outputting certain nodes or attributes. In the next
chapters, we'll see how the body of a custom tag can include other custom tags
to allow cooperation with very powerful results.
Summary
What are custom tags? Why use them?
Custom tags are unique JSP compo-nents that make it easy to integrate portions
of Java logic into a JSP file in an easy-to-use, well-recognized for-mat.
Custom tags also answer to well-known API and life cycle definitions (to be
discussed in chapter 4) that make it clear how tags behave in any development
or runtime environment.
Why use custom tags? Custom tags
represent a great way to separate the business logic and presentation, thus
enhancing manageability and reducing overall maintenance costs. Another benefit
is their ease of use. By using tag syntax, many of the scriptlets and other
portions of Java code associated with the classic JSP programming are no longer
needed, and the JSP development can be opened to content (commonly, HTML)
developers.
We also discussed the mechanics
related to tag development, and saw that it is not so difficult to develop
simple, but useful, tags. This chapter provided a solid foundation for you to
start developing custom JSP tags. It presented four important tools that you
will use in your daily tag development:
- How to configure a simple (and free) development environment with which you can compile and test your tags. .
- How to develop, compile, and test simple tags using this development environment.
- How to write a TLD file to describe your tag's runtime behavior and attributes. .
- How to package your tag library in a distributable .jar file.
If you have a lot of questions at
this point, that's good. We've only lightly touched on many of the nuances of
tag development in order to help you get started right away. In the next
chapters, we will dive in and explore more fully each of the topics presented
here.
<%@ page import="java.util.*" %>
<HTML>
<BODY>
<%!
Date theDate = new Date();
Date getDate()
{
System.out.println( "In getDate() method" );
return theDate;
}
%>
Hello! The time is now <%= getDate() %>
</BODY>
</HTML>
use bean
public class UserData {
String username;
String email;
int age;
public void setUsername( String value )
{
username = value;
}
public void setEmail( String value )
{
email = value;
}
public void setAge( int value )
{
age = value;
}
public String getUsername() { return username; }
public String getEmail() { return email; }
public int getAge() { return age; }
}
savename.jsp
<jsp:useBean id="user" class="UserData" scope="session"/>
<jsp:setProperty name="user" property="*"/>
<HTML>
<BODY>
<A HREF="NextPage.jsp">Continue</A>
</BODY>
</HTML>
nextpage.jsp
<jsp:useBean id="user" class="UserData" scope="session"/>
<HTML>
<BODY>
You entered<BR>
Name: <%= user.getUsername() %><BR>
Email: <%= user.getEmail() %><BR>
Age: <%= user.getAge() %><BR>
</BODY>
</HTML>
No comments:
Post a Comment