Re: Calling JDE from external menues
Ron,
rtuohy wrote:
> There is no problem per se in using MONMSG as below, it is a perfectly
> acceptable and common use of a 'catchall'. It simply prevents the program
> falling over and allows the flow to continue to the end.
I'm actually a bit surprised at having to defend my original statement. The problem
with 'this catchall' MONMSG is that it is an indescriminate 'catchall'. Not only
does it catch the pesky little messages that might interupt your program needlessly,
it also will catch (and obscure!) those big ugly error messages that can and should
cause your program to fail. As I'm sure you are already aware, the CPF0000 is a
generic message ID that is used to trap all error messages from CPF0001 through
CPF9999. Placing that MONMSG as the first executable line in a CL program causes it
to act as a program wide "Global" error monitor. By monitoring for this error
message and then not taking an approriate error action, you are basically telling
the program "I don't care how big awful and scary the error message you receive is,
ignore the message and attempt to continue processing".
This can have potentially disasterous results. If one uses this global error
message monitor (MONMSG CPF0000) at the beginning of their CL program, you will not
be warned of any error condition that occurs. If for example you have aprogram call
RPGPROGA, and it's job is to process the daily orders from FILEB, and you have a CL
program that looks like this:
PGM
MONMSG CPF0000 /* but do nothing */
CPYF FROMFILE(FILEA) TOFILE(FILEB) MBROPT(*REPLACE)
CALL RPGPROGA /* Process daily orders */
ENDPGM
Imagine that one day there are no records in FILEA. The CPF2869 error message that
is generated by the CPYF statement would get supressed by the MONMSG CPF0000 (and
tthen do nothing) statement. This would cause the records that were left in FILEB
from yesterday to get reprocessed..... oooops!
However, if you remove the MONMSG CPF0000, or better still, you take some error
recovery action when it occurs (as Doug Belcher sugggested), then you would be
notified of the problem before it had a chance to corrupt your program. This is
called "coding defensively", and it is an excellent practice to take up. It helps
protect you and your data even if somebody else screws up.
Here is an example of the smae program, but with graceful error handling inserted:
PGM
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Declare message handling variables. */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
DCL VAR(&ERRORFLAG) TYPE(*CHAR) LEN(1)
DCL VAR(&MSGID) TYPE(*CHAR) LEN(7)
DCL VAR(&MSGDTA) TYPE(*CHAR) LEN(100)
DCL VAR(&MSGF) TYPE(*CHAR) LEN(10)
DCL VAR(&MSGFLIB) TYPE(*CHAR) LEN(10)
DCL VAR(&MSG) TYPE(*CHAR) LEN(80)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Global monitor for messages */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(MESSAGE))
CPYF FROMFILE(FILEA) TOFILE(FILEB) MBROPT(*REPLACE)
CALL RPGPROGA /* Process daily orders */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Error Handleing routine. */
/* Send error message */
/* Re-display screen */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
MESSAGE: RCVMSG MSGTYPE(*DIAG) RMV(*NO) MSG(&MSG) +
MSGDTA(&MSGDTA) MSGID(&MSGID) MSGF(&MSGF) +
MSGFLIB(&MSGFLIB)
IF COND(&MSG *NE ' ') THEN(DO)
SNDPGMMSG MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) +
MSGDTA(&MSGDTA) TOPGMQ(*EXT) MSGTYPE(*COMP)
GOTO CMDLBL(MESSAGE)
ENDDO
MESSAG2: RCVMSG MSGTYPE(*EXCP) RMV(*NO) MSG(&MSG) +
MSGDTA(&MSGDTA) MSGID(&MSGID) MSGF(&MSGF) +
MSGFLIB(&MSGFLIB)
IF (&ERRORFLAG *EQ '1' ) THEN(DO)
RETURN /* Program is in a loop */
ENDDO
CHGVAR &ERRORFLAG '1'
IF COND(&MSG *NE ' ') THEN(DO)
SNDPGMMSG MSGID(&MSGID) MSGF(&MSGFLIB/&MSGF) +
MSGDTA(&MSGDTA) TOPGMQ(*EXT) MSGTYPE(*STATUS)
ENDDO
EXIT: ENDPGM
All this extra (seemingly superfluous) code will cause th eprogram to fail
gracefully by writing the error message to the joblog, and not giving the user a (C
D I R) screen that they can reply to! Now you will know of the fatal error, and
any diagnostic error that preceeds it.
It is much easier to fix problems if you know about them. MONMSG CPF0000 obscures
error messages from the user and the programmer, and is just trouble waiting to
happen.
> causes a loop because of this is extremely badly written. A typical use of
> this code may be where a CPYF (copy file) in the CL may attempt to copy from
> an empty member. If this does not affect the program processing, there is no
> need to take any action, but failure to monitor for the error may cause the
> program to hang waiting for operator/user action, or may cancel by default,
> neither of which is at all useful and may create more problems.
Without belaboring the point, if the CPYF of an empty member is a benign action in
your program, then a MONMSG CPF2869 directly after the CPYF statement is what you
need. A MONMSG CPF0000 (without an associated GOTO) as the first executable line in
the program (causing it to act as a global error monitor) is just reckless.
IMHO
jte
--
John Earl - VP / CTO
The PowerTech Group
Kent, Washington - 253-872-7788
[email protected]
www.400security.com
--