Overview of Generated Java Code
There are many approaches to PowerBuilder-to-Java code translation, including modeling each PowerBuilder visual type directly as a visual Java class, such as a Swing class. However, believing this approach will not achieve the best results, Techné has chosen to translate applications to a peer model instead.
This document discusses Techné’s approach to the design of JConvert/PB’s generated Java code and the requirements that this imposes on the Java runtime library PBJ.
The majority of top-level types defined in a PowerBuilder application are visual objects like regular windows (corresponding to top-level frames in Java), DataWindows, and user objects. Instances of these types act as visual containers for other visual components, like controls, or other user-defined components. PowerBuilder enforces a strict correspondence between the visual containment hierarchy and the type structure of the program. For each internal component inside a visual container, PowerBuilder defines an inner type inside the type of the container, and then declares exactly one instance of that type (typically having the same name as the type.) Each of these inner types can have event handlers or methods associated with them.
Since Java directly supports inner classes, the most natural translation is to transform each PowerBuilder type into a Java class: top-level PowerBuilder types become top-level Java classes, and inner PowerBuilder types become inner Java classes. This is, however, in conflict with the requirement that the (translated) Java user interface objects should be fully editable in most GUI designers. For example, JBuilder GUI Designer only accepts top-level GUI classes, and cannot handle inner GUI classes.
A second – and perhaps more important – constraint is that the Swing library class structure is not completely parallel with the PowerBuilder type hierarchy. The resulting Java code must, however, satisfy both hierarchies in order for the translated code to work correctly. This will inevitably lead to conflicts when some methods that are implemented in separate classes in Swing must be available in a common class in the translated code, or the other way around. Since Java doesn’t support multiple inheritance, there is no direct solution for this problem. (Relying only on Java interfaces would require duplication of code, since interfaces don’t offer implementation inheritance.)
De-coupling the PowerBuilder-imposed type hierarchy from the Swing-imposed one can solve these problems. This is achieved by using a peer model, where each PowerBuilder type is implemented as a non-Swing class, which in turn delegates all the visual responsibilities to a Swing peer. Beside resolving the conflicts enumerated above, it also makes it easier to re-target PBJ to another low-level widget toolkit, such as the one included in the IBM’s Eclipse framework, without affecting the core of the library.
The Java translated code is therefore partitioned into high-level code, dealing with features mostly specific to PowerBuilder, and low-level GUI-specific code, delegated to a widget toolkit, like Swing.
The high-level code doesn’t have direct dependencies on any specific low-level GUI classes. The access to the required functionality is mediated instead by a set of Peer interfaces. Creation of actual peers (needed in the high-level code) is done via a PeerFactory, which instantiates objects from a particular peer back-end according to a static library setting.
This scheme allows both the generated code and the library code to satisfy all requirements:
- A hierarchy of Java interfaces mirrors the PowerBuilder type hierarchy. These interfaces declare all the properties, events, and functions supported by the original PowerBuilder types. PowerBuilder code that depends on the reflection capabilities of PowerScript can be translated into equivalent Java code;
- Application code is translated to non-Swing classes, which implement the above interfaces. They inherit from base non-Swing classes from the PBJ runtime library, which are free to use any inheritance/composition scheme that makes sense for implementation. However, the original PowerBuilder type hierarchy is preserved via the Java interfaces hierarchy.
- The visual peers are Swing objects that implement the peer interfaces accessed from the high-level classes described above. They specialize standard Swing objects, and follow the usual Swing programming conventions;
- The GUI is implemented by top-level Swing peer classes, which can be manipulated with GUI designers;
- The translated application code is composed of top-level (i.e. non-inner) and inner classes arranged in the same hierarchy as the original code. This greatly simplifies the generated code.
One consequence of this design is that the number of Java classes required to translate all visual PowerBuilder types from an application doubles: each PowerBuilder visual type translates into one “high-level” class, and one peer (GUI-specific) class. All the PowerBuilder user code implementing custom event handlers and methods is translated into methods belonging to the high-level classes. The peer classes contain only the Swing definition of the visual objects, and don’t contain any business logic code. This increase in the number of classes is reasonable considering the advantages gained by this approach.