ClientObject Tutorial
Introduction
In BBj 2.0 and higher, programmers can embed Java to access the full functionality of the Java language from within a BBj program. So, for example, a program might use the following code to print the current time using embedded (server-side) objects.
Print Time and TimeZone of Server Machine
|
In many configurations, the user display is on a different machine (the client machine) than that on which the BBjInterpreterServer is running (the server machine). Because these machines may be in different time zones, this small program may display results that are different from what the programmer intended. This code is executed within the Java Virtual Machine (JVM) of the server and so it will display the time and time zone of the server machine while the programmer may have wanted to display the local time on the client machine.
Prior to BBj 8.0, there has not been a mechanism by which a program could execute code within the JVM of the client. BBj 8.0 introduces syntax that provides an RMI (Remote Method Invocation) interface that allows the embedded Java code within a BBj program to access objects that reside in the client JVM rather than within the server JVM.
In order to access this RMI capability, append an @ symbol to a class name to indicate that the class will be accessed in the client JVM rather than in the server JVM as shown in the sample below using ClientObjects:
|
When this code is executed it will use the time of the client machine to create a new Date Object in the client JVM and will use the locale of the client to create a DateFormat object in the client JVM. The result of running this program will be to display the time and TimeZone of the client machine rather than the time and TimeZone of the server.
When objects are created in the client JVM those objects are referred to as client-side objects. The server-side variables that reference those client-side objects are referred to as ClientObjects. So, for example, when line 40 is executed a client-side instance of Date is created and the variable remoteDate! is a ClientObject that represents an RMI handle to that client-side object. The ClientObject can be manipulated in the same way as a server-side object.
This tutorial provides a short example of how to use ClientObjects. If unfamiliar with the use of Java objects within a BBj program, read the following references about using server-side embedded Java before attempting to use ClientObjects:
Exponentially Better Applications: Embedded Java and BBj (PDF)
Syntax of ClientObjects
There are three ways in which the @ symbol is used in BBj to indicate that embedded Java is to use ClientObjects; when
-
Creating a new ClientObject
-
Invoking a static method on a client-side class
-
Declaring a value to be a ClientObject
In each case, the @ is appended to the class name. The class name can be a fully qualified class name or it can be an abbreviated class name if the fully qualified class name has appeared in a USE statement.
The following sample shows the various uses of the @ character within a BBj program.
|
At lines 040-070 a number of variables are declared to be ClientObjects. At lines 090-110 two client-side objects are created and assigned to ClientObject variables. At lines 120-130, two static methods are called on client-side classes and the return values of those static methods are assigned to ClientObject variables.
Using a ClientObject
The methods of a ClientObject are called in the same way that the methods of other objects are called; by using the standard dot notation. In general, the parameters that are passed when calling a method on a ClientObject must themselves be ClientObjects. If a method accepts a string or a number then it will accept a server-side value (see the ClientObject vs. Server-side Objects section for details).
The return value of a method called on a ClientObject is again generally a ClientObject unless that return value is a number or a string. If the return value is a number or a string then the return value will be a server-side value.
This code sample calls methods on ClientObjects:
|
Running the code sample results in output similar to the following.
|
The toString() value of a ClientObject consists of the string "[CLIENTOBJECT]" followed by an ID followed by the toString() value of the client-side object.
Notice that looking at the output above, calendar! is a ClientObject and that the return value of calendar!.getTime() is also a ClientObject. If we place calendar! into a client-side HashMap and then retrieve it, we will receive the same ClientObject. And if we place the server-side number 456 into the client-side HashMap and then retrieve it, we will receive the server-side number.
The field values of a client-side object can also be accessed through the ClientObject and the static fields of a client-side class can be accessed by addressing that class using the @ symbol as shown below.
|
ClientObject vs. Server-side Objects
It is important to understand the difference between a ClientObject and a server-side Object. Any Object that was created using the '@' notation is a ClientObject. Any Object that was created without the '@' notation is a server-side Object. BBjAPI is a server-side Object. Any Object that is obtained through calls on BBjAPI is a server-side Object. In particular, all BBjControls are server-side Objects even though they 'represent' GUI Objects that exist on the client.
In general, the parameters passed to a ClientObject must be ClientObjects while the parameters passed to a server-side object must be server-side objects.
The exceptions to this general rule are:
-
Strings and Numbers are always server-side values. Strings and Numbers may be passed as parameters to methods of ClientObjects.
-
The method BBjWindow::addWrappedJComponent (which is a method call on a server-side object) accepts as a parameter a ClientObject.
-
A BBjControl (which is a server-side object) can be passed as a parameter to a ClientObject if that ClientObject represents a client-side swing component.
-
A BBj CustomObject (which is server-side object) can be registered as an event listener on a ClientObject that represents a swing component
These exceptions allow a program to place objects that extend javax.awt.JComponent@ (ie any client-side JComponent) onto a BBjWindow as well as to place BBjControls onto JComponents and to respond to events that occur on JComponents. All these use cases are demonstrated in the following sections.
Similarly, the return value of a method invocation on a ClientObject is itself a ClientObject and the return value of a method invocation on a server-side Object is a server-side Object except that:
-
Strings and Numbers are always server-side values.
-
BBjBarChart, BBjLineChart, and BBjPieChart (which are server-side Objects) each have a method getClientChart() which returns a ClientObject.
Placing a JComponent into a BBjWindow
BBj 8.0 provides a new BBjWindow::addWrappedJComponent method that allows the program to create a BBjControl that contains a client-side Java Component. In order to place a client-side JComponent onto a BBjWindow, the program first creates a ClientObject that represents the JComponent and then 'wraps' the Object in a BBjWrappedJComponent by calling addWrappedJComponent.
Note: BBjWrappedJComponent depends on the assumption that the client is Java. In the BUI and DWC browser-based clients, use BBjWebComponent.
The following code creates a JButton and places it onto a BBjWindow.
|
Registering a BBj Callback as a Listener on a JComponent
A BBj CustomObject may be registered as an event listener on a ClientObject by calling an add<some>Listener method of the ClientObject.
Note: The BBj API that manages ClientObject event listeners expects the Listener to be a java.util.EventListener and the event object to be a java.util.EventObject.
The CustomObject must have methods that 'correspond' to the methods of <some>Listener. Each of the corresponding methods of the CustomObject must have the same name as the method of the <some>Listener and must accept ClientObjects where the <some>Listener accepts events.
So, for example, the following code sample registers a CustomObject named Listener as a PropertyChangeListener on a JSplitPane. A PropertyChangeListener has a single method.
void PropertyChange(PropertyChangeEvent event)
So the CustomObject, Listener, must have a corresponding method.
void PropertyChange(PropertyChangeEvent@event)
with the same name but accepting a PropertyChangeEvent@ rather than a PropertyChangeEvent.
This sample adds several JComponents to a BBjWindow and registers some listeners:
|
The screen that this code sample generates appears as:
Mixing ClientObjects and BBjControls to Provide a BBjWindow with a LayoutManager
We are now in a position to build a program that provides an interesting mix of JComponents and BBjContols. The following sample provides a BBjWindow that contains a JSplitPane. The left side of the JSplitPane contains both BBjControls and JComponents. In addition, the left panel has a layout manager so that all the controls (both the JComponents and the BBjControls) change sizes as the separator of the JSplitPane is moved.
Note: In BBj 22.10 and higher, the BBjSplitter control replicates the functionality of the JSplitPane, and can be used in the BUI and DWC browser-based clients.
This code sample shows a mix of JComponents and BBjControls with a LayoutManager:
|
This sample generates this screen:
If the user moved the separator, the screen might look like this:
In addition to managing the Layout of the left panel, this sample also reports FocusGain and FocusLoss whenever the JTextField gains or loses focus and reports PropertyChangeEvents whenever the user moves the separator of the JSplitPane.
Requirements for Class files Used to Create ClientObjects
In order to create a ClientObject the Java Class file that defines the client-side Object must be visible to the server as well as the client. For core Java classes like JButton, this happens automatically. Custom Java classes that don't come with BBj must be explicitly added to both the server and client classpaths.