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