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.
.