In the next chapter, we will expand this example to illustrate how OrbixWeb applications can be integrated with Java applets. We will also introduce some of the issues which affect this integration.
At this early stage, we will explain only what is necessary to understand the example. We will avoid being slowed down by unnecessary details.
The server and client can be run on different machines in the distributed system; or in different address spaces in the same machine; or indeed within the same address space.
The grid example has been chosen here because it is an abstract view of a number of commonly used components, such as a spreadsheet or a relational table. Some comments will be made at the end of this chapter to discuss how our simple application can be extended to handle added complexity that may arise in a real application.
A version of the sample code described in this chapter is available in the
grid
demonstration directory of your OrbixWeb installation. However, readers should be aware that the documented code may differ slightly from the installation example.
The interface to our grid can be defined in IDL as follows:
// IDL // In file grid.idl. interface Grid { readonly attribute short height; readonly attribute short width; void set(in short n, in short m, in long value); long get(in short n, in short m); };The interface provides two attributes:
height
and width
which define the size of the grid. Since these are labelled readonly
they cannot be directly modified by a client.There are also two operations:
|
which allows an element of the grid to be changed, and
|
|
which returns an element.
|
The parameters to the operations are labelled as
in
, which means that they are being passed from the client to the server. In other interfaces, parameters may have to be labelled as out
(from the server to the client) or inout
(in both directions).
The OrbixWeb IDL compiler can be run as follows1:
idl grid.idlIDL compilation results in the generation of several Java data types which correspond to the IDL definition, in accordance with the OrbixWeb mapping from IDL to Java. In particular, the IDL compiler produces a set of Java data types which allow a client to access an object through the
Grid
interface, and another set of data types which allow a Grid
object to be implemented in a server.
Grid
. In compliance with Java requirements, each public class or interface is located in a single source file with a .java
suffix. Each source file is located in a directory which follows the Java mapping for package names to directory structures.By default, the OrbixWeb IDL compiler creates a local
java_output
directory into which the generated Java directory structure is placed. An alternative target directory can be specified with the IDL compiler -jO
switch.Given the above IDL definition and compilation command, the IDL compiler produces the directory structure shown in Figure 2.1.
|
2.6 The Generated Source Files
The IDL compiler produces seven Java source files (for a single IDL interface definition). Each generated file contains a Java class or interface (scoped within the package specified in the -jP
switch, if any) which serves a specific role in application development:
_GridHolder
is not relevant to the programs developed in this chapter.-jP
switch to specify a package name into which all generated Java classes are placed. This can be done as follows:
idl -jP <package name> grid.idl
Grid
to a
Java interface and a corresponding Java class which implements that interface. The code described here was not compiled with the IDL -jP
switch, so the Java types are not scoped within a package name.The
_GridRef.java
file produced by the IDL compiler contains the following Java interface definition:
// Java // Automatically produced // in file _GridRef.java. public interface _GridRef extends IE.Iona.Orbix2.CORBA._ObjectRef { public short get_height() throws IE.Iona.Orbix2.CORBA.SystemException; public short get_width() throws IE.Iona.Orbix2.CORBA.SystemException; public void set(short n, short m, int value) throws IE.Iona.Orbix2.CORBA.SystemException; public int get(short n, short m) throws IE.Iona.Orbix2.CORBA.SystemException; }This Java interface defines an OrbixWeb client view of the IDL interface defined in
grid.idl
. It is implemented by the Java class Grid
in the file Grid.java
:
// Java // Automatically produced // in file Grid.java. import IE.Iona.Orbix2._CORBA; import IE.Iona.Orbix2.CORBA.CompletionStatus; public class Grid extends IE.Iona.Orbix2.CORBA.BaseObject implements _GridRef { public short get_height() throws IE.Iona.Orbix2.CORBA.SystemException { // Method details omitted. } public short get_width() throws IE.Iona.Orbix2.CORBA.SystemException { // Method details omitted. } public void set(short n, short m, int value) throws IE.Iona.Orbix2.CORBA.SystemException { // Method details omitted. } public int get(short n, short m) throws IE.Iona.Orbix2.CORBA.SystemException { // Method details omitted. } public static final _GridRef _bind() throws IE.Iona.Orbix2.CORBA.SystemException { // Method details omitted. } public static final _GridRef _bind(String markerServer) throws IE.Iona.Orbix2.CORBA.SystemException { // Method details omitted. } public static final _GridRef _bind(String markerServer, String host) throws IE.Iona.Orbix2.CORBA.SystemException { // Method details omitted. } public static final _GridRef _narrow(IE.Iona.Orbix2.CORBA._ObjectRef src) throws IE.Iona.Orbix2.CORBA.SystemException { // Method details omitted. } public static final _GridRef _nil() { // Method details omitted. } // Other class details omitted. }The primary role of this Java class is to transparently forward client invocations on
Grid
operations to the appropriate Grid
implementation object.The IDL compiler generates both a Java interface and a class which implements that interface in order to allow the mapping of IDL multiple interface inheritance to Java (which supports multiple inheritance of interfaces, but not multiple inheritance of classes). This issue is covered in detail in Chapter 13, "Inheritance".
Let us now consider the mapping of the operations
set()
and get()
. The mapping to Java is very straightforward: each IDL operation is mapped to a Java method. The parameters, which were IDL basic types in the IDL definition, are mapped to roughly equivalent Java basic types. For example, the IDL type long
(a 32 bit integer type) maps to the Java type int
(also a 32 bit integer type).readonly
attributes have been mapped to with Java methods (get_height()
and get_width()
). Since the server and client might not be in the same address space, there would be no point in mapping attributes with Java public member variables.throws
clause, which specifies that they can throw the OrbixWeb system exception type SystemException
. Class SystemException
is defined in the OrbixWeb package IE.Iona.Orbix2.CORBA
and is the base class for all OrbixWeb system exceptions. OrbixWeb system exceptions allow clients to handle errors raised during manipulation of or communication with objects in the distributed system.2.7.2 The Server: Types _GridOperations, _boaimpl_Grid and _tie_Grid:
The generated Java interface _GridOperations
defines the Java methods which a server class must implement in order to support the IDL interface Grid
. The file _GridOperations.java
contains the following:
// Java // Automatically produced // in file _GridOperations.java. public interface _GridOperations { public short get_height() throws IE.Iona.Orbix2.CORBA.SystemException ; public short get_width() throws IE.Iona.Orbix2.CORBA.SystemException ; public void set(short n, short m, int value) throws IE.Iona.Orbix2.CORBA.SystemException ; public int get(short n, short m) throws IE.Iona.Orbix2.CORBA.SystemException ; }In OrbixWeb servers, Java classes are used to implement IDL interfaces. There are two alternative approaches used to indicate that a Java class implements an IDL interface: the BOAImpl approach and the TIE approach. To provide support for each approach, the IDL compiler generates code for two Java classes. In our example, these classes are class
_boaimpl_Grid
and class _tie_Grid
.For reasons which will be discussed in Chapter 6, "Programming OrbixWeb using Java", the TIE approach is often the preferred strategy for IDL interface implementation in OrbixWeb servers; we will focus on this approach in this chapter.
// Java // Automatically produced // in file _tie_Grid.java. public class _tie_Grid extends Grid { // Programmer's implementation object. private _GridOperations m_impl; // Constructors - must specify an implementation // object when creating a TIE object. public _tie_grid (_gridOperations impl) throws IE.Iona.Orbix2.CORBA.SystemException { ... this.m_impl = impl; } public _tie_grid (_gridOperations impl, String markerName) throws IE.Iona.Orbix2.CORBA.SystemException { ... this.m_impl = impl; } // Mappings for IDL attributes and operations. public short get_height () throws IE.Iona.Orbix2.CORBA.SystemException { return m_impl.get_height (); } public short get_width () throws IE.Iona.Orbix2.CORBA.SystemException { return m_impl.get_width (); } public void set (short n, short m, int value) throws IE.Iona.Orbix2.CORBA.SystemException { m_impl.set (n, m, value); } public int get (short n, short m) throws IE.Iona.Orbix2.CORBA.SystemException { return m_impl.get (n, m); } ... }
Grid
interface, the programmer must write a Java class which implements the methods listed in the Java interface _GridOperations
. The programmer must also indicate that this class implements the interface Grid
using either the BOAImpl or TIE approach. In this section, we will illustrate how to achieve this using the TIE method.In the example server and client applications, we will assume that the IDL file described above was compiled with the following command:
idl -jP gridtest grid.idlAll the application data types will then be placed within the
gridtest
package.We will call our implementation class
GridImplementation
(in file GridImplementation.java
), and we will ensure that it implements the attributes and operations defined in IDL type Grid
by implementing Java interface _GridOperations
, as follows:
// Java // In file gridtest/GridImplementation.java. package gridtest; class GridImplementation implements _GridOperations { // Details shown later. }Interface
_GridOperations
is automatically produced by the IDL compiler and defines the Java methods which our implementation class must provide in order to support IDL type Grid
.Class
GridImplementation
will implement each of the methods get_width()
, get_height()
, get()
and set()
; and it will also add some member data and a constructor:
// Java // In file gridtest/GridImplementation.java. package gridtest; class GridImplementation implements _GridOperations { public int m_height; // Store the height. public int m_width; // Store the width. public long m_a[][]; // 2D array for grid data. public GridImplementation (int height, int width) { m_a = new long[height][width]; m_height = (short)height; // Set up height. m_width = (short)width; // Set up width. } // Implementation of the operation which reads // the height attribute. public short get_height() { return (short)m_height; } // Implementation of the operation which reads // the width attribute. public short get_width(){ return (short)m_width; } // Implementation of the set operation. public void set(short n, short m, int value) { m_a[n][m] = value; } // Implementation of the get operation. public int get(short n , short m) { return (short)m_a[n][m]; } }
Grid
interface, we need to write a server application in which we can instantiate a Grid
implementation object (of type GridImplementation
). We then indicate to OrbixWeb that this object can be accessed through IDL interface Grid
by passing it to the constructor of a _tie_Grid
object.Conceptually, the simple Java class illustrated below demonstrates how this could be achieved. However, this Java class will not compile without the addition of error handling code as described in section 2.9.1.
// Java // In file GridServer.java. // // Note - This will not compile // without the addition of error // handling code. package gridtest; import IE.Iona.Orbix2._CORBA; import IE.Iona.Orbix2.CORBA.SystemException; public class GridServer { public static void main(String args[]) { GridImplementation gridImpl; _GridRef gridTie; gridImpl = new GridImplementation (100,100); gridTie = new _tie_Grid (gridImpl); _CORBA.Orbix.impl_is_ready("GridSrv"); } }This server program creates a
GridImplementation
object, giving it an initial size. It then creates a TIE object which stores a reference to the GridImplementation
object and indicates to OrbixWeb that the server's initialisation has completed, by calling impl_is_ready()
. The parameter to
impl_is_ready()
is the name of the server as registered in the Implementation Repository (see section 2.11). _CORBA.Orbix
is an object which is used to communicate directly with OrbixWeb. As used here, impl_is_ready()
is a blocking call that returns only when OrbixWeb times-out the idle server. Hence the call to impl_is_ready()
will not return for some time.
2.9.1 Error Handling: Integration with Java Exceptions
If an error occurs during an OrbixWeb method invocation, the method may raise a Java exception to indicate this. Therefore, it is necessary to enclose such calls within Java try
statements. Exceptions thrown by OrbixWeb method invocations can then be handled by subsequent Java catch
clauses.SystemException
(defined in package IE.Iona.Orbix2.CORBA
), so it is possible to handle all possible system exceptions by passing this type to a catch
clause. This can be done as follows:
try { ... } catch (IE.Iona.Orbix2.CORBA.SystemException se) { ... }or as follows:
import IE.Iona.Orbix2.CORBA.SystemException; ... try { ... } catch (SystemException se) { ... }For example, the server class described above could be coded as follows:
// Java // In file GridServer.java. package gridtest; import IE.Iona.Orbix2._CORBA; import IE.Iona.Orbix2.CORBA.SystemException; public class GridServer { public static void main(String args[]) { GridImplementation gridImpl = new GridImplementation (100,100); _GridRef gridTie; try { gridTie = new _tie_Grid (gridImpl); } catch(SystemException se) { System.out.println( "TIE constructor failed"); System.out.println( "Unexpected exception:"); System.out.println(se.toString()); return; } try { _CORBA.Orbix.impl_is_ready("GridSrv"); } catch(SystemException se) { System.out.println( "impl_is_ready() call failed"); System.out.println( "Unexpected exception:"); System.out.println(se.toString()); return; } } }The code in the
catch
clauses simply displays details of possible system exceptions raised by OrbixWeb. It achieves this by printing the result of the SystemException.toString()
method to the Java System.out
print stream.In this example, it is particularly important to note that the constructor for the IDL generated
_tie_Grid
type may raise a system exception; so the instantiation of the TIE object should be enclosed in a try
statement.
To compile the server (or any OrbixWeb application), it is first necessary to ensure that the Java compiler can access the following:
IE.Iona.Orbix2
.
IE.Iona.Orbix2
package is normally installed in the OrbixWeb classes
directory.For example, if using the
javac
compiler to build the grid client application, the location of Java API classes and that of the IE.Iona.Orbix2
package should be added to the CLASSPATH
environment variable or specified in the -classpath
switch as follows:
javac -classpath <Java API dir>:<OrbixWeb classes dir> ...The server application can be compiled by invoking the Java compiler on all the associated Java source files. In the grid server example, the necessary source files are:
gridtest/_dispatcher_Grid.java
gridtest/_tie_Grid.java
gridtest/_GridOperations.java
gridtest/Grid.java
gridtest/GridImplementation.java
gridtest/GridServer.java
grid
demonstration directory provides a makefile 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
Grid
object.To register the server, use the
putit
command on your local machine:
putit GridSrv -java <class name> <class path>NOTE
orbixd
) is running on the server machine.The first parameter to
putit
is the server's name which we have chosen as GridSrv
. This was also the name of the server passed to impl_is_ready()
in section 2.9.
The second parameter is the name of the class which contains the server
main()
method, that is the name of the class which should be interpreted by the Java interpreter. Finally, the third parameter indicates the class path for the server classes.putit
. If the server were not registered, minor modifications to the client and server code, or a special OrbixWeb daemon setting would be required.putit
command.
2.12 Writing a Client Application
We have now outlined how to define and compile IDL interfaces, how to implement these interfaces and how to provide an OrbixWeb server which instantiates implementation objects. In this section, we will demonstrate how Java clients can be written which access implementation objects through IDL interfaces.
// Java // In file gridtest/Client.java. // // Note - This will not compile // without the addition of error // handling code. package gridtest; import IE.Iona.Orbix2._CORBA; public class Client { public static void main(String args[]) { _GridRef gRef = null; String srvHost; short h, w; int v; srvHost = new String (args[0]); gRef = Grid._bind(":GridSrv", srvHost); w = gRef.get_width(); h = gRef.get_height(); System.out.println("height is " + h); System.out.println("width is " + w); gRef.set((short)2, (short)4, 123); v = gRef.get((short)2, (short)4); System.out.println ("value at grid position (2,4) is " + v); } }Class
Client
defines a member variable of type _GridRef
. The client calls the static method _bind()
on class Grid
to create an instance of Grid
which can be accessed via the _GridRef
Java interface. This object acts as a proxy for an object that implements IDL interface Grid
in the OrbixWeb server. A proxy is a local Java object which acts as a representative for a remote object; its purpose is to transparently forward Java method invocations to the remote object. The
_bind()
method creates a proxy object of type Grid
and binds it to an implementation object, running in the GridSrv
server. The first parameter to _bind()
is a string of the form:
"<object name>:<server name>"It names the object and the server in which the object is running. In the example, the object is not named so OrbixWeb is free to choose any
Grid
object in the specified server. The server name, GridSrv
, is the name of the server as registered in the Implementation Repository on the server host (as described in section 2.11).
The second parameter to
_bind()
specifies the host name for the target server. In this example application, the host name is taken from a command line argument.2.12.1 Error Handling: Integration with Java Exceptions
A valid OrbixWeb client must check for and handle errors. In particular, the call to _bind()
or to any of the Grid
operations could fail, especially if the call is to a remote machine. Such calls should be enclosed within Java try
blocks which will allow any exceptions thrown by method invocations within the block to be handled by the subsequent catch
clauses. Thus, the previous example could be rewritten in a valid form as shown below.
// Java // In file gridtest/Client.java. package gridtest; import IE.Iona.Orbix2._CORBA; import IE.Iona.Orbix2.CORBA.SystemException; public class Client { public static void main(String args[]) { _GridRef gRef = null; String srvHost; short h, w; int v; srvHost = new String (args[0]); try { gRef = Grid._bind(":GridSrv", srvHost); } catch (SystemException se) { System.out.println( "Bind to object failed"); System.out.println( "Unexpected exception:"); System.out.println(se.toString()); return; } try { w = gRef.get_width(); h = gRef.get_height(); } catch (SystemException se) { System.out.println( "Call to height or width failed"); System.out.println( "Unexpected exception:"); System.out.println(se.toString()); return; } System.out.println("height is " + h); System.out.println("width is " + w); try { gRef.set((short)2,(short)4,123); v = gRef.get((short)2,(short)4); } catch (SystemException se) { System.out.println( "Call to get or set failed"); System.out.println( "Unexpected exception:"); System.out.println(se.toString()); return; } System.out.println( "value at grid position (2,4) is " + v); } }
It is necessary to ensure that the Java compiler can access the Java API packages, the OrbixWeb
IE.Iona.Orbix2
package, and all application-specific classes. The compiler should then be invoked on all the Java source files for the application. In this example, the required files are gridtest/Grid.java
, gridtest/_GridRef.java
, and gridtest/Client.java
.grid
demonstration directory provides a makefile 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
.class
files) produced in the compilation. When running an OrbixWeb client application, it is necessary to ensure that the interpreter can load the following:
IE.Iona.Orbix2
.
CLASSPATH
environment variable to include the location of Java API classes, the location of the IE.Iona.Orbix2
package, and the directory into which the application bytecode files were output in the compilation stage. For an OrbixWeb demonstration, the output files are typically redirected to the classes
directory.The
gridtest/Client.class
bytecode can then be run through the Java interpreter, for example by typing:
java gridtest.Client <server host>The makefile in the OrbixWeb
grid
demonstration directory generates a script which implements these steps. This script is named javaclient1
and can be run as follows:
javaclient1 <server host>
set()
and get()
operations could raise user defined exceptions, such as an attempt to access the grid out of bounds.
value
parameter to set()
and the return value of get()
would then be changed to type any
. A value of type any
contains information at runtime about its type and about its actual data. The implementation of the set()
operation would then determine the type of value being sent to it.
In the next chapter, we will demonstrate how OrbixWeb functionality can be integrated with Java applets.
Orbix.cfg
. On Unix, if this file has been installed in the /etc
directory, it will be automatically located. If not, or if OrbixWeb is installed on Windows 95 or Windows NT, the environment variable IT_CONFIG_PATH
must be set as described in Chapter 2, "Compilation of IDL and Java" of the OrbixWeb Reference Guide.