1 /*****************************************************************************/
2 /* Software Testing Automation Framework (STAF)                              */
3 /* (C) Copyright IBM Corp. 2002, 2004                                        */
4 /*                                                                           */
5 /* This software is licensed under the Eclipse Public License (EPL) V1.0.    */
6 /*****************************************************************************/
7 
8 package com.ibm.staf.service.stax;
9 import org.w3c.dom.Node;
10 import org.w3c.dom.NamedNodeMap;
11 import org.w3c.dom.NodeList;
12 import com.ibm.staf.*;
13 import com.ibm.staf.service.*;
14 import java.util.Map;
15 import java.util.TreeMap;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.ArrayList;
19 import java.util.Iterator;
20 import java.util.Vector;
21 
22 public class STAXProcessActionFactory implements STAXActionFactory,
23                                                  STAXSTAFQueueListener,
24                                                  STAXListRequestHandler,
25                                                  STAXQueryRequestHandler,
26                                                  STAXGenericRequestHandler,
27                                                  STAXJobManagementHandler
28 {
29     static boolean debug = false;
30 
31     static final String STAX_PROCESS_EVENT = new String("Process");
32 
33     static final String sProcessInfoMapClassName = new String(
34         "STAF/Service/STAX/ProcessInfo");
35     static final String sQueryProcessMapClassName = new String(
36         "STAF/Service/STAX/QueryProcess");
37 
38     // Constructor
39 
STAXProcessActionFactory(STAX staxService)40     public STAXProcessActionFactory(STAX staxService)
41     {
42         staxService.registerListHandler("PROCESSES", this);
43         staxService.registerQueryHandler("PROCESS", "Location:Handle", this);
44         staxService.registerJobManagementHandler(this);
45 
46         // Set up parser that supports stopping a process or a testcase to
47         // determine if it is a STOP PROCESS or a STOP TESTCASE request
48 
49         fStopGenericParser.addOption("STOP", 1,
50                                      STAFCommandParser.VALUENOTALLOWED);
51         fStopGenericParser.addOption("JOB", 1,
52                                      STAFCommandParser.VALUEREQUIRED);
53         fStopGenericParser.addOption("PROCESS", 1,
54                                      STAFCommandParser.VALUEREQUIRED);
55         fStopGenericParser.addOption("TESTCASE", 1,
56                                      STAFCommandParser.VALUEREQUIRED);
57         fStopGenericParser.addOption("KEY", 1,
58                                      STAFCommandParser.VALUEREQUIRED);
59 
60         fStopGenericParser.addOptionNeed("STOP", "JOB");
61         fStopGenericParser.addOptionNeed("JOB", "PROCESS TESTCASE");
62         fStopGenericParser.addOptionNeed("KEY", "TESTCASE");
63 
64         fStopGenericParser.addOptionGroup("PROCESS TESTCASE", 0, 1);
65 
66         // Set up Process Stop parser
67 
68         fStopParser.addOption("STOP", 1,
69                               STAFCommandParser.VALUENOTALLOWED);
70         fStopParser.addOption("JOB", 1,
71                               STAFCommandParser.VALUEREQUIRED);
72         fStopParser.addOption("PROCESS", 1,
73                               STAFCommandParser.VALUEREQUIRED);
74 
75         fStopParser.addOptionNeed("STOP", "JOB");
76         fStopParser.addOptionNeed("JOB", "PROCESS");
77 
78         // Construct map-class for list process information
79 
80         fProcessInfoMapClass = new STAFMapClassDefinition(
81             sProcessInfoMapClassName);
82 
83         fProcessInfoMapClass.addKey("processName", "Process Name");
84         fProcessInfoMapClass.addKey("location",    "Location");
85         fProcessInfoMapClass.addKey("handle",      "Handle");
86         fProcessInfoMapClass.addKey("command",     "Command");
87         fProcessInfoMapClass.addKey("parms",       "Parms");
88 
89         // Construct map-class for query process information
90 
91         fQueryProcessMapClass = new STAFMapClassDefinition(
92             sQueryProcessMapClassName);
93 
94         fQueryProcessMapClass.addKey("processName",  "Process Name");
95         fQueryProcessMapClass.addKey("location",     "Location");
96         fQueryProcessMapClass.addKey("handle",       "Handle");
97         fQueryProcessMapClass.addKey("blockName",    "Block Name");
98         fQueryProcessMapClass.addKey("threadID",     "Thread ID");
99         fQueryProcessMapClass.addKey("startTimestamp", "Start Date-Time");
100         fQueryProcessMapClass.addKey("command",      "Command");
101         fQueryProcessMapClass.addKey("commandMode",  "Command Mode");
102         fQueryProcessMapClass.addKey("commandShell", "Command Shell");
103         fQueryProcessMapClass.addKey("parms",        "Parms");
104         fQueryProcessMapClass.addKey("title",        "Title");
105         fQueryProcessMapClass.addKey("workdir",      "Workdir");
106         fQueryProcessMapClass.addKey("workload",     "Workload");
107         fQueryProcessMapClass.addKey("varList",      "Vars");
108         fQueryProcessMapClass.addKey("envList",      "Envs");
109         fQueryProcessMapClass.addKey("useProcessVars", "Use Process Vars");
110         fQueryProcessMapClass.addKey("userName",     "User Name");
111         fQueryProcessMapClass.addKey("password",     "Password");
112         fQueryProcessMapClass.addKey("disabledAuth", "Disabled Auth");
113         fQueryProcessMapClass.addKey("stdin",        "Stdin");
114         fQueryProcessMapClass.addKey("stdoutMode",   "Stdout Mode");
115         fQueryProcessMapClass.addKey("stdoutFile",   "Stdout File");
116         fQueryProcessMapClass.addKey("stderrMode",   "Stderr Mode");
117         fQueryProcessMapClass.addKey("stderrFile",   "Stderr File");
118         fQueryProcessMapClass.addKey("returnStdout", "Return Stdout");
119         fQueryProcessMapClass.addKey("returnStderr", "Return Stderr");
120         fQueryProcessMapClass.addKey("returnFileList", "Returned Files");
121         fQueryProcessMapClass.addKey("stopUsing",    "Stop Using");
122         fQueryProcessMapClass.addKey("console",      "Console");
123         fQueryProcessMapClass.addKey("focus",        "Focus");
124         fQueryProcessMapClass.addKey("staticHandleName", "Static Handle Name");
125         fQueryProcessMapClass.addKey("other",        "Other");
126 
127         // Register as a GenericRequestHandler
128         try
129         {
130             // Assign STAFServiceInterfaceLevel class that this handler uses
131 
132             Class serviceInterfaceClass = Class.forName(STAX.INTERFACE_LEVEL_30);
133 
134             int rc = staxService.registerGenericRequestHandler(
135                 this, serviceInterfaceClass);
136 
137             if (rc != 0)
138             {
139                 STAX.logToJVMLog(
140                     "Error", "STAXProcessActionFactory: " +
141                     "registerGenericRequestHandler() failed");
142             }
143         }
144         catch (ClassNotFoundException e)
145         {
146             STAX.logToJVMLog(
147                 "Error", "STAXProcessActionFactory: " +
148                 "registerGenericRequestHandler: " + e);
149         }
150     }
151 
getName()152     public String getName() { return fName; }
153 
154     // STAXActionFactory methods
155 
getDTDInfo()156     public String getDTDInfo()
157     {
158         return fDTDInfo;
159     }
160 
getDTDTaskName()161     public String getDTDTaskName()
162     {
163         return "process";
164     }
165 
parseAction(STAX staxService, STAXJob job, org.w3c.dom.Node root)166     public STAXAction parseAction(STAX staxService, STAXJob job,
167                                   org.w3c.dom.Node root) throws STAXException
168     {
169         STAXProcessAction process = new STAXProcessAction();
170 
171         process.setActionFactory(this);
172         process.setLineNumber(root);
173         process.setXmlFile(job.getXmlFile());
174         process.setXmlMachine(job.getXmlMachine());
175 
176         NamedNodeMap rootAttrs = root.getAttributes();
177 
178         for (int i = 0; i < rootAttrs.getLength(); ++i)
179         {
180             Node thisAttr = rootAttrs.item(i);
181 
182             process.setElementInfo(new STAXElementInfo(
183                 root.getNodeName(), thisAttr.getNodeName()));
184 
185             if (thisAttr.getNodeName().equals("name"))
186             {
187                 process.setName(
188                     STAXUtil.parseAndCompileForPython(
189                         thisAttr.getNodeValue(), process));
190             }
191         }
192 
193         NodeList children = root.getChildNodes();
194 
195         for (int i = 0; i < children.getLength(); ++i)
196         {
197             Node thisChild = children.item(i);
198 
199             if (thisChild.getNodeType() == Node.COMMENT_NODE)
200             {
201                 /* Do nothing */
202             }
203             else if (thisChild.getNodeType() == Node.ELEMENT_NODE)
204             {
205                 if (thisChild.getNodeName().equals("envs"))
206                     process.setLineNumber(thisChild, "env");
207                 else if (thisChild.getNodeName().equals("vars"))
208                     process.setLineNumber(thisChild, "var");
209                 else if (thisChild.getNodeName().equals("returnfiles"))
210                     process.setLineNumber(thisChild, "returnfile");
211                 else
212                     process.setLineNumber(thisChild);
213 
214                 if (thisChild.getNodeName().equals("location"))
215                 {
216                     process.setLocation(handleChild(thisChild, process));
217                 }
218                 else if (thisChild.getNodeName().equals("command"))
219                 {
220                     NamedNodeMap attrs = thisChild.getAttributes();
221 
222                     for (int j = 0; j < attrs.getLength(); ++j)
223                     {
224                         Node thisAttr = attrs.item(j);
225 
226                         process.setElementInfo(new STAXElementInfo(
227                             thisChild.getNodeName(), thisAttr.getNodeName()));
228 
229                         if (thisAttr.getNodeName().equals("mode"))
230                         {
231                             String mode = STAXUtil.parseAndCompileForPython(
232                                 thisAttr.getNodeValue(), process);
233 
234                             process.setCommandMode(mode);
235                         }
236                         else if (thisAttr.getNodeName().equals("shell"))
237                         {
238                             String shell = STAXUtil.parseAndCompileForPython(
239                                 thisAttr.getNodeValue(), process);
240 
241                             process.setCommandShell(shell);
242                         }
243                     }
244 
245                     process.setCommand(handleChild(thisChild, process));
246                 }
247                 else if (thisChild.getNodeName().equals("workload"))
248                 {
249                     process.setWorkload(
250                         handleChild(thisChild, process),
251                         handleIfAttribute(thisChild, process));
252                 }
253                 else if (thisChild.getNodeName().equals("title"))
254                 {
255                     process.setTitle(
256                         handleChild(thisChild, process),
257                         handleIfAttribute(thisChild, process));
258                 }
259                 else if (thisChild.getNodeName().equals("parms"))
260                 {
261                     process.setParms(
262                         handleChild(thisChild, process),
263                         handleIfAttribute(thisChild, process));
264                 }
265                 else if (thisChild.getNodeName().equals("workdir"))
266                 {
267                     process.setWorkdir(
268                         handleChild(thisChild, process),
269                         handleIfAttribute(thisChild, process));
270                 }
271                 else if (thisChild.getNodeName().equals("vars"))
272                 {
273                     process.setVars(
274                         handleChild(thisChild, process, "var"),
275                         handleIfAttribute(thisChild, process, "var"));
276                 }
277                 else if (thisChild.getNodeName().equals("var"))
278                 {
279                     process.setVars(
280                         handleChild(thisChild, process),
281                         handleIfAttribute(thisChild, process));
282                 }
283                 else if (thisChild.getNodeName().equals("envs"))
284                 {
285                     process.setEnvs(
286                         handleChild(thisChild, process, "env"),
287                         handleIfAttribute(thisChild, process, "env"));
288                 }
289                 else if (thisChild.getNodeName().equals("env"))
290                 {
291                     process.setEnvs(
292                         handleChild(thisChild, process),
293                         handleIfAttribute(thisChild, process));
294                 }
295                 else if (thisChild.getNodeName().equals("useprocessvars"))
296                 {
297                     process.setUseprocessvars(
298                         "useprocessvars",
299                         handleIfAttribute(thisChild, process));
300                 }
301                 else if (thisChild.getNodeName().equals("stopusing"))
302                 {
303                     process.setStopusing(
304                         handleChild(thisChild, process),
305                         handleIfAttribute(thisChild, process));
306                 }
307                 else if (thisChild.getNodeName().equals("console"))
308                 {
309                     String ifValue = new String();
310                     String useValue = new String();
311 
312                     NamedNodeMap attrs = thisChild.getAttributes();
313 
314                     for (int j = 0; j < attrs.getLength(); ++j)
315                     {
316                         Node thisAttr = attrs.item(j);
317 
318                         process.setElementInfo(new STAXElementInfo(
319                             thisChild.getNodeName(), thisAttr.getNodeName()));
320 
321                         if (thisAttr.getNodeName().equals("if"))
322                             ifValue = STAXUtil.parseAndCompileForPython(
323                                       thisAttr.getNodeValue(), process);
324                         else if (thisAttr.getNodeName().equals("use"))
325                             useValue = STAXUtil.parseAndCompileForPython(
326                                        thisAttr.getNodeValue(), process);
327                     }
328 
329                     process.setConsole(useValue, ifValue);
330                 }
331                 else if (thisChild.getNodeName().equals("focus"))
332                 {
333                     String ifValue = new String();
334                     String modeValue = new String();
335 
336                     NamedNodeMap attrs = thisChild.getAttributes();
337 
338                     for (int j = 0; j < attrs.getLength(); ++j)
339                     {
340                         Node thisAttr = attrs.item(j);
341 
342                         process.setElementInfo(new STAXElementInfo(
343                             thisChild.getNodeName(), thisAttr.getNodeName()));
344 
345                         if (thisAttr.getNodeName().equals("if"))
346                             ifValue = STAXUtil.parseAndCompileForPython(
347                                       thisAttr.getNodeValue(), process);
348                         else if (thisAttr.getNodeName().equals("mode"))
349                             modeValue = STAXUtil.parseAndCompileForPython(
350                                         thisAttr.getNodeValue(), process);
351                     }
352 
353                     process.setFocus(modeValue, ifValue);
354                 }
355                 else if (thisChild.getNodeName().equals("username"))
356                 {
357                     process.setUsername(
358                         handleChild(thisChild, process),
359                         handleIfAttribute(thisChild, process));
360                 }
361                 else if (thisChild.getNodeName().equals("password"))
362                 {
363                     process.setPassword(
364                         handleChild(thisChild, process),
365                         handleIfAttribute(thisChild, process));
366                 }
367                 else if (thisChild.getNodeName().equals("disabledauth"))
368                 {
369                     String ifValue = new String();
370                     String actionValue = new String();
371 
372                     NamedNodeMap attrs = thisChild.getAttributes();
373 
374                     for (int j = 0; j < attrs.getLength(); ++j)
375                     {
376                         Node thisAttr = attrs.item(j);
377 
378                         process.setElementInfo(new STAXElementInfo(
379                             thisChild.getNodeName(), thisAttr.getNodeName()));
380 
381                         if (thisAttr.getNodeName().equals("if"))
382                             ifValue = STAXUtil.parseAndCompileForPython(
383                                       thisAttr.getNodeValue(), process);
384                         else if (thisAttr.getNodeName().equals("action"))
385                             actionValue = STAXUtil.parseAndCompileForPython(
386                                           thisAttr.getNodeValue(), process);
387                     }
388 
389                     process.setDisabledauth(actionValue, ifValue);
390                 }
391                 else if (thisChild.getNodeName().equals("statichandlename"))
392                 {
393                     process.setStatichandlename(
394                         handleChild(thisChild, process),
395                         handleIfAttribute(thisChild, process));
396                 }
397                 else if (thisChild.getNodeName().equals("stdin"))
398                 {
399                     process.setStdin(
400                         handleChild(thisChild, process),
401                         handleIfAttribute(thisChild, process));
402                 }
403                 else if (thisChild.getNodeName().equals("stdout"))
404                 {
405                     String ifValue = new String();
406                     String modeValue = new String();
407 
408                     NamedNodeMap attrs = thisChild.getAttributes();
409 
410                     for (int j = 0; j < attrs.getLength(); ++j)
411                     {
412                         Node thisAttr = attrs.item(j);
413 
414                         process.setElementInfo(new STAXElementInfo(
415                             thisChild.getNodeName(), thisAttr.getNodeName()));
416 
417                         if (thisAttr.getNodeName().equals("if"))
418                             ifValue = STAXUtil.parseAndCompileForPython(
419                                       thisAttr.getNodeValue(), process);
420                         else if (thisAttr.getNodeName().equals("mode"))
421                             modeValue = STAXUtil.parseAndCompileForPython(
422                                         thisAttr.getNodeValue(), process);
423                     }
424 
425                     process.setStdout(handleChild(thisChild, process),
426                                       modeValue, ifValue);
427                 }
428                 else if (thisChild.getNodeName().equals("stderr"))
429                 {
430                     String ifValue = new String();
431                     String modeValue = new String();
432 
433                     NamedNodeMap attrs = thisChild.getAttributes();
434 
435                     for (int j = 0; j < attrs.getLength(); ++j)
436                     {
437                         Node thisAttr = attrs.item(j);
438 
439                         process.setElementInfo(new STAXElementInfo(
440                             thisChild.getNodeName(), thisAttr.getNodeName()));
441 
442                         if (thisAttr.getNodeName().equals("if"))
443                             ifValue = STAXUtil.parseAndCompileForPython(
444                                       thisAttr.getNodeValue(), process);
445                         else if (thisAttr.getNodeName().equals("mode"))
446                             modeValue = STAXUtil.parseAndCompileForPython(
447                                         thisAttr.getNodeValue(), process);
448                     }
449 
450                     process.setStderr(handleChild(thisChild, process),
451                                       modeValue, ifValue);
452                 }
453                 else if (thisChild.getNodeName().equals("returnstdout"))
454                 {
455                     process.setReturnStdout(
456                         "returnstdout",
457                         handleIfAttribute(thisChild, process));
458                 }
459                 else if (thisChild.getNodeName().equals("returnstderr"))
460                 {
461                     process.setReturnStderr(
462                         "returnstderr",
463                         handleIfAttribute(thisChild, process));
464                 }
465                 else if (thisChild.getNodeName().equals("returnfile"))
466                 {
467                     process.setReturnFiles(
468                         handleChild(thisChild, process),
469                         handleIfAttribute(thisChild, process));
470                 }
471                 else if (thisChild.getNodeName().equals("returnfiles"))
472                 {
473                     process.setReturnFiles(
474                         handleChild(thisChild, process, "returnfile"),
475                         handleIfAttribute(thisChild, process, "returnfile"));
476                 }
477                 else if (thisChild.getNodeName().equals("other"))
478                 {
479                     process.setOther(
480                         handleChild(thisChild, process),
481                         handleIfAttribute(thisChild, process));
482                 }
483                 else if (thisChild.getNodeName().equals("process-action"))
484                 {
485                     String ifValue = new String();
486 
487                     NamedNodeMap attrs = thisChild.getAttributes();
488 
489                     for (int j = 0; j < attrs.getLength(); ++j)
490                     {
491                         Node thisAttr = attrs.item(j);
492 
493                         process.setElementInfo(new STAXElementInfo(
494                             thisChild.getNodeName(), thisAttr.getNodeName()));
495 
496                         if (thisAttr.getNodeName().equals("if"))
497                             ifValue = STAXUtil.parseAndCompileForPython(
498                                       thisAttr.getNodeValue(), process);
499                     }
500 
501                     NodeList processActionChildren = thisChild.getChildNodes();
502 
503                     STAXAction processAction = null;
504 
505                     for (int j = 0; j < processActionChildren.getLength(); ++j)
506                     {
507                         Node processActionChild =
508                             processActionChildren.item(j);
509 
510                         if (processActionChild.getNodeType() ==
511                             Node.COMMENT_NODE)
512                         {
513                             /* Do nothing */
514                         }
515                         else if (processActionChild.getNodeType() ==
516                             Node.ELEMENT_NODE)
517                         {
518                             if (processAction != null)
519                             {
520                                 process.setElementInfo(
521                                     new STAXElementInfo(
522                                         thisChild.getNodeName(),
523                                         STAXElementInfo.NO_ATTRIBUTE_NAME,
524                                         STAXElementInfo.LAST_ELEMENT_INDEX,
525                                         "Invalid element type \"" +
526                                         processActionChild.getNodeName() +
527                                         "\""));
528 
529                                 throw new STAXInvalidXMLElementCountException(
530                                     STAXUtil.formatErrorMessage(process),
531                                     process);
532                             }
533 
534                             STAXActionFactory factory =
535                                 staxService.getActionFactory(
536                                 processActionChild.getNodeName());
537 
538                             if (factory == null)
539                             {
540                                 process.setElementInfo(new STAXElementInfo(
541                                     thisChild.getNodeName(),
542                                     STAXElementInfo.NO_ATTRIBUTE_NAME,
543                                     STAXElementInfo.LAST_ELEMENT_INDEX,
544                                     "No action factory for element type \"" +
545                                     processActionChild.getNodeName() + "\""));
546 
547                                 throw new STAXInvalidXMLElementException(
548                                     STAXUtil.formatErrorMessage(process),
549                                     process);
550                             }
551 
552                             processAction = factory.parseAction(staxService,
553                                 job, processActionChild);
554                         }
555                     }
556 
557                     process.setProcessAction(processAction, ifValue);
558                 }
559             }
560             else
561             {
562                 process.setElementInfo(new STAXElementInfo(
563                     root.getNodeName(), STAXElementInfo.NO_ATTRIBUTE_NAME,
564                     STAXElementInfo.LAST_ELEMENT_INDEX,
565                     "Contains invalid node type: " +
566                     Integer.toString(thisChild.getNodeType())));
567 
568                 throw new STAXInvalidXMLNodeTypeException(
569                     STAXUtil.formatErrorMessage(process), process);
570             }
571         }
572 
573         return process;
574     }
575 
handleIfAttribute(Node thisChild, STAXProcessAction action)576     private String handleIfAttribute(Node thisChild, STAXProcessAction action)
577                                      throws STAXException
578     {
579         return handleIfAttribute(thisChild,action, thisChild.getNodeName());
580     }
581 
handleIfAttribute(Node thisChild, STAXProcessAction action, String elementName)582     private String handleIfAttribute(Node thisChild, STAXProcessAction action,
583                                      String elementName)
584                                      throws STAXException
585     {
586         String ifValue = new String();
587 
588         NamedNodeMap attrs = thisChild.getAttributes();
589 
590         for (int i = 0; i < attrs.getLength(); ++i)
591         {
592             Node thisAttr = attrs.item(i);
593 
594             action.setElementInfo(new STAXElementInfo(
595                 elementName, thisAttr.getNodeName(),
596                 STAXElementInfo.LAST_ELEMENT_INDEX));
597 
598             if (thisAttr.getNodeName().equals("if"))
599                 ifValue = STAXUtil.parseAndCompileForPython(
600                     thisAttr.getNodeValue(), action);
601         }
602 
603         return ifValue;
604     }
605 
handleChild(Node root, STAXProcessAction action)606     private String handleChild(Node root, STAXProcessAction action)
607                                throws STAXException
608     {
609         return handleChild(root, action, root.getNodeName());
610     }
611 
handleChild(Node root, STAXProcessAction action, String elementName)612     private String handleChild(Node root, STAXProcessAction action,
613                                String elementName)
614                                throws STAXException
615     {
616         NodeList children = root.getChildNodes();
617 
618         for (int i = 0; i < children.getLength(); ++i)
619         {
620             Node thisChild = children.item(i);
621 
622             // XXX: Should I be able to have a COMMENT_NODE here?
623 
624             if (thisChild.getNodeType() == Node.COMMENT_NODE)
625             {
626                 /* Do nothing */
627             }
628             else if (thisChild.getNodeType() == Node.TEXT_NODE)
629             {
630                 action.setElementInfo(new STAXElementInfo(
631                     elementName, STAXElementInfo.NO_ATTRIBUTE_NAME,
632                     STAXElementInfo.LAST_ELEMENT_INDEX));
633 
634                 return STAXUtil.parseAndCompileForPython(
635                     thisChild.getNodeValue(), action);
636             }
637             else if (thisChild.getNodeType() == Node.CDATA_SECTION_NODE)
638             {
639                 /* Do nothing */
640             }
641             else
642             {
643                 action.setElementInfo(
644                     new STAXElementInfo(
645                         elementName, STAXElementInfo.NO_ATTRIBUTE_NAME,
646                         STAXElementInfo.LAST_ELEMENT_INDEX,
647                         Integer.toString(thisChild.getNodeType())));
648 
649                 throw new STAXInvalidXMLNodeTypeException(
650                     STAXUtil.formatErrorMessage(action), action);
651             }
652         }
653 
654         return new String();
655     }
656 
657 
658     // STAXSTAFQueueListener methods
659 
handleQueueMessage(STAXSTAFMessage message, STAXJob job)660     public void handleQueueMessage(STAXSTAFMessage message, STAXJob job)
661     {
662         // XXX: How to make sure that the machine they registered
663         //      with is the machine on the queue (long vs. short
664         //      names)?  Maybe try
665         //          a.startsWith(b) || b.startsWith(a)
666 
667         String machine = message.getMachine();
668         int handle = message.getProcessHandle();
669 
670         String key = "";
671 
672         if (!message.getProcessKey().equals(""))
673         {
674             key = message.getProcessKey();
675         }
676         else
677         {
678             // XXX Does lower casing the machine name cause any other problems?
679             key = (machine + "/" + handle).toLowerCase();
680         }
681 
682         @SuppressWarnings("unchecked")
683         HashMap<String, Object> processMap =
684             (HashMap<String, Object>)job.getData("processMap");
685 
686         if (processMap == null)
687         {
688             // Could occur if job is being terminated
689             return;
690         }
691 
692         synchronized (processMap)
693         {
694             STAXProcessCompleteListener listener =
695                 (STAXProcessCompleteListener)processMap.get(key);
696 
697             if (listener != null)
698             {
699                 if (debug)
700                 {
701                     STAX.logToJVMLog(
702                         "Debug", job.getJobNumber(),
703                         "ProcessActionFactory::handleQueueMessages() - " +
704                         "Remove from processMap");
705                 }
706 
707                 listener.processComplete(
708                     machine, handle, message.getProcessRC(),
709                     message.getProcessResultAsList(),
710                     message.getProcessTimestamp());
711 
712                 processMap.remove(key);
713             }
714             else
715             {
716                 // Log a warning message in the job log
717 
718                 if (debug)
719                 {
720                     String msg = "STAXProcessActionFactory.handle" +
721                         "QueueMessage: No listener found for message:\n" +
722                         STAFMarshallingContext.unmarshall(
723                             message.getResult()).toString();
724 
725                     msg += "\nCurrentKeys=";
726 
727                     Iterator iter = processMap.keySet().iterator();
728 
729                     while (iter.hasNext())
730                     {
731                         msg += iter.next() + ";";
732                     }
733 
734                     job.log(STAXJob.JOB_LOG, "warning", msg);
735 
736                     STAX.logToJVMLog(
737                         "Debug", job.getJobNumber(),
738                         "ProcessActionFactory::handleQueueMessages() - " +
739                         "Add to processMap");
740                 }
741 
742                 // If we received the "process end" message before we placed
743                 // the machine/handle in the process map, just save the key
744                 // and the message in the process map.  When STAXProcessAction
745                 // receives the requestComplete message, since the key already
746                 // exists, it will just remove it.
747 
748                 processMap.put(key.toLowerCase(), message);
749             }
750         }
751     }
752 
753 
754     // STAXJobManagement methods
755 
initJob(STAXJob job)756     public void initJob(STAXJob job)
757     {
758         boolean result = job.setData("processMap", new HashMap<String, Object>());
759 
760         if (!result)
761         {
762             String msg = "STAXProcessActionFactory.initJob: setData for " +
763                          "processMap failed.";
764             job.log(STAXJob.JOB_LOG, "error", msg);
765         }
766 
767         result = job.setData("processRequestMap",
768                              new TreeMap<String, STAXProcessAction>());
769 
770         if (!result)
771         {
772             String msg = "STAXProcessActionFactory.initJob: setData for " +
773                          "processRequestMap failed.";
774             job.log(STAXJob.JOB_LOG, "error", msg);
775         }
776 
777         job.registerSTAFQueueListener("STAF/Process/End", this);
778     }
779 
terminateJob(STAXJob job)780     public void terminateJob(STAXJob job)
781     { /* Do Nothing */ }
782 
783 
784     // STAXListRequestHandler method
785 
handleListRequest(String type, STAXJob job, STAXRequestSettings settings)786     public STAFResult handleListRequest(String type, STAXJob job,
787                                         STAXRequestSettings settings)
788     {
789         if (type.equalsIgnoreCase("processes"))
790         {
791             // LIST JOB <Job ID> PROCESSES
792 
793             // Create the marshalling context and set its map class definitions
794             // and create an empty list to contain the block map entries
795 
796             STAFMarshallingContext mc = new STAFMarshallingContext();
797             mc.setMapClassDefinition(fProcessInfoMapClass);
798             List<Map<String, Object>> processOutputList =
799                 new ArrayList<Map<String, Object>>();
800 
801             // Iterate through the process map, generating the output list
802 
803             TreeMap processes = (TreeMap)job.getData("processRequestMap");
804 
805             if (processes != null)
806             {
807                 synchronized (processes)
808                 {
809                     Iterator iter = processes.values().iterator();
810 
811                     while (iter.hasNext())
812                     {
813                         STAXProcessAction process =
814                             (STAXProcessAction)iter.next();
815 
816                         Map<String, Object> processMap =
817                             new TreeMap<String, Object>();
818                         processMap.put("staf-map-class-name",
819                                        fProcessInfoMapClass.name());
820                         processMap.put("processName", process.getName());
821                         processMap.put("location", process.getLocation());
822                         processMap.put(
823                             "handle", "" + process.getProcessHandle());
824                         processMap.put(
825                             "command", STAFUtil.maskPrivateData(
826                                 process.getCommand()));
827                         processMap.put(
828                             "parms", STAFUtil.maskPrivateData(
829                                 process.getParms()));
830 
831                         processOutputList.add(processMap);
832                     }
833                 }
834             }
835 
836             mc.setRootObject(processOutputList);
837 
838             return new STAFResult(STAFResult.Ok, mc.marshall());
839         }
840         else
841             return new STAFResult(STAFResult.DoesNotExist, type);
842     }
843 
844     // STAXQueryRequestHandler methods
845 
handleQueryRequest(String type, String key, STAXJob job, STAXRequestSettings settings)846     public STAFResult handleQueryRequest(String type, String key, STAXJob job,
847                                          STAXRequestSettings settings)
848     {
849         if (type.equalsIgnoreCase("process"))
850         {
851             // QUERY JOB <Job ID> PROCESS <Location:Handle>
852 
853             // Create the marshalling context and set its map class definition
854 
855             STAFMarshallingContext mc = new STAFMarshallingContext();
856             mc.setMapClassDefinition(fQueryProcessMapClass);
857 
858             key = key.toLowerCase();
859 
860             TreeMap processes = (TreeMap)job.getData("processRequestMap");
861 
862             if (processes == null)
863                 return new STAFResult(STAFResult.DoesNotExist, key);
864 
865             STAXProcessAction process = null;
866 
867             synchronized (processes)
868             {
869                 process = (STAXProcessAction)processes.get(key);
870             }
871 
872             if (process == null)
873                 return new STAFResult(STAFResult.DoesNotExist, key);
874 
875             Map<String, Object> processMap = new TreeMap<String, Object>();
876             processMap.put("staf-map-class-name",
877                            fQueryProcessMapClass.name());
878             processMap.put("processName", process.getName());
879             processMap.put("location", process.getLocation());
880             processMap.put("handle", "" + process.getProcessHandle());
881             processMap.put("blockName", process.getCurrentBlockName());
882             processMap.put("threadID",
883                            "" + process.getThread().getThreadNumber());
884             processMap.put("startTimestamp", process.getStartTimestamp().
885                            getTimestampString());
886             processMap.put("command",
887                            STAFUtil.maskPrivateData(process.getCommand()));
888 
889             // The rest of the process elements are optional.
890 
891             if (!process.getCommandMode().equals(""))
892                 processMap.put("commandMode", process.getCommandMode());
893 
894             if (!process.getCommandShell().equals(""))
895                 processMap.put("commandShell", process.getCommandShell());
896 
897             if (!process.getParms().equals(""))
898                 processMap.put("parms",
899                                STAFUtil.maskPrivateData(process.getParms()));
900 
901             if (!process.getTitle().equals(""))
902                 processMap.put("title", process.getTitle());
903 
904             if (!process.getWorkdir().equals(""))
905                 processMap.put("workdir", process.getWorkdir());
906 
907             if (!process.getWorkload().equals(""))
908                 processMap.put("workload", process.getWorkload());
909 
910             List<String> varList = new ArrayList<String>();
911             Vector<String> vars = process.getVars();
912 
913             for (int i = 0; i < vars.size(); i++)
914             {
915                 varList.add(vars.elementAt(i));
916             }
917 
918             processMap.put("varList", varList);
919 
920             List<String> envList = new ArrayList<String>();
921             Vector<String> envs = process.getEnvs();
922 
923             for (int i = 0; i < envs.size(); i++)
924             {
925                 envList.add(envs.elementAt(i));
926             }
927 
928             processMap.put("envList", envList);
929 
930             if (!process.getUseprocessvars().equals(""))
931                 processMap.put("useProcessVars", "true");
932 
933             if (!process.getUsername().equals(""))
934                 processMap.put("userName", process.getUsername());
935 
936             // Mask the true value for the password
937             if (!process.getPassword().equals(""))
938                 processMap.put("password", "*******");
939 
940             if (!process.getDisabledauth().equals(""))
941                 processMap.put("disabledAuth", process.getDisabledauth());
942 
943             if (!process.getStdin().equals(""))
944                 processMap.put("stdin", process.getStdin());
945 
946             if (!process.getStdout().equals(""))
947             {
948                 processMap.put("stdoutMode", process.getStdoutMode());
949                 processMap.put("stdoutFile", process.getStdout());
950             }
951 
952             if (!process.getStderr().equals(""))
953                 processMap.put("stderrFile", process.getStderr());
954 
955             if (!process.getStderrMode().equals(""))
956                 processMap.put("stderrMode", process.getStderrMode());
957 
958             if (!process.getReturnStdout().equals(""))
959                 processMap.put("returnStdout", "true");
960 
961             if (!process.getReturnStderr().equals(""))
962                 processMap.put("returnStderr", "true");
963 
964             List<String> returnFileList = new ArrayList<String>();
965             Vector<String> returnfiles = process.getReturnFiles();
966 
967             for (int i = 0; i < returnfiles.size(); i++)
968             {
969                 returnFileList.add(returnfiles.elementAt(i));
970             }
971 
972             processMap.put("returnFileList", returnFileList);
973 
974             if (!process.getStopusing().equals(""))
975                 processMap.put("stopUsing", process.getStopusing());
976 
977             if (!process.getConsole().equals(""))
978                 processMap.put("console", process.getConsole());
979 
980             if (!process.getFocus().equals(""))
981                 processMap.put("focus", process.getFocus());
982 
983             if (!process.getStatichandlename().equals(""))
984                 processMap.put("staticHandleName",
985                                process.getStatichandlename());
986 
987             if (!process.getOther().equals(""))
988                 processMap.put("other", process.getOther());
989 
990             mc.setRootObject(processMap);
991 
992             return new STAFResult(STAFResult.Ok, mc.marshall());
993         }
994         else
995             return new STAFResult(STAFResult.DoesNotExist, type);
996     }
997 
handleQueryJobRequest(STAXJob job, STAXRequestSettings settings)998     public STAFResult handleQueryJobRequest(STAXJob job,
999                                             STAXRequestSettings settings)
1000     {
1001         return new STAFResult(STAFResult.Ok, "");
1002     }
1003 
1004     // STAXGenericRequestHandler Interface Methods
1005 
handleRequest(Object infoObject, STAX staxService)1006     public STAFResult handleRequest(Object infoObject, STAX staxService)
1007     {
1008         STAFServiceInterfaceLevel30.RequestInfo info =
1009             (STAFServiceInterfaceLevel30.RequestInfo)infoObject;
1010 
1011         String lowerRequest = info.request.toLowerCase();
1012 
1013         if (lowerRequest.startsWith("stop"))
1014         {
1015             // Need to make sure that the STAXTestcaseActionFactory gets a
1016             // chance to handle a STOP TESTCASE request so using a parser
1017             // that supports either a STOP PROCESS or STOP TESTCASE request.
1018 
1019             // XXX: A better way of determining if it is a STOP PROCESS or
1020             // STOP TESTCASE request would be nice because now if the syntax
1021             // of a STOP TESTCASE request changes, have to make the same
1022             // change to the fStopGenericParser here.
1023 
1024             STAFCommandParseResult parseResult = fStopGenericParser.parse(
1025                 info.request);
1026 
1027             if (parseResult.rc != STAFResult.Ok)
1028             {
1029                 return new STAFResult(STAFResult.InvalidRequestString,
1030                                       parseResult.errorBuffer);
1031             }
1032 
1033             if (parseResult.optionTimes("TESTCASE") > 0)
1034             {
1035                 // This is a STOP TESTCASE request, not a STOP PROCESS request.
1036                 // Returning nothing in the result indicates that this parser
1037                 // does not support this request.
1038                 return new STAFResult(STAFResult.InvalidRequestString, "");
1039             }
1040 
1041             return handleStopRequest(info, staxService);
1042         }
1043         else
1044         {   // Returning nothing in the result indicates that this parser
1045             // does not support this request.
1046             return new STAFResult(STAFResult.InvalidRequestString, "");
1047         }
1048     }
1049 
handleStopRequest( STAFServiceInterfaceLevel30.RequestInfo info, STAX staxService)1050     private STAFResult handleStopRequest(
1051         STAFServiceInterfaceLevel30.RequestInfo info, STAX staxService)
1052     {
1053         // Verify the requesting machine/user has at least trust level 5
1054 
1055         STAFResult trustResult = STAFUtil.validateTrust(
1056             4, staxService.getServiceName(), "STOP",
1057             staxService.getLocalMachineName(), info);
1058 
1059         if (trustResult.rc != STAFResult.Ok) return trustResult;
1060 
1061         // Parse the request
1062 
1063         STAFCommandParseResult parseResult= fStopParser.parse(info.request);
1064 
1065         if (parseResult.rc != STAFResult.Ok)
1066         {
1067             return new STAFResult(STAFResult.InvalidRequestString,
1068                                   parseResult.errorBuffer);
1069         }
1070 
1071         // Resolve the value specified for JOB and get its integer value
1072 
1073         STAFResult res = STAFUtil.resolveRequestVarAndCheckInt(
1074             "JOB", parseResult.optionValue("JOB"),
1075             staxService.getSTAFHandle(), info.requestNumber);
1076 
1077         if (res.rc != 0) return res;
1078 
1079         Integer jobID = new Integer(res.result);
1080 
1081         // Verify that the JOB ID is a currently active job
1082 
1083         STAXJob job = null;
1084 
1085         job = (STAXJob)staxService.getJobMap().get(jobID);
1086 
1087         if (job == null)
1088         {
1089             return new STAFResult(
1090                 STAFResult.DoesNotExist,
1091                 "Job " + jobID + " is not currently running.");
1092         }
1093 
1094         // Resolve the value specified for PROCESS
1095 
1096         res = STAFUtil.resolveRequestVar(
1097             parseResult.optionValue("PROCESS"),
1098             staxService.getSTAFHandle(), info.requestNumber);
1099 
1100         if (res.rc != 0) return res;
1101 
1102         String processKey = res.result;
1103 
1104         // Verify that the process is a currently active process
1105         // (according to STAX)
1106 
1107         STAXProcessAction processAction = null;
1108         TreeMap processes = (TreeMap)job.getData("processRequestMap");
1109 
1110         if (processes != null)
1111         {
1112             synchronized (processes)
1113             {
1114                 processAction = (STAXProcessAction)processes.get(processKey);
1115             }
1116         }
1117 
1118         if (processAction == null)
1119         {
1120             return new STAFResult(
1121                 STAFResult.DoesNotExist,
1122                 "The specified process (" + processKey + ") does not exist." +
1123                 "  Note its format must be: <location>:<handle#>");
1124         }
1125 
1126         String location = processAction.getLocation();
1127         int processHandle = processAction.getProcessHandle();
1128 
1129         long processRC = 0;  // Assume 0 if cannot obtain
1130         String stopTimestamp = "";
1131 
1132         // Stop the STAF process (if still running) by submitting a
1133         // PROCESS STOP HANDLE request on the machine where the process is
1134         // running.
1135 
1136         res = job.submitSync(
1137             location, "PROCESS", "QUERY HANDLE " + processHandle);
1138 
1139         if (debug)
1140         {
1141             STAX.logToJVMLog(
1142                 "Debug", job.getJobNumber(),
1143                 "STAXProcessActionFactory::handleStopRequest: " +
1144                 "PROCESS QUERY HANDLE " + processHandle + ", RC=" + res.rc);
1145         }
1146 
1147         if (res.rc == STAFResult.Ok)
1148         {
1149             // If the process is complete (indicated by rc = null),
1150             // get the process's completion info (RC and stopTimestamp)
1151 
1152             Map processMap = (Map)res.resultObj;
1153             String processRCString = (String)processMap.get("rc");
1154 
1155             if (processRCString != null)
1156             {
1157                 processRC = Long.parseLong(processRCString);
1158                 stopTimestamp = (String)processMap.get("endTimestamp");
1159             }
1160             else
1161             {
1162                 // Process is not yet complete, so stop it
1163 
1164                 res = job.submitSync(
1165                     location, "PROCESS", "STOP HANDLE " + processHandle);
1166 
1167                 if (debug)
1168                 {
1169                     STAX.logToJVMLog(
1170                         "Debug", job.getJobNumber(),
1171                         "STAXProcessActionFactory::handleStopRequest: " +
1172                         "PROCESS STOP HANDLE " + processHandle +
1173                         ", RC=" + res.rc);
1174                 }
1175 
1176                 if (res.rc == STAFResult.Ok)
1177                 {
1178                     // Delay to allow the STAF/Process/End message (generated
1179                     // by the PROCESS STOP HANDLE request) to be sent to the
1180                     // STAX service machine and processed.
1181 
1182                     try
1183                     {
1184                         Thread.sleep(1000);   // Sleep 1 second
1185                     }
1186                     catch (InterruptedException ex)
1187                     { }
1188 
1189                     // Now check if the handle exists (just in case the
1190                     // STAF/Process/End message was not successfully sent)
1191 
1192                     res = job.submitSync(
1193                         location, "PROCESS", "QUERY HANDLE " + processHandle);
1194 
1195                     if (debug)
1196                     {
1197                         STAX.logToJVMLog(
1198                             "Debug", job.getJobNumber(),
1199                             "STAXProcessActionFactory::handleStopRequest: " +
1200                             "PROCESS QUERY HANDLE " + processHandle +
1201                             ", RC=" + res.rc);
1202                     }
1203 
1204                     if (res.rc == STAFResult.Ok)
1205                     {
1206                         // Get the process's completion info (RC and
1207                         // stopTimestamp)
1208 
1209                         processMap = (Map)res.resultObj;
1210                         processRCString = (String)processMap.get("rc");
1211 
1212                         if (processRCString != null)
1213                         {
1214                             processRC = Long.parseLong(processRCString);
1215                             stopTimestamp = (String)processMap.get(
1216                                 "endTimestamp");
1217                         }
1218                     }
1219                     else if (res.rc == STAFResult.HandleDoesNotExist)
1220                     {
1221                         // The process handle no longer exists so the
1222                         // STAF/Process/End message was successfully sent to
1223                         // the STAX service machine and processed so we can
1224                         // return.
1225 
1226                         return new STAFResult(STAFResult.Ok);
1227                     }
1228                 }
1229             }
1230         }
1231 
1232         if (stopTimestamp.length() == 0)
1233         {
1234             // Assign the current timestamp as the time the process was stopped
1235 
1236             stopTimestamp = (new STAXTimestamp()).getTimestampString();
1237         }
1238 
1239         // Assign an null fileList since no file data returned by the process
1240         // is available to us
1241 
1242         List fileList = null;
1243 
1244         // Note that if this process has an active process-action, stopping
1245         // the process does not "terminate" the process-action.,
1246 
1247         // Notify STAX that the process is complete
1248 
1249         processAction.processComplete(
1250             location, processHandle, processRC, fileList, stopTimestamp);
1251 
1252         return new STAFResult(STAFResult.Ok);
1253     }
1254 
getHelpInfo(String lineSep)1255     public String getHelpInfo(String lineSep)
1256     {
1257         return "STOP      JOB <Job ID> PROCESS <Location:Handle>";
1258     }
1259 
1260     private String fName;
1261     private STAFMapClassDefinition fProcessInfoMapClass;
1262     private STAFMapClassDefinition fQueryProcessMapClass;
1263     private STAFCommandParser fStopParser = new STAFCommandParser();
1264     private STAFCommandParser fStopGenericParser = new STAFCommandParser();
1265 
1266     private static String fDTDInfo =
1267 "\n" +
1268 "<!--================= The STAF Process Element ===================== -->\n" +
1269 "<!--\n" +
1270 "     Specifies a STAF process to be started.\n" +
1271 "     All of its non-empty element values are evaluated via Python.\n" +
1272 "-->\n" +
1273 "<!ENTITY % procgroup1 '((parms?, workdir?) | (workdir?, parms?))'>\n" +
1274 "<!ENTITY % procgroup2 '((title?, workload?) | (workload?, title?))'>\n" +
1275 "<!ENTITY % procgroup1a '((parms?, workload?) | (workload?, parms?))'>\n" +
1276 "<!ENTITY % procgroup2a '((title?, workdir?) | (workdir?, title?))'>\n" +
1277 "<!ENTITY % procgroup3 '(((vars | var | envs | env)*, useprocessvars?) |\n" +
1278 "                        (useprocessvars?, (vars | var | envs | env)*))'>\n" +
1279 "<!ENTITY % procgroup4 '(((username, password?)?, disabledauth?) |\n" +
1280 "                        ((disabledauth?, (username, password?)?)))'>\n" +
1281 "<!ENTITY % procgroup5 '((stdin?, stdout?, stderr?) |\n" +
1282 "                        (stdout?, stderr?, stdin?) |\n" +
1283 "                        (stderr?, stdin?, stdout?) |\n" +
1284 "                        (stdin?, stderr?, stdout?) |\n" +
1285 "                        (stdout?, stdin?, stderr?) |\n" +
1286 "                        (stderr?, stdout?, stdin?))'>\n" +
1287 "<!ENTITY % returnfileinfo '(returnfiles | returnfile)*'>\n" +
1288 "<!ENTITY % procgroup5a '((%returnfileinfo;, returnstdout?, returnstderr?) |\n" +
1289 "                        (returnstdout?, returnstderr?, %returnfileinfo;) |\n" +
1290 "                        (returnstderr?, %returnfileinfo;, returnstdout?) |\n" +
1291 "                        (%returnfileinfo;, returnstderr?, returnstdout?) |\n" +
1292 "                        (returnstdout?, %returnfileinfo;, returnstderr?) |\n" +
1293 "                        (returnstderr?, returnstdout?, %returnfileinfo;))'>\n" +
1294 //"<!ENTITY % procgroup6 '((stopusing?, console?, statichandlename?) |\n" +
1295 //"                        (stopusing?, statichandlename?, console?) |\n" +
1296 //"                        (console?, stopusing?, statichandlename?) |\n" +
1297 //"                        (console?, statichandlename?, stopusing?) |\n" +
1298 //"                        (statichandlename?, stopusing?, console?) |\n" +
1299 //"                        (statichandlename?, console?, stopusing?))'>\n" +
1300 "<!ENTITY % procgroup6 '((stopusing?, console?, focus?, statichandlename?) |\n" +
1301 "                        (stopusing?, console?, statichandlename?, focus?) |\n" +
1302 "                        (stopusing?, focus?, console?, statichandlename?) |\n" +
1303 "                        (stopusing?, focus?, statichandlename?, console?) |\n" +
1304 "                        (stopusing?, statichandlename?, console?, focus?) |\n" +
1305 "                        (stopusing?, statichandlename?, focus?, console?) |\n" +
1306 "                        (console?, focus?, stopusing?, statichandlename?) |\n" +
1307 "                        (console?, focus?, statichandlename?, stopusing?) |\n" +
1308 "                        (console?, stopusing?, focus?, statichandlename?) |\n" +
1309 "                        (console?, stopusing?, statichandlename?, focus?) |\n" +
1310 "                        (console?, statichandlename?, focus?, stopusing?) |\n" +
1311 "                        (console?, statichandlename?, stopusing?, focus?) |\n" +
1312 "                        (focus?, console?, stopusing?, statichandlename?) |\n" +
1313 "                        (focus?, console?, statichandlename?, stopusing?) |\n" +
1314 "                        (focus?, stopusing?, console?, statichandlename?) |\n" +
1315 "                        (focus?, stopusing?, statichandlename?, console?) |\n" +
1316 "                        (focus?, statichandlename?, console?, stopusing?) |\n" +
1317 "                        (focus?, statichandlename?, stopusing?, console?) |\n" +
1318 "                        (statichandlename?, stopusing?, console?, focus?) |\n" +
1319 "                        (statichandlename?, stopusing?, focus?, console?) |\n" +
1320 "                        (statichandlename?, console?, focus?, stopusing?) |\n" +
1321 "                        (statichandlename?, console?, stopusing?, focus?) |\n" +
1322 "                        (statichandlename?, focus?, console?, stopusing?) |\n" +
1323 "                        (statichandlename?, focus?, stopusing?, console?))'>\n" +
1324 "<!ELEMENT process    (location, command,\n" +
1325 "                      ((%procgroup1;, %procgroup2;) |\n" +
1326 "                       (%procgroup2;, %procgroup1;) |\n" +
1327 "                       (%procgroup1a;, %procgroup2a;) |\n" +
1328 "                       (%procgroup2a;, %procgroup1a;)),\n" +
1329 "                      %procgroup3;,\n" +
1330 "                      ((%procgroup4;, %procgroup5;, %procgroup5a;, %procgroup6;) |\n" +
1331 "                       (%procgroup4;, %procgroup6;, %procgroup5;, %procgroup5a;) |\n" +
1332 "                       (%procgroup5;, %procgroup5a;, %procgroup4;, %procgroup6;) |\n" +
1333 "                       (%procgroup5;, %procgroup5a;, %procgroup6;, %procgroup4;) |\n" +
1334 "                       (%procgroup6;, %procgroup4;, %procgroup5;, %procgroup5a;) |\n" +
1335 "                       (%procgroup6;, %procgroup5;, %procgroup5a;, %procgroup4;)),\n" +
1336 "                      other?, process-action?)>\n" +
1337 "<!ATTLIST process\n" +
1338 "          name        CDATA   #IMPLIED\n" +
1339 ">\n" +
1340 "\n" +
1341 "<!--\n" +
1342 "     The process element must contain a location element and a\n" +
1343 "     command element.\n" +
1344 "-->\n" +
1345 "<!ELEMENT location            (#PCDATA)>\n" +
1346 "<!ELEMENT command             (#PCDATA)>\n" +
1347 "<!ATTLIST command\n" +
1348 "          mode        CDATA   \"'default'\"\n" +
1349 "          shell       CDATA   #IMPLIED\n" +
1350 ">\n" +
1351 "\n" +
1352 "<!--\n" +
1353 "     The parms element specifies any parameters that you wish to\n" +
1354 "     pass to the command.\n" +
1355 "     The value is evaluated via Python to a string.\n" +
1356 "-->\n" +
1357 "<!ELEMENT parms               (#PCDATA)>\n" +
1358 "<!ATTLIST parms\n" +
1359 "          if        CDATA     \"1\"\n" +
1360 ">\n" +
1361 "\n" +
1362 "<!--\n" +
1363 "     The workload element specifies the name of the workload for\n" +
1364 "     which this process is a member.  This may be useful in\n" +
1365 "     conjunction with other process elements.\n" +
1366 "     The value is evaluated via Python to a string.\n" +
1367 "-->\n" +
1368 "<!ELEMENT workload            (#PCDATA)>\n" +
1369 "<!ATTLIST workload\n" +
1370 "          if        CDATA     \"1\"\n" +
1371 ">\n" +
1372 "\n" +
1373 "<!--\n" +
1374 "     The title element specifies the program title of the process.\n" +
1375 "     Unless overridden by the process, the title will be the text\n" +
1376 "     that is displayed on the title bar of the application.\n" +
1377 "     The value is evaluated via Python to a string.\n" +
1378 "-->\n" +
1379 "<!ELEMENT title               (#PCDATA)>\n" +
1380 "<!ATTLIST title\n" +
1381 "          if        CDATA     \"1\"\n" +
1382 ">\n" +
1383 "\n" +
1384 "<!--\n" +
1385 "     The workdir element specifies the directory from which the\n" +
1386 "     command should be executed.  If you do not specify this\n" +
1387 "     element, the command will be started from whatever directory\n" +
1388 "     STAFProc is currently in.\n" +
1389 "     The value is evaluated via Python to a string.\n" +
1390 "-->\n" +
1391 "<!ELEMENT workdir             (#PCDATA)>\n" +
1392 "<!ATTLIST workdir\n" +
1393 "          if        CDATA     \"1\"\n" +
1394 ">\n" +
1395 "\n" +
1396 "<!--\n" +
1397 "     The vars (and var) elements specify STAF variables that go into the\n" +
1398 "     process specific STAF variable pool.\n" +
1399 "     The value must evaluate via Python to a string or a list of \n" +
1400 "     strings. Multiple vars elements may be specified for a process.\n" +
1401 "     The format for each variable is:\n" +
1402 "       'varname=value'\n" +
1403 "     So, a list containing 3 variables could look like:\n" +
1404 "       ['var1=value1', 'var2=value2', 'var3=value3']\n" +
1405 "     Specifying only one variable could look like either:\n" +
1406 "       ['var1=value1']      or \n" +
1407 "       'var1=value1'\n" +
1408 "-->\n" +
1409 "<!ELEMENT vars                (#PCDATA)>\n" +
1410 "<!ATTLIST vars\n" +
1411 "          if        CDATA     \"1\"\n" +
1412 ">\n" +
1413 "\n" +
1414 "<!ELEMENT var                 (#PCDATA)>\n" +
1415 "<!ATTLIST var\n" +
1416 "          if        CDATA     \"1\"\n" +
1417 ">\n" +
1418 "\n" +
1419 "<!--\n" +
1420 "     The envs (and env) elements specify environment variables that will\n" +
1421 "     be set for the process.  Environment variables may be mixed case,\n" +
1422 "     however most programs assume environment variable names will\n" +
1423 "     be uppercase, so, in most cases, ensure that your environment\n" +
1424 "     variable names are uppercase.\n" +
1425 "     The value must evaluate via Python to a string or a list of \n" +
1426 "     strings. Multiple envs elements may be specified for a process.\n" +
1427 "     The format for each variable is:\n" +
1428 "       'varname=value'\n" +
1429 "     So, a list containing 3 variables could look like:\n" +
1430 "       ['ENV_VAR_1=value1', 'ENV_VAR_2=value2', 'ENV_VAR_3=value3']\n" +
1431 "     Specifying only one variable could look like either:\n" +
1432 "       ['ENV_VAR_1=value1']      or \n" +
1433 "       'ENV_VAR_1=value1'\n" +
1434 "-->\n" +
1435 "<!ELEMENT envs                (#PCDATA)>\n" +
1436 "<!ATTLIST envs\n" +
1437 "          if        CDATA     \"1\"\n" +
1438 ">\n" +
1439 "\n" +
1440 "<!ELEMENT env                 (#PCDATA)>\n" +
1441 "<!ATTLIST env\n" +
1442 "          if        CDATA     \"1\"\n" +
1443 ">\n" +
1444 "<!--\n" +
1445 "     The useprocessvars element specifies that STAF variable\n" +
1446 "     references should try to be resolved from the STAF variable\n" +
1447 "     pool associated with the process being started first.\n" +
1448 "     If the STAF variable is not found in this pool, the STAF\n" +
1449 "     global variable pool should then be searched.\n" +
1450 "-->\n" +
1451 "<!ELEMENT useprocessvars      EMPTY>\n" +
1452 "<!ATTLIST useprocessvars\n" +
1453 "          if        CDATA     \"1\"\n" +
1454 ">\n" +
1455 "\n" +
1456 "<!--\n" +
1457 "     The stopusing element allows you to specify the method by\n" +
1458 "     which this process will be STOPed, if not overridden on the\n" +
1459 "     STOP command.\n" +
1460 "     The value is evaluated via Python to a string.\n" +
1461 "-->\n" +
1462 "<!ELEMENT stopusing           (#PCDATA)>\n" +
1463 "<!ATTLIST stopusing\n" +
1464 "          if        CDATA     \"1\"\n" +
1465 ">\n" +
1466 "\n" +
1467 "<!--\n" +
1468 "     The console element allows you to specify if the process should\n" +
1469 "     get a new console window or share the STAFProc console.\n" +
1470 "\n" +
1471 "     use    Must evaluate via Python to a string containing either:\n" +
1472 "            - 'new' specifies that the process should get a new console\n" +
1473 "              window.  This option only has effect on Windows systems.\n" +
1474 "              This is the default for Windows systems.\n" +
1475 "            - 'same' specifies that the process should share the\n" +
1476 "              STAFProc console.  This option only has effect on Windows\n" +
1477 "              systems.  This is the default for Unix systems.\n" +
1478 "-->\n" +
1479 "<!ELEMENT console             EMPTY>\n" +
1480 "<!ATTLIST console\n" +
1481 "          if        CDATA     \"1\"\n" +
1482 "          use       CDATA     #REQUIRED\n" +
1483 ">\n" +
1484 "\n" +
1485 "<!--\n" +
1486 "     The focus element allows you to specify the focus that is to be\n" +
1487 "     given to any new windows opened when starting a process on a Windows\n" +
1488 "     system.  The window(s) it effects depends on whether you are using\n" +
1489 "     the 'default' or the 'shell' command mode:\n" +
1490 "       - Default command mode (no SHELL option):  The focus specified is\n" +
1491 "         given to any new windows opened by the command specified.\n" +
1492 "       - Shell command mode:  The focus specified is given only to the\n" +
1493 "         new shell command window opened, not to any windows opened by\n" +
1494 "         the specified command.\n" +
1495 "\n" +
1496 "     The focus element only has effect on Windows systems and requires\n" +
1497 "     STAF V3.1.4 or later on the machine where the process is run.\n" +
1498 "\n" +
1499 "     mode   Must evaluate via Python to a string containing one of the\n" +
1500 "            following values:\n" +
1501 "            - 'background' specifies to display a window in the background\n" +
1502 "              (e.g. not give it focus) in its most recent size and position.\n" +
1503 "              This is the default.\n" +
1504 "            - 'foreground' specifies to display a window in the foreground\n" +
1505 "              (e.g. give it focus) in its most recent size and position.\n" +
1506 "            - 'minimized' specifies to display a window as minimized.\n" +
1507 "-->\n" +
1508 "<!ELEMENT focus               EMPTY>\n" +
1509 "<!ATTLIST focus\n" +
1510 "          if        CDATA     \"1\"\n" +
1511 "          mode      CDATA     #REQUIRED\n" +
1512 ">\n" +
1513 "\n" +
1514 "<!--\n" +
1515 "     The username element specifies the username under which \n" +
1516 "     the process should be started.\n" +
1517 "     The value is evaluated via Python to a string.\n" +
1518 "-->\n" +
1519 "<!ELEMENT username            (#PCDATA)>\n" +
1520 "<!ATTLIST username\n" +
1521 "          if        CDATA     \"1\"\n" +
1522 ">\n" +
1523 "\n" +
1524 "<!--\n" +
1525 "     The password element specifies the password with which to\n" +
1526 "     authenticate the user specified with the username element.\n" +
1527 "     The value is evaluated via Python to a string.\n" +
1528 "-->\n" +
1529 "<!ELEMENT password            (#PCDATA)>\n" +
1530 "<!ATTLIST password\n" +
1531 "          if        CDATA     \"1\"\n" +
1532 ">\n" +
1533 "\n" +
1534 "<!-- The disabledauth element specifies the action to take if a\n" +
1535 "     username/password is specified but authentication has been disabled.\n" +
1536 "\n" +
1537 "     action  Must evaluate via Python to a string containing either:\n" +
1538 "             - 'error' specifies that an error should be returned.\n" +
1539 "             - 'ignore'  specifies that any username/password specified\n" +
1540 "               is ignored if authentication is disabled.\n" +
1541 "             This action overrides any default specified in the STAF\n" +
1542 "             configuration file.\n" +
1543 "-->\n" +
1544 "<!ELEMENT disabledauth        EMPTY>\n" +
1545 "<!ATTLIST disabledauth\n" +
1546 "          if        CDATA     \"1\"\n" +
1547 "          action    CDATA     #REQUIRED\n" +
1548 ">\n" +
1549 "\n" +
1550 "<!--\n" +
1551 "     Specifies that a static handle should be created for this process.\n" +
1552 "     The value is evaluated via Python to a string.  It will be the\n" +
1553 "     registered name of the static handle.  Using this option will also\n" +
1554 "     cause the environment variable STAF_STATIC_HANDLE to be set\n" +
1555 "     appropriately for the process.\n" +
1556 "-->\n" +
1557 "<!ELEMENT statichandlename    (#PCDATA)>\n" +
1558 "<!ATTLIST statichandlename\n" +
1559 "          if        CDATA     \"1\"\n" +
1560 ">\n" +
1561 "\n" +
1562 "<!--\n" +
1563 "     The stdin element specifies the name of the file from which\n" +
1564 "     standard input will be read.  The value is evaluated via\n" +
1565 "     Python to a string.\n" +
1566 "-->\n" +
1567 "<!ELEMENT stdin               (#PCDATA)>\n" +
1568 "<!ATTLIST stdin\n" +
1569 "          if        CDATA     \"1\"\n" +
1570 ">\n" +
1571 "\n" +
1572 "<!--\n" +
1573 "     The stdout element specifies the name of the file to which\n" +
1574 "     standard output will be redirected.\n" +
1575 "     The mode and filename are evaluated via Python to a string.\n" +
1576 "-->\n" +
1577 "<!ELEMENT stdout              (#PCDATA)>\n" +
1578 "<!--  mode  specifies what to do if the file already exists.\n" +
1579 "            The value must evaluate via Python to one of the\n" +
1580 "            following:\n" +
1581 "            'replace' - specifies that the file will be replaced.\n" +
1582 "            'append'  - specifies that the process' standard\n" +
1583 "                        output will be appended to the file.\n" +
1584 "-->\n" +
1585 "<!ATTLIST stdout\n" +
1586 "          if        CDATA     \"1\"\n" +
1587 "          mode      CDATA     \"'replace'\"\n" +
1588 ">\n" +
1589 "\n" +
1590 "<!--\n" +
1591 "     The stderr element specifies the file to which standard error will\n" +
1592 "     be redirected. The mode and filename are evaluated via Python to a\n" +
1593 "     string.\n" +
1594 "-->\n" +
1595 "<!ELEMENT stderr              (#PCDATA)>\n" +
1596 "<!-- mode   specifies what to do if the file already exists or to\n" +
1597 "            redirect standard error to the same file as standard output.\n" +
1598 "            The value must evaluate via Python to one of the following:\n" +
1599 "            'replace' - specifies that the file will be replaced.\n" +
1600 "            'append'  - specifies that the process's standard error will\n" +
1601 "                        be appended to the file.\n" +
1602 "            'stdout'  - specifies to redirect standard error to the\n" +
1603 "                        same file to which standard output is redirected.\n" +
1604 "                        If a file name is specified, it is ignored.\n" +
1605 "-->\n" +
1606 "<!ATTLIST stderr\n" +
1607 "          if        CDATA     \"1\"\n" +
1608 "          mode      CDATA     \"'replace'\"\n" +
1609 ">\n" +
1610 "\n" +
1611 "<!--\n" +
1612 "     The returnstdout element specifies to return in STAXResult\n" +
1613 "     the contents of the file where standard output was redirected\n" +
1614 "     when the process completes.\n" +
1615 "-->\n" +
1616 "<!ELEMENT returnstdout        EMPTY>\n" +
1617 "<!ATTLIST returnstdout\n" +
1618 "          if        CDATA     \"1\"\n" +
1619 ">\n" +
1620 "\n" +
1621 "<!--\n" +
1622 "     The returnstderr element specifies to return in STAXResult\n" +
1623 "     the contents of the file where standard error was redirected\n" +
1624 "     when the process completes.\n" +
1625 "-->\n" +
1626 "<!ELEMENT returnstderr        EMPTY>\n" +
1627 "<!ATTLIST returnstderr\n" +
1628 "          if        CDATA     \"1\"\n" +
1629 ">\n" +
1630 "\n" +
1631 "<!--\n" +
1632 "     The returnfiles (and returnfile) elements specify that the\n" +
1633 "     contents of the specified file(s) should be returned in\n" +
1634 "     STAXResult when the process completes.  The value must evaluate\n" +
1635 "     via Python to a string or a list of strings.  Multiple returnfile(s)\n" +
1636 "     elements may be specified for a process.\n" +
1637 "-->\n" +
1638 "<!ELEMENT returnfiles         (#PCDATA)>\n" +
1639 "<!ATTLIST returnfiles\n" +
1640 "          if        CDATA     \"1\"\n" +
1641 ">\n" +
1642 "\n" +
1643 "<!ELEMENT returnfile          (#PCDATA)>\n" +
1644 "<!ATTLIST returnfile\n" +
1645 "          if        CDATA     \"1\"\n" +
1646 ">\n" +
1647 "\n" +
1648 "<!--\n" +
1649 "     The process-action element specifies a task to be executed\n" +
1650 "     when a process has started.\n" +
1651 "-->\n" +
1652 "<!ELEMENT process-action      (%task;)>\n" +
1653 "<!ATTLIST process-action\n" +
1654 "          if        CDATA     \"1\"\n" +
1655 ">\n" +
1656 "<!--\n" +
1657 "     The other element specifies any other STAF parameters that\n" +
1658 "     may arise in the future.  It is used to pass additional data\n" +
1659 "     to the STAF PROCESS START request.\n" +
1660 "     The value is evaluated via Python to a string.\n" +
1661 "-->\n" +
1662 "<!ELEMENT other               (#PCDATA)>\n" +
1663 "<!ATTLIST other\n" +
1664 "          if        CDATA     \"1\"\n" +
1665 ">\n";
1666 
1667 } // end Class
1668