The reader should be familiar with the material covered in Chapter 2, "Getting Started with Java Applications" before continuing with this chapter.
3.1 Review of OrbixWeb Programming Steps
Recall the programming steps typically required in creating a distributed client/server application using OrbixWeb:
putit
.
A version of the sample code described in this chapter is available in the
gridApplet
demonstration directory of your OrbixWeb installation. However, readers should be aware that the documented code may differ slightly from the installation example.
This client-server architecture is a common requirement in the Java domain, where small, dynamic client applets may be downloaded to communicate with large, powerful back-end service applications. Architectures in which full OrbixWeb servers must be coded as downloadable applets are less common, and these will not be described here.
3.3 Writing a Client Applet
We will now develop a simple Java applet which provides a graphical user interface to the IDL interface Grid
. This example builds upon the concepts introduced in the OrbixWeb grid client application.
GridPanel.java
).
GridEvents.java
).
GridApplet.java
).
GridApplet.html
).
gridAppletDemo
. Therefore, each of the above files is located in the gridAppletDemo
subdirectory and we will assume that the IDL file grid.idl
was compiled with the following command:
idl -jP gridAppletDemo grid.idlNote that development of an OrbixWeb client can be completely decoupled from the server-side development process, so the choice of package name when compiling the IDL file for the client may differ from the choice of package name for the server.
The grid applet provides a very simple user interface. This interface is divided into two sections, each with a specific objective: a "Server Details" section designed to allow users to specify a target OrbixWeb server, and an "Object Details" section which allows a
Grid
object to be queried and updated.The source code for
GridPanel.java
simply uses the Java Abstract Windowing Toolkit package (java.awt
) to create and arrange each of the elements within a java.awt.Panel
container. The details of how the interface is assembled are not relevant to this description, but we will reference the individual component names in the next section:
// Java // In file gridAppletDemo/GridPanel.java. package gridAppletDemo; import java.awt.*; public class GridPanel extends Panel { // Button string constants. final String conBStr = "Connect"; final String disBStr = "Disconnect"; final String dimBStr = "Get Grid Dimensions"; final String getBStr = "Get Cell Value"; final String setBStr = "Set Cell Value"; // Components for Server Details section // _bind() labels. Label nameL; Label hostL; // _bind() text fields. TextField nameField; TextField hostField; // _bind() buttons. Button connectButton; Button disconnectButton; // Components for Object Details section // operation labels. Label dL; Label xL; Label yL; Label vL; // Operation text fields. TextField dField; TextField xField; TextField yField; TextField vField; // Operation buttons. Button getDButton; Button getVButton; Button setVButton; // Sub panels. Panel bindPanel; Panel botPanel; // Constructor. public GridPanel () { } }
Grid
object:The text fields provide a means of obtaining and reporting operation parameter values and operation results.
To implement the functionality of the interface buttons, we add support for user interaction by detecting
java.awt.Event.ACTION_EVENT
events. There are several methods of achieving this, but in this example we define a subclass of GridPanel
, called GridEvents
, which overrides the java.awt.Component.action()
method. This method allows us to receive notification of a button click event, and to determine which button in the interface received that event. We can then react by invoking the appropriate operation on a Grid
proxy object.Note that all sample code described below includes error handling as described in the section "Error Handling: Integration with Java Exceptions", but the method
displayMsg()
is introduced to display operation results. The functionality of this method will be explained in the next subsection.// Java // In file gridAppletDemo/GridEvents.java. package gridAppletDemo; import java.awt.*; import java.lang.*; import IE.Iona.Orbix2._CORBA; import IE.Iona.Orbix2.CORBA.SystemException; public class GridEvents extends gridAppletDemo.GridPanel { // Grid proxy object. public _GridRef gRef = null; // Notify method for action event. public boolean action (Event event, Object arg) { if (conBStr.equals (arg)) { // Connect button clicked, // so _bind to Grid object. bindObject (); } else if (disBStr.equals (arg)) { // Disconnect button clicked, // so simply destroy proxy. gRef = null; } else if (dimBStr.equals (arg)) { // Get Dimensions button clicked, // so call get_height() and get_width() on // Grid object. getHeightAndWidth (); } else if (getBStr.equals (arg)) { // Get Cell Value button clicked, // so call get() on Grid object. getCellValue (); } else if (setBStr.equals (arg)) { // Set Cell Value button clicked, // so call set() on Grid object. setCellValue (); } return true; } // Connect button implementation. public void bindObject () { // Details will be described // later in this section. } // Get Grid Dimensions button implementation. public void getHeightAndWidth () { // Details will be described // later in this section. } // Get Cell Value button implementation. public void getCellValue () { // Details will be described // later in this section. } // Set Cell Value button implementation. public void setCellValue () { // Details will be described // later in this section. } }In this sample code, a method is provided to handle the client functionality required by each button in the interface. The "Disconnect" button is the only exception, as it is implemented by a single line of Java code.
We will now explain in detail the functionality of each button implementation. The "Connect" button functionality is implemented in the method
bindObject()
:
// Connect button implementation. public void bindObject () { String tmp; String markerServer; String hostName; // Get server name from text field. if ((tmp = nameField.getText ()) == null) markerServer = ""; else markerServer = ":" + tmp; // Get host name from text field. hostName = hostField.getText (); // Bind to server object. try { gRef = Grid._bind(markerServer, hostName); } catch (SystemException se) { displayMsg ("Connect failed.\n" + "Unexpected exception:\n" + se.toString ()); return; } displayMsg ("Connect succeeded."); }The "Connect" button forces the client to bind to a
Grid
object in the server specified by the "Server Name" and "Server Host" text fields. The _bind()
method creates a proxy object of type Grid
and binds it to an implementation object in the specified server. No object marker is specified in the _bind()
call, so OrbixWeb is free to choose any Grid
object in that server.The "Disconnect" button is implemented by the following line of code:
gRef = null;This button simply allows the user to destroy a previously created proxy object by assigning it to the Java value
null
.The "Get Grid Dimensions", "Get Cell Value" and "Set Cell Value" buttons allow
Grid
operations to be invoked on a proxy created by the "Connect" button. Therefore, the methods which implement these buttons simply attempt invocations on the proxy member variable gRef
:
// Get Grid Dimensions button implementation. public void getHeightAndWidth () { short h, w; // Check that proxy exists. if (gRef == null) { displayMsg ("Get dimensions failed" + " - not connected to server."); return; } // Call attribute methods. try { h = gRef.get_height (); w = gRef.get_width (); } catch (SystemException se) { displayMsg ("Get dimensions failed.\n" + "Unexpected exception:\n" + se.toString ()); return; } dField.setText (Integer.toString (w) + " x " + Integer.toString (h)); displayMsg ("Get dimensions succeeded."); } // Get Cell Value button implementation. public void getCellValue () { short x, y; int cellVal = 0; // Get position from text fields. try { x = (short) Integer.parseInt ( xField.getText ()); y = (short) Integer.parseInt ( yField.getText ()); } catch (java.lang.NumberFormatException nfe) { displayMsg ("Get cell value failed - " + "invalid co-ordinate values.\n"); return; } // Call get operation. try { cellVal = gRef.get (x, y); } catch (SystemException se) { displayMsg ("Get cell value failed.\n" + "Unexpected exception:\n" + se.toString ()); return; } vField.setText (Integer.toString (cellVal)); displayMsg ("Get cell value succeeded."); } // Set Cell Value button implementation // (error handling code included). public void setCellValue () { short x, y; int cellVal; // Get position and value from text fields. try { x = (short) Integer.parseInt ( xField.getText ()); y = (short) Integer.parseInt ( yField.getText ()); cellVal = Integer.parseInt ( vField.getText ()); } catch (java.lang.NumberFormatException nfe) { displayMsg ("Set cell value failed - " + "invalid co-ordinate or cell value."); return; } // Call set operation. try { gRef.set (x, y, cellVal); } catch (SystemException se) { displayMsg ("Set cell value failed.\n" + "Unexpected exception:\n" + se.toString ()); return; } displayMsg ("Set cell value succeeded."); }
catch
clauses by displaying the exception toString()
output in the System.out
print stream. Access to this string information is often useful and can facilitate debugging of OrbixWeb clients. In a client applet, it may not be practical to output the information to a print stream, so for this example we display exception strings in information dialog boxes. The file MsgDialog.java
implements a generic dialog class for this purpose:
// Java
// In file gridAppletDemo/MsgDialog.java
.
package gridAppletDemo;
import java.awt.*;
public class MsgDialog extends Frame {
protected Button button;
protected gridAppletDemo.Msg label;
public MsgDialog(String title, String message){
// Details omitted.
}
// Other class details omitted.
}
The details of this class implementation and that of class Msg
(on which class MsgDialog
relies) are not important. OrbixWeb error handling is now added to our GridEvents
class by defining a display method:
void displayMsg (String msg) { gridAppletDemo.MsgDialog msgDlog = new gridAppletDemo.MsgDialog ("Grid Operation Result", msg); msgDlog.resize (380, 200); msgDlog.show (); }This simply allows any string (including a system exception string) to be displayed in a dialog box.
Grid
client applet, we simply define a subclass of java.applet.Applet
and add a GridEvents
object to it:
// Java // In file gridAppletDemo/GridApplet.java. package gridAppletDemo; import java.applet.*; import java.awt.*; public class GridApplet extends Applet { // Main display panel. gridAppletDemo.GridEvents gridEvents; public void init () { gridEvents = new gridAppletDemo.GridEvents (); // Add panel to applet. this.add (gridEvents); } }
<APPLET>
tag. The source for GridApplet.html
is an example of this:
<HTML> <HEAD> <TITLE>OrbixWeb grid applet demo</TITLE> </HEAD> <BODY> <H1>Grid Client</H1> <APPLET code="gridAppletDemo/GridApplet.class" width=408 height = 500> </APPLET> </BODY> </HTML>
In particular, it is necessary to ensure that the Java compiler can access the Java API packages (including
java.awt
for this sample code), the OrbixWeb IE.Iona.Orbix2
package, and any applet-specific classes. The compiler should then be invoked on all the Java source files for the application. In this example applet, the required files are Grid.java
, _GridRef.java
, GridPanel.java
, GridEvents.java
, GridApplet.java
, MsgDialog.java
, and Msg.java
.gridApplet
demonstration directory provides a make file which invokes the javac
compiler as required. In this directory, it is simply necessary to type (on Unix):
makeor (on Windows 95 or Windows NT):
nmake
appletviewer
can be used as follows:
appletviewer GridApplet.htmlJava applets differ slightly from standalone Java applications in the requirements for providing access to the relevant class directories.
If an OrbixWeb applet is loaded into the viewer from a file, then it is possible to specify the locations of required classes in the
CLASSPATH
environment variable before running the viewer. The classes required are identical to those for an OrbixWeb client application, as described in section 2.14.
An alternative approach, when loading the applet from a file, is to provide access (for example, via links) to all the classes the applet requires in a single directory. Then, rather than setting an environment variable, the
CODEBASE
attribute of the HTML flag <APPLET>
could be used to indicate the location of the applet bytecode.<APPLET>
tag in GridApplet.html
to the following:
<APPLET codebase="/tmp/orbixweb/classes" code="gridAppletDemo/GridApplet.class">When loading an applet from a Web server, the
CLASSPATH
environment variable approach to specifying the location of bytecode is not universally available. In this case, the only suitable strategy is to set the CODEBASE
attribute as described above. Note that when using a Java-enabled Web browser to view an applet, it is not necessary to provide access to the Java API classes, as these will already be available.Java applets are subject to important security restrictions, imposed by the Java environment and by web browsers. The severity of these restrictions is often dependent on browser technology, but the general issues are outlined in section 10.2.3 "Security Issues for Client Applets".
3.4 Learning more about OrbixWeb
The OrbixWeb Programming Guide describes the features of OrbixWeb in more detailit expands on the information presented here and: