% dbpl_system2.tex

\chapter{A Complete DBPL Example}

\label{DBPLXple}

The following small application is taken from \cite{BMSW89} and \cite{SWBM89}
where it serves as an example for the DAIDA methodology of database
programming by formal refinement of conceptual designs.

The task is to model research companies that are engaged in research
projects and that are supported by grants from third parties. Furthermore
they can hire employees to work on some of their own projects.

The following DBPL program addresses all aspects of such a prototypical
data-intensive application:
\begin{itemize}
\item Representation of the data objects of the application domain (projects,
employees, companies) with their relationships (gets grant from, works on,
belongs to).

\item Maintenance of the application-specific integrity constraints during
database updates (a company is not allowed to hire employees that work on
projects the company is not engaged in).

\item Interaction with the user to display the database contents, to initiate
database transactions and to accept transaction parameters.
\end{itemize}


This database application is broken down into several manageable and reusable
modules. Each module consists of a specification called {\sf DEFINITION
MODULE} and an implementation part called {\sf IMPLEMENTATION MODULE}:

\begin{description}
\item[RCDemo] is the main module. It controls the global program execution
    according to the users requests using a simple menu and from interface. 
    It calls (predefined) transactions that are imported from other modules.

\item[RCOps] exports a single transaction to hire an employee for a set
    of projects. Furthermore it contains the definition of the database
    schema.

\item[RCTypes] exports type declarations needed for the database schema
    definition. All application programs accessing the research company 
    database will import these types to declare local variables or 
    parameters of procedures and transactions.

\item[Identifer] encapsulates a  mechanism to generate database-wide unique
      identifiers. This particular implementation simply demonstrates the use
      of scalar database variables and does not scale up for real database
      applications.
 
\item[String, Form and Selector] are modules from a standard library
    that comes with the DBPL system. They provide string handling procedures 
    and a simple user interface based on (overlapping) text-windows.
\end{description}

Figure \ref{Abb:ResExple} shows the module relationships of this particular
example. An arrow from a box A to a box B indicates that the definition or the
implementation of module A uses types, variables or operations exported by the
definition module of B.

\begin{figure}
\begin{center}
\setlength{\unitlength}{1mm}
\mbox{\special{illustration Modulgraph.EPSF}	
\hspace*{7truecm}
\rule{0cm}{7truecm}}
\end{center}
\caption{Modules and Import Relationships of the Application Example}
\label{Abb:ResExple}
\end{figure}  

In the following listings, compilation units are separated by a
horizontal bar.


{\small  % -------------------------------

\begin{xple}
DEFINITION MODULE Identifier;
(* Generates database-wide unique identifiers
*)
TYPE 
  Type = CARDINAL;

PROCEDURE New () : Type;
(* Returns a unique identifier *)

PROCEDURE Nil () : Type;
(* Returns NIL-identifier *)

END Identifier.
\end{xple}

\separate

\begin{xple}
DATABASE IMPLEMENTATION MODULE Identifier;
(* Implementation uses a database variable 'count' that is incremented
   for every New operation.
*)
VAR
  count: Type;

PROCEDURE New () : Type;
BEGIN 
  INC(count); 
  RETURN count;
END New;

PROCEDURE Nil () : Type;
BEGIN
  RETURN 0;
END Nil;

DATABASE IMPLEMENTATION
  count:= Nil ();
END Identifier.
\end{xple}

\separate

\begin{xple}
DEFINITION MODULE RCTypes;                   
IMPORT Identifier, String;

(* global type declarations needed for the database schema and all
   transactions running against that schema *)

TYPE  
  (* basic types *)      
  EmpIds = Identifier.Type;
  Agencies = (ESPRIT, DFG, NSF);
  CompNames = String.Type;
  PersNames = String.Type;
  ProjNames = String.Type;
                                               
  (* One project and a set of projects *)
  ProjIdRecType = RECORD
                    ProjName : ProjNames;
                    GetsGrantFrom : Agencies;
                  END;
  ProjIdRelType = RELATION OF ProjIdRecType;

  ProjRecType = RECORD               
                  ProjId : ProjIdRecType;
                  Consortium : RELATION OF CompNames; (* multivalued *)
                END;                    
  ProjRelType = RELATION ProjId OF ProjRecType;
         
  (* One employee and a set of employees *)
  EmpRecType = RECORD
                 EmpId : Identifier.Type; (* unique identifier *)
                 PersName : PersNames;
                 BelongsTo: CompNames;
                 WorksOn : ProjIdRelType; (* multivalued *)
               END;                                          
  EmpRelType = RELATION EmpId OF EmpRecType;

  (* One company and a set of companies *)
  CompRecType = RECORD
                  CompName : CompNames; (* unique identifier *)
                  EngagedIn : ProjIdRelType; (* multivalued *)
                END;
  CompRelType = RELATION CompName OF CompRecType;

END RCTypes.                   
\end{xple}

\separate

\begin{xple}
IMPLEMENTATION MODULE RCTypes;
(* Since the definition module RCTypes already contains all delcarations,
   the implementation part is empty
*)
END RCTypes.
\end{xple}

\separate

\begin{xple}
DATABASE DEFINITION MODULE RCOps;
(* The keyword DATABASE indicates that all variables declared within
   this module are persistent.
*)
FROM RCTypes IMPORT 
  CompRelType, EmpRelType, ProjRelType, ProjIdRelType, EmpIds, PersNames,
  CompNames;  

VAR (* persistent database relations *)
  compRel : CompRelType;
  empRel : EmpRelType;
  projRel : ProjRelType;      

TRANSACTION hireForProject (name : PersNames;                           
                            belongs : CompNames;
                            works : ProjIdRelType) : EmpIds;

(* Hires the employee described by 'name' for the set of projects 'works' in
   which the company with name 'belongs' is engaged in. In case of success a new
   unique identifier for the hired employee will be returned, (otherwise
   'Identifier.Nil'). 
*)
END RCOps.
\end{xple}

\separate


\begin{xple}
IMPLEMENTATION MODULE RCOps;

IMPORT Identifier;
FROM RCTypes IMPORT 
  PersNames, CompNames, ProjIdRelType, EmpIds, ProjRecType, CompRecType, 
  EmpRecType, ProjIdRecType, Agencies;

TRANSACTION hireForProject (name    : PersNames;                           
                            belongs : CompNames;
                            works   : ProjIdRelType) : EmpIds;
  VAR emp : EmpRecType;
BEGIN       
  IF SOME v1 IN compRel (v1.CompName = belongs) THEN
    IF ALL v2 IN works 
       SOME v3 IN compRel[belongs].EngagedIn 
         ((v2.ProjName = v3.ProjName) AND
          (v2.GetsGrantFrom = v3.GetsGrantFrom)) THEN
      (* referential integrity assured; employee can be hired *)
      WITH emp DO
        EmpId := Identifier.New ();
        PersName := name;
        BelongsTo := belongs;
        WorksOn := works;
      END;
      INCL (empRel, emp);                      
      RETURN emp.EmpId
    ELSE
      RETURN Identifier.Nil ()
    END
  ELSE
    RETURN Identifier.Nil ()
  END
END hireForProject;
                  
END RCOps.
\end{xple}

\separate

\begin{xple}
MODULE RCDemo;
(* Main program, interaction with the user, global program control
*)

IMPORT Conversions, Form, Selector, Identifier;      
FROM RCTypes IMPORT
  EmpRecType, PersNames, Agencies, CompRecType, ProjIdRecType, 
  ProjRecType, ProjIdRelType, CompNames, EmpIds;
FROM RCOps IMPORT
  empRel, compRel, projRel, hireForProject;

TRANSACTION ShowEmployees; (* displays the contents of empRel *)
...
END ShowEmployees;             

TRANSACTION ShowProjects; (* displays the contents of projRel *)
...
END ShowProjects;

TRANSACTION ShowCompanies; (* displays the contents of compRel *)
...
END ShowCompanies;
        
PROCEDURE TryToHireEmployee;
(* accepts parameters from the user and calls transaction hireForProject *)

  PROCEDURE BuildLeftSide (VAR form : Form.T);
  BEGIN
    form:= Form.Create("Hire Employee");
    Form.ConstField(0, 1, "Employee Name");  
    Form.ConstField(1, 1, "Company");
    Form.ConstField(2, 1, "Works On");
    Form.ConstField(3, 1, "Grant From");
    Form.ConstField(4, 1, "Another Project");
  END BuildLeftSide;
                                  
  CONST (* valid strings for user inputs: *)
    YesNoStr = "\verb$|$y\verb$|$n";
    AgenciesStr = "\verb$|$ESPRIT\verb$|$DFG\verb$|$NSF";
  TYPE 
    YesNoType = (y, n);
  VAR 
    form : Form.T;
    emp : PersNames; 
    comp : CompNames; 
    projid : ProjIdRecType;
    localproj : ProjIdRelType;
    yesno : YesNoType;
    edit : BOOLEAN;
\end{xple}
\begin{xple} 
BEGIN  
  Form.Message ("Trying to a hire an Employee for some Projects", FALSE);
  (* get user inputs for attributes of an employee: *)
  BuildLeftSide (form);
  emp := ""; Form.TextField( 0, 19, emp);
  comp := ""; Form.TextField( 1, 19, comp);
  projid.ProjName := ""; Form.TextField( 2, 19, projid.ProjName);
  Form.EnumField (3, 19, AgenciesStr, projid.GetsGrantFrom);
  Form.EnumField (4, 19, YesNoStr, yesno);
  Form.Display (form, 1, 1);
  IF Form.Edit (form) THEN       
    INCL (localproj, projid);      
    Form.Erase (form); edit := TRUE;
    (* get values for the other projects the employee is engaged in: *)
    WHILE (yesno = y) AND edit DO      
      BuildLeftSide (form);
      Form.ConstField (0, 19, emp);
      Form.ConstField (1, 19, comp);
      projid.ProjName := ""; Form.TextField( 2, 19, projid.ProjName);
      Form.EnumField (3, 19, AgenciesStr, projid.GetsGrantFrom);
      Form.EnumField (4, 19, YesNoStr, yesno);
      Form.Display (form, 1, 1);
      edit := Form.Edit (form);
      IF edit THEN
        INCL (localproj, projid)
      ELSE
        Form.Message ("The last form was ignored.", TRUE)
      END;
      Form.Erase (form);
    END;                                       
    (* call transaction: *)
    Form.Message ("Cheking integrity constraints...", FALSE);
    IF hireForProject (emp, comp, localproj) \# Identifier.Nil() THEN
      IF CARD (localproj) = 1 THEN
        Form.Message ("The Employee has been hired for the Project.", FALSE)
      ELSE (* $>$= 2 *)
        Form.Message ("The Employee has been hired for the Projects.", FALSE);
      END;
      Employees.ShowEmployees;
    ELSE
      Form.Message ("Integrity constraints violated - no Employee hired!", TRUE)
    END
  ELSE (* first form has not been edited *)
    Form.Erase (form);
    Form.Message ("You just abandoned hiring another Employee", TRUE);
  END;                              
END TryToHireEmployee;                   
\end{xple}
\begin{xple}                                         
PROCEDURE MainMenu;                
  CONST MenuStr = "Your Choice ?\verb$|$Hire an Employee\verb$|$ShowEmployees"
       "\verb$|$ShowCompanies\verb$|$ShowProjects\verb$|$ShowAll\verb$|$QuitProgram"; 
  VAR quit : BOOLEAN; choice : CARDINAL;
BEGIN                
  quit := FALSE;
  REPEAT              
    choice := Selector.Select (1, 2, MenuStr);
    CASE choice OF
      1 : TryToHireEmployee;
    \verb$|$ 2 : Employees.ShowEmployees;
    \verb$|$ 3 : Companies.ShowCompanies;
    \verb$|$ 4 : Projects.ShowProjects; 
    \verb$|$ 5 : Employees.ShowEmployees; 
          Companies.ShowCompanies; 
          Projects.ShowProjects; 
    \verb$|$ 6 : quit := TRUE
    END
  UNTIL quit
END MainMenu;

BEGIN (* this is the main program: *)                   
  Employees.ShowEmployees;              
  Companies.ShowCompanies; 
  Projects.ShowProjects;   
  MainMenu;
END RCDemo.
\end{xple}


} % end small ---------------------------------

\nocite{BMSW89,BJMSV89,DAIDA2,DAIDA3,DAIDA4,JGLR88,MaSc89,SEM88,SGLJ89}
\nocite{SWBM89}

