http://www.udev.info
Mail/Login: Password : forgot my password!
[UPDATE MODE]
Back

Understanding and hacking browser side Uniface RIA

Direct link http://www.udev.info/uniface/understanding-and-hacking-browser-side-uniface-ria
Written by RichardGill // Tags: dsp widgets dojo javascript tutorial hack uniface

Compuware provided with its Uniface 9.4 the RIA stuff through Dynamic Server Pages, working with browser side javascript code making the mapping between the two worlds. This stuff is made of Compuware's own mini javascript framework which knowns how to talk with Uniface, and with the help of the Dojo Toolkit for the widgets implementation.

If the base framework which connects to Uniface is almost an untouchable part, the widgets implementation can completly be changed, enabling widgets extensions, or why not, a complete replacement of your application widgets.

This article will show what is provided, what can be safely changed, and will give opportunities for widgets modifications.

This article is also available on uniface.info: http://uniface.communityzero.com/uniface?go=2398757

uniface webapp directory organization


Let's start with the webapps/uniface directory. What can we find inside it? Well, the webapp specific directory WEB-INF with the servlet implementation - opaque content.

We find two sibling directories : common and css. The later just provide default styles for USP and DSP HTML content. They're referenced in the layout of the component, and can safely be ignored (you may provide your own default styles).

Then we have the interesting part : common. It's a common directory for USP and DSP browser execution (though javascript and java applets) and basic resources (some images and css).

For USP, there'are some files not interesting us for this article:
- uniface directory: extracted uwe.cab
- UGomezTag5.1.js: interface with another product
- uwe.cab: USP browser side validation
- webapplet.js: USP applets enabler
- webext.js: some javascript helper functions
- websyntax.js: browser side validation stuff

All remaining files are for DSP!

The Uniface javascript framework


Uniface sends an HTML document to the browser (on a full page load). This document contains the layout of the top level (not contained in another one) DSP, and a set of javascript commands, which will initiate the whole process. All the data passing through javascript (initial commands and subsequent requests) are then JSON streams, containing the entities/occurrences/fields definitions, and their data.

Initial downloaded page SOURCE CODE
Sorry- ... please log-in or register to get this!


All javascript files used in RIA are referenced in uweb.ini, which defines the physical webwidgets (which are mapped to logical webwidgets in usys.ini). One specific and pseudo widget is the page one, which is used whenever ... a page is loaded.

Do not touch that thing


The files which provide the communication between Uniface and the browser are not too much, and are referenced in the page pseudo webwidget:
- ubase.js well, start of the framework, with some tools
- uluv.js fields/entities/components definitions
- uscope.js triggers access management
- udatalayer.js commands to make the link between the browser and Uniface
- usyntax.js syntax checking (not for all types)
- uwindow.js implements the browser part of webmessage
- ubusyindicator.js implements the spinner AJAX

Although you should not touch them, there're some problems which can be solved with a bit of modification. For example, if you want to change the url or execute javascript from Uniface, you can add a command in udatalayer.js (well, before the 9.5, which will provide what missed). I'll make another little article about that trick.

The not so mandatory part


The uweb.ini contains also physical widgets definitions. Like forms logical widgets, you can define DSP logical webwidgets. So all remaining files in common aren't needed for a proper use of Uniface RIA. They're just there as a set for webwidgets implementation.

Going deeper in widgets definitions


The Uniface datalayer make use of a widget definition interface, or abstract widget, to create with and respond events from. The way widgets are used is by all defined in uweb.ini (yes this file is really important for DSP), provided widgets implement the abstract widget interface.

First, the factory pattern and the abstract interface are defined in uwidget.js. The factory (UNIFACE.widgetFactory) knows how to create registered widgets (with UNIFACE.widgetFactory.addCreator()) implementing an UNIFACE.widget.AbstractWidget.

A third object type can be found in this file : UNIFACE.eventMapper, which maps javascript events to Uniface triggers; obvious, but needed.

From this point, we don't have any implementation, just abstract (conceptual) definitions. With the default Compuware set of widgets, we then have two families of widgets :
- simple Uniface widgets (children of UNIFACE.widget)
- Dojo powered widgets (children of UNIFACE.dijit)

Basic widgets


The first family is used for simple widgets, and non Dojo ones. They're all defined in uhtmlcontrols.js. We find :
- plain used for RawHTML, StaticText and FlatButton
- genericHTML used for AttributeOnly
- label for Label
- img for Picture and PictureButton
- embeddedDSP for DSPContainer (this's the exception, this one is defined in its own file : udsp.js)

Unused (pre Dojo) widgets


The second set of widgets use the Dojo toolkit, and particulary the dijit subproject. But it seems Compuware's labs did not use Dojo as a first choice. The uhtmlcontrols.js indeed contains other widget definitions, under the UNIFACE.widget namespace, and providing the (almost) same set of widgets than the Dojo'ed ones. Those widgets are not referenced in uweb.ini, but are usable:
- input for EditBox
- multilinebox for TextArea
- password for Password
- checkbox for CheckBox
- button for CommandButton
- select or dropdownlist for DropDownList
- listbox for ListBox

The only two missing, compared to Dojo widgets, are RadioGroup (this one can be developped to use simple HTML controls embedded in a table tag) and DatePicker. Changing uweb.ini permits to make rid of Dojo, and to use initial simple Uniface widgets. I tried, it works! Of course, you loose of benefits from Dojo, but it can be a good starting point if you want to provide your own powered widgets.

Creating widgets


Adding a simple Uniface widget: form


What I really dislike in Uniface made RIA project is a the pure non-sens of not supporting data submission through a button (just like a form's submit button). In fact, with the original CommandButton, you can't make a real form submission (pressing the Enter key for example). For this to work, you must:
- define a form tag, with a javascript action
- insert a dummy input with the submit type (to throw the form submission)
- insert your command button (visible or not), which click will be simulated by the onsubmit event of the form.

Classic form submission SOURCE CODE
Sorry- ... please log-in or register to get this!


Of course, you still have to define the fake acme.simulateClick() function, to find the command button object with a particular id (which is not so simple with Uniface mapping).

It would be so simple to have a Form widget, whose Detail trigger would be fired when submiting! In fact, it's really easy to make one, with a few lines of javascript code.

First, it's a good habit to define our own namespace. Let's use ACME. We then create a acme.js containing the following lines :

acme.js SOURCE CODE
Sorry- ... please log-in or register to get this!


We just define two embedded namespaces: ACME and it's child widget. Now let's create the acme.form.js file:

acme.form.js SOURCE CODE
Sorry- ... please log-in or register to get this!


The first function, ACME.widget.form, is the constructor. You never start from scratch, so the first thing to do when creating a widget is to find the proper base class. Here I choose genericHTML (the implementation of the AttributeOnly) because it does not touch the HTML structure, and do not replace the tag content with the widget value. In the constructor, we call the base class's constructor.

Then we define the new prototype, using the base class object creation as a starting point.

Finally, we have to implement functions, or to override some of the base class. I won't lie here. You have to study the base class implementation to know what to do. But there's basic things to know :

The widget is inserted in the document with the render process, which main part is done within the doRender function. UNIFACE widgets tend to use the element field as the related tag object. Here, we don't touch the original tag, so we define that element is the DOM node passed to the function. As our form won't submit to an URL, we have to force a javascript URL with the element (form) action.

The form won't submit to an URL, because we want to fire the Detail trigger of the field. So we have to tell Uniface that the form submission fires the Detail trigger. That's done with the mapEvent function, which is called for every public web trigger on the field. We say here that the detail trigger is fired when the onsubmit event occurs on the form tag (the element field).

The last step is to register our new widget to the widget factory (so that Uniface knows how to create our widget with an identifying string).

That's all! Of course, acme.form.js is not used yet. We've to reference it. Let's go into uweb.ini, and write the following lines at the end:

uweb.ini for acme.widget.form SOURCE CODE
Sorry- ... please log-in or register to get this!


This will ensure that when the aform physical widget will be referenced, the following files will be downloaded and evaluated (in order):
- ../common/uwdiget.js needed for the factory and abstract widget
- ../common/uhtmlcontrols.js for the genericHTML widget
- ../acme.js for our base namespace
- ../acme.form.js - our new widget

The section also inform the IDE about the available widget properties and what to insert in the layout for the Copy as HTML action.

Now in usys.ini, we define a Logical Widget in the [webwidgets] section:

usys.ini for acme.form.js SOURCE CODE
Sorry- ... please log-in or register to get this!


Restart the IDF, and add a new field in your structure. Choose AForm as widget type, copy as HTML, and fill with a submit button and other fields:

DSP layout for AForm SOURCE CODE
Sorry- ... please log-in or register to get this!


Compile, test, and enjoy!

Adding a Dojo widget


Uniface comes with several Dojo widgets from a predefined set. All included Dojo widgets aren't mapped to Uniface, so it's possible to add Dojo widgets just adding a few javascript code lines. For our example, I'll choose one user experience attractive widget: the TitlePane. This widget offers a way to show/hide a content clicking on a title. We'll also add a new property to manage the hiding/showing effect duration.

A Dojo'ed Uniface widget is defined the same way classic HTML widgets are, but with an improved base prototype. The widget must map the Uniface field value to the visibility state of the widget, and react to mouse clicks. Here's the definition:

acme.titlepane.js SOURCE CODE
Sorry- ... please log-in or register to get this!


We then add the definition in uweb.ini:

uweb.ini for acme.widget.titlepane SOURCE CODE
Sorry- ... please log-in or register to get this!


Note the duration property in the properties field. We'll declare this new custom property in uproperties.ini, adding at the end:

uproperties.ini for duration SOURCE CODE
Sorry- ... please log-in or register to get this!


And we can now add a logical widget in usys.ini:

usys.ini for acme.titlepane.js SOURCE CODE
Sorry- ... please log-in or register to get this!


If we now create a DSP, with a field TP with the following characteristics:
- Widget: ATitlePane
- Datatype: boolean
- Interface: B

And paste it in the HTML layout, we have our titlepane. All elements contained between the opening and the closing tags will be affected by the pane state. For example:

HTML layout for TitlePane SOURCE CODE
Sorry- ... please log-in or register to get this!


Let's initialize our pane to hidden at startup, and set an effect duration of 500 milliseconds:

Execute trigger SOURCE CODE
Sorry- ... please log-in or register to get this!


And why not another framework?


The Uniface framework is composed of several parts, which are in fact distincts, as long as a common interface is respected. This's true for widgets: they all derive from UNIFACE.AbstractWidget and make use of other UNIFACE namespace tools, but beside that, there's no coupling between Uniface and Dojo. So, by reimplementing the widgets, we could use another toolkit, or another Dojo version.

Conclusion


This contribution, while quite long, is far from complete. The subject is very interesting and many details were omited for the sake of simplicity (and reading time). With a good understanding of Uniface javascript framework and how Uniface generates and reads its JSON data coupled with the HTML layout, one can even define it's own framework.

The Uniface RIA jingle is develop RIA applications in Uniface without HTML nor javascript knowledge. Well, for samples or really simple applications, it's true. But for a full user experience, extensions must be created. The force of Uniface is its smooth integration with any technology - just see the web 2.0 as another integrated technology. We just have to beautify it !

Note on 9.5


As of 2011, may 10, Compuware released a controlled release of Uniface version 9.5, which provides a new javascript API. This API tends to show that customers behavior extensions can't be bypassed. We, as developers and solution architects, need flexibility, to overcome provided defaults limitations. The new javascript API is a key to a clean way to extend Uniface RIA possibilities, whereas evil hacks had to be made on Compuware's javascripts before.

Comments

on 2012-04-13 15:40:24 hollerith wrote:

Do not touch that thing - why not? Hack to learn! For instance ubase.js contains an eval() which really should be replaced with a JSON parser for speed and security.

2868 view(s) / 2011-03-26 23:52:02 / LAST UPDATED: 2011-07-13 16:12:58