Consultor Eletrônico



Kbase 21106: 4GL Super Procedures: Why, When and How to Use Them.
Autor   Progress Software Corporation - Progress
Acesso   Público
Publicação   12/2/2008
Status: Verified

GOAL:

Brief overview of Super Procedures and Sample code

GOAL:

4GL Super Procedures: Why, When and How to Use Them.

FACT(s) (Environment):

Progress 9.x

FIX:

Sample code is included to illustrate some of the Super Procedure Functionality.

EXPLANATION.

Super Procedures have two important advantages.  One use deals with reusable code.  The same process runs once for all the processes in the application.  Less memory and r-code are used and maintenance is simplified.  The other important feature is the ability to share variables and temp-tables in a Progress session which uses procedures or dynamic functions within the Super Procedure.

Super Procedures were introduced in Progress Version 9.0 as a component of the new ADM2 architecture.  Super Procedures are used instead of include files because Super Procedures use less memory and are easy to maintain.  The procedures query.p, smart.p, panel.p, etc., run just once in the Progress session.

To accommodate adding and modifying these new Super Procedures, the V9 Progress 4GL provides several new Statements, Attributes, Methods and Functions.  Some examples are:

   ADD-SUPER-PROCEDURE method
   RUN SUPER statement
SUPER function
   REMOVE-SUPER-PROCEDURE method
   SUPER-PROCEDURES attribute
   TARGET-PROCEDURE and SOURCE-PROCEDURE system handles

When running procedures or dynamic-functions, Progress searches for these processes in the Super Procedures stack.  Progress starts to search the processes beginning with the last procedure added.  Accordingly, this is how procedures are overridden.  A way to customize ADM2 procedures or dynamic functions is to add a new Super Procedure to the ADM2 architecture.

For example, say you want to override the displayFields procedure.  To do this you must create a new procedure.  Also, an internal procedure 'displayFields' must be created.  When you add this procedure to the Super Procedure stack and run the displayFields procedure, the displayFields in the last procedure added will be executed first. In order to run the next displayFields in the super procedures stack, you must add the RUN SUPER statement.

Super Procedures can belong to either SESSION or THIS-PROCEDURE handles.  If the Super Procedure is a SESSION super procedure, functions are internal procedures that can be called from any process in the same session.  Therefore, it could be used to share variables or temp-tables in the whole session.  Procedures superMain.p, super.p and super2.p at the end of this solution are examples of how to share variables using GET and SET functions.

In order to add a Super Procedure in the stack, this procedure must first be a persistent procedure.  Here is an example of how to add a new session Super Procedure.

   DEFINE VARIABLE hSuper AS HANDLE NO-UNDO.

  RUN procedure.p PERSISTENT SET hSuper.

  SESSION:ADD-SUPER-PROCEDURE(hSuper).

When adding super procedures to the THIS-PROCEDURE handle, this Super Procedure can be used just for the procedure that inserted the Super Procedure in the stack.  Adding a Super Procedure to the THIS-PROCEDURE handle is similar in method to adding the SESSION Super Procedure.  Here is an example:

   DEFINE VARIABLE hSuper AS HANDLE NO-UNDO.

  RUN procedure.p PERSISTENT SET hSuper.

  THIS-PROCEDURE:ADD-SUPER-PROCEDURE(hSuper).

An example of a Super Procedure of the THIS-PROCEDURE handle is when a new or different behavior is needed for each SmartDataBrowser in the whole application.  In this case it is not necessarily a SESSION Super Procedure because the other objects do not need this behavior.  But if this procedure is added in each SmartDataBrowser, it will be running more than once in the session.  To solve this problem, Progress added the START-SUPER-PROCEDURE procedure as an internal procedure in the smart.p Super Procedure.  Here is an example of how to use it:

   RUN START-SUPER-PROCEDURE("mySuper.p").

START-SUPER-PROCEDURE searches to see if the procedure is already running.  If this procedure is already running, the. procedure handle is added to the THIS-PROCEDURE stack, and the process is not executed again. If the process is not running, START-SUPER-PROCEDURE runs the process persistently and then adds the procedure to the Super Procedure stack using the THIS-PROCEDURE:ADD-SUPER-PROCEDURE statement.


EXAMPLE PROGRAMS


/*---------------------------------------------------------*/
/* SuperMain.p */
/*---------------------------------------------------------*/

ASSIGN CURRENT-WINDOW:HEIGHT-CHARS = 11
CURRENT-WINDOW:WIDTH-CHARS = 78.


DEFINE BUTTON bSetVar1
    LABEL "SET"
     SIZE 15 BY 1.14.

DEFINE BUTTON bGetVar1
    LABEL "GET"
    SIZE 15 BY 1.14.

DEFINE BUTTON bSetVar2
    LABEL "SET"
    SIZE 15 BY 1.14.

DEFINE BUTTON bGetVar2
    LABEL "GET"
    SIZE 15 BY 1.14.

DEFINE BUTTON BUTTON-5
    LABEL "RUN Super2"
    SIZE 15 BY 1.14.

DEFINE VARIABLE FILL-IN-1 AS CHARACTER FORMAT "X(256)":U
    LABEL "Valor"
    VIEW-AS FILL-IN
    SIZE 14 BY 1 NO-UNDO.

DEFINE VARIABLE FILL-IN-2 AS CHARACTER FORMAT "X(256)":U
    LABEL "Valor"
    VIEW-AS FILL-IN
    SIZE 14 BY 1 NO-UNDO.

DEFINE RECTANGLE RECT-125
    EDGE-PIXELS 2 GRAPHIC-EDGE NO-FILL
    SIZE 23 BY 5.48.

DEFINE RECTANGLE RECT-126
    EDGE-PIXELS 2 GRAPHIC-EDGE NO-FILL
    SIZE 23 BY 5.48.

DEFINE FRAME DEFAULT-FRAME
    FILL-IN-1 AT ROW 4.1 COL 13 COLON-ALIGNED
    FILL-IN-2 AT ROW 4.1 COL 50 COLON-ALIGNED
    bSetVar1 AT ROW 5.29 COL 14
     bSetVar2 AT ROW 5.29 COL 51
    bGetVar1 AT ROW 6.95 COL 14
    bGetVar2 AT ROW 6.95 COL 51
    BUTTON-5 AT ROW 10.29 COL 57
    RECT-125 AT ROW 3.14 COL 8
    RECT-126 AT ROW 3.14 COL 45
    "Variable 1" VIEW-AS TEXT
     SIZE 9 BY .62 AT ROW 2.91 COL 9
    "Variable 2" VIEW-AS TEXT
       SIZE 11 BY .62 AT ROW 2.91 COL 46
    WITH 1 DOWN NO-BOX KEEP-TAB-ORDER OVERLAY
        SIDE-LABELS NO-UNDERLINE THREE-D
        AT COL 1 ROW 1 SIZE 78 BY 11.

ON CHOOSE OF bSetVar1 IN FRAME DEFAULT-FRAME /* SET */
DO:
DYNAMIC-FUNCTION('setVarbl':U, INPUT fill-in-1:SCREEN-VALUE).
END.

ON CHOOSE OF bGetVar1 IN FRAME DEFAULT-FRAME /* GET */
DO:
MESSAGE DYNAMIC-FUNCTION('getVarbl':U).
END.

ON CHOOSE OF bSetVar2 IN FRAME DEFAULT-FRAME /* SET */
DO:
DYNAMIC-FUNCTION('setVarbl2':U, INPUT fill-in-2:SCREEN-VALUE).
END.

ON CHOOSE OF bGetVar2 IN FRAME DEFAULT-FRAME /* GET */
DO:
MESSAGE DYNAMIC-FUNCTION('getVarbl2':U).
END.

ON CHOOSE OF BUTTON-5 IN FRAME DEFAULT-FRAME /* RUN Main2 */
DO:
RUN superMain2.w.
END.

/*---------------------------------------------------------*/
/* Add The Super Procedure */
/*---------------------------------------------------------*/

 DEFINE VARIABLE hSuprProcdr AS HANDLE NO-UNDO.
 
  RUN SUPER.p PERSISTENT SET hSuprProcdr.
 
  IF VALID-HANDLE(hSuprProcdr) THEN
  SESSION:ADD-SUPER-PROCEDURE(hSuprProcdr).

ENABLE ALL WITH FRAME DEFAULT-FRAME.

WAIT-FOR CLOSE OF CURRENT-WINDOW.


/*---------------------------------------------------------*/
/* Super2.p */
/*---------------------------------------------------------*/

ASSIGN CURRENT-WINDOW:HEIGHT-CHARS = 11
CURRENT-WINDOW:WIDTH-CHARS = 78.

DEFINE BUTTON bSetVar1
    LABEL "SET"
    SIZE 15 BY 1.14.

DEFINE BUTTON bGetVar1
   LABEL "GET"
     SIZE 15 BY 1.14.

DEFINE BUTTON bSetVar2
    LABEL "SET"
     SIZE 15 BY 1.14.

DEFINE BUTTON bGetVar2
    LABEL "GET"
     SIZE 15 BY 1.14.

DEFINE VARIABLE FILL-IN-1 AS CHARACTER F.ORMAT "X(256)":U
    LABEL "Valor"
    VIEW-AS FILL-IN
    SIZE 14 BY 1 NO-UNDO.

DEFINE VARIABLE FILL-IN-2 AS CHARACTER FORMAT "X(256)":U
   LABEL "Valor"
    VIEW-AS FILL-IN
     SIZE 14 BY 1 NO-UNDO.

DEFINE RECTANGLE RECT-125
    EDGE-PIXELS 2 GRAPHIC-EDGE NO-FILL
    SIZE 23 BY 5.48.

DEFINE RECTANGLE RECT-126
    EDGE-PIXELS 2 GRAPHIC-EDGE NO-FILL
    SIZE 23 BY 5.48.

DEFINE FRAME DEFAULT-FRAME
    FILL-IN-1 AT ROW 4.1 COL 13 COLON-ALIGNED
    FILL-IN-2 AT ROW 4.1 COL 50 COLON-ALIGNED
    bSetVar1 AT ROW 5.29 COL 14
     bSetVar2 AT ROW 5.29 COL 51
    bGetVar1 AT ROW 6.95 COL 14
     bGetVar2 AT ROW 6.95 COL 51
    RECT-125 AT ROW 3.14 COL 8
    RECT-126 AT ROW 3.14 COL 45
    "Variable 1" VIEW-AS TEXT
       SIZE 9 BY .62 AT ROW 2.91 COL 9
     "Variable 2" VIEW-AS TEXT
        SIZE 11 BY .62 AT ROW 2.91 COL 46
   WITH 1 DOWN NO-BOX KEEP-TAB-ORDER OVERLAY
         SIDE-LABELS NO-UNDERLINE THREE-D
         AT COL 1 ROW 1 SIZE 78 BY 11.

ON CHOOSE OF bSetVar1 IN FRAME DEFAULT-FRAME /* SET */
DO:
 DYNAMIC-FUNCTION('setVarbl':U, INPUT fill-in-1:SCREEN-VALUE).
END.

ON CHOOSE OF bGetVar1 IN FRAME DEFAULT-FRAME /* GET */
DO:
MESSAGE DYNAMIC-FUNCTION('getVarbl':U).
END.

ON CHOOSE OF bSetVar2 IN FRAME DEFAULT-FRAME /* SET */
DO:
 DYNAMIC-FUNCTION('setVarbl2':U, INPUT fill-in-2:SCREEN-VALUE).
END.

ON CHOOSE OF bGetVar2 IN FRAME DEFAULT-FRAME /* GET */
DO:
MESSAGE DYNAMIC-FUNCTION('getVarbl2':U).
END.

ENABLE ALL WITH FRAME DEFAULT-FRAME.

WAIT-FOR CLOSE OF CURRENT-WINDOW.


/*---------------------------------------------------------*/
/* Super.p */
/*---------------------------------------------------------*/

DEFINE VARIABLE gcVarbl  AS CHARACTER NO-UNDO.
DEFINE VARIABLE gcVarbl2 AS CHARACTER NO-UNDO.

FUNCTION getVarbl RETURNS CHARACTER ():

RETURN gcVarbl.

END FUNCTION.

FUNCTION getVarbl2 RETURNS CHARACTER ():

RETURN gcVarbl2.

END FUNCTION.

FUNCTION setVarbl RETURNS LOGICAL (pcVarbl AS CHARACTER):

ASSIGN gcVarbl = pcVarbl NO-ERROR.
 
RETURN NOT ERROR-STATUS:ERROR.

END FUNCTION.


FUNCTION setVarbl2 RETURNS LOGICAL (pcVarbl2 AS CHARACTER):

ASSIGN gcVarbl2 = pcVarbl2 NO-ERROR.
 
RETURN NOT ERROR-STATUS:ERROR.

END FUNCTION.
.