Creating components for a 3-tier architecture is no different from creating components for a 2-tier architecture - they are all based on component templates and all use standard UNIFACE commands without any reference to any external 3GL routines. Component templates are discussed in detail in a separate document entitled UNIFACE Development Guidelines - Part 3 (Component Templates).
Please note that the templates used in the 2-tier architecture have a "CT_" prefix whereas those for the 3-tier architecture have a "CT3_" prefix. It was not possible to simply change the trigger code in the component templates and then re-compile all the components so that they would inherit all the changes as only the form-level trigger code can be inherited in this way. Some of the entity-level and field-level trigger was changed therefore I decided to create a completely new set of component templates. This meant that each component had to be deleted and rebuilt from the new template, but this was easier than trying to change the trigger code manually and making mistakes.
The major difference between the two architectures is that a presentation layer component in a 3-tier architecture cannot access the database directly, so it will need an additional component known as a session service with which it can exchange data in the form of XML streams. Most types of presentation layer component will need a standard session service of type 1, but others require different processing from different types of session service, such as:
|2-tier||3-tier||Associated Session Service|
Each presentation layer component should have a component constant named <P_LAYER> which should have its expression set to "T" (True). This is referenced by the include procs in the entity triggers and will cause the I/O commands such as
DELETE to be removed from those triggers. This allows for the same include procs to be used in non-presentation layer components and leave the I/O commands intact.
Each presentation layer components that accesses a session service to acquire data must have the following component variables defined:
Both of these variables are used in the session service as arguments on the
READ command. Please refer to the UNIFACE documentation for details and limitations.
Values for these component variables can be supplied in any of the following ways:
retrieve/e command is still used in presentation layer components to initiate the acquisition of data. This in turn will fire the entity's <read> trigger which should have the
read command replaced by one of the following include procs:
retrieve/xcommand. A retrieve profile must be defined for the entity. If a single occurrence is returned in the XML stream this will automatically issue a
retrieve/efor any inner entities.
Note that the component templates will automatically insert the relevant include procs for the generic entities defined within their structures.
Retrieve profiles will be extracted from the current occurrence by using the
putlistitems command. Values can be inserted into the occurrence in any combination of the following ways:
getlistitemscommand with a list prepared previously.
The <store> trigger is still fired to update the database, but in the component templates the
store command is replaced by a call to the PUT_DATA proc. If the component requires to update data using more than one XML stream then the inherited code in the <store> trigger contains a call to local proc LP_STORE2 which can be modified as necessary.
This is where a component has an outer entity and an inner foreign entity. In order to select an occurrence for the foreign entity a separate component known as a popup form is activated which will display a list of available occurrences. When an occurrence is selected within this component its primary key is passed back, the occurrence is retrieved and the primary key is transported down to the foreign key of the outer entity. This processing is identical to that found in my 2-tier code.
The triggers for the popup entity need to be amended as follows:
|detail (of popup field)||
if ($foreign) call POPUP_DTL("popup_form") #include STD:FATAL_ERROR if ($status = 0) macro "^NEXT_FIELD" endif endif
|leave field (of popup field)||
if ($foreign) call POPUP_LFLD if ($status) return($status) endif
|start mod (of popup field)||
if ($foreign) release/e endif
There may be occasions when you need to have more than one copy of the same entity in a presentation layer component. As UNIFACE does not allow duplicate entity names in a component you must use a subtype, which is a method of providing an alias name for an entity. In order to handle subtypes successfully in a 3-tier structure you must take the following steps:
The standard GET_DATA and PUT_DATA procs will detect that the entity is a subtype and automatically use the
/incldefmap switch on the
XMLSAVE commands to map between the subtype name in the component and the supertype name in the XML stream. The session service will be unaware of the fact that a subtype is involved.