When running DataPA with an AppServer in a stateless mode we face the same challenges as a business application using a stateless AppServer does.


Each request received by the AppServer has no context and this means that the AppServer knows nothing about the user running the query.


A common situation where context is required is for example where a business application has a ‘company number’ within it and this is used to identify separate operating units within the business application. This concept is also used in the SaaS (Software as a Service) deployment model where a service provider has several customers using the same database.


In order to implement this level of control on a stateless AppServer we need to work with the two of the Progress AppServer procedures that are available to us.

These are the procedures for the startup and connect events.


Example Connect Procedure - Connect.p


This procedure will execute when the user first connects to the AppServer. We can use the session server connection context property to store the company ID for this user’s connection once the user’s identity has been verified. Then we will be able to use this later on when the users runs some queries. For this example we have a UserTable table which will contain the user ID, password and the company ID for the user.


/* Connect.p */
DEFINE INPUT PARAMETER ipUserID AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER ipPassword AS CHARACTER NO-UNDO.
DEFINE INPUT PARAMETER ipAppInfo AS CHARACTER NO-UNDO.

FIND UserTable WHERE UserTable.ID  = ipUserID and
                     UserTable.Pwd = encode(ipPassword) NO-LOCK NO-ERROR.
IF NOT AVAILABLE User THEN RETURN ERROR.

SESSION:SERVER-CONNECTION-CONTEXT = UserTable.CompanyID.

/* EOF */


Example Startup Procedure - Startup.p


The startup procedure executes when the AppServer is started and we use this procedure to add any functions or procedures we might want to use from DataPA. The procedure we start persistently here is DataPAFunctions.p which, in this case, contains a function GetCurrentCompany which we can use from both within our freeform queries and also our business logic functions and procedures.


/* Startup.p */
DEFINE INPUT PARAMETER startup-data AS CHARACTER NO-UNDO.
DEFINE VARIABLE hProc AS HANDLE NO-UNDO.
   
RUN DataPAFunctions.p PERSISTENT SET hProc.
SESSION:ADD-SUPER-PROCEDURE(hProc).
     
/* EOF */



Example Library Procedure - DataPAFunctions.p


This procedure contains a function called GetCurrentCompany which will access the server connection context property of the session to obtain the CompanyID that should be used for the current request. 


/* DataPAFunctions.p */
FUNCTION GetCurrentCompany RETURNS CHARACTER:
  RETURN SESSION:SERVER-CONNECTION-CONTEXT.
END FUNCTION.




Once the steps above have been completed then to use the GetCurrentCompany function in a freeform subject, to ensure that users can only see data from their own operating unit, you just need to add condition to the subject as shown below.


This is a simple example which only deals with storing one piece of context information. It would also be possible to create a database record to hold more complex context information about the connection as some systems do. If this is being done a disconnect.p procedure would also be required to delete the context record from the database.