As I’ve mentioned in previous posts … building tools can be a fun & rewarding part of the job.

As part of a recent programming task, I had to do some analysis on commands to determine what parameters were supported in the SQL variant of the language compiler and what parameters were not supported.

I knew that the QCDRCMDD command could extract a commands definition to XML … and a little digging determined that the JT400 object Command could do it in Java.

A little bit of XML processing and I could get some good analysis very easily…

Here’s the code I put together … it’s quite specialized … but I think it could give you some ideas:

import java.util.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
public class AnalyzeCommand {
     private static final DocumentBuilderFactory BUILDER_FACTORY = 
     public static class CompareSet {
          public String sqlCmd;
          public String nonSqlCmd;
          public CompareSet(String sqlCmd, String nonSqlCmd) {
               this.sqlCmd = sqlCmd;
               this.nonSqlCmd = nonSqlCmd;
          public String toString() {
               return sqlCmd + "/" + nonSqlCmd;
     private static final CompareSet[] CMD_SETS = new CompareSet[] {
          new CompareSet("CRTSQLRPG", "CRTRPGPGM"),
          new CompareSet("CRTSQLCBL", "CRTCBLPGM"),
          new CompareSet("CRTSQLPLI", "CRTPLIPGM"),
          new CompareSet("CRTSQLCI", "CRTBNDC"),
          new CompareSet("CRTSQLCI", "CRTCMOD"),
          new CompareSet("CRTSQLCPPI", "CRTBNDCPP"),
          new CompareSet("CRTSQLCPPI", "CRTCPPMOD"),
          new CompareSet("CRTSQLRPGI", "CRTRPGMOD"),
          new CompareSet("CRTSQLRPGI", "CRTBNDRPG"),
          new CompareSet("CRTSQLCBLI", "CRTCBLMOD"),
          new CompareSet("CRTSQLCBLI", "CRTBNDCBL"),
     * @param args
     public static void main(String[] args) {
          AnalyzeCommand rt = new AnalyzeCommand();
     private void go() {
          AS400 as400 = new AS400("", "userprofile", "password");
          CommandCall cc = new CommandCall(as400);
          try {
     "addlible qpli");
          } catch (Exception e) {
          for (CompareSet set : CMD_SETS) {
               Document nonSqlCmd = loadCommand(as400, set.nonSqlCmd);
               Document sqlCmd = loadCommand(as400, set.sqlCmd);
               List nonSqlKeywords = getParameterNames(nonSqlCmd);
               List sqlKeywords = getParameterNames(sqlCmd);
               System.out.println("Comparing " + set);
               for (String keyword : nonSqlKeywords) {
                    if (!sqlKeywords.contains(keyword)) {
                         System.out.println("t" + set.sqlCmd + " does not contain " + keyword);
//             for (String keyword : sqlKeywords) {
//                 if (!nonSqlKeywords.contains(keyword)) {
//                     System.out.println("t" + set.nonSqlCmd + " does not contain " +
//                            keyword);
//                 }
//             }
     * Extract command parameter names from dom object.
     * @param cmdDoc dom object containing parsed command
     * @return list of parameter names used on command
     private List getParameterNames(Document cmdDoc) {
          List keywords = new ArrayList();
          Node rootNode = cmdDoc.getDocumentElement().getChildNodes().item(0);
          NodeList elementList = rootNode.getChildNodes();
          for (int i=0;i<elementList.getLength();i++) {
               Node element = elementList.item(i);
               String elementName = element.getNodeName();
               if (elementName.equalsIgnoreCase("parm")) {
                    NamedNodeMap attributes = element.getAttributes();
                    Node keywordNode = attributes.getNamedItem("Kwd");
                    String keywordName = keywordNode.getNodeValue();
          return keywords;
     * Load the command, from the host, into a Dom object.
     * @param as400 host
     * @param cmdName base command name
     * @return document object containing parsed command structure
     private Document loadCommand(AS400 as400, String cmdName) {
          Document doc = null;
          String path = new QSYSObjectPathName("*LIBL", cmdName, "CMD").getPath();
          try {
               ObjectDescription od = new ObjectDescription(as400, path);
               path = od.getPath();
               Command cmd = new Command(as400, path);
               String xml = cmd.getXML();
               InputStream is = new ByteArrayInputStream(xml.getBytes());
               DocumentBuilder builder = BUILDER_FACTORY.newDocumentBuilder();
               doc = builder.parse(is);
          } catch (Exception e) {
          return doc;
About David:
David is a Principal Software Engineer for PTC, Integrity Business Unit. He cut his teeth on the S/36 and has more than 25 years of experience on the IBM i / System i / iSeries / AS400. He primarily works in Java and ILE RPG specializing in cross platform integrations. David has received the COMMON Distinguished Service award and was named an IBM Power Systems Champion. David is an active volunteer with the American Diabetes Association's Tour de Cure fundraising bike ride. He is currently captain of Team RED Chicago. David runs and maintains His personal blog is Geeky Ramblings.