Wednesday, 1 March 2017

Java RMI example.doc



A Simple Java RMI example

An example of text fields in Java

The following applet reads text from one TextField and capitalizes it in another TextField.
Capitalizer applet
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

The java.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.
Text area widget
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

Both TextArea 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 TextEvents.
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

Both TextArea and TextField can install a TextListener that catches TextEvents. TextComponents fire TextEvents 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

The java.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

The java.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.)
Choice menu
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
  1. Declare the Choice
  2. Allocate the Choice
  3. Add the menu items to the Choice
  4. Add the Choice to the layout
  5. Add an ItemListener to the Choice
For example
 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

The Choice 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 a Choice, 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 a boolean 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
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 a Checkbox 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.
Checkboxes
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 a CheckboxGroup 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.
Radio buttons in an applet
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 widget

List Methods

You create a new List 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, the List 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

Lists, TextAreas, and ScrollPanes 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.
Scrollbar widget
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

  1. 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.
  1. 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 greceiveMessageh, 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 gregistryh. 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 grmiServerh and it-self(RmiServer.class) in the registry.
3.    RmiClient looks up the remote object (RmiServer) by the name grmiServerh.

4.    RmiClient calls the method greceiveMessageh of the RmiServer class.
5.    The method greceiveMessageh 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 <serverfs 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 gReceiveMessageInterfaceh.
    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(registryfs 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 gregistryh
           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 greceiveMessageh, 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 gregistryh. 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 grmiServerh and it-self(RmiServer.class) in the registry.
3.    RmiClient looks up the remote object (RmiServer) by the name grmiServerh.

4.    RmiClient calls the method greceiveMessageh of the RmiServer class.
5.    The method greceiveMessageh 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 <serverfs 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 gReceiveMessageInterfaceh.
    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(registryfs 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 gregistryh
           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

  1. 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.
  2. 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.
  3. 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.
  4. 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
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 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 thehello 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).
Aborts the execution upon errors We watch out for 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 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_HOMEenvironment 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> 

6 XML is briefly described in appendix A.
<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:
  1. Create a web application for your tags (in our case, HelloWorldTag).
  2. Deploy your tags in the application.
  3. Write a JSP file that will use HelloWorldTag.
  4. 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:
  1. Make a directory named testapp in Tomcat's webapps directory.
  2. 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:
·  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
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.

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.
Uses the 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
BodyTagSupport is an abstract class which is part of the JSP tag APIs.
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
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.
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