|
<snip>
Could you provide some information on where you would use this method?
</snip>
I have seen it used for a Data Mediator (A generic data engine that lives
between the program and service programs implementing data base access) by
David Morris from Plum Tree Lumber. If anyone knows where to find the article
he wrote on the Data Mediator, I would appreciate it. A brilliant piece of
work. I believe it was in Midrange Computing.
I used it for a Trigger Mediator. My Trigger Mediator was the only program
called by the data base and it dynamically loaded the correct service program
for a given data base table. All this was loaded from a data base table and a
user space allowing me to dynamically load and unload tables from triggers. It,
also, allowed me to turn triggers on and off for all tables instantly.
I was thinking of using at shipping software company I was at to dynamically
load different shipping company modules but left before I could do anything.
I used it for a FEDX parser. I built a generic front end for a State Transition
Engine and then dynamically loaded the correct module containing specific
routines for parsing specific strings. In that scenario, I could have one
generic parsing engine, load the parsing tables from a user space and only have
to write a single service program to implement unique logic. I would just need
to give the user space name and the service program would be loaded from tables
in the user space. I just happened to use the concept to implement a FEDX
string parser.
<snip>
Could you explain what criteria you use for deciding that a particular scenario
is a good candidate for this method?
</snip>
Basically, you can dynamically load service programs anytime that you need to
defer decisions about which service program to load until runtime. In the
shipping example, a customer may have FEDX and UPS but not DHL. You don't want
to load everything, just the shippers you needed. You might, also, have a
scenario where the customer uses DHL but only occasionally.
The one requirement is that all the service programs procedures that you call
have the same type and number of parameters. For example, all the service
programs that interface to the trigger mediator have the same interface.
Dynamic service programs allow you to do late binding, have multiple entry
points(Multiple procedures) and have the performance of the service program.
In my trigger mediator, it gave me the ability to load and unload tables from
triggers dynamically, have the performance of a service program and have the
data base call only one program.
In the case of the Data Mediator, it gave the author the ability to have one
program called by all programs requiring data base access and the mediator took
care of the rest calling the correct service program and managing the data
movement.
I always wanted to expand this concept to a generic data engine but figured no
one would ever use it.
Another example of this I could think of would be an interface program between
RPG code and an PC client. A standard interface could be established and tables
created which store which service program to call for a given transaction
coming in from a TCP/IP interface. If a service program was not needed, it
would not get loaded instead of loading everything. The interface program would
then be generic and would know nothing about the actual processing of the data.
<snip>
Of course, code samples would always be useful. ;-)
</snip>
This is kind of long. This was test program I wrote to test my Dynamic Load
service program. I had a service program that did reads and writes to the IFS.
In this case, I just wanted to load all the functions dynamically instead
binding into the program at compile time as a test.
No guarantee on any of this code. I provide just as example of using dynamic
service programs. Note that the program does not bind in XVIFSX.
Sorry, this is not the service programs themselves. Too big to put all in here.
I have two service programs that do the work, XVRSLV (Resolve System
Pointer-Takes an object name and get a system pointer to it. XVDYNL calls
XVRSLV and does the actual work.
There is a price for this power. Because you are loading dynamically, the
compiler cannot validate parameters. If you screw up and pass parameters
incorrectly, things are going to get interesting. I have seen some differences
in performance between static binding and dynamic but not a lot and, of course,
it is mega times faster than a dynamic program call.
Everything that I have developed for dynamic service programs has come from
work done by David Morris whom I am very grateful to.
Prototype for XVDYNL:
* ---------------------------------------------------------------
* Prototype: XVDYNL_PR Project.....:
* Author...: A. Campin Date written: 02/15/2003
* Purpose..: Prototypes for Dynamically Load Procedures or Exp
* variables.
* ---------------------------------------------------------------
* Revision history:
* Project # Pgmr Date Desc
*
* End Revision History
* ---------------------------------------------------------------
d DYNL_ActivateServiceProgram...
d pr
d PR_InServiceProgramName...
d Like(StdNam)
d Value
d PR_InServiceProgramLibrary...
d Like(StdNam)
d Value
d PR_OutActivationMark...
d Like(StdInt)
d DYNL_GetPointerToProcedure...
d pr
d PR_InProcedureName...
d 4096 Varying
d Value
d PR_InActivationMark...
d Like(StdInt)
d Value
d PR_OutProcedurePointer...
d Like(StdPrcPtr)
d DYNL_GetPointerToExportVariable...
d pr
d PR_InVariableName...
d 4096 Varying
d Value
d PR_InActivationMark...
d Like(StdInt)
d Value
d PR_OutVariablePointer...
d Like(StdPtr)
Code:
*_> CNLLSTSPLF SRCFILE(@2/@1) SRCMBR(@3)
*_> DLTMOD MODULE(@5/@4)
*_> DLTPGM PGM(@5/@4)
*_> CRTRPGMOD MODULE(@5/@4) SRCFILE(@2/@1) SRCMBR(@3) +
*_> DBGVIEW(@9) OPTIMIZE(@8) INDENT('| ')
*_> CRTPGM PGM(@5/@4) MODULE(@5/@4) +
*_> ENTMOD(@5/@4) BNDSRVPGM(XVDYNL) +
*_> ACTGRP(QILE)
h
/copy *libl/qsrcf,cb_Std_Con
/copy *libl/qsrcf,cb_StdType
/copy *libl/qsrcf,XVDYNL_PR
* Included only for constants needed on opens.
/copy *libl/qsrcf,XVIFSX_PR
d cFilePath c '/home/tranwork/alantest.txt'
d cCodePage c const(819)
d cRecord1 c '=Now is the time for all good men t-
d o come to the aid of their country. -
d Now is the time for all good men to -
d come to the aid of their country. No-
d w is the time for all good men to co-
d me to the aid of their country. Now -
d is the time for all good men to come-
d to the aid of their country. Now is-
d the time for all good men to come t-
d o the aid of their country.'
d cRecord2 c '=Now is the time for all good men t-
d o come to the aid of their country. -
d Now is the time for all good men to -
d come to the aid of their country.'
d FileHandle1 s Like(StdInt)
d RtnEOF s Like(StdChr)
d RtnString s 32767 Varying
d x s Like(StdIntSml)
d ActivationMark...
d s Like(StdInt)
* Procedure pointer to various routines.
d OpenFile...
d s Like(StdPrcPtr)
d CloseFile...
d s Like(StdPrcPtr)
d ReadFile...
d s Like(StdPrcPtr)
d WriteFile...
d s Like(StdPrcPtr)
d DeleteFile...
d s Like(StdPrcPtr)
/Free
DYNL_ActivateServiceProgram('XVIFSX' :
'*LIBL' :
ActivationMark);
DYNL_GetPointerToProcedure('IFSX_OpenFile':
ActivationMark :
OpenFile );
DYNL_GetPointerToProcedure('IFSX_CloseFile':
ActivationMark :
CloseFile );
DYNL_GetPointerToProcedure('IFSX_DeleteFile':
ActivationMark :
DeleteFile );
DYNL_GetPointerToProcedure('IFSX_ReadFile':
ActivationMark :
ReadFile );
DYNL_GetPointerToProcedure('IFSX_WriteFile':
ActivationMark :
WriteFile );
// Call to procedures are through procedure pointer instead of to
the procedures directly.
OpenFile(cFilePath :
(O_CREAT +
O_CODEPAGE +
O_RDWR) :
FileHandle1 :
(S_IRWXU +
S_IROTH) :
cCodePage );
CloseFile(FileHandle1);
OpenFile(cFilePath :
(O_WRONLY +
O_TEXTDATA):
FileHandle1 );
For x = 1 to 5;
WriteFile(FileHandle1 :
cYes :
%Editc(Counter:'X') + cRecord1);
WriteFile(FileHandle1 :
cYes :
%Editc(Counter:'X') + cRecord2);
EndFor;
CloseFile(FileHandle1);
OpenFile(cFilePath:
(O_RDONLY +
O_TEXTDATA):
FileHandle1 );
DoU RtnEOF = cYes;
ReadFile(FileHandle1:
RtnEOF :
RtnString );
EndDo;
CloseFile(FileHandle1);
DeleteFile(cFilePath);
*INLR = *On;
Return;
As you can see, this example uses multiple procedures. It just as well could be
one procedure calling different service programs. I would just activate
multiple service programs and use the correct service program I needed to call.
Because what is returned is just a pointer, I can store it in a table in the
program and retrieve it when I need it.
Unfortunatly, I don't have my trigger mediator with me to show example of this
and I would need to get it.
Anyway, I hope this helps.
-----Original Message-----
From: Larry Ducie [mailto:Larry_Ducie@xxxxxxxxxxx]
Sent: Saturday, February 19, 2005 9:24 AM
To: rpg400-l@xxxxxxxxxxxx
Subject: RE: Program binds to Serviceprogram in an fixed library instead
of searching the LibraryList.
Hi Alan,
<snip>
I have service programs that implement dynamic load of service programs if
anyone is interested. You just make the calls and it handles the rest. There
is
a trick to making it work.
</snip>
Could
you explain what criteria you use for deciding that a particular scenario is
a good candidate for this method?
<snip/>
That sounds VERY interesting. I'd more than welcome you sharing this info -
dynamic linking is about as close as we can get to late-binding and is
something I've looked into but not (yet) found a practical use for. It would
be interesting to see how this technique can be used in an RPG environment.
Could you provide some information on where you would use this method? Could
you explain what criteria you use for deciding that a particular scenario is
a good candidate for this method? Could you tell us what benefits this
method affords you?
Of course, code samples would always be useful. ;-)
Cheers
Larry Ducie
As an Amazon Associate we earn from qualifying purchases.
This mailing list archive is Copyright 1997-2025 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].
Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.