AWS Mainframe Modernization Service (Managed Runtime Environment experience) is no longer open to new customers. For capabilities similar to AWS Mainframe Modernization Service (Managed Runtime Environment experience) explore AWS Mainframe Modernization Service (Self-Managed Experience). Existing customers can continue to use the service as normal. For more information, see AWS Mainframe Modernization availability change.
Sort Utilities
The sort utilities rely on datasets whose reference holds a special meaning for the utility. Hence, all the sort utilities on the modernized side share the same invokation pattern in groovy scripts:
mpr.withFileConfigurations(<FILE CONFIGURATIONS DETAILS>...) .withParameters(params) .runProgram("<SORT UTILITY ALIAS>")
where mpr is a MainProgramRunner instance (see the Scripts calling programs section in this page). The sort utilities aliases are given in the sections below.
The DD (datasets definitions) entries from the JCL script are modernized as entries in the details of the file configuration which serve as argument to the mpr.withFileConfigurations() method. See the samples below for illustrations of that concept.
SORT/SYNCSORT/ICEMAN
Purpose
This program emulates various mainframe SORT utilities, used to sort/merge/copy data from datasets, based on provided criteria. The following program aliases can be used (and match the corresponding legacy sort utility name):
SORTSYNCSORTICEMAN
The details about the SORT/MERGE directives found in the control cards and the legacy sort utility features are not given here but should be fetched from the existing relevant legacy platforms documentations.
Signature
The program does not take any argument but relies on specific datasets references instead:
The
SYSINdataset (a.k.a the "control card") holds the sort/merge control statementsThe optional
SYMNAMESdataset holds variable substitution directives in the SYSIN contentThe optional
SORTXDUPorSORTXSUMdataset can be used to store duplicate recordsThe datasets prefixed with
SORTINorSORTDBINhold records to be processed (inputs)The
SORTOUTdataset holds the results from the program (output)The
SORTWKdefinitions for SORT WORK datasets found in some legacy jobs scripts are ignored (and not represented in the modernized call); sort work data sets will always be dynamically allocated in the modern environmentThe two datasets whose DD starts with
SORTJN(prefix) contain records that will be concerned by join keys directives (used to join datasets during the sort process)
For instance, considering the following join keys directives:
JOINKEYS FILE=F1,FIELDS=(13,5,A) JOINKEYS FILE=F2,FIELDS=(24,5,A)
Here, the join key is of length 5, and starts at:
position 13 for records in dataset
SORTJNF1(concatenation ofSORTJNprefix and fileF1)position 24 for records in dataset
SORTJNF2(concatenation ofSORTJNprefix and fileF2)
Checks / Errors Handling
If the input file (
SORTIN) has aSHRdisposition but cannot be found, an error message is logged, the program return code is set to 1 and the program run is halted (no sort will happen, no output will be produced)
For the following cases, a RuntimeException holding a dedicated message will be thrown:
If the program invokation requires connection to a database (when
SORTDBINdataset is used, notSORTIN) but not valid data source could be foundIf the output file (
SORTOUT) is not properly definedIf a command found in the control card cannot be understood or is not supported
If not exactly two input files are provided for a
SORT JOINKEYScase
Sample Usage
MERGE Sample
Here is a sample ICEMAN invokation from a job script snippet:
The control card is inlined and commands to merge fields from the input files (see the SYSIN entry)
//* //PASOSO03 EXEC PGM=ICEMAN,REGION=0M //SORTIN01 DD DSN=input(input809a.data),DISP=SHR,LRECL=10 //SORTIN02 DD DSN=input(input809b.data),DISP=SHR,LRECL=10 //SORTOUT DD DSN=output(out809.txt),DISP=(,PASS),LRECL=10 //SORTWK01 DD SPACE=(281,(156300,156300),RLSE),AVGREC=U //SORTWK02 DD SPACE=(281,(156300,156300),RLSE),AVGREC=U //SYSIN DD * MERGE FIELDS=(1,6,PD,A,7,2,CH,A) END /*
And the matching modernized groovy script snippet -- please note that, as already mentioned, the SORTWK entries are not taken into account during the modernization process, and that the inlined control card is exactly matching the legacy control card content.
// STEP PASOSO03 - PGM - ICEMAN*************************************************** def stepPASOSO03(Object shell, Map params, Map programResults){ shell.with { if (checkValidProgramResults(programResults)) { return execStep("PASOSO03", "ICEMAN", programResults, { mpr .withFileConfigurations(new FileConfigurationUtils() .withJobContext(jobContext) .fileSystem("SORTIN01") .path("input(input809a.data)").recordSize(10) .disposition("SHR") .build() .fileSystem("SORTIN02") .path("input(input809b.data)").recordSize(10) .disposition("SHR") .build() .fileSystem("SORTOUT") .path("output(out809.txt)").recordSize(10) .normalTermination("PASS") .build() .fileSystem("SYSIN") .stream( """ MERGE FIELDS=(1,6,PD,A,7,2,CH,A) END """, getEncoding()) .build() .getFileConfigurations()) .withParameters(params) .runProgram("ICEMAN") }) } } }
Simple SORT Sample
A simple legacy SORT step (job script snippet) with inlined control card, picked up from the carddemo sample application:
//********************************************************************* //* CREATE COPY OF TRANSACT FILE WITH CARD NUMBER AND TRAN ID AS KEY //********************************************************************* //STEP010 EXEC PGM=SORT //SORTIN DD DISP=SHR,DSN=AWS.M2.CARDDEMO.TRANSACT.VSAM.KSDS //SYSPRINT DD SYSOUT=* //SYSOUT DD SYSOUT=* //SORTOUT DD DSN=AWS.M2.CARDDEMO.TRXFL.SEQ, // DISP=(NEW,CATLG,DELETE),UNIT=SYSDA, // DCB=(LRECL=350,BLKSIZE=3500,RECFM=FB), // SPACE=(CYL,(1,1),RLSE) //SYSIN DD * SORT FIELDS=(263,16,CH,A,1,16,CH,A) OUTREC FIELDS=(1:263,16,17:1,262,279:279,50) /*
and the matching modernized groovy script snippet:
// STEP STEP010 - PGM - SORT****************************************************** def stepSTEP010(Object shell, Map params, Map programResults){ shell.with { if (checkValidProgramResults(programResults)) { return execStep("STEP010", "SORT", programResults, { mpr .withFileConfigurations(new FileConfigurationUtils() .withJobContext(jobContext) .bluesam("SORTIN") .dataset("AWS.M2.CARDDEMO.TRANSACT.VSAM.KSDS") .disposition("SHR") .build() .systemOut("SYSPRINT") .output("*") .build() .systemOut("SYSOUT") .output("*") .build() .fileSystem("SORTOUT") .path("AWS.M2.CARDDEMO.TRXFL.SEQ").recordSize(350) .disposition("NEW") .normalTermination("CATLG") .abnormalTermination("DELETE") .build() .fileSystem("SYSIN") .stream( """ SORT FIELDS=(263,16,CH,A,1,16,CH,A) OUTREC FIELDS=(1:263,16,17:1,262,279:279,50)""", getEncoding()) .build() .getFileConfigurations()) .withParameters(params) .runProgram("SORT") }) } } }
Please note that the inlined control card is used "as-is", without any modification from the legacy control card content.
ICETOOL
Purpose
The ICETOOL utility is used to perform multiple operations on datasets in a single job step (data manipulation, sorting and analysis).
The following core operators are being supported:
COPY- Copies data from input to output filesSORT- Sorts data using specified sort cards/criteriaSELECT- Filters and selects specific records based on conditionsSPLICE- Merges/joins data from multiple sourcesCOUNT- Counts records meeting specified criteriaOCCUR- Analyzes occurrence patterns in data
For the SPLICE operator, the utility will use a multi-threaded approach based on data chunking strategies to ensure an optimized performance.
Details about operators should be fetched from the proper legacy platform documentation.
Signature
The ICETOOL utility does not take any parameter, but relies on specific datasets:
TOOLINdataset contains the control statements to be processed by the utilityTOOLMSGandDFSMSGdatasets are not used by the modernizedICETOOLutility for now (ignored)INis the prefix for input datasets (records to be processed)OUTis the prefix for output datasets (records resulting from the processing)other datasets might be referenced by control statements in the control card
Checks / Errors Handling
For the following cases, a RuntimeException will be thrown with a related message:
If the operator used in one of the control statements is not supported
For any operator, if an unsupported directive is provided
Sample Usage
ICETOOL SORT Sample
Here is a legacy jcl sample using ICETOOL for sorting purposes:
each SORT operator control statement uses a dedicated control card, whose reference is specified through the USING keyword
all control cards are defined after the
TOOLINdefinition, and are inlined (seeSEL1CNTLand following*CNTLentries)
//SAMPLO52 EXEC PGM=ICETOOL,REGION=1024K //TOOLMSG DD SYSOUT=* //DFSMSG DD SYSOUT=* //IN1 DD DSN=input(input846a.data),DISP=SHR // DCB=(RECFM=F,LRECL=8) //IN2 DD DSN=input(input846b.data),DISP=SHR // DCB=(RECFM=F,LRECL=8) //OUT1 DD DSN=output(out846a.txt),DISP=(,CATLG) // DCB=(RECFM=F,LRECL=8) //OUT2 DD DSN=output(out846b.txt),DISP=(,CATLG) // DCB=(RECFM=V) //OUT3 DD DSN=output(out846c.txt),DISP=(,CATLG) // DCB=(RECFM=V) //TOOLIN DD * SORT FROM(IN1) TO(OUT1) USING(SEL1) SORT FROM(IN2) TO(OUT1) USING(SEL2) SORT FROM(IN1) TO(OUT2) USING(SEL3) SORT FROM(IN2) TO(OUT2) USING(SEL4) SORT FROM(IN1) TO(OUT3) USING(SEL5) SORT FROM(IN2) TO(OUT3) USING(SEL6) /* //SEL1CNTL DD * OPTION COPY OUTFIL BUILD=(1,8,JFY=(SHIFT=LEFT,TRAIL=C'*')) //* //SEL2CNTL DD * OPTION COPY,SKIPREC=1 OUTFIL BUILD=(1,8,JFY=(SHIFT=LEFT,TRAIL=C'*')) //* //SEL3CNTL DD * OPTION COPY OUTFIL BUILD=(1,8,JFY=(SHIFT=LEFT,TRAIL=C'*')), FTOV,VLTRIM=C' ' //* //SEL4CNTL DD * OPTION COPY,SKIPREC=1 OUTFIL BUILD=(1,8,JFY=(SHIFT=LEFT,TRAIL=C'*')), FTOV,VLTRIM=C' ' //* //SEL5CNTL DD * OPTION COPY OUTFIL BUILD=(1,8,JFY=(SHIFT=LEFT,TRAIL=C'*')), FTOV,VLTRIM=C' ' //* //SEL6CNTL DD * OPTION COPY,SKIPREC=1 OUTFIL BUILD=(1,7,JFY=(SHIFT=LEFT,TRAIL=C'*')), FTOV,VLTRIM=C' ' //*
Once modernized, the matching groovy script snippet looks like:
// STEP SAMPLO52 - PGM - ICETOOL************************************************** def stepSAMPLO52(Object shell, Map params, Map programResults){ shell.with { if (checkValidProgramResults(programResults)) { return execStep("SAMPLO52", "ICETOOL", programResults, { mpr .withFileConfigurations(new FileConfigurationUtils() .withJobContext(jobContext) .systemOut("TOOLMSG") .output("*") .build() .systemOut("DFSMSG") .output("*") .build() .fileSystem("IN1") .path("input(input846a.data)").recordSize(8) .disposition("SHR") .build() .fileSystem("IN2") .path("input(input846b.data)").recordSize(8) .disposition("SHR") .build() .fileSystem("OUT1") .path("output(out846a.txt)").recordSize(8) .normalTermination("CATLG") .build() .fileSystem("OUT2") .path("output(out846b.txt)").rdw(true) .normalTermination("CATLG") .build() .fileSystem("OUT3") .path("output(out846c.txt)").rdw(true) .normalTermination("CATLG") .build() .fileSystem("TOOLIN") .stream( """ SORT FROM(IN1) TO(OUT1) USING(SEL1) SORT FROM(IN2) TO(OUT1) USING(SEL2) SORT FROM(IN1) TO(OUT2) USING(SEL3) SORT FROM(IN2) TO(OUT2) USING(SEL4) SORT FROM(IN1) TO(OUT3) USING(SEL5) SORT FROM(IN2) TO(OUT3) USING(SEL6) """, getEncoding()) .build() .fileSystem("SEL1CNTL") .stream( """ OPTION COPY OUTFIL BUILD=(1,8,JFY=(SHIFT=LEFT,TRAIL=C'*')) """, getEncoding()) .build() .fileSystem("SEL2CNTL") .stream( """ OPTION COPY,SKIPREC=1 OUTFIL BUILD=(1,8,JFY=(SHIFT=LEFT,TRAIL=C'*'))""", getEncoding()) .build() .fileSystem("SEL3CNTL") .stream( """ OPTION COPY OUTFIL BUILD=(1,8,JFY=(SHIFT=LEFT,TRAIL=C'*')), FTOV,VLTRIM=C' '""", getEncoding()) .build() .fileSystem("SEL4CNTL") .stream( """ OPTION COPY,SKIPREC=1 OUTFIL BUILD=(1,8,JFY=(SHIFT=LEFT,TRAIL=C'*')), FTOV,VLTRIM=C' '""", getEncoding()) .build() .fileSystem("SEL5CNTL") .stream( """ OPTION COPY OUTFIL BUILD=(1,8,JFY=(SHIFT=LEFT,TRAIL=C'*')), FTOV,VLTRIM=C' '""", getEncoding()) .build() .fileSystem("SEL6CNTL") .stream( """ OPTION COPY,SKIPREC=1 OUTFIL BUILD=(1,7,JFY=(SHIFT=LEFT,TRAIL=C'*')), FTOV,VLTRIM=C' '""", getEncoding()) .build() .getFileConfigurations()) .withParameters(params) .runProgram("ICETOOL") }) } } }
Notes:
The inlined control cards are used "as-is"; no transformation whatsoever happened, from the legacy control cards
TOOLMSGandDFSMSGare defined in the modernized version, but will be ignored at run timeBoth in legacy and modernized versions, the control cards are defined with the
CNTLsuffix, but referenced without the suffix in the directives fromTOOLINdataset: e.g. InSORT FROM(IN1) TO(OUT1) USING(SEL1), theUSING(SEL1)refers to theSEL1CNTLdataset definition
ICETOOL COPY Sample
Here is another ICETOOL sample, using the COPY operator. The TOOLIN is inlined in the jcl script snippet:
//SAMPLO51 EXEC PGM=ICETOOL,REGION=1024K //TOOLMSG DD SYSOUT=* //DFSMSG DD SYSOUT=* //IN1 DD DSN=input(input831.data),DISP=SHR // DCB=(RECFM=F,LRECL=12) //OUT1 DD DSN=output(out831a.txt),DISP=OLD // DCB=(RECFM=F,LRECL=12) //OUT2 DD DSN=output(out831b.txt),DISP=OLD // DCB=(RECFM=F,LRECL=12) //TOOLIN DD * COPY FROM(IN1) TO(OUT1,OUT2) USING(SEL1) /* //SEL1CNTL DD * OPTION COPY OUTFIL INCLUDE=(7,2,CH,EQ,C'10') //*
And here is the matching modernized groovy script snippet:
// STEP SAMPLO51 - PGM - ICETOOL************************************************** def stepSAMPLO51(Object shell, Map params, Map programResults){ shell.with { if (checkValidProgramResults(programResults)) { return execStep("SAMPLO51", "ICETOOL", programResults, { mpr .withFileConfigurations(new FileConfigurationUtils() .withJobContext(jobContext) .systemOut("TOOLMSG") .output("*") .build() .systemOut("DFSMSG") .output("*") .build() .fileSystem("IN1") .path("input(input831.data)").recordSize(12) .disposition("SHR") .build() .fileSystem("OUT1") .path("output(out831a.txt)").recordSize(12) .disposition("OLD") .build() .fileSystem("OUT2") .path("output(out831b.txt)").recordSize(12) .disposition("OLD") .build() .fileSystem("TOOLIN") .stream( """ COPY FROM(IN1) TO(OUT1,OUT2) USING(SEL1) COPY FROM(IN1) TO(OUT3,OUT4) COPY FROM(IN1) TO(OUT4) COPY FROM(IN1) TO(OUT5,OUT6) """, getEncoding()) .build() .fileSystem("SEL1CNTL") .stream( """ OPTION COPY OUTFIL INCLUDE=(7,2,CH,EQ,C'10')""", getEncoding()) .build() .getFileConfigurations()) .withParameters(params) .runProgram("ICETOOL") }) } } }
MFSORT
Purpose
This utility program is intended to mimic the behaviour of the sort utility named MFSORT found on Micro Focus environments (it is usually invoked from the command line or in scripts on legacy environments).
Internally, the program is delegating the actual sort operations to the SORT/SYNCSORT/ICEMAN utility program.
Signature
Only the following legacy syntax is being supported: mfsort take <control card>
The direct instructions call as mfsort <instructions> is NOT supported.
It does not take any argument; the take directive is emulated using a dataset referenced as TAKE, that contains the commands for MFSORT to operate.
Checks / Errors Handling
If the
TAKEdataset is missing or invalid, aRuntimeExceptionwill be thrownThe Checks / Errors Handling apply here as well, given the delegation from MFSORT to SORT
Sample Usage
The following command invocation shows a sample MFSORT usage:
mfsort take TESTSRT1.CTL
Here is the matching modernized adapted groovy script snippet:
mpr.withFileConfigurations(new FileConfigurationUtils() .fileSystem("TAKE") .path("input(TESTSRT1.CTL)") .build() .getFileConfigurations()) .withArguments("input") // relative path for use and give files .runProgram("MFSORT");