On 17/02/2008, at 2:17 PM, M. Lazarus wrote:
  A software vendor installs a *SRVPGM to be utilized by clients'  
software.
Scenario:
  Signature is hardcoded.
  Version 1 has two exports.
  Version 2 with 3 exports gets shipped and installed.
  If the manual signature has not changed, the new version will not
throw an error if the calling programs have not been rebound.  This
may be a desired behavior, if the new version handles it
properly.
It is reasonable to expect that developers who are changing binder  
source have some idea of what they  are doing. If you employ idiots  
then you get what you deserve. As others have pointed out a decent  
comment block explaining what to do may help. An example from my own  
source:
/*   Restrictions  . . . . . : Ensure you understand ILE signatures  
before   */
/*                             modifying this source. All new exports  
MUST   */
/*                             go at the end of the export  
block.            */
/ 
*                                                                        
    */
Also, a proper test harness would include test programs specifically  
compiled to use previous signatures.
But the oversight may allow undesirable results if an
export was dropped.
This made me curious--always a dangerous thing. I discovered that you  
can remove a public export and either use a manual signature or use a  
generated signature with or without *PRV signature support and the  
removed export is still callable by programs that use the service  
program.
Right now I'll bet many of you are saying "What the f...?"
I performed various tests but I'll only document the most obvious one  
here. The service program ran in ACTGRP(*CALLER) and the calling  
program ran in ACTGRP(*NEW) and used *LIBL to locate the service  
program.
Module TEST_BIND1 contains 3 procedures tagged with EXPORT:
	proc1		returns 1
	proc2		returns 2
	proc3		returns 3
Procedures are coded in that physical order in the source.
Binder source TEST_BINDZ exports all three procedures with fixed  
signature:
            STRPGMEXP  PGMLVL(*CURRENT) SIGNATURE('MY_SIG')
            EXPORT     SYMBOL(PROC1)
            EXPORT     SYMBOL(PROC2)
            EXPORT     SYMBOL(PROC3)
            ENDPGMEXP
CRTSRVPGM SRVPGM(TEST_BINDZ) MODULE(TEST_BIND1) SRCFILE(TEMP)
Service program  . . . . . . . . . . . . :   TEST_BINDZ
  Library  . . . . . . . . . . . . . . . :     TEMP
                              Procedure Exports:
Procedure  
Name                                                          ARGOP
PROC1                                                                    
*NO
PROC2                                                                    
*NO
PROC3                                                                    
*NO
                                  Signatures:
 MY_SIG
Trivial program TEST_BINDY:
D proc1           PR             5I 0
D   parm1                       10    CONST OPTIONS(*NOPASS)
D proc2           PR             5I 0
D   parm1                       10    CONST OPTIONS(*NOPASS)
D result          S              5I 0
C                   EVAL      result = proc1
C     result        DSPLY
C                   EVAL      result = proc2
C     result        DSPLY
C                   SETON                                        LR
C                   RETURN
crtpgm test_bindy bndsrvpgm(test_bindz)
CALL TEST_BINDY gives:
2 > call test_bindy
    DSPLY      1
    DSPLY      2
Now, remove export for proc2 from binder source TEST_BINDZ
             STRPGMEXP  PGMLVL(*CURRENT) SIGNATURE('MY_SIG')
             EXPORT     SYMBOL(PROC1)
/*           EXPORT     SYMBOL(PROC2) */
             EXPORT     SYMBOL(PROC3)
             ENDPGMEXP
CRTSRVPGM SRVPGM(TEST_BINDZ) MODULE(TEST_BIND1) SRCFILE(TEMP)
Service program  . . . . . . . . . . . . :   TEST_BINDZ
  Library  . . . . . . . . . . . . . . . :     TEMP
                              Procedure Exports:
Procedure  
Name                                                          ARGOPT
PROC1                                                                    
*NO
PROC3                                                                    
*NO
                                 Signatures:
MY_SIG
Do NOT recreate program TEST_BINDY, just invoke it.
2 > call test_bindy
    DSPLY      1
    DSPLY      2
Same result--even though proc2 is no longer part of the public  
interface in the service program. I wondered if physically shifting  
the procedure code around in the module source would have an effect  
because this is a normal side-effect of code maintenance. I did not  
think it would cause a problem but I moved the code for proc3 so it  
was now between the code for proc1 and proc2 (i.e., the physical code  
order changed from:
	proc1
	proc2
	proc3
to
	proc1
	proc3
	proc2
I recompiled the module, recreated the service program still  
exporting only proc1 and proc3 and then WITHOUT rebuilding TEST_BINDY:
2 > call test_bindy
    DSPLY      1
    DSPLY      2
Same result. The trick, of course, is that the procedure code remains  
in the service program (and possibly also requires EXPORT specified  
but I did not test that).
Attempting to recreate the TEST_BINDY program gives:
> crtpgm test_bindy bndsrvpgm(test_bindz)
  Definition not found for symbol 'PROC2'.
  Program TEST_BINDY not created.
which is the expected behaviour when referencing a procedure not  
listed in the public interface.
I cannot say that I would have expected this behaviour before the  
experiment, nor can I recall such behaviour being documented but it  
does make a lot of sense. It provides a way to remove a deprecated  
procedure from the public interface without breaking existing code. I  
can imagine such a scenario (indeed Java does it frequently). Imagine  
a procedure that for some reason is no longer required by current  
code or is replaced by another procedure (with a better name or  
easier interface). This technique allows the creator to remove the  
deprecated procedure from the public interface while still allowing  
old code to run. The creator can modify the deprecated procedure to  
output a message such as "Procedure ABC is deprecated. Change your  
code to use procedure XYZ and recompile". At some future point the  
actual code could be removed from the service program module.
Not quite as flexible as using *CURRENT and *PRV signatures to  
replace a deprecated function (see previous appends from me showing  
how this can be accomplished) with another of the same name but does  
have the advantage of making the deprecated procedure impossible to  
invoke in recompiled code. That has a robustness advantage.
All in all, a useful addition to the toolbox.
Regards,
Simon Coulter.
--------------------------------------------------------------------
   FlyByNight Software         OS/400, i5/OS Technical Specialists
   
http://www.flybynight.com.au/
   Phone: +61 2 6657 8251   Mobile: +61 0411 091 400        /"\
   Fax:   +61 2 6657 8251                                   \ /
                                                             X
                 ASCII Ribbon campaign against HTML E-Mail  / \
--------------------------------------------------------------------
 
As an Amazon Associate we earn from qualifying purchases.