There are many times when I want/need to have an interactive program submit a job to batch, and the interactive program would be so small it seems a waste to have such a program. For example the interactive program presents the user with a confirmation screen and then submits a program to batch that does all the processing. Perhaps the solution would be to have both the interactive and batch commands in the same program and it somehow know when it is running interactively or in batch.
Fortunately the 'Retrieve Job Attributes', RTVJOBA, command allows to retrieve which environment (interactive or batch) the job is running in. Combine this with subroutines in CL, see Subroutine in CL, and I can create a program that can run different commands in both environments.
The keyword in the RTVJOBA command that contains the environment is TYPE. It is a 1 character field that contains '0' (zero) if it is in batch or '1' if it is interactive.
RTVJOBA TYPE(&JOBTYPE) |
In this example program, PGM001, I want to display a confirmation screen if the job is interactive, then if Enter is pressed it will submit itself to batch. By using subroutines I can separate the interactive commands from the batch ones, see below:
01 PGM PARM(&STRDTE &ENDDTE) 02 DCL VAR(&JOBTYPE) TYPE(*CHAR) LEN(1) 03 DCLF FILE(PGM001DF) 04 RTVJOBA TYPE(&JOBTYPE) 05 SELECT 06 WHEN COND(&JOBTYPE = '0') THEN(CALLSUBR SUBR(SR_BATCH)) 07 WHEN COND(&JOBTYPE = '1') THEN(CALLSUBR SUBR(SR_INTERAC)) 08 ENDSELECT /*============================================================*/ /* When running interactively */ 09 SUBR SUBR(SR_INTERAC) 10 SNDRCVF 11 IF COND(&IN03) THEN(RETURN) 12 SBMJOB CMD(CALL PGM(PGM001)) JOB(PGM001_TST) 13 ENDSUBR /*============================================================*/ /* When running in batch */ 14 SUBR SUBR(SR_BATCH) 98 ENDSUBR /*============================================================*/ 99 ENDPGM |
The job type/environment is retrieved by the RTVJOBA command on line 4. If the value is '1' I call the subroutine to run the interactive commands, SR_INTERAC, line 7. If the value is '0' then I call the batch subroutine, SR_BATCH, line 6.
If you have not used the SELECT command you can learn about it in the post Select in CL.
The interactive subroutine just executes a display file, line 10, and submits the PGM001, itself, to batch, line 12.
If the program needed to pass parameters when submitting itself to batch it would need to be called with blank parameter(s) from the menu. For example if PGM002 needs 2 parameters when it is submitted to batch I would code the following in the menu:
CALL PGM(PGM002) PARM('' '') |
You can learn more about the RTVJOBA command from the IBM website here.
This article was written for IBM i 7.1, and should work for earlier releases.
Update
I have been informed if you are programming for a web or mobile app the method mentioned above may not work. But it will if you are programming in traditional green screen style.
To learn more read these two comments:
It's amazing how many shops are not using this technique and are creating separate C/L's for the submit. It's been around since the platform was born and may have even existed on the S/38, although I can't vouch for that.
ReplyDeleteExcelente tip Simon, solo una consulta, a partir de que versiĆ³n se pueden utilizar SELECT/WHEN y SUBR. Saludos!!
ReplyDeleteEl SELECT en CL ha estado disponible desde V5R4.
DeleteThere are circumstances where this approach will not work Simon. And the number of such users is on the increase. Many (all?) of the tools that run through browsers will report batch - which is technically correct but not helpful.
ReplyDeleteThe usual work round is for the vendor of the tool in use to add an additional environment variable which ca be tested. This is the technique that Profound use for example. I also know of users who added their own variable to deal with the issue.
Thank you for the "heads up" on the issue. Then this approach would only work when used by the traditional green screen programs.
DeleteI would hope that over time IBM will see this short coming and give us a third value to indicate the status for a job being run through a browser or app. Until they do then the programmer does need to have a qualifying variable to indicate if this is really running in batch or not.
I've not tried it for a job run through a browser or app but you could use the QUSRJOBI API which has a Job Subtype field that breaks the standard batch job down into 6 subtypes (http://www-01.ibm.com/support/knowledgecenter/ssw_i5_54/apis/qusrjobi.htm?lang=en)
ReplyDeleteI have been swapping messages with Jon Paris after his initial comment (see above). I mentioned to him about the variable return from the QUSRJOBI API (or can be seen using the WRKACTJOB) command. This is his reply:
Delete"I am pretty certain that will not always work Simon.
Some couple of years ago I spend a very long time trying to find a definitive solution and after many chats with folks in Rochester and elsewhere came to the conclusion that there was no 100% guaranteed method except to "do it yourself" via an environment variable.
That was the recommendation from IBM to the ISVs too - hence Profound's approach.
I honestly cannot recall where/why your approach fails - I'm thinking maybe Java/JSPs for one."
I want to give a big "thank you" to Jon for his feedback.
Simon,
ReplyDeleteI've never been a fan of this technique. I think it is just too "clever" for it's own good. In addition to Jon's point, it is trickier to debug interactively. The ONLY advantage I can see is that you have one fewer object. But personally, I'd prefer two simpler programs to one more complex one.
We use the RTVJOBA approach extensively. If the CL is running interactively, we run the prompt program for the user to enter any parameters and selections then submit the same CL to batch. This time it detects it is in batch and branches around the interactive section.
ReplyDeleteI almost never need to run a CL program (they're usually there to override files, clear files, and other sorts of setup before calling an RPG program - all things I can just do in the RPG). If I needed to do this I would add a procedure to my utilities service program that calls the QUSRJOBI API and returns the batch/interactive type.
ReplyDeleteMy RPG programs could determine if they're running interactive or batch, they know (with PSDS) who they are, and could easily submit themselves to batch. I would just ditch the CL and let the RPG do it itself. The only complicated code (the API call) would be isolated and reusable, and I'd have one less program to maintain.
This may seem at first to be a cool trick. I used it myself on the S/38 back in the early 80's, but it was a mistake and should be considered an anti-pattern. It flies in the face of every principle of good software design developed over these decades. It violates separation of concerns. It is terrible cohesion -- these two functions have no need to be in the same program. It creates very poor coupling. The parameters needed for the interactive portion are probably not the same as those for the batch process. It is inefficient. The list could go on.... But what are we gaining on the other side? One less program object? Big deal. Do we combine five different kinds of reports on into a single RPG program, merely to decrease the number of programs? No. And we should not use that excuse here either.
ReplyDeleteI appreciate your blog, Simon, normally introducing good programming techniques concepts for those who are learning. Please keep up the good work.
Disagree, control language has it's place and if used for control it's find. I would never code an interactive screen in CL but for submission control it's fine. Splitting it up into multiple programs for the purposes originally discussed in this thread does not make any sense.
DeleteI like the self submitting CL program, been using that method for many years. I will also self submit the CL to batch if the current user ID is not one that can access certain areas of the IFS root system since it does not support adopted authority.
ReplyDeleteAnd I *always* code the HOLD(&HOLD) parm and define &HOLD as 5A Value '*NO'. If I'm in debug, I can set the value to *YES and then put the batch job in debug a few seconds later
I've used this for years. In the Interactive/Batch check I also check for the existence of a data area in the *LIBL called NOBATCH - if it exists, then the job does not submit.
ReplyDeleteNOBATCH is created in QTEMP by a command, NOBATCH, and deleted by a command BATCH. This means I can run interactively if I want to debug a process without having to go through the service job route.
Warren, I appreciate your concern, but I would not use this technique in programs where there was a difference between the parameter list for rinteractive, and that for batch. It is standard code, and easily controlled.
Of course, in the modern environment it only works for green-screen QINTER-QBATCH environments. C'est la vie. If we need to, we can find some other way.
I recall doing something years ago with part of the program interactive then submits itself to batch to complete the program. But in that envirionment we used switches, We checked one of the positions of the on/off bits to determine if the CL was in interactive or batch mode and diverted the program to the proper place in the program. Don't recall the specific details anymore as I haven't needed to use it.
ReplyDeleteI tried to do the following but am slightly new to sumbitting CL off to batch within the same code. But now my CL program is in a loop constantly submitting itself off to batch again and again. How do i go about stopping this?
ReplyDeleteYou have probably got the value of &JOBTYPE the wrong way around.
Delete&JOBTYPE = '1' interactive, SBMJOB
&JOBTYPE = '0' batch
Use debug to make sure you have that value the right way around.
Hello ,
ReplyDeleteWhat could be the best way to submit three jobs such that Job 2 is submitted after completion of first and likewise for job 3 .
Use a data area. Simple to do.
Delete