Project

General

Profile

Code Preparation

This chapter documents the issues requiring the application being converted to have code modifications before conversion can occur. In particular, for each issue there are suggested strategies that can be used for resolution.

This assumes that the entire project can be parsed successfully. Thus any broken 4GL source code or other syntax issues must have been previously resolved.

Many of these topics or issues can be very complex. Golden Code Development, the creators and maintainers of the FWD technology, provide a wide range of services in support of Progress 4GL conversions. For help, see www.goldencode.com.

Runtime Preprocessor Arguments

As described in the Runtime Preprocessor Usage section in the Resolving Preprocessing Issues chapter, the use of preprocessor arguments on a RUN statement is not supported in FWD. Consider the following code in a file called message.p:

MESSAGE “{1} {2} {3}”.

If that file is used as an include, FWD can fully, correctly and automatically handle the conversion. As an example, if there was a procedure named call-via-include.p:

{message.p “Hello” “World” “!”}

The fully preprocessed version call-via-include.p.cache would look like this:

MESSAGE “Hello World !”.

Any number of other procedures and include files would be able to include message.p and the results would be just as expected in the Progress 4GL. It is irrelevant that the filename message.p ends in the .p extension which is traditionally associated with a procedure file. Progress 4GL and FWD both allow that file to be used as in include, the filename extension is simply a convention used to provide a hint to programmers as to the purpose of the file.

The problem for FWD occurs only in the case where the file (that references preprocessor arguments) is executed as a procedure via the RUN statement. The Progress 4GL RUN statement allows preprocessor arguments to be passed. In such a case, the argument references in the called procedure must be positional (e.g. {1}) since named arguments (e.g. {&name1}) are not allowed to be defined in the RUN statement. The result is that Progress will detect the preprocessor usage and it will dynamically compile the called procedure every time the RUN statement executes.

Consider this calling code:

def var txt as char init “Hello World!”.
update txt.
run message.p txt.

The txt variable can be different each time the RUN statement executes. The first time it runs, if the user accepts the default value for txt, the preprocessed message.p would be this:

MESSAGE “Hello World!”.

But if the user modifies txt on a subsequent RUN, the resulting preprocessed message.p could be something like this:

MESSAGE “Something Else”.

The idea here is that a single procedure file can have different source code every time it runs by passing custom arguments to the preprocessor as part of the RUN statement. The preprocessor then expands the argument references in the called procedure using those RUN statement arguments. This on-the-fly preprocessed file is then further processed by the Progress compiler and finally it is executed. Each time that RUN statement executes, the resulting code for that procedure is potentially different. Theoretically there are an infinite number of possible versions of message.p, only limited by the variability of the arguments passed to the RUN statement.

Since there can be any number of different RUN statements (in other procedures or in a different location in the same procedure) that use preprocessor arguments to invoke message.p, to understand the variability of message.p, the developer must analyze all locations which execute the RUN statement on message.p.

The problem in FWD has nothing to do with using the message.p as an include file. Rather, the issue is that in FWD the preprocessor runs once (and only once), at conversion time and the result is compiled into a Java class that doesn't change with each execution.

Reliance on this feature means that the Progress 4GL environment in use for the application would require a compiler in order to run since the compiler is used every time such procedures execute. If the application is precompiled and is run in a runtime-only Progress 4GL environment, then runtime preprocessor usage is not possible.

In the case where this feature is in use, it must be removed or replaced. The following approaches are possible:

  1. Do nothing. This is possible when the file is used, but each of the call sites (RUN statements that call the procedure in question) don't use preprocessor arguments. This file may have positional preprocessor argument references but it is no longer dynamically compiled. It is compiled once and at that time those references are removed since there are no arguments to insert. The same result will occur in FWD when the preprocessor runs.
  2. Remove the code if it is unnecessary. This is possible if:
    • No call sites exist. This means that the procedure is a dead file since it cannot be executed. The entire file can be deleted from the project.
    • The positional argument references are in a portion of the procedure that cannot be reached. Just remove the unreachable code and remove any preprocessor arguments passed at the call sites.
    • The positional argument references result in code that has no meaningful purpose. Just remove the code with the argument references and remove any preprocessor arguments passed at the call sites.
  3. Rewrite the 4GL code to replace the preprocessor argument usage with a FWD supported approach that has the same result. The best options include:
    • Replace invariant arguments with hard coded constants. In older code that may have been modified many times since inception, it is possible that there is no actual variability in some or all of the arguments passed. If the same hard coded string literals or other invariant data are used as arguments in all the call sites, then there is no variability. This means that the RUN statement arguments can be removed and the values hard coded into the procedure.
    • Use parameters (e.g. DEFINE PARAMETER) instead of arguments. This works in the case where the preprocessor substitution(s) doesn't cause the syntax or static elements of the 4GL to change, so that the arguments can feasibly be replaced by variable references. Both the called and calling code must be reworked accordingly.
    • Make a complete list of all the argument variants that cause expansions that affect syntax or static elements of the 4GL code. For example, if there is a preprocessor argument which passes a table name, each time the RUN statement executes, the resulting expanded source code potentially queries a different table and uses that table in the UI or other statements. For each variant of the program, create a hard coded procedure file that passes the necessary arguments via the normal preprocessor include directive. This results in a .p for each of the variants and these procedures then just use the old procedure file as a common include file. The idea is to convert all usage into include file usage and then rewrite the RUN statements to call the proper replacement .p that implements the variant necessary.
  4. Write a pure Java replacement for the called procedure that references preprocessor arguments. Then modify the conversion process to add custom conversion rules to replace/rewrite the RUN statements to call the new hand-written code from the converted code. Delete the original procedure from the project before conversion.

Runtime Code Generation and Execution

In a Progress 4GL runtime environment which includes a compiler, it is possible to use the stream output facilities (e.g. PUT statement) to write a valid 4GL procedure file during the application's execution. If that program is then dynamically executed while the application is still running, then this is called runtime code generation and execution.

Here is an example of runtime code generation and execution:

define stream s.
output stream s to dynamic.p.
put “message 'Hello World!'.”.
output stream s close.
run dynamic.p.

Similar to the FWD problem with runtime preprocessor usage, FWD doesn't handle runtime code generation and execution since the FWD conversion tools only run once and only the compiled Java classes are used at runtime. In other words, the FWD conversion tools don't run on demand at runtime, so all usage of runtime code generation and execution must be removed or replaced.

The potential solutions include:

  1. Remove the code if it is unnecessary. This is possible if:
    • No call sites exist. This means that the procedure is a dead file since it cannot be executed. The entire file can be deleted from the project.
    • The code generation and execution is in a portion of the procedure that cannot be reached. Just remove the unreachable code.
    • The code generation and execution results in code that has no meaningful purpose. Just remove it.
  2. Rewrite the 4GL code to replace the code generation and execution with a FWD supported approach that has the same result. The best options include:
    • Newer 4GL features (if they are supported by FWD) may have been added after the original code was written, which give options to allow the same code to be used more flexibly. If the original reason for code generation and execution was to compensate for the static nature of older 4GL code, this is a possibility. Rewrite the code accordingly.
    • Make a complete list of all the output variants that affect syntax or static elements of the 4GL code. For example, if the generated code could be a report writing program which varies by which table name is used. For each variant of the program, create a hard coded procedure file for each variant (possibly using the preprocessor include directive). This results in a .p for each of the variants. Then convert the code generation and execution sites to use the proper replacement .p that implements the variant necessary.
  3. Write a pure Java replacement for the runtime generated procedures. Then modify the conversion process to add custom conversion rules to replace/rewrite the RUN statements to call the new hand-written code from the converted code. Delete the original procedure from the project before conversion.

Supported CONNECT Statement Options

Only a subset of the available options to the CONNECT statement is supported by conversion:

Option Meaning Notes
-db Physical database name
-ld Logical database name
-H Host name or address
-S Port number or service name Service names must be mapped to port numbers in the directory (see port services mappings)
-U Userid
-P Password
-1 Single-User Mode Currently, this option is accepted and reported via DBPARAM() (i.e., ConnectionManager.dbParam()), but it is not enforced

Supported CONNECT statement options

Any other CONNECT statement options are ignored by the conversion process. In some cases, additional options may even interfere with the parsing process at the front end of conversion. Any such errors should be reported to the FWD development team, and any such options should be removed from the CONNECT statement as a workaround.

Platform Specific Features

Sometimes when an application is converted to Java its execution environment is moved to different hardware and/or to a different operating system. The combination of hardware and operating system is referred to as a “platform”.

Since Java as a technology is the most highly portable enterprise development environment, virtually every platform created in the last 15 years can run a recent Java version. Java runs on everything from smart cards, phones and embedded devices to mainframes.

Progress 4GL does provide an abstract interface for application development. However, its portability is limited to only those platforms on which it is offered by Progress Software Corporation.

Moving from Progress to Java therefore opens up the possibility that an application will be moved to a new platform. If that is the case, then there may be issues that require code modifications to the application before it is converted. It is important to note that these issues have nothing to do with FWD. Rather, these code modifications are purely caused by the platform move. If the platform were not changing, then the application could convert via FWD without any modification and without any issues.

Each of the following Progress 4GL facilities encodes code that may be platform-specific. For each one, use the FWD reporting infrastructure to find all of the related usage. See the Reporting chapter for more details on running the canned reports. Examine each case to determine if the target platform is compatible with the source platform. Note that even systems with very close lineage (e.g. Linux and UNIX) will have differences that may be subtle. It is best to test the feature on the target system to confirm its compatibility.

  • All language statements that rely upon shell command usage (e.g. OS-COMMAND, UNIX) or child process launching (e.g. INPUT THROUGH, OUTPUT THRU). Each of these cases executes a child process using some executable binary on the runtime platform. If those binaries are not available, not found in the same paths or even if available they operate differently, then problems will occur.
  • The applicaton may have file system dependencies including dependencies on the structure (e.g. a particular directory name in which to find files), permissions and/or specific file dependencies. Even simple file system issues such as the separator characters used in fully qualified file names can be an issue. For example, on Windows the \ backslash character is used in filenames, but in Linux the path separator is a / forward slash. Make sure the target platform is set up the same way as the source platform. Anything that cannot be made compatible must have code modifications to handle the differences. Review all usage of file and path names in the application.
  • Each platform provides different methods to set up an applications environment. There are different ways to set up search paths for binaries and libraries. There are different ways to specify environment “variables” which may hold configuration information that can be read by the application. The locale (character set, date/number formats...) for an application may be different between platforms. The application must be examined to identify and resolve dependencies on the environment.
  • Platforms have highly-specific printing interfaces. Some platforms have proprietary APIs while other platforms rely upon the piping of an output stream to a given printing command. Review all application printing mechanisms.
  • Any direct use of libraries (dynamic link libraries or DLLs on Windows and shared objects or SOs on Linux/UNIX) from within Progress is a platform dependency. Since any such library is a native binary, a compatible version must be present on the target system. Examine all instances of the PROCEDURE language statement where the EXTERNAL option is specified. That is the “registration” of an API in the shared library as a callable procedure (with parameters). The shared library name and its list of APIs must be made available on the target platform.
  • COM Automation is similar to native library calls except is both Windows-specific and it follows a more object-like programming paradigm (invoke methods and access/set properties). This is a special kind of Windows DLL, most often used as a way for 4GL code to use a specific application (e.g. Excel, Word, IE) as a library.
  • Non-interactive .NET class usage is usually Windows specific. Although the open source version of the .NET CLR (Common Language Runtime) and some core .NET libraries do exist on some UNIX/Linux platforms, most .NET code leverages features that can only run on Windows.
  • .NET GUI (Windows Forms) usage.
  • Direct access to the Windows Registry is a hard coded dependency on Windows.
  • Windows Dynamic Data Exchange (DDE) usage.
  • Windows Help files can be accessed via the SYSTEM-HELP language statement. This is a deprecated feature of Windows, but one that still works.

In all of the above cases, the simplest resolution is to ensure that a compatible version of the facility of the source platform is available on the target platform. If that is not possible, then the usage should be removed or replaced. If replacement is used, it is best to choose an option that is portable.

Common GUI Facilities Needing Replacement

Some of the above noted platform specific features are not yet implemented (e.g. COM Automation, Windows Help support, .NET class usage, DDE) but most of the facilities are in fact already present.

There do exist some features that are not planned to be implemented. The following Windows-specific features should be removed and/or replaced with an alternate version that will work in the converted environment.

OCX Usage

The 4GL GUI facilities have not changed much since the late 1990s. The only real exception is the .NET GUI support (see below). As a result, most GUI applications heavily use OCX (a.k.a. Active-X Controls) support. These are special purpose COM objects that usually are interactive. They are usually implemented using the AppBuilder, which will encode a .wrx file with some design-time configuration for the control. At runtime, the 4GL code will create a CONTROL-FRAME widget and load the OCX into it. That control is then manipulated with the same syntax that is used for COM Automation.

The interactive nature of this is not a good fit for inclusion into FWD. It is technically possible, but is not planned for inclusion at this time.

Some common OCX controls have some good alternatives that can be used:

OCX Replacement Description
PSTimer Timer Service This is a 4GL syntax enhancement that exists only in FWD. It allows the user to create and configure a Java timer thread that will call the given internal procedure when the timer fires.
TabFolder Tab Folder This is 4GL code that manually draws folder tabs on a window and manages the user's interaction with the multiplexed common area between different screens. Eventually, a built-in FWD widget will be written, but until then this works well.
TreeControl Tree Widget This is 4GL code that manually draws a tree widget and manages the user's expansion and collapse of the tree as needed. Eventually, a built-in FWD widget will be written, but until then this works well.

It is quite reasonable to write a widget in FWD and add that to both the 4GL syntax (and conversion) as well as the runtime parts to support that widget's operations. This is something that can be done during a conversion project. Of course, if there are existing web or Java technologies that can be used, it is also possible to integrate these into the interactive UI of the system.

Regardless of the approach, it is important to eliminate all OCX usage.

.NET GUI (Windows Forms Usage)

Since 2010, it has been increasingly clear that customers don't want a Windows application. Faced with customer requirements to shift a UI to the web and mobile, most 4GL organizations are finding that most options for moving to the web and mobile will take so much time to implement that they are impractical. The exception is FWD, which can achieve a web UI in a surprisingly short time scale.

The customer pressure is often leading to the idea that quickly delivering a slightly more modern Windows UI allows organizations to claim that they have updated the UI. The hope is that this will buy some time with customers while other options are explored. The way this is being done is to leverage the .NET GUI/Windows Forms support which Progress provided in Openedge 10.2A (November 2008). Doing this does nothing to actually get an application to web or mobile and adds substantial complexity to the resulting application. Nevertheless, if it is being leveraged in an application, it needs to be removed or replaced.

The interactive nature of Windows Forms this is not a good fit for inclusion into FWD. It is technically possible, but is not planned for inclusion at this time.

HWND Usage

Many 4GL GUI applications have code that directly references the HWND attribute and/or passes the HWND of a 4GL GUI window or widget to a WIN32 API call. This doesn't work in FWD because there is no one to one relation between a widget and a Windows native control. All widgets in FWD are written in Java and they interact with the GUI driver using a set of common drawing and event primitives. The same Java widget code can render on the web client or the Swing client without any changes. This means there is no HWND to report for a widget.

The two most common reasons to use this in the 4GL have good replacement mechanisms available in FWD:

Mouse Position Location
Screen Refresh Control

If the use case is not one of the above and cannot be easily removed, then a similar approach can be written to implement a built-in feature of the UI to replace the hard coded HWND usage.

RECID/ROWID Usage in a Permanent Database

RECID and ROWID values do not survive a dump from OpenEdge and load into whatever RDBMS is used by FWD. These fields will not export from a Progress database, and even if they did, the values of any stored RECID or ROWID fields will not match those assigned on import to the migrated database. It is likely that these are not relied upon as persistent values, because this problem would already have presented itself across Progress dump and load updates in the past. Nevertheless, it is very important to check that any such uses are for purely transient purposes. For example, storing a RECID in a temp-table and then accessing it in a more deeply nested part of the call stack will work fine. Generally, if RECID/ROWID are used in a transient manner, it will work in FWD.

Another thing to check is whether there are any other similar cases, where a RECID or ROWID is string-ified and stored in a permanent table. Although such fields would export from the old system and import into the new without error, any logic that depends on them matching the string-ified RECID/ROWID in the new system will break.

Use of the Host Language Call (HLC) Interface

Progress 4GL provides a mechanism to directly link a custom binary module (written in C language) with the Progress 4GL runtime executable. That custom code is written using header files that provide access to Progress 4GL data structures and low level functions. The code must export a dispatcher routine with a specific name (PRODSP) and the 4GL runtime will invoke that dispatcher when the application executes a CALL language statement. The first parameter to the CALL statement is the routine name that is to be invoked. The dispatcher code then invokes the identified function and returns when complete.

While Java can call native code, there is no standard mechanism to directly link a custom native binary with the Java binary that is used to run the Java environment. Likewise, the tight coupling of the low level Progress 4GL data structures and functions is not something that is cleanly duplicated in Java (nor would one want to do so). For this reason, it is important to migrate this code to some other approach.

The potential solutions include:

  1. Remove the code if it is unnecessary. This is possible if:
    • No CALL statements exist in the application. This means that the HLC code is dead since it cannot be executed. That code can be deleted from the project.
    • The CALL statements are in a portion of the application code that cannot be reached. Remove the unreachable code and remove the HLC code.
    • The CALL statements can be executed by it has no meaningful purpose. Remove the unreachable code and remove the HLC code.
  2. Rewrite the 4GL code to replace the CALL statements with a FWD supported approach that has the same result. The best options include:
    • Newer 4GL features (if they are supported by FWD) may have been added after the original code was written, which give options to allow the same code to be used more flexibly. If the original reason for HLC code was to compensate for something missing in the 4GL which has now been added, then this is a possibility. Rewrite the code accordingly.
    • Convert the C code into a shared library. Use PROCEDURE EXTERNAL and RUN statements to call that native code from the 4GL application. Convert using the FWD facilities that are available. Warning: at the time of this writing, the generic FWD support for calling shared libraries is designed but not yet implemented. Details on the current support can be found in the book FWD Conversion Reference. Do not implement a shared library approach before checking that reference to confirm that the functionality has been added to FWD.
  3. Write a pure Java replacement for the HLC code. Then modify the conversion process to add custom conversion rules to replace/rewrite the CALL statements to call the new hand-written code from the converted code. Delete the original HLC code from the project.

Data Server Usage

At the time of this writing, FWD does not support conversion of data server code constructs. If your 4GL source code contains data server specific language statements, these must be removed and/or replaced with standard, Progress 4GL data access statements.

Some applications are written using preprocessor directives to conditionally include either data server statements or standard data access statements, depending upon the type of data back-end in use. In such cases, be sure to specify the proper conversion hints (see the chapter Conversion Hints), or to supply the correct include file(s), which would cause the appropriate preprocessor directives to be used for standard data access, before attempting conversion.

OPSYS Use

FWD provides support for the OPSYS built-in function. In addition, FWD provides a new built-in function called RT-OPSYS. RT-OPSYS returns the 'runtime operating system' for the current FWD client, always.

The OPSYS support is not as simple as just reporting the name of the operating system being used to run the FWD client session. This complexity comes from the fact that in the 4GL GUI the programs are always run on Windows systems but in FWD the GUI can be (and is often) run on Linux. This means that there are cases where one may want to execute code as if it were running on Windows even if it is not running on Windows.

Without any configuration in the directory.xml, OPSYS will return the current OS name of the FWD client. In other words, without extra configuration OPSYS will work the same as RT-OPSYS.

OPSYS in FWD can be configured to return the OS name of the 'legacy operating system' on which the application used to run. This can be configured in the directory.xml of the FWD server (see the opsys/override section near legacy-system). For example, this can be used to specify that OPSYS should always return WIN32 even if the converted code is running on Linux:

            <node class="container" name="opsys">
              <node class="string" name="override">
                <node-attribute name="value" value="WIN32"/>
              </node>
            </node>

If this is not specified, there are still reasons to inform FWD if the legacy runtime OS is different from the FWD runtime OS. To do this you will need to add this under legacy-system:

            <node class="container" name="legacy-system">
              <node class="string" name="opsys">
                <node-attribute name="value" value="win32"/>
              </node>

This provides the FWD runtime some knowledge about the fact that the legacy OS was win32 (but this will not affect OPSYS).

It is important to review the OPSYS occurrences in the 4GL code to see if there is platform-specific logic which may need to be adjusted for running in FWD.

  • Specify opsys/override in the directory if there is logic which must execute as if the client is running on win32, even if it is running on linux. In such cases, OPSYS will always report whatever is specified in opsys/override. Any 4GL code which needs to know the actual runtime OS would need to use RT-OPSYS instead.
  • Do not specify opsys/override and instead specify the legacy-system/opsys if it is important for OPSYS to always report the runtime operating system, even in FWD. In such a case, some code might need to be modified if it always must execute a certain way without regard to the OPSYS in FWD but was dependent upon the OPSYS in the legacy 4GL.

Usage of Developer-Only Features

Some 4GL features have no legitimate end-user function, but are provided by Progress to implement a development environment. These are typically only used in code that is a developer tool and thus that code can be dropped from a conversion. It is possible this code could appear in some end user code that would only be executed on a conditional basis but would not normally be available to production users.

The following is a list of developer-only features that should be removed:

  • COMPILE language statement
  • COMPILER system-handle
  • DEBUGGER system-handle
  • PROFILER system-handle

Unsupported Language Features

The book entitled FWD Conversion Reference is the definitive list of supported Progress 4GL features and functionality. That book lists each supported 4GL feature and describes how the converted Java code will be formed on output, including any variations and caveats that may exist. Use of that book is essential in performing a gap analysis. The approach is to run the FWD reporting tools on the project and to cross-reference the features found in the application with the supported features in the book. Anything missing or not fully supported will require modifications.

The following approaches can be used to resolve an issue with an unsupported language feature:

  1. Remove the code containing that feature if that code is not really required. There is often a great deal of code in a project that is unused, is inaccessible (cannot be reached through any navigation mechanism of the application), is only for testing/debugging, is a build/support tool or is otherwise not critical.
  2. Rewrite the code to achieve the equivalent result through the use of supported features.
  3. Write a pure Java replacement. Then modify the conversion process to add custom conversion rules to generate the proper integration logic to call the new code from the converted code.
  4. Update the FWD conversion and/or runtime to support that feature. Some features may only require changes in the conversion and others may be purely runtime changes. Most features will require changes in both.

Golden Code Development, the creators and maintainers of the FWD technology, provide a wide range of services in support of Progress 4GL conversions. Enhancing FWD is one of the services that their expert developers can provide. Please see www.goldencode.com for more details.


© 2004-2022 Golden Code Development Corporation. ALL RIGHTS RESERVED.