Nice technique. My first reaction was "why would you want to not let a
subroutine failure be catastrophic?!". I could see where it could allow
data to get scrambled. Let's say an decryption routine unable to decrypt
so the encrypted data gets sent back exactly the same.
But then I could see where this would create resiliency with some
non-critical function that could be fixed after the fact, like a
cross-referencing subroutine which sets up cross-references, just to add
feature.
Your technique allows the failure and keeps moving forward, with
hopefully an error log entry so someone could fix it.
Almost like an error message from the system when you don't initialize a
variable to zero, so it does that for you and gives you a nastrygram in
the process, but it doesn't effect operation (in many cases).
Thanks for the tip.
Robert Norman
ROBERT NORMAN AND ASSOCIATES
23441 Golden Springs Dr., #289, Diamond Bar, CA 91765
(951) 541-1668
[email protected] <mailto:[email protected]>
http://users.keyway.net/~ice/ <http://users.keyway.net/%7Eice/>
Affordable computer consulting services and computer programming for
UNIVERSE, UNIDATA, U2, PICK/BASIC, DATA/BASIC, UniVerseBasic,
UniBasic, R/BASIC, jBC.
"Ask about our lowest $45 discounted rate for long-term telecommuting
projects".
On 1/30/2014 9:03 AM, Bruce Decker wrote:
Not sure if this is helpful or not but I write software that allows
users to create their own subroutines that plug into my architecture.
Users can forget to catalog or have other issues with their
subroutine. So, I require the user subroutine to accept an argument
called 'mode'. In my system, mode=2 means 'test mode'. If a user
subroutine is called with mode set to 2, then it should set test data
and when processing is complete, output the string /%%validated%%/ to
standard out.
In my program where I will be calling the subroutine, I reference it
twice. First to validate the subroutine and second to actually call
the subroutine. I use the EXECUTE/CAPTURING on the first pass using a
special test executable to validate the subroutine then if I find
%%validated%% in the captured output, then I mke the second pass and
actually call the subroutine with CALL @. On the first pass, I EXECUTE
using my validator program so that even if the subroutine fails or
dies, only that execute levels is affected. i.e., you can execute a
program that calls a failing subroutine and the main program that
executed will carry on after the failure. I leveraged this behavior
to mitigate the chance that a user subroutine would cause my main
program to abort. Yes, I understand the EXECUTE is expensive but it's
less expensive than me having to spend my time helping a user restart
my process because one of their subroutines failed. This technique
might be used in combination with the global catalog checker to
provide a richer level of validation. Here are some code fragments
is case anyone finds this technique useful:
*The Main Program*
userSubroutineName = \MY.SUBROUTINE.NAME\
* check the subroutine to make sure it is valid before calling
EXECUTE \bpixmlize.validateSubroutine \:userSubroutineName CAPTURING
result
* check result to see if the subroutine responded cordially
IF (INDEX(reuslt, \%%validated%%\, 1) THEN
* yep, the subroutine is alive and well, it's okay to call it.
itemId=\\
mode=1; * 1 means 'run' mode
error = \\
CALL @userSubroutineName(itemId, mode, error)
END ELSE
* not sure what happened but subroutine is not playing nicely
CRT \So sorry, but \:userSubroutineName:\ does not appear to be valid\
CRT \result=\:result
END
------------------------------------------------------------------------
* The subroutine validator program*
*bpixmlize.validateSubroutine
*a executable program that will attempt to call subroutine or error if
not
*to be executed in a basic program with captured output. Evaluate the
captured
*result and it should contain the string %%validated%% otherwise it's
a bad
*or invalid subroutine. The prevents the caller from crashing with
object not
*found so that it can wrap-up normally. It's the job of the called
subroutine
*to output %%validated%% or something agreed by the caller in order to
validate
*the subroutine. Since this is executed and not called, it will fail
but return
*control to the calling program after failing.
*
------------------------------------------------------------------------------
INCLUDE bpi.xml.bp bpixmlize.common ; * to get common variables
GOSUB ParseSentence
GOSUB Validate
GOTO Exit
*
------------------------------------------------------------------------------
Validate:
IF subroutine.name NE \\ THEN
item.id = \\; mode=2; error = \\
CALL @subroutine.name( item.id, mode, error)
END
RETURN
*
ParseSentence:
pgm.id = \bpixmlize.validateSubroutine\
start = @FALSE
sentence = CHANGE( @SENTENCE, SPACE(1), @AM)
max.words = DCOUNT( sentence, @AM)
subroutine.name = \\
FOR i = 1 to max.words
BEGIN CASE
CASE start
BEGIN CASE
CASE subroutine.name EQ \\
subroutine.name = sentence< i >
CASE @TRUE
* ignore
END CASE
CASE sentence<i> EQ pgm.id
start = @TRUE
CASE @TRUE
* ignore
END CASE
NEXT i
RETURN
*
Exit:
STOP
------------------------------------------------------------------------
*
**A sample user subroutine:*
SUBROUTINE MY.SUBROUTINE.NAME(item.id, mode, error)
* Copyright (c) 2013 by Blue Prairie, Inc.
* All Rights Reserved
*
* item.id is the item ID of the main file to process
* mode If caller sets mode=2, then subroutine will
simply output
* string '%%validated%%\ and return. This is so
that the
* caller can use the subroutine test program to
validate that
* the subroutine name is valid and callable before
actually
* calling it. If the subroutine sets mode to zero,
the calling
* program should consider this a signal that
something is wrong
* and it should stop processing. The caller should
normally set
* mode to 1 for normal processing.
* error is an error code to be returned to caller.
*-------------------------------------------------------------------------------
*
INCLUDE bpi.xml.bp bpixmlize.common ; * to get common variables
BEGIN CASE
CASE UNASSIGNED(mode)
mode = 1
CASE mode EQ 2
GOSUB Validate
GOTO Exit
CASE @TRUE
* allow to drop through
END CASE
*
pgm.id = \MY.SUBROUTINE.NAME\
*
GOSUB DoSomethingUseful
GOTO Exit
*-------------------------------------------------------------------------------
DoSomethingUseful:
* here is where we do the main task of this subroutine
RETURN
*
Validate:
*do some sanity checks, make sure subroutine can function (i.e.,
open files, etc)
*then if all looks good, simply output th %%validated%% string
CRT \%%validated%%\
RETURN
*
Exit:
RETURN
------------------------------------------------------------------------
Bruce Decker
Blue Prairie, Inc.
http://www.bluepinc.com
720.733.0459
On 1/30/2014 8:13 AM, Daniel McGrath wrote:
In particular, when using the CALL @ syntax to dynamically call
something.
Dan
-----Original Message-----
From: [email protected]
[mailto:[email protected]] On Behalf Of Ross Ferris
Sent: Wednesday, January 29, 2014 10:56 PM
To: U2 Users List
Subject: Re: [U2] [UV] Programmatic Verification of Globally
Cataloged Subroutine
Knowing how many arguments a subroutine is expecting is a good way to
check/confirm that the call you are about to make isn't going to blow
up in your face!
Ross Ferris
Stamina Software
Visage > Better by Design!
-----Original Message-----
From: [email protected]
[mailto:[email protected]] On Behalf Of Wjhonson
Sent: Wednesday, January 29, 2014 10:15 AM
To: [email protected]
Subject: Re: [U2] [UV] Programmatic Verification of Globally
Cataloged Subroutine
I was just trying to think of a reason why I'd want specifically to
know how many arguments the subroutine has.
That is, why was this particular fact chosen as the returned status
code ?
-----Original Message-----
From: Keith Johnson [DATACOM] <[email protected]>
To: '[email protected]' <[email protected]>
Sent: Tue, Jan 28, 2014 3:10 pm
Subject: Re: [U2] [UV] Programmatic Verification of Globally
Cataloged Subroutine
Hi,
LeRoy Dreyfuss said that you would have to change 52 to 12 for EXIST
to work.
The globally cataloged programs have an extra 40 characters put on
the front, so that would cause a problem.
@RECORD[1,4] is a count of the number of times the program has been
used.
@RECORD[5,8] is who cataloged it
@RECORD[13,4] are the date and time (I think)
Regards, Keith
_______________________________________________
U2-Users mailing list
[email protected]
http://listserver.u2ug.org/mailman/listinfo/u2-users
_______________________________________________
U2-Users mailing list
[email protected]
http://listserver.u2ug.org/mailman/listinfo/u2-users
_______________________________________________
U2-Users mailing list
[email protected]
http://listserver.u2ug.org/mailman/listinfo/u2-users
_______________________________________________
U2-Users mailing list
[email protected]
http://listserver.u2ug.org/mailman/listinfo/u2-users
_______________________________________________
U2-Users mailing list
[email protected]
http://listserver.u2ug.org/mailman/listinfo/u2-users
_______________________________________________
U2-Users mailing list
[email protected]
http://listserver.u2ug.org/mailman/listinfo/u2-users