Jan 2, 2000 - 19:53
Status: Work in Progress
This document describes the operational princiles of the cgi standard process as it is used for the ACDE processs.
A CGI prcoess is invoked by the http server via a HTML-Page on the users brwosers. After evaluating the recieved parameters, the CGI process sends back a HTML document which is presented to the user. This interface misses two basic features which have to be implemented by the CGI-process it self:
The authorization problem cannot be solved completly, but for the ACDE environement a simple solution based on a login via user id, password or transaction identified is implemented.
A solution for the second problem would be to store state information for a dialog using the transaction identifier as key. Due to the fact, that the dialog can be aborted without any notification to the server, a resource monitor would be requiered to clean up such dead transations context records. In order to simplify the problem it is assumed, that if long term information is requiered the information has to be stored in the HTML-document as well. This could be either an text field or additional information assigned to a HTML-link.
The CGI base process supplies an interface to the ACDE database, the configuration files and the CGI parameter interface. The autorization problem is addressed by an login feature.
During initialization of the base process opens the configuration file and searches for the db-Section. This section contains the login name and the server name where the ACDE database is located.
[db] serverUser=ACDE_USER server=SERVER
If this section is available, the connection to the server using the user name is established and the acde database is opend. The data base name is not configurable. After this, the configaration section is set to [process].
After this step the parameters recevied for the authorization process are analyzed. If the CGI parameter P_Transaction is received a check is done if transaction id is stored with the username a given in the CGI-Parameter P_login_Name. If no transaction identifier has been recieved a normal login procedure is assumed. This means the paramter P_login_Name and P_Password are checked agains the Userlist (T_userlist.sql) table. If an entry is available a transaction identifier is evaluated and stored for the user logging in.
The combination transaction identifier and user name are allways contained in every HTML form generated in this environement. This is ensured by seperating the input processing from generating the output. The application will generate its output in the context of a large from which contains the user name and the transaction identifier and three buttons, the Submit button, the Reset button and the Cancel button.
This form will set the CGI-paramter P_Action according to these button to different values. In case the Submit-button is pressed, the Perform and the Display procedure are called. In case of Cancel the Cancel and the Display procedure are called. The sequence diagram below shows the flow of events.
All CGI processes are dervied from a CGI base process. The base process provides interfaces to the data base, the configration data and the CGI-Data recevied from a form. There are four procedures to be implemented in the apllication:
The package definition of the a CGI-Process looks like this:
package Admin is type Object is new Process.Object with private;
procedure Prepare( this : in out Object ); procedure Display( this : in out Object ); procedure Perform( this : in out Object ); procedure Cancel( this : in out Object );
private type Object_Data; type Object_Data_Access is access Object_Data; type Object is new Process.Object with record data : Object_Data_Access := null; end record; end Admin;
The Object data defined within the body of the CGI process will contain at least the following components:
type Object_Data is record Next_Page : Customized_Page_Handler := null; Next_Title : Unbounded_String; ................. end record;
These components are at least required for interworking with the CGI base process.
The prepare procedure is used to perform certain initialzations, i.e. setting up the list of expected CGI parameters and to initialize all data base Objects as shown below:
procedure Prepare( this : in out Object ) is Data : Object_Data_Access; begin Data := new Object_Data; this.Data := Data; Data.Debug := Debug(this);
Component( This, P_Next_Action, Optional ); Component( This, P_Project_Name, Optional ); ............. -- Define the first page to be generated Data.Next_Page := Entry_Panel'Access; Data.Next_Title := To_Unbounded_String("Entry Panel");
-- Initialize and Assign the user object to a database User.Initialize( Data.User_Obj, Data.Debug ); Data_Base( Data.User_Obj, Data_Base(this) );
Please be aware that in this procedure not all procedures of the base process interface are allowed.
The Procedure Perform processes the commands which are recevied from the HTML page via the CGI Parameter P_Next_Action. The proposed implementation of this prcoedure is shown below. This procedure copies in the first step all information from the recieved form into the local data base objects or other intance components. After this has been done, a list of name/command mapping records is checked for the command recevied with the parameter P_Next_Action. If the action is found the associated handling procedure is called.
procedure Perform( this : in out Object ) is Data : Object_Data_Access := Instance( this, ".Perform" ); Debug : Debugging_Support.Handle renames Data.Debug; Action : Unbounded_String := Component( this, P_Next_Action ); Cmd_Handler : Action_Handler := null; cmds : Commands := ( ( To_Unbounded_String(V_Project), Handle_Project'Access ), ( To_Unbounded_String(V_Maint_Project), Handle_Project_Maintenance'Access ), ....... ( To_Unbounded_String(V_Delete_User), Handle_Delete_User
'Access ) ); begin Enter( Debug, Module & ".Perform"); -- copy the data from the html form into the objects Login_Name( Data.User_Obj, To_String(Component( This, P_New_Login))); ...................... Email( Data.User_Obj, To_String(Component( This, P_Email))); -- find the handling procedure for the currently recevied action for i in 1..Cmds'Length loop if Cmds(i).Name = Action then Cmd_Handler := Cmds(i).Handler; exit; end if; end loop;
if Cmd_Handler /= null then Cmd_Handler( this ); else CGI.Put_Variables; end if; Leave( Debug, ""); ..... end Perform;
The so called handling procedures do react only to the commands. The HTML result document is not shown by the command handler. A typical handler procedure looks like this:
procedure Handle_Delete_User( this : in out Object) is Data : Object_Data_Access := Instance( This, ".Handle_Create_User"); Debug : Debugging_Support.Handle renames Data.Debug; begin Enter( Debug, Module & ".Handle_Delete_User"); Delete( Data.User_Obj ); Handle_User_Maintenance( this ); Leave(Debug, "" ); end Handle_Delete_User;
It perform the job of deleting a user from the user data base and calls a procedure which defines the next panel to be drawn:
procedure Handle_User_Maintenance( this : in out Object) is Data : Object_Data_Access := Instance( This, ".Handle_User_Maintenace"); begin ..... Data.Next_Page := User_Maint_Panel'Access; Data.Next_Title := To_Unbounded_String("User Maintenace"); ...... end Handle_User_Maintenance;
Only the important lines are shown where the title of the panel and the generate procedure for the HTML-document are set. There is no explicit requirement to place these two lines into a prcoedure, both lines could be written instead of the procedure call.
The procedure generating the HTML document may look like this. Important is, that somewhere in the document, the parameter P_Next_Action is defined. In the example below, the user has a choice of Create, Modify and Delete using radio buttons:
procedure User_Maint_Panel( this : in out Process.Object'Class ) is begin Heading(2,"User Adminitration"); Put_Line("<BR>Login Name : "); Input(this, P_New_Login); Put_Line("<BR><B>First Name :"); Input(this, P_Real_First_Name); Put_Line(" Last Name : "); Input(this, P_Real_Name); ............... Put_Line( "New User "); Radio_Button( Name => P_Next_Action, Value => V_Create_User ); Break; Put_Line( "Update User"); Radio_Button( Name => P_Next_Action, Value => V_Modify_User ); Break; Put_Line("Delete User "); Radio_Button( Name => P_Next_Action, Value => V_Delete_User ); Break; end User_Maint_Panel;
The procedure Display is used to generate the result HTML-document in the context of the dialog form it self. The proposed implementation of the procedure looks like this:
procedure Display( this : in out Object ) is Data : Object_Data_Access := Instance( this, ".Display" ); Debug : Debugging_Support.Handle renames Data.Debug; begin Enter( Debug, Module & ".Display");
if Data.Next_Page /= null then Page( this, Data.Next_Page, To_String(Data.Next_Title) ); end if;
Leave( Debug, ""); exception when The_Error : Others => Error( this, The_Error, ".Display" ); raise; end Display;
The variables Next_Page and Title are components of the object instance data.