Revasoft Revasoft Banner
HomeOur ExpertiseOur ServicesOUR ProductsAbout UsCareersContactsupport
Print this page UI Engine Extensions
Implementing the Widget
Implementing the UI half
Implementing the faceless half in Java

The ULC UI Engine can be extended to support new kinds of ULC objects like widgets and data types (i.e. type converters and formatters). This section demonstrates the required steps for implementing a ULC widget. As is shown in the Architecture Overview a ULC Widget consists of two half objects:

  • The faceless half defines the ULC API for application developers.
  • The UI half communicates with a real widget and adapts it so that it can used by the UI Engine.

In addition to the half objects there is the real widget, which often already exists and needs to be adapted to be used for ULC. The development of a ULC extension is demonstrated based on PieChart widget, which is shown in the following figure.

Pie Sample

Implementing a new ULC widget requires the following steps:

  1. Implement the real widget, if the widget doesn't exist. In this sample the widget is called PieChart.
  2. Implement the UI half (UIPieChart).
  3. Implement the faceless half (ULCPieChart).

The real widget and the UI half must be implemented in Java. It is assumed that the reader is familiar with developing Java user interfaces. The faceless half must be implemented for each language supported by ULC (Java and Smalltalk).

Note: All the strings that are used as tags/keys in the ULC protocol between UI and faceless half must contain 8-bit characters (16-bit Unicode is only supported for data and not for the internal ULC protocol).

top

Implementing the widget

The pie chart widget was implemented from scratch and is called PieChart. A PieChart supports setting the values to be shown, their names, and colors. Clicking on a pie segment sends an action with the name of the clicked segment as an argument.

For simplicity PieChart is not implemented as a model-based widget. Implementing a model-based widget would require implementing a corresponding half object which accesses and tracks changes of a model object.

top

Implementing the UI half

The UI half objects of an extension to the base ULC widgets can be placed in one or more separate packages. It is important to follow the rules described below (i.e. provide a typeString method that returns the fully qualified class name). Do not modify the existing ULC Java packages! In this example the package is called com.ibm.ulc.examples.pieExtension.

Note: Inside VAJava the project that contains this extension must be added to the Project path of the UI class before starting the UIEngine. Outside VAJava the extensions must be placed on the classpath of the UIEngine. The simplest way of doing this is to export the extension to the UIEngine/lib directory.

When the UI Engine needs to instantiate an object it uses the following rules:

  • If the typeString supplied by the ULC half object contains a period then the name is assumed to be a fully qualified class name and the UI tries to instantiate the class matching the supplied name.
  • If the name does not contain a period then the IClassLookUp object of the UI searches in its known class mappings for a match. If a match is found the matched class is instantiated.
  • If the IClassLookUp object cannot find a match the default UI package prefix com.ibm.ulc.ui.UI is prefixed to the typeString and the resulting class name is attempted to be instantiated.

Note: In this case The association of the two half objects is based on the name of the widget. The convention is to use the UI prefix for the UI half object (UIPieChart) and the ULC prefix for the faceless half (ULCPieChart). The ULC protocol uses the base widget name (PieChart) to identify the widget if the typeString method is not implemented in the ULCPieChart class.

Each UI half object must initialize its state from the faceless half. In addition, the PieChart offers the following API:

  1. Handle a request to set the data (values, labels, colors),
  2. Send an event to the faceless half when a pie segment is clicked.

UIPieChart descends from com.ibm.ulc.UIComponent. UIPieChart adapts PieChart so that it can be used by the UI Engine. To do so, it keeps a reference to the PieChart widget. Here is an excerpt from the class definition of UIPieChart:

public class UIPieChart extends UIComponent implements ActionListener {
private PieChart fPieChart= null; }

To restore its state from the faceless half object UIPieChart overrides restoreState.

public void restoreState(ORBConnection conn, Anything args) {
	super.restoreState(conn, args);
	fPieChart= new PieChart(args.get("w", 200), args.get("h", 150));
	fPieChart.setData(args.get("data"));
	fPieChart.addActionListener(this);
}

A call to the inherited restoreState method restores the inherited state. The PieChart widget is created and initialized with the restored state. The ORBConnection argument isn't used in this example and is just passed on to the base class.

The communication of data between the UI Engine and the faceless widgets is based on data objects called Anythings. An Anything is a dynamic data structure which can be transferred between processes. The method restoreState receives an Anything as its argument and uses Anything accessor methods to retrieve the individual arguments. Anythings can either contain a simple data type or arrays and dictionaries of Anythings. To retrieve the arguments requires that the faceless and the UI half objects agree on how they package their arguments into an Anything. In this case the Anything is a dictionary and restoreState retrieves the arguments by name. For example, args.get("w") retrieves the width argument of the pie chart. In the same way the method setData restores the pie chart's data from the Anything and passes it on to the PieChart widget.

Since UIPieChart wants to inform the faceless widget when a pie segment is clicked it implements the ActionListener interface. It also registers itself as an action listener of PieChart.

Requests sent from the faceless object are dispatched to handleRequest. This method receives the name of the request together with its arguments packaged as an Anything. UIPieChart implements only a single request named setData to set the pie chart's data:

public void handleRequest(ORBConnection conn, String request, Anything args){
if (request.equals("setData")) {
setData(args);
return;
}
super.handleRequest(conn, request, args);
}

The method handleRequest uses the method setData to extract the data from the Anything and install it into the PieChart. Invoking the inherited handleRequest allows the base classes to handle its requests.

UIPieChart needs to send an event to the faceless widget when the user clicks a pie segment. To do so it implements the ActionListener method actionPerformed and calls sendEventULC to send the event.

public void actionPerformed(ActionEvent e) {
    sendEventULC("action", "cmd", new Anything(e.getActionCommand()));
}

SendEventULC takes the name of the event, its type name, and an argument. The event's argument is wrapped into an Anything. In this case it is a simple string which corresponds to the label of the clicked pie segment.

Implementing the faceless half

The above example has shown how to handle requests and send events in the UI half. This section describes how to implement the faceless half of the PieChart.

top

Implementing the faceless half in Java

The Java half of PieChart is defined in the class ULCPieChart. In contrast to the UIPieChart you can define the ULCPieChart in a package of your choice. The ULC implementation uses the convention prefixing faceless widgets with the prefix ULC. Internally, when the faceless widget wants to create its UI counterpart it passes the type name of the widget to be created to the UI Engine. By default the type name corresponds to the class name without the ULC prefix. If desired, this default can be changed by overriding the method typeString defined in ULCProxy.

The faceless half objects have to retain the state of the corresponding UI half. To do so ULCPieChart stores the values, labels, and colors of the pie chart widget in its instance variables.

public class ULCPieChart extends ULCComponent {
	protected double[] fValues;
	protected String[] fColors;
	protected String[] fLabels;
	int fWidth;
	int fHeight;
}

The ULCPieChart needs to tell the UI the location of its proxy class. This is done by implementing the typeString method that returns the fully qualified class path.

public String typeString() { return "com.ibm.ulc.examples.pieExtension.UIPieChart"; }

The ULCPieChart has to implement the UI Engine requests symmetrically. First it needs to transfer the widget state to the UI engine. This is done by overriding saveState to fill the arguments kept in its instance variables into an Anything.

public void saveState(Anything a) {
    super.saveState(a);
    a.put("w", fWidth);
    a.put("h", fHeight);
    Anything data= new Anything();
    fillData(data);
    a.put("data", data);
}

ThesetData request is implemented in the following ULCPieChart method.

public void setData(String[] labels, double[] values, String[] colors) {
    fValues= new double[values.length];
    fColors= new String[colors.length];
    fLabels= new String[labels.length];
    System.arraycopy(labels, 0, fLabels, 0, labels.length);
    System.arraycopy(values, 0, fValues, 0, values.length);
    System.arraycopy(colors, 0, fColors, 0, colors.length);
    Anything data= new Anything();

    fillData(data);
    sendUI("setData", data);
}

A request method only needs to package its arguments into an Anything. In this case the arrays with the values, labels, and colors are wrapped into the Anything structure which is expected by the UI half. Then, the request is sent to the UI with sendUI,which transmits the request name and the Anything argument to the UI Engine.

The last step is to handle action events from the UI pie chart. To handle requests you override handleRequest. This method receives the name of the request together with an Anything that stores the request data.

public void andleRequest(ORBConnection conn, String request, Anything args) {
if (request.equals("event")) {   // (1)
	String type= args.get("type", "???");
		if (type.equals("action")) // (2)
			distributeToListeners("action",new ULCActionEvent
			(this, args.get("cmd", "???"))); // (3)
return;
}
super.handleRequest(conn, request, args);
}

These are steps to be implemented in handleRequest:

  1. Test whether the request is an event.
  2. Check the type of the event request to find out if it is an action event.
  3. If it is an action event create an ULCActionEvent and use the distributeToListeners method to notify the registered listeners.
  4. If it is not an action event pass it on to the base class.

top

Back to Products Print this page Back to ULC Demo
ULC
Getting Started
Release Notes
Installation
Running the Samples
Concepts
Architecture Overview
Internal Architecture
Using Layout
UI Engine Extensions
Web Integration
Bringing the Advantage of Thin Client Computing to JAVA
The ULC Tour

top of page
Home | Our Expertise | Our Services | Our Products | About Us | Careers | Contact Us | Support
ULC Demo | ULC Tour | ULC R4.0 | Download | FAQ

 © Copyright 2001 Revasoft Private Limited.
 info@revasoft.com