Portus currently supports the calling of C functions, COBOL subroutines and Natural subprograms. In the future, it will also support PL1 and potentially assembler in a similar way. All of these languages have the following concepts
Simple or base types to represent data
Structures, which are chunks of memory split up into individual fields with simple/base types
Arrays which are two or more instances of a structure or simple type.
A field area in the language which is mapped over by a language structure. In COBOL or Natural terms, this is called a redefinition of the field while in C it is represented by a union or could potentially be done with pointer arithmetic.
This section of the documentation will describe how such constructs are treated by Portus.
Portus externally knows everything as a single node within an XML document. XML documents can contain structures of XML nodes, arrays of XML nodes or arrays of structures so it can represent any data structure that is required. Different languages and databases have different ways of representing data and it is necessary within Portus to enable the mapping of these external fields into the type of structures that are required internally by the various drivers supported by Portus. In particular, if the Portus representation of the data is modified in a way that is incompatible with how an application program expects to be called, at best, incorrect results will be returned but more than likely the stability of Portus itself will be impacted due to program abends.
A ‘tuple’ based database is simply a database technology for which the data is presented in name/value pairs or ‘tuples’. ADABAS is a tuple based database as when requests are being provided to ADABAS, or data is being returned by ADABAS, it is returned as a field name/Value pair which can easily be translated from and to the external XML structures.
Relational databases such as DB2 also work on the principle of a tuple. The data is provided using column names along with the data associated with the column. Again, this is easily mapped to the external XML field structure and does not need further explanation.
Databases such as VSAM and IMS/DB present their data in the form of records. A record is simply a single contiguous piece of storage that contains the data related to the request. While it is held contiguously internally in the database, it will almost always be made up of multiple individual fields. The individual fields within the record are then addressed by offset, length and type. While they could be addressed in this most simple way, most if not all organizations will have a language definition of the individual fields in the form of a structure. When referencing fields in the structure, the language implementation can then calculate the offset and length of each field referenced and then process it base on its type. Portus uses these language definitions to create definitions for record based databases.
When calling an application program, generally there will be one or more parameters to the program. Note that while the application may treat these as input or output parameters, the application must receive all of the parameters during the call.
To be clear on this point, Portus has the concept of input parameters, output parameters, input-output parameters and parameters which are neither input nor output in its input and output messages for a service. This relates purely to the input/output messages that Portus will build for the service definition. The parameters _Must_ be passed in their entirety to the application being called regardless of their direction definition to Portus.
Depending on the programming language, parameters can be provided as:
A list of individual fields (the most common way for C)
A single structure containing all of the input/output information (mostly used in CICS)
A list of fields or structures (used by COBOL and Natural most commonly)
Essentially it can be stated that an application program will be called with one or more parameters and each parameter may be a single field, a structure or an array. Within a structure we could have other structures or arrays while it is also possible to have arrays of structures.
While all this sounds quite complicated and involved, when it’s broken down it is not as complicated as it may seem. Portus has the concept of a level 1 field name which may itself be a field or the name of a structure. There may be multiple levels below this level 1 field but the number level 1 fields will dictate how many parameters are passed to the applications.
The following are equivalent parameter definitions in various languages:
PARAMETER
1 OPERATION (A3)
1 OPERAND_1 (I4)
1 OPERAND_2 (I4)
1 RESULT (I4) BY VALUE RESULT
END-DEFINE
linkage section.
01 Operation PIC X(3).
01 Operand1 PIC S9(9) COMP-4.
01 Operand2 PIC S9(9) COMP-4.
01 Result PIC S9(9) COMP-4.
procedure division USING Operation Operand1 Operand2 Result.
int calc( char operation[3], int *operand1, int *operand2, int *result )
Each of the above represents in their respective languages:
A 3 character field that will contain an operation code.
A 4 byte binary field that will contain the first operand for the calculation
A 4 byte binary field that will contain the second operand for the calculation
A 4 byte binary field that will contain the result of the calculation
The screenshot below illustrates the Portus representation created based on the Natural PDA area, however, this could also be used for any of the other languages:
Some points to note about this.
- The external names have no significance in terms of the internal call to the application code.
- You will note that OPERATION, OPERAND_1 and OPERAND_2 are input/output fields while FUNCTION_RESULT is output only. Again, this will have no significance internally as all fields must be passed to the application program as it expects this.
- If you do not wish a field to be included in the input or output messages, it must be set with a direction of ‘none’. It must not be deleted as if it is deleted, Portus will end up passing an incorrect set of parameters to the program being called.
The principle of not deleting anything in the Portus representations of this data is critical for the consistent and stable running of the SOA Gateway. This is because Portus representation must reflect what an application program expects to receive as parameters. Any removal or changing of the order here will cause problems because it will result in a different representation being provided to the application program.
In most cases, far more data must be passed to or returned from an application than will fit in a single field. For this reason, structures are generally used to pass data backwards and forwards between applications.
The following show how individual fields along with a simple structure are represented in various languages:
PARAMETER
1 INITIAL (P7)
1 I_RATE (P2.2)
1 YEARS (I2)
1 RESULT
2 YEAR (I2) BY VALUE RESULT
2 SIMPLE (A17) BY VALUE RESULT
2 COMPOUND (A17) BY VALUE RESULT
END-DEFINE
LINKAGE SECTION.
01 INITIAL-AMOUNT PIC S9(7) COMP-3.
01 I-RATE PIC S99V99 COMP-3.
01 YEARS PIC S9(4) COMP.
01 RESULT.
02 RESULT-TABLE.
03 YEAR PIC S9(5) COMP .
03 SIMPLE PIC ZZ,ZZZ,ZZZ,ZZ9.99 DISPLAY .
03 COMPOUND PIC ZZ,ZZZ,ZZZ,ZZ9.99 DISPLAY .
*
PROCEDURE DIVISION USING INITIAL-AMOUNT I-RATE YEARS RESULT .
typedef struct {
short year;
char simple[17];
char compound[17];
} result_h ;
int interest ( int *INITIAL, int *I_RATE, int *YEARS, struct result_h *result )
The equivalent representation of this parameter list in Portus is as follows:
It will be noted that the INITIAL, I_RATE, YEARS and RESULT fields are at level 1 while the elements of the RESULT structure YEAR, SIMPLE and COMPOUND are at level 2. This will result in 4 parameters being passed to the application code with the 4th parameter being a structure. The following should be noted:
As with the previous example, if any of the fields in the structure are removed, it renders the structure invalid unless the application program is changed too. If an element or elements of a structure are not to appear in the output or input messages, they should be given a direction of ‘none’ so that they are still in the structure passed to the application but will not be seen in the service definition.
The format of the fields also cannot be changed as this could impact on their length and thus pass what is not expected to the application program.
Arrays are a very common way of providing a lot of the same information or returning lists from application programs. The following example builds on the previous example to return an array of 50 structures. To return simply an array of values, the ‘structure’ would simply contain one element.
PARAMETER
1 INITIAL (P7)
1 I_RATE (P2.2)
1 YEARS (I2)
1 RESULT (1:50)
2 YEAR (I2) BY VALUE RESULT
2 SIMPLE (A17) BY VALUE RESULT
2 COMPOUND (A17) BY VALUE RESULT
END-DEFINE
LINKAGE SECTION.
01 INITIAL-AMOUNT PIC S9(7) COMP-3.
01 I-RATE PIC S99V99 COMP-3.
01 YEARS PIC S9(4) COMP.
01 RESULT.
02 RESULT-TABLE OCCURS 50.
03 YEAR PIC S9(5) COMP .
03 SIMPLE PIC ZZ,ZZZ,ZZZ,ZZ9.99 DISPLAY .
03 COMPOUND PIC ZZ,ZZZ,ZZZ,ZZ9.99 DISPLAY .
*
PROCEDURE DIVISION USING INITIAL-AMOUNT I-RATE YEARS RESULT .
typedef struct {
short year;
char simple[17];
char compound[17];
} result_h ;
int interest ( int *INITIAL, int *I_RATE, int *YEARS, struct result_h *result[50] )
The above is represented in Portus in the following way:
Again, the application program is expecting a 4th parameter with 50 instances of the following array above. Removing a field from the structure or changing the number of array occurrences without changing the application will result in invalid results and potentially will destabilise the system. Once again if the field should not appear in the input or output messages for the service, simply set the field’s direction to ‘none’ and leave the structure intact.
Redefines ultimately involve the mapping of a base field to one or more different layouts. The base field in this case is the original field upon which the redefine(s) are based. Redefines are used for a number of reasons:
It may be that the format of an area is different depending on some value passed as a parameter or perhaps earlier in the area itself.
Some programmers like to define a large base area and redefine it so that fields may be added at a later date without changing the memory profile of the application. It should be noted here that a redefinition of a base area may have a smaller length than the base area but may never be larger than the base area as otherwise, storage overwrites will be the results.
Ultimately it could be said that a redefine will generally involve mapping a structure on to a flat piece of storage. The reason this is relevant to Portus is that in most cases for a service, the input and output messages will be created from the redefinition (i.e. the discrete fields), however, Portus must create the base field based on the structure and pass the base field to the application program.
The following shows a simple redefine in multiple languages as before. Note in the following examples:
The base field is 200 bytes long.
The total of the redefined structure is 78 bytes long
PARAMETER
1 BASE-FIELD (B200)
1 REDEFINE BASE-FIELD
2 FIELD1 (A20)
2 FIELD2 (B4)
2 FIELD3 (I4)
2 FIELD4 (B50)
END-DEFINE
LINKAGE SECTION.
01 BASE-FIELD PIC X(200).
01 FILLER REDEFINES BASE-FIELD.
02 FIELD1 PIC X(20).
02 FIELD2 PIC 9(4) BINARY.
02 FIELD3 PIC 9(8) COMPUTATIONAL.
02 FIELD4 PIC 9(50) BINARY.
union {
unsigned char base_field[200];
struct {
char field1[20];
unsigned char field2[4];
int field3;
unsigned char field4[50];
} redef_base;
} base;
This is represented in Portus as follows:
Some notes about this:
You will notice that by default, the base field is disabled. In order for Portus to know which version of the field to expose, one or the other must be disabled. If you wish to expose the base field in the input/output messages, then enable the field ‘BASE_FIELD’ and the field ‘REDEFINE_001_BASE_FIELD’ will be automatically disabled.
Note that then a structure is disabled, only the base of the structure is disabled in order to maintain the direction settings for the fields in the event that the structure is enabled again.
Never remove/delete a field from a redefinition as the presence of fields illustrates to Portus how to build the base field expected by the application. Change its direction to ‘none’ if you do not wish to see it in an input or output message for the service.
The base field, even though disabled, must never be removed. This is the actual field type the application is expecting with language constructs enabling it to process the data based on the redefinition.
In essence, a redefine is similar to a structure and from an external point of view with input and output messages will appear the same way, however, Portus must know the base field to correctly call the application program.
When dealing with Portus views/XRDs created based on application program parameter lists or structures, follow these simple rules:
Never delete fields from the generated Portus view. If you do not wish to make the fields available as input and/or output messages, set their direction as ‘none’. You may also elect to set a fixed value for such fields to force specific behaviour in an application.
Always ensure that with redefinitions, only the base OR the redefined fields are enabled; never both.
If an application program changes, Ostia recommend that you recreate the view of the application using Portus Control Centre wizard rather than attempting to modify an existing XRD.