Javascript on z/OS For Beginners – Getting It To Run

(Originally posted 2009-04-26.)

Here’s another “For Beginners” post to encourage people to just leap in and try it…

Javascript is a language popularly used for such things as web pages with some programming in them (and that includes frameworks like dojo), building Firefox extensions, and the Adobe AIR (desktop) runtime. As it happens I’m pretty familiar with Javascript anyway – having done all 3 of the above. This post shows how I got it to run on z/OS using Mozilla’s Rhino…

Mozilla’s Rhino project is a javascript interpreter written in java. (Java 6 does in fact have a general-purpose scripting interface – with javascript as a prime target.) It’s important to note that Rhino requires Java 5.

So here’s what I did…

  1. Downloaded the Rhino package to my PC from here.
  2. Unpacked it on my PC using a Zip tool (in my case 7-Zip).
  3. Tested it out on my PC – just to get comfortable with how it worked (and that was well worth the half an hour it took).
  4. FTP’ed binary the included js.jar file to an HFS file (in my case /u//rhino/js.jar). The file was under 1MB in size.
  5. Adjusted my CLASSPATH to point additionally to js.jar (including js.jar explicitly, not just the directory it was in).
  6. Invoked Rhino in interactive mode:
    java org.mozilla.javascript.tools.shell.Main
  7. Typed in a few javascript statements such as
    print(1+2)
  8. Quit by typing “quit()”

You can pass the name of a javascript file to Rhino by adding eg “test.js” to the command to invoke it.

In my case I also used the “.profile” startup script to adjust my CLASSPATH and to alias “js” to mean “run the Rhino javascript interpreter”.

So, it’s actually VERY straightforward to run Javascript under z/OS – thanks to Rhino. (And I suspect anyone with Java 6 installed would find it even easier.)

As always, if you know better please feel free to comment here. Remember, I’m learning as I go, and I just want to encourage others to try a few things.

z/OS Unix System Services For Beginners – Java Hello World

(Originally posted 2009-04-25.)

In this post (and any others in a similar vein) I'm going to be displaying a great deal of ignorance – but I think I'm doing it in a good cause.

I know a fair amount about things like Java, XML and C++ – but NOT on z/OS. So I'm determined to learn and present what I learn as "For Beginners" posts here.

The idea is that I'll encourage other people with more traditional z/OS skills to try some simple new things, such as java. So, if you've not done these things before do have a go. Stuff is remarkably straightforward to do.

Here's how I created a simple "Hello World" java application in Unix System Services.

  1. Log onto TSO with a region of 64MB (64000 in the logon panel). When I tried this with 32000 I got a "JVMDBG001" message, complaining of not being able to GETMAIN enough memory to start the JVM (but the JVM started anyway).
  2. Type OMVS. (If your userid has been set up to use Unix System Services it should start you in a directory (mine being "/u/userid").
  3. Create a subdirectory using "mkdir javatest".
  4. Change to this subdirectory using "cd javatest".
  5. List what's in this subdirectory (actually nothing) using "ls".
  6. Create a new java source file using "oedit Hello.java".
  7. While in the (ISPF) Editor add the following lines:
    
    public class Hello{
      public static void main(String args[]){
        System.out.println("Welcome!");
      }
    }
    
    
  8. Press PF3 to save. (Treat the resulting dialog as any "leaving ISPF" dialog.)
  9. Compile the resulting java with "javac Hello.java".
  10. Run the compiled java bytecode with "java Hello".

And that's all there is to it. One note – if you're not familiar with java: Case is significant. Mismatches would cause problems.

The java book I used to get started (and then some) was Deitel & Deitel's "Java How To Program" but there are lots of them to choose from.

If you're more experienced at this than me please feel free to comment as you see fit. But remember this is a "For Beginners" post. I'm trying to encourage people to GET STARTED.

DB2 Data Sharing and XCF Job Name

(Originally posted 2009-04-25.)

Back in z/OS R.9 RMF Parallel Sysplex New Fields (in 2007) I mentioned a new field: R742MJOB (XCF Member Job Name.)

At the time I had no real customer data so I could only espouse the HOPE that this field would be useful. (When I asked for it to be added to the SMF 74 Subtype 2 record it seemed to me it probably would be.)

Now that z/OS R.9 is “mainstream” I’m seeing lots of data at this level. And so, because it’s mainstream, I think it’s time to talk some more about this field (and to tell you what I’m seeing in customer data). I think you’ll like it.

But first some preliminaries:

XCF Groups and Members

Before there was Parallel Sysplex there was Sysplex. And the main ingredient of (base) Sysplex was XCF signalling. Applications that use XCF consist of groups and members. A group is essentially an application. So the “SYSGRS” group is the GRS application. Members are address spaces participating in the application.

XCF’s job is to pass messages within members of the same group, whether on one system or several within the Sysplex.

Instrumentation

Since the advent of XCF we’ve had group names, member names and messages sent and received in the 74-2 record. But there’s a problem here, best illustrated by the example of DB2 Data Sharing:

A DB2 Data Sharing group comprises, amongst other Coupling Facility structures, a “LOCK1” structure. It’s a Lock structure and it’s called the “LOCK1” structure because its name is always “_LOCK1”. We can easily identify this structure and the group it belongs to. Associated with the LOCK1 structure are 2 XCF groups:

  • IXCLOnnn – which is a particularly unhelpful name as ALL Lock structures have such an XCF group associated with them. (There usually being several other Lock structures in a single Parallel Sysplex – such as GRS Star and VSAM RLS’s Lock structure.) The member name, by the way, would be something equally unhelpful like “M102”.

    The purpose of this group is to resolve potential “False Contention” situations in the Lock1 structure (possibly caused by too small a lock table).

  • DXRabcd – where the “abcd” is the Data Sharing Group Name. This is slightly better but it doesn’t help that the member name is e.g. “DXRDPG0$$IPB1003”.

    This XCF group is used by the various IRLM address spaces in the group to resolve locking conflicts from DB2’s perspective. (IXCLOnnn group traffic resolves to either a False Contention or an XES contention, the latter having to be resolved to either a lock being granted or IRLM negotiation causing the requester to wait.)

So, it would be really handy to isolate these two types of traffic for a particular DB2 Data Sharing group (and perhaps to work on reducing it). As you can see, it’s rather hard to do that without more useful information. This is where 74-2 XCF Jobname comes in…

It turns out that for BOTH the IXCLOnnn group and the DXRabcd group the job name is the IRLM address space name. So, if you know the IRLM job name (hopefully because you’ve given it a name close to that of the Data Sharing group it supports) you can easily tell which XCF groups relate to that Data Sharing group. And then perhaps you can do something about the traffic.

Perhaps I’m displaying my ignorance of DB2 here but in the test case I’m looking at right now I see 2 IRLM address spaces in one system and one in the other, all sharing the same XCF groups – both IXCLOnnn and DXRabcd. I didn’t know one could run 2 IRLMs in the same DB2 Data Sharing group in the same LPAR. I’ll admit I’m not really sure what to make of that.

But what about other XCF groups? It turns out that they also have good mnemonic address space names. But then for most other groups it’s obvious what the XCF group is anyway.

Glancing over a friend’s shoulder at a modern RMF XCF Activity Report I didn’t see the job name in the report (but rather the member name). But then I, and I expect most other people, don’t often look at RMF Postprocessor reports all that often.

What is REMOVECC?

(Originally posted 2009-04-10.)

To whoever (In the USA I think) Googled “what is REMOVECC” and got to this blog let me give you my thoughts on the matter. (And yes I know, it being a search, you might never come back to read this.)

To understand REMOVECC you have to understand that the “CC” refers to ASA (American Standards Association) Carriage Control, described here.

ASA (formerly ANSI) control characters appear in Position 5 for variable-length records (just after the Record Descriptor Word (RDW)). So a EBCDIC “1” in Position 5 would tell a printer to start a new page, and a “0” would tell it to skip a line.

Originally OUTFIL was used to create PRINTABLE reports. So these kinds of control characters were needed. But more modern (perhaps more complex) uses often don’t require ASA CC characters. So coding REMOVECC on the OUTFIL statement suppresses the control characters.

In this blog entry I used OUTFIL REMOVECC because my output is HTML. No HTML reader (such as a web browser) is going to tolerate ASA control characters. So I removed them.

I hope that clears this up. And I know the question was asked because my Firefox Extension has a “Referer URL” reporting element that tells me things like the Google searches that got people to my blog. I’d be flattered to think it was someone who was trying to understand the referenced blog post.

Update 10 April 2009

Perhaps I should also mention the relatively recent BLKCCH1, BLKCCH2 and BLKCCT1 OUTFIL options:

These replace the page eject carriage control character “1” with a blank in HEADER1, HEADER2 and TRAILER1 respectively. (HEADER3, TRAILER2 and TRAILER3 don’t need equivalent options.) Replacing with a blank still shifts the output to the right by 1 character, so REMOVECC may still be the best choice.

The PTFs for this enhancement appeared in April, 2006 (UK90006 / UK90007).

DFSORT Sorting Without Sorting Header / Trailer Lines

(Originally posted 2009-04-10.)

For whoever got to my blog with this Google search here’s how you sort data without a header:

First you need to be using z/OS DFSORT Release 10 or to have applied the PTFs for UK90013 (July 2008).

Second, the vehicle for doing this is ICETOOL rather than DFSORT itself.

Use the new DATASORT operator. Here’s an example:

If you code

DATASORT FROM(DD1) TO(DD) FIRST(3) USING(CTL1)

and code a CTL1CNTL like

//CTL1CNTL DD *  SORT FIELDS=(1,8,CH,A,9,4,BI,D)

ICETOOL will sort everything after the first 3 records, leaving the first 3 records unchanged. (In this case the sorted lines are, obviously, collated on two distinct fields.)

In the CTL1CNTL set of control statements you can code an OUTFIL statement (or several) if you want to. There are some restrictions on what statements you can code in the CTL1CNTL data set (and these are documented here.)

As well as being able to avoid sorting header records (FIRST,FIRST(n),HEADER,HEADER(n)) you can also avoid sorting the last few records with LAST, LAST(n), TRAILER or TRAILER(n).

Workload Manager Policy in XML Format – Part IV

(Originally posted 2009-04-09.)

So here’s yet another way of parsing the WLM XML Service Definition. This time it’s on z/OS, using DFSORT. Relatively recent features in DFSORT have made it easier to do useful things with XML.

In this example I’ve made some attempt to make the output pretty – by creating a HTML table.

Below is the SYSIN you need to parse the <SchedulingEnvironment> elements. I’m assuming you know how to code a basic DFSORT invocation.

(To be able to run this example you need the PTFs for APAR UK90013 – WHEN=GROUP – and for UK90006/UK90007 – JFY and PARSE.)

  OPTION COPY,VLSHRT                                     INREC IFTHEN=(WHEN=INIT,BUILD=(1,4,3X,5)),             IFTHEN=(WHEN=GROUP,                                      BEGIN=(8,80,SS,EQ,C'<SchedulingEnvironment>'),         END=(8,80,SS,EQ,C'</SchedulingEnvironment>'),          PUSH=(5:ID=3))                                       OUTFIL INCLUDE=(5,1,CH,EQ,C'0'),REMOVECC,              HEADER1=('<html>',/,                                   '<body>',/,                                              '<h1>Scheduling Environments</h1>',/,                  '<table border="1">',/,                                '<tr>',/,                                              '<th>Name</th>',/,                                     '<th>Description</th>',/,                              '<th>Resources Required</th>',/,                       '</tr>'),                                              IFTHEN=(WHEN=(8,80,SS,EQ,C'<SchedulingEnvironment>'),      BUILD=(1,4,C'<tr>')),                                             IFTHEN=(WHEN=(14,6,CH,EQ,C'<Name>'),                                  PARSE=(%00=(STARTAFT=C'<Name>',ENDBEFR=C'</Name>',                  FIXLEN=64)),                                                        BUILD=(1,4,%00,JFY=(SHIFT=LEFT,LEAD=C'<td>',TRAIL=C'</td>'))),    IFTHEN=(WHEN=(8,80,SS,EQ,C'<Description>'),                           PARSE=(%01=(STARTAFT=C'<Description>',ENDBEFR=C'</Description>',    FIXLEN=64)),                                                        BUILD=(1,4,%01,JFY=(SHIFT=LEFT,LEAD=C'<td>',TRAIL=C'</td>'))),    IFTHEN=(WHEN=(8,80,SS,EQ,C'<ResourceNames>'),                         BUILD=(1,4,C'<td><ul>')),                                         IFTHEN=(WHEN=(8,80,SS,EQ,C'<ResourceName>'),                          BUILD=(1,4,C'<li>')),                                             IFTHEN=(WHEN=(18,6,CH,EQ,C'<Name>'),                                  PARSE=(%02=(STARTAFT=C'<Name>',ENDBEFR=C'</Name>',                  FIXLEN=64)),                                                        BUILD=(1,4,%02)),                                                 IFTHEN=(WHEN=(8,80,SS,EQ,C'<RequiredState>'),                         PARSE=(%03=(STARTAFT=C'<RequiredState>',                            ENDBEFR=C'</RequiredState>',                                        FIXLEN=64)),                                                        BUILD=(1,4,%03)),                                       IFTHEN=(WHEN=(8,80,SS,EQ,C'</ResourceName>'),               BUILD=(1,4,C'</li>')),                                  IFTHEN=(WHEN=(8,80,SS,EQ,C'</ResourceNames>'),              BUILD=(1,4,C'</ul></td>')),                             IFTHEN=(WHEN=(8,80,SS,EQ,C'</SchedulingEnvironment>'),      BUILD=(1,4,C'</tr>')),                                  TRAILER1=('</table>',/,'</body>',/,'</html>')                       

The best way to read this is as a sequence of two steps:

  1. INREC
  2. OUTFIL

There’s also a COPY as we’re not sorting, just preserving record order.

INREC

This statement uses WHEN=GROUP to label all records not between the <SchedulingEnvironment> and </SchedulingEnvironment> lines in the XML stream. The label is a sequence number:”PUSH=5:ID=3″ says “overlay position 5 (just after the RDW) with 3 bytes of sequence number, the sequence number incrementing for each group of records. (The “BUILD=1,4,3X,5” beforehand says “insert 3 blanks between the 4-byte RDW and the first byte of actual data”.)

So any line in the input file not in a <SchedulingEnvironment> element have no such tag. For the ones that have a tag we have sequence numbers “000”,”001″ etc. As we’ll see this is wide enough for 99 distinct scheduling environments – and can be adapted if you have more.

OUTFIL

This statement throws away records that aren’t part of a group (and so aren’t within a <SchedulingEnvironment> element), reformats the contents of each <SchedulingEnvironment> element and wraps header and trailer HTML around the result.

“INCLUDE=(5,1,CH,EQ,C’0′)” says “keep records that were tagged as part of a <SchedulingEnvironment> element in the INREC statement”.

“REMOVECC” prevents OUTFIL from writing ANSI carriage-control characters.

“HEADER1” and “TRAILER1” write “boilerplate” HTML.

The remainder – the IFTHEN “pipeline” – does the bulk of the work…

There are several IFTHEN “stages”. Note: If “HIT=NEXT” had been coded on any of them records matching the “WHEN=” clauses would be passed onto the next IFTHEN “stage”, In that sense it would be a true pipeline. In this case I didn’t code “HIT=NEXT” – as each matching “WHEN=” is the only one I want to operate on the matched record.

There are several distinct types of IFTHEN “stage”:

  • Ones like
    IFTHEN=(WHEN=(8,80,SS,EQ,C'<SchedulingEnvironment>'),      BUILD=(1,4,C'<tr>')), 

    which is a substring search, with a literal replacement string. “Substring search” means “find the match ANYWHERE in the character range”.

  • Ones like
    IFTHEN=(WHEN=(14,6,CH,EQ,C'<Name>'),                                  PARSE=(%00=(STARTAFT=C'<Name>',ENDBEFR=C'</Name>',                  FIXLEN=64)),                                                        BUILD=(1,4,%00,JFY=(SHIFT=LEFT,LEAD=C'<td>',TRAIL=C'</td>'))),  

    This one has a simple search – for a specific string in a particular position. But it also has a free-format parsing:

    PARSE fills a variable (%00) with whatever is between “<Name>” and “</Name>”, now matter how wide or how narrow (subject to a limit of 64 characters – the FIXLEN value).This variable is used in the BUILD specification.

    BUILD uses the new JFY (APAR UK00013) function to sandwich the contents of %00 between “<td>” and “</td>”, removing any trailing spaces.

  • Ones like
      IFTHEN=(WHEN=(8,80,SS,EQ,C'<RequiredState>'),                         PARSE=(%03=(STARTAFT=C'<RequiredState>',                            ENDBEFR=C'</RequiredState>',                                        FIXLEN=64)),                                                        BUILD=(1,4,%03)),                                     

    which are a hybrid of the two.

Input Data

Disregarding the lines in the XML file that will ultimately be thrown away we have

    <SchedulingEnvironment>      <Name>DB2P</Name>      <Description>Run for DB2P</Description>      <ResourceNames>        <ResourceName>          <Name>DB2P</Name>          <RequiredState>On</RequiredState>        </ResourceName>      </ResourceNames>    </SchedulingEnvironment>

You’ll notice two different uses of the <Name> element. To distinguish between those the IFTHEN “stages” for the two use fixed offsets: e.g “WHEN=(18,6,CH,EQ,C'<Name>’)”.

Output HTML

For that one <SchedulingEnvironment> the code produces:

<html><body><h1>Scheduling Environments</h1><table border="1"><tr><th>Name</th><th>Description</th><th>Resources Required</th></tr><tr><td>DB2P</td><td>Run for DB2P</td>

<td><ul><li>DB2POn</li></ul></td></tr></table></body></html>

which ultimately formats as



NameDescriptionResources Required
DB2PRun for DB2P
  • DB2POn

though I’ve taken out the <html>, </html>, <body>, </body>, <h1> and </h1> tags – to make this blog entry format a little better.

So, admittedly this looks complex but if you pick through it should all make sense. If you’re lucky enough to have the PTFs on (and the latest is from July 2008) or are on z/OS Release 10 you can try this out and adapt the techniques for other parts of the WLM XML Service Definition or indeed other pieces of XML.

One other thing: In this example the <ResourceName> elements relate to a different part of the Service Definition, which looks like:

 <Resources>    <Resource>      <Name>DB2P</Name>      <Description>Subsystem DB2P</Description>    </Resource> </Resources>

which I haven’t attempted to look up in the above code sample. To do it I think I’d be tempted to create 2 flat files – one from <SchedulingEnvironment> elements and one from <ResourceName> elements – and then use ICETOOL SPLICE to fold them in. And then emit HTML by reformatting the result.

But then this blog entry is quite long enough as it is. 🙂

Please DO Twitter In My Sessions

(Originally posted 2009-04-09.)

It’s approaching conference season again – at least the UKCMG / European System z Conference portion of it.

Bearing that in mind I want to share this article with you: “Professor Encourages Students to Pass Notes During Class — via Twitter”. It’s well worth reading the comments that follow the article. They’re rather more enlightening and illustrative than the (short) article itself.

I’ve been in the habit for two years now of Tweeting in sessions where I’ve been in the audience. Yes, some of it has been irrelevant to the topic but much of it has been relaying items of importance from the session itself. I hope it hasn’t been too distracting, and certainly I’ve used “low key” technologies to do it. (Of course before that I’d blog about sessions.)

Now that Twitter has become mainstream (evidenced by me no longer asking “are you on Twitter?” but rather “what’s your Twitter ID?” and the HUGE onrush of people (including mainframe folks) onto Twitter in the past year) I’d expect a fair proportion of people in my audiences to be on Twitter. And so we can begin to do what the article suggests: Encourage participation via Twitter.

So, in MY sessions please feel free to use Twitter. If you want to turn it into a “back channel” that’s fine. In fact, as the article says and the comments amplify, that’s a very valuable thing to do.

If you happen not to be in the room but some friend of yours is feel free to tweet at them to get them to ask questions. Or whatever.

I guess, as a presenter, the thing you fear most is “loss of control”. Personally that’s a very minor fear for me. I’m much more interested in making the time we have together, thinking about the topic and hopefully discussing it, as valuable as possible.

A while ago I adopted the practice of leaving my favourite Twitter client – Twhirl – on. It was a fun stunt to pull – as tweets flew across my beloved presentation foils live on screen. 🙂 I mightn’t do that anymore, though some of the tweets undoubtedly were FAR more interesting than the slides. 🙂 And, though I’d like to be able to, I don’t think I can tweet and speak at the same time. 😦 So don’t expect me to participate until after the session.

One other thing: I realise that not having access to Twitter during a session is disenfranchising. And it’s been annoying when I’ve been in the back of someone else’s session when NONE of my Twitter clients – whether on phones or laptops – have been functional.

But, in general, feel free to use Twitter whenever I’m presenting. And hopefully I won’t give you much occasion to tweet about my dress sense. 🙂

Workload Manager Policy in XML Format – Part III

(Originally posted 2009-04-08.)

Here’s another way to process a WLM Service Definition – once you’ve got it into XML format.

XSLT (XML Stylesheet Transformations if you prefer) is another technology that’s been around for a while.

In simple terms you write another piece of XML (the stylesheet) that describes how to transform your original XML into something else. There’s a lot of flexibility in this but the example in this post is plain old HTML as a target.

There are lots of tools to take the XSLT file and use it to transform the original XML. In my case I’m using a java-based free engine(Saxon)but you could, for example, do it from javascript. Saxon’s command-line based and works fast and well – for my purposes.

So here’s a sample XSLT file:

<?xml version="1.0"?><xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:wlm="http://www.ibm.com/WLM/ServiceDefinition/Level008">

<xsl:output method="xhtml" /> <xsl:template match="/"> <xhtml> <body> <h1><xsl:value-of select="wlm:ServiceDefinition/wlm:Name"/> - <xsl:value-of select="wlm:ServiceDefinition/wlm:Description"/></h1> <table border="1"> <tr> <th>Name</th> <th>Description</th> <th>Subsystem Type</th> <th>Limit</th> <th>Procedure Name</th> <th>Start Parameters</th> </tr> <xsl:apply-templates select="wlm:ServiceDefinition/wlm:ApplicationEnvironments/wlm:ApplicationEnvironment"/> </table> </body> </xhtml> </xsl:template>

<xsl:template match="wlm:ServiceDefinition/wlm:ApplicationEnvironments/wlm:ApplicationEnvironment"> <tr> <td><xsl:value-of select="wlm:Name"/></td> <td><xsl:value-of select="wlm:Description"/></td> <td><xsl:value-of select="wlm:SubsystemType"/></td> <td><xsl:value-of select="wlm:Limit"/></td> <td><xsl:value-of select="wlm:ProcedureName"/></td> <td><xsl:value-of select="wlm:StartParameter"/></td> </tr> </xsl:template>

</xsl:stylesheet>

Again, I’m showing you a sample that handles a different fragment of the Service Definition.

In this case it’s the Application Environment definitions (most notably for use with DB2 Stored Procedures). The stylesheet does two things.

  • Shows the Service Definition name and associated description.
  • Lists in a table information about each Application Environment. (For me the most interesting thing here is the NUMTCB value.)

The “wlm:” throughout is required because the XML file has a namespace associated with it. So all the searches have to respect that. An example of such a search is

match="wlm:ServiceDefinition/wlm:ApplicationEnvironments/wlm:ApplicationEnvironment">

Searches in XSLT are in XPath format. Basically this one says “match on ApplicationEnvironment elements within ApplicationEnvironments elements within the ServiceDefinition element, respecting the use of the namespace “wlm” which is really “http://www.ibm.com/WLM/ServiceDefinition/Level008&#8221;.

As both XPath and XSLT are widely documented on the web (and because this is a technology I’m still almost at the bottom of the learning curve for) I won’t describe the code any further. Again I’d suggest you try it, having taken a text editor to your XML-format Service Definition, and then play with it some.

(Annoyingly there’s an emoticon that appeared in the code instead of “xmlns : xsl” and you’ll need to take the spaces out of this to make it work.)

This is and XSLT file I wrote myself. It was a little fiddly at first but now I think it’s quite easy to understand and modify. But I know I’ve missed many tricks, XSLT and XPath being incredibly powerful.

Have fun playing!

Workload Manager Policy in XML Format – Part II

(Originally posted 2009-04-07.)

In Workload Manager Policy in XML Format – Part I I showed you how you can use PHP to extract Classification Rules information from the WLM Service Definition (once converted to XML format).

This post gives an example of extracting a different set of information from the XML Service Definition, using javascript and, in particular, XMLHttpRequest (sometimes known as XHR).

There is a slightly ulterior motive here: Acquainting mainframe people with some of the more modern web techniques. (I’m hoping you’ll explore some of them for yourselves.)

Here’s some sample code:

<html><body><h2>Workloads</h2><ul id="workloads"></ul><script type="text/javascript">  var req = new XMLHttpRequest();  req.open('GET', 'wlmpolicy.xml', true)  req.onreadystatechange = function (aEvt)  {    if (req.readyState == 4)    {      if(req.status == 200)      {        DOM=req.responseXML;                // Get list of workloads        workloads=DOM.getElementsByTagName("Workload")                // Add a list item for each workload        ul=document.getElementById("workloads")        for(w=0;w<workloads.length;w++)        {          // Get workload name          nameNode=workloads[w].getElementsByTagName("Name")[0].firstChild          workloadName=nameNode.nodeValue

// Get workload description descNode=workloads[w].getElementsByTagName("Description")[0].firstChild workloadDesc=descNode.nodeValue

// Create list item and add workload name / desc to it li=document.createElement("li") liText=document.createTextNode(workloadName+" - "+workloadDesc) li.appendChild(liText) // List item to the list ul.appendChild(li) } } } } req.send(null);</script></body></html>

Now, hopefully that wasn’t too intimidating: If you have a webserver to stick your XML on try it for yourself: The only thing you’ll need to change is the target URL in the XMLHttpRequest.

Most of the code is designed to fire – as a block – when the XML document is retrieved. It parses the returned XML, looking for “<Workload>” elements. The list of those is in array “workloads”.

For each of the workloads it looks for “<Name>” and “<Description>” elements and retrieves the text associated with them.

Finally, for each workload, a new “<li>” tag is created and populated with the workload’s name and description.

Thus the code sample prints a list of workloads and their descriptions.

There’s obviously a lot more in the WLM Service Description. I’ve shown you two techniques for parsing it. The simplest thing to do next is to convert your own WLM Service Definition to XML and browse it with a text editor. (On Windows I’m using Notepad++ but any editor will do, preferably one that syntax highlights XML).

Workload Manager Policy in XML Format – Part I

(Originally posted 2009-04-06.)

This isn't particularly new – but I'm guessing most people who work with WLM don't know about this…

For some time now you've been able to download a java application that enables you to convert your WLM Service Definition to and from XML. Perhaps more importantly, the application provides a nice way to edit the Service Definition – and that is actually its main purpose.

You can get the program from here. Unfortunately – from my perspective as someone who aspires to migrate to Linux over time – it is packaged for Windows. (I have mentioned this to Development – as it appears to be a java/Swing application and hence potentially portable.)

To retrieve the ISPF-based Service Definition, to convert it to and from XML, and to update it on z/OS a pair of batch jobs are used, submitted via FTP. If you get the setup right – and this is quite easy – the whole round-trip works well.

In any case the java application is a nice way to edit the Service Definition.

Now to the main purpose of this blog entry.

Manipulating the XML WLM Service Definition using PHP

The java application saves a copy of the XML Service Definition to your local workstation.XML is really nice as you can manipulate it in so many different ways.

Consider PHP, as an example. I may blog about this some more one day but I've installed Apache, with PHP support, on my Thinkpad. And this webserver is permanently up but only accessible via "localhost" URLs. (I've written a few scripts that automate most of the tedious parts of retrieving performance reports from the mainframe and displaying them.)

PHP is a good webserver scripting language, well suited to lots of tasks, and with an active development community. One of the things it's good at is processing XML. The following code example does some basic processing that's useful to me. You might find it useful to build on.


<?php
$dom=new DOMDocument;
$dom->load('wlmpolicy.xml');
$xpath=new DOMXPath($dom);
$xpath->registerNamespace("wlm","http://www.ibm.com/WLM/ServiceDefinition/Level008");

// List classification rules
echo "<h2>Classifications</h2>\n";
echo "<ul>\n";
$classifications=$xpath->query('/wlm:ServiceDefinition/wlm:Classifications/wlm:Classification');
foreach($classifications as $c)
{
  $subsysNode=$xpath->query("wlm:SubsystemType",$c);
  $subsys=$subsysNode->item(0)->nodeValue;
  $descNode=$xpath->query("wlm:Description",$c);
  $desc=$descNode->item(0)->nodeValue;
  echo "<li>$subsys - $desc\n";
  echo "<ul>\n";
  $crs=$xpath->query('wlm:ClassificationRule',$c);
  foreach($crs as $cr)
  {
    $qtypeNode=$xpath->query("wlm:QualifierType",$cr);
    $qtype=$qtypeNode->item(0)->nodeValue;
    $qvalueNode=$xpath->query("wlm:QualifierValue",$cr);
    $qvalue=$qvalueNode->item(0)->nodeValue;
    $sclassNode=$xpath->query("wlm:ServiceClassName",$cr);
    $sclass=$sclassNode->item(0)->nodeValue;
    $rclassNode=$xpath->query("wlm:ReportClassName",$cr);
    $rclass=$rclassNode->item(0)->nodeValue;
    echo "<li>$qtype - $qvalue ($sclass / $rclass)\n";
  }
  echo "</ul></li>\n";
}
echo "</ul>\n";?>

In XML terms the root node is <ServiceDefinition>. You can get to the classification rules with an XPath of

"/wlm:ServiceDefinition/wlm:Classifications/wlm:Classification"

The "wlm" in the above XPath expression refers to the need to register a namespace. The line

$xpath->registerNamespace("wlm","http://www.ibm.com/WLM/ServiceDefinition/Level008");

does that. Using this XPath expression yields a list of <Classification> nodes, which the code stores in the PHP variable $classifications. The rest of the code loops through the list, pumping out list items. Each list item in this sample describes the classification rule and (in brackets) the Service Class and Report Class the rule's firing leads to.

This is all simple PHP. I chose this small part of the WLM Service Definition to format as it's an example of something that's not in RMF's Type 72 record. When I look at how customers have set up WLM I really think I need to know how the classification rules were coded.

I'm hoping this code fragment will get you thinking about the value of having the WLM Service Definition in XML form. (By the way the XML form is saved on z/OS as part of the conversion and download process – and the conversion code is very visible if you nose around a bit.)

I've written "Part I" in the title of this blog post because I think I'm going to play with some more XML-related technologies – just to show the flexibility of the approach.