RTC Enterprise Extensions has the ability to tag load modules with a timestamp when they were created using the SSI. In the translator for the link edit use the SSI(@{ssi_info}) option to tell RTC to put the timestamp into the SSI.

Once the load module members are created the SSI will contain a hex representation of the timestamp.

If you want to quickly know when a load module was created but have lost your AMBLIST JCL you can easily check the timestamp in the SSI. Cut out the 8 character hex value and past it into your calculator in hex mode and then convert to decimal. This will give you the timestamp in Unix Epoch format, that is the number of seconds elapsed since the 1st January 1970. You can now cut that value and using a website that converts Unix Epoch timestamps such as http://www.epochconverter.com/, paste the value into the entry field and it will tell you the date the load module was created.

The Rational team Concert infocenter is a bit of a daunting place for a z/OS System Programmer. They are used to separate guides, either written on paper or possibly chiseled out of stone tablets, I should know I was one. Installation Guild, Configuration Guide, User Guide, User Reference are all the norm for z/OS products. Rational Team Concert (RTC) is just part of the bigger Collaborative Lifecycle Management (CLM) picture, so as such the infocenter covers a lot of information, much of which the z/OS system programmer does not care too much about when installing the RTC z/OS bits and pieces.

The purpose of this blog entry is to provide the z/OS system programmer with the links to the stuff that is really really relevant so they don't spend all their time navigating through the web content looking for the relevant information that they require to perform an install of the RTC z/OS bits. We will be using the 4.0.3 infocenter as a reference point.

The first thing to note is all the install information is in the section on Rational Solution for Collaborative Lifecycle Management, and not in the section on Rational Team Concert. Once you open the documentation tree for Rational Solution for Collaborative Lifecycle Management you will see a section on installing. This is where all the relevant pieces you will need are contained.

So the first thing you need to check is the hardware and software prerequisites. The image below where you need to navigate to for this information. Click on the Hardware and software requirements link to display the page, and then click on System requirements link.

There are system variables which are in the form @{source.member.name}.

You can reference any property that is defined as a build property in the properties section of your build definition, with the ${build.property} format.

There are translator variables that are used by specifying the variable in the form &COMPILEROPTIONS. Translator variables are defined in the translator and become the default values. They can then be overridden at the file level.

There are language definition properties that can be used to control conditions in language definitions and translators. The specified properties are similar to build properties, but only apply to the language definitions; they do not apply to the rest of the build. Conditions should be specified as Ant conditions, such as <istrue value="${isV5Compiler}"/>

However, there is a use case of requiring conditional processing based on an individual file property. Translator variables or the overridden value at a file level can be used to drive conditional processing in a translator.

The following example illustrates the use case where the majority of COBOL members use the earlier v4 compiler, but there is an instance at a file level where the V5 compiler has to be used.

As described above, translator variables, by default, are referenced with a & prefix within the translator, for example &COMPILEROPTIONS. However, if we want to use these translator variables in Ant conditions we need to reference them by the translator step number or name within the language definition. What this means is the first translator within a language definition is number 1, the second is number 2. So to reference a translator variable in this context, it would be referenced by var.1.COMPILEROPTIONS. However, if a translator is being used by multiple language definitions, then the index for a particular translator may vary depending on the steps within each language definition. For this reason it is better to give the translator a step name in the language definition, then refer to the translator variables in this manner, e.g. var.STEPNAME.COMPILEROPTIONS.

In the language definition properties we are going to give the LD-COBOL compilation a step name of COBCOMP by editing the Translator step and adding a step name:

In the following translator we define two different translator variables. The first, COMPILEROPTIONS, is specified in the Default Options field in the Translator, and defines the default compiler options. The second, ISV5COMPILER, is the default translator variable for the COBOL compiler and is set to false. Notice that translator variables are always uppercase.

We reference the COMPILEROPTIONS variable in the translator in the normal way translator variables are referenced, i.e. &COMPILEROPTIONS. As the ISV5COMPILER variable is going to be used in an Ant condition we need to reference it differently, by using the step name we gave the translator in the language and using the @{variable} construct. So the variable being reference is @{var.COBCOMP.ISV5COMPILER}.

Once the variable has been defined in the translator it can, if required, be overridden at the file level. To do this, click on the file and select Properties from the resulting context menu. From the wizard then select Enterprise Extensions. The variable section will display the list of translator variables defined in the translators that are referenced by the specified language definition, with their default values.

You can now change the compiler options if your program requires some different options. But for this use case we are going to say our program is a COBOL V5 compiled program, and therefore set the value of ISV5COMPILER to true. Do this by clicking the Edit… option and typing in the new value.

Notice the Restore Default button has activated. You can click this and variables will be returned to the default values as specified in the translator.

Before we finish with the file properties select Jazz Source Control à User Properties

Notice that the translator variables have an internal name that RTC uses. So our ISV5COMPILER internally has the name team.enterprise.build.var.ISV5COMPILER. This is irrelevant in this use case, but if you are creating translator variables en-mass using system definition XML then you will need this value. This concept is covered in another topic.

Many of the compilers and utility programs, when called by an assembler interface, as is done by Rational Team Concert (RTC), will utilize something call DD name substitution lists. These substitution lists allow you, the programmer, to use different DD names than the normal ones expected by the compilers, for compiler input and output.

The reason for this is to allow other processes that do not have DD name flexibility to precede or follow compiler steps. In this way the compiler can accept a different DD name as SYSIN input or can write output to a different DD name other than SYSPRINT.

The reason we have to use this method of substituting DD names is because dynamic data set allocation APIs such as BPXWDYN, behave differently than processes coded using JCL. JCL will allow you to pass the temporary data set between steps without having any regard for the DD name that it is allocated to. With BPXWDYN or TSO ALLOCATE, when a temporary data set is allocated to a DD name and that DD name is freed, the temporary data set is de-allocated and lost.

User Scenarios

When thinking of multistep language definitions in RTC, the classic example is a COBOL compile, followed by a link-edit. The output from the compile is an object deck, and the input to the binder is the same object deck. However this scenario works just fine. In the compiler step we allocate SYSLIN to a temporary object deck as output using the “Keep” option to keep the DD allocated after the compile finishes. Then in the binder step SYSLIN is allocated as input using the same temporary object deck.

This scenario works because both steps are using the same DD name, SYSLIN as output from the first step, and input into the second step.

COBOL compile translator

Link-Edit translator

The user scenario that requires us to use DD name substitution lists is when an initial step allocates a DD name that is output to a subsequent step, such as SYSUT2, but SYSUT2 in the subsequent step has a totally different use. To show this we will use an IEBGENER step that copies source code from SYSUT1 to SYSUT2, standard IEBGENER behaviour. The SYSUT2 output then needs to be passed as input into SYSIN for the COBOL compiler.

IEBGENER step

COBOL Compiler Step

In the above example the IEBGENER step keeps the SYSUT2 DD name allocated. But when the COBOL compiler step needs to run, it also needs SYSUT2 as a work DD so when it tries to allocate it the compile fails with message that SYSUT2 could not be allocated as it was in use:

Successfully using DD name substitution

As long as one of the programs you are calling in a multistep language definition can support DD name substitution, you will be able to manipulate the DD names to pass data between the translators. In the example above we used IEBGENER passing input into the COBOL compiler. Both of these programs support DD name substitution, so we will look at 2 examples of utilizing DD name substitution. The first in the IEBGENER step and the second in the COBOL compile step.

DD name substitution in IEBGENER

In the following screen capture we are replacing the SYSUT2 DD allocation with a SYSIN DD name. However because IEBGENER expects a SYSIN DD to be allocated, we also need to substitute the SYSIN DD allocation with something else. In this case we have chosen SYSDUMMY as SYSIN is actually dummied out.

Note that the DD names list is positional, so we have entered all of the required DDs in the correct order, with their substituted names. So SYSIN, which is at DD position 5 becomes SYSDUMMY and SYSUT2, at DD position 9, becomes SYSIN.

The COBOL translator step can then remain as normal without using DD names list, keeping its default DDs:

When the language definition is run through a build we can see how RTC manages the allocations:

DD name substitution in the COBOL compiler

In this example we leave the IEBGENER step as default, with no DD names list and normal IEBGENER allocations:

We then manage the incoming DDs through DD name substitution in the COBOL compiler.

Note again the positional DD names list, replacing only the required DDs with our substitute names. As the output from IEBGENER is SYSUT2 we need to have that as our replacement DD for SYSIN. However as the COBOL compiler requires a SYSUT2 already we need to substitute that for a different name. We could have use Tom, Dick or Harry as the name, but chose to use SYSUT02 by just adding an extra “0”. We are then able to use SYSUT2 from the IEBGENER step as a replacement DD for SYSIN.

Again looking at the output from the build we can see how RTC handles the allocations and free statements of these DD names:

Additional information

The DD names substitutions lists for the compilers (COBOL, PLI), the Assembler and the Utilities can all be found listed in the relevant manuals for the specific compilers or utilities, normally in the programmers guide. However for a quick reference of the position of the various DD names in each of the compiles and utilities looks in Appendix E of the SCLM Redbook : Getting Started with SCLM: A Practical Guide to SCLM and SCLM Advanced Edition

Think of this blog entry as an example of converting an existing process into an RTC language definition and translator. For some reason, after a recent work trip I had made a note to test whether I could build a translator that would run SQL. Not sure why I had that note on a scrap of paper, but there must have been a reason for it. With the usual "challenges" that DB2 throws up with SCMs, especially when it comes to Binding, I was not anticipating a simple task. Couple with that that most DB2 requests run through IKJEFT01 it meant that we would have to factor in the ISPF Gateway as well to invoke this translator.

In the end, it turned out not to be too challenging, but a couple of peculiar tweaks needed to be adhered to.

Running SQL means calling DSNTEP2 and giving it the SQL in a SYSIN DD allocation. So the easy part of the task was creating an SQL data set definition that would hold my various SQL members.

The translator and language definition seemed pretty straight forward as well. Calling some REXX that invoked DSNTEP2 and allocating SYSIN to the source being built.

The question was how to get DSNTEP2 working as a REXX exec. Normally DSNTEP2 is invoked as a TSO command through the SYSTSIN. However because of the way RTC invokes TSO/ISPF commands, through the ISPF Gateway, as well as how SYSPRINT is allocated, we need to provide a REXX that does the DSNTEP2 invocation. The DSNTEP2 REXX that we run from the TSO command or exec looks like this:

Tuesday morning and a brave new world, me blogging on developerWorks! I wanted to start a blog as a place to put useful information about Rational Team Concert. Probably a good place holder for myself as well judging how my memory seems to be going. So look out for words of wisdom over the coming months. In the meantime take a look at these two other RTC developer blogs which may in fact render mine obsolete already!