Wednesday, 27 May 2009

Extending the GUI runtime

Earlier postings have discussed the benefits of a runtime, for example, simplifying the development environment and allowing developers to concentrate on the business logic. We discussed how we have extended the runtime with custom action diagram functions. However the area where we have made the most use of a customised runtime is the GUI interface.
It is no secret that the standard Gen window designer offers limited features and the resulting look and feel often leaves users underwhelmed!

The majority of our products are client/server applications with a Windows GUI presentation layer designed in Gen. A few years ago we decided that it was important to improve the usability of the products and one of the key areas that we felt needing enhancement was the GUI front-end.

Some of the areas that we felt could be improved were:
  • Resizable windows and dialog boxes. These have to be designed for a minimum screen resolution (for example 800x600), but if a user has a larger monitor, it would be useful for them to be able to have larger window/dialog boxes. Two issues in a Gen application are a) if you resize a window, you then need a lot of code to reposition/resize the controls on the dialog box and b) the new size should be remembered since the user will not want to resize the dialog box each time they open it.

  • List Boxes. Most windows applications utilise list boxes where the user can change column widths, re-sequence columns, sort on columns by clicking on the column heading. Often a bitmap will make the data much more readable.

  • Tabs. These can reduce the complexity of an application that requries a lot of dialog boxes.

We investigated various approaches to implementing the above requirements. Most solutions involved a lot of additional code (for example to move controls around when a window is resized or to manipulate an OCX control) and would have involved a lot of effort. We also wanted to keep a common look and feel across all parts of the products and hence if we decided to enhance the products, we would have to re-code all of the windows and dialogs and not just the commonly used ones.

This is where we come back to the concept of a runtime. In our normal use of Gen, we did not have to add in a lot of window handling code – this was handled by the Gen GUI runtime. What if this runtime were extended to support our additional requirements? It transpired that a Gen list box could be ‘enhanced’ via Windows functions and still appear as a normal list box to the Gen GUI runtime. We were therefore able to extensively enhance and improve the functionality of the Gen GUI without needing to change either the action diagram code or the Gen GUI runtime.

Simple NOTE statements in the action diagram were used to provide parameters to the extended runtime and we were able to enhance the entire product line in a matter of days because the complexity was ‘hidden’ in the runtime functions and did not have to be coded by the developer.

The example below illustrates a window that utilises enhanced list boxes that can display bitmaps, it can be resized and the list boxes are resized automatically to fill the window, and various tabs are available with associated bitmaps as well.

The results of this effort are now available to other Gen sites as the IETeGUI product.

Monday, 18 May 2009

Beware hidden READ properties

We encountered a problem recently where some code worked fine on our main Oracle test system but did not work correctly on z/OS DB2.

We could not see anything wrong, so ran the code in trace using xTrace and it was then that it was noticed that there was a LIMIT 1 clause set on a READ EACH properties. This limits the rows returned to 1, but only for MS/SQL or DB2. The statement should not have had the property set, but had been copied from another READ EACH that did have the LIMIT since there was an ESCAPE after the first READ and hence it worked correctly in all databases.

This highlights the danger of using properties that affect the results set, for example, LIMIT or DISTINCT since these are not visible to the designer when viewing the action diagram.

My recommendation would be that if you decide to use these properties, add a NOTE statement indicating this above the statement. This will act as a warning if the statement is copied, and also should also indicate that the properties might need modifying.

Wednesday, 13 May 2009

Client/Server Versioning

Our products are designed as client/server applications where the client code resides on the user’s workstation and the server code resides on a central windows, UNIX or z/OS server.

The majority of our customers install the client code on each user’s workstation, though it is also possible to install it on a central file server. Because the changes to the workstation software are often strictly controlled and require the involvement of desktop support departments, in many sites there are restrictions on the timing and frequency that desktop software can be updated.

With a Gen client/server application, if the interface to a server changes (i.e. import/export views), then the client window manager needs to be re-generated and therefore a new version of the client software is required.

This presents two issues with the development and deployment of new releases of software.

The first issue is to prevent the client software invoking the wrong version of the server software. For example, if the server software is updated and a user attempts to access it with an older version of the client software, the software might fail (typically with a common format buffer error) or even worse, complete execution but with incorrect results.

The solution that we have adopted to the first issue is to incorporate a version number in the client software . This is passed to the server on each server call and the first thing that each server does is to verify that the client version number is compatible with the server. The version number is nearly always the same as the major release of the software and hence this ensures that the client and server software is at the same release, for example 7.7.

The second issue is to allow fixes and minor updates to the software within a release that does not require a complete refresh of the client software on all user’s workstations.

To address this requirement, we do not make any changes to the server interface (import/export views, view properties, transaction codes, etc) within a major release that would require a new client version. This means that the server code (and client code if required) can be updated to the latest service pack or with emergency fixes without needing to re-distribute or update the client code.

If there is a real need for a new client/server flow within a release, this can be accommodated with a completely new server procedure step. Updated clients can access the new p-step, but existing clients will be unaware of it and hence continue to operate unaffected. With this approach, the only consideration is that the server code will need to be deployed before the client code.

Friday, 1 May 2009

Single Logon

When launching our products (GUI client/server or local windows based ‘fat clients’) the user has to logon by providing a userid and password. These are then used to validate that the user has access to the system and optionally are also provided to the Gen client/server runtime modules for authentication at the server level, for example, to RACF on the mainframe.

Since we have multiple applications available via a program folder or accessed via the Gen toolset plug-in menu, we wanted to avoid having to ask the user to logon each time they started a new application if another one was already open.

This meant that we needed to find a way of sharing the logon credentials. This method had to be secure and reliable, so storing the values in an environment variable or file was ruled out. The solution we adopted was to use a DLL that was shared by all of the clients and the user credentials stored in the DLL’s memory with encryption.

Normally if multiple executables share the same DLL, each instance will have its own private copy of the memory, thus precluding the sharing that we were trying to achieve. The solution was to use a shared memory segment in the DLL so that the contents of the shared segment could be accessed by all executables.

The result is that once the user has logged on to one client, then all subsequent clients do not ask for the userid and password. An additional benefit of the shared DLL is that when the last client is closed, the DLL is no longer resident in memory unlike using persistent storage methods.