001: /*
002: * This file or a portion of this file is licensed under the terms of
003: * the Globus Toolkit Public License, found in file GTPL, or at
004: * http://www.globus.org/toolkit/download/license.html. This notice must
005: * appear in redistributions of this file, with or without modification.
006: *
007: * Redistributions of this Software, with or without modification, must
008: * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
009: * some other similar material which is provided with the Software (if
010: * any).
011: *
012: * Copyright 1999-2004 University of Chicago and The University of
013: * Southern California. All rights reserved.
014: */
015:
016: package org.griphyn.vdl.planner;
017:
018: import java.io.*;
019: import java.util.*;
020: import org.griphyn.common.util.Version;
021: import org.griphyn.common.util.Currently;
022: import org.griphyn.common.util.Separator;
023: import org.griphyn.common.util.VDSProperties;
024: import org.griphyn.vdl.Chimera;
025: import org.griphyn.vdl.dax.*;
026: import org.griphyn.vdl.classes.LFN;
027: import org.griphyn.vdl.util.Logging;
028: import org.griphyn.common.catalog.*;
029: import org.griphyn.common.catalog.replica.*;
030: import org.griphyn.common.catalog.transformation.TCMode;
031:
032: /**
033: * This class generates the shell scripts from a DAX. There is a script
034: * for each job in the dag, and there is a control script to coordinate
035: * these jobs.<p>
036: *
037: * The scripts are assembled mostly from template files and substitutions.
038: * The template files reside in <code>$PEGASUS_HOME/share</code>:<p>
039: *
040: * <table border="1">
041: * <tr><th>template</th><th>purpose</th></tr>
042: * <tr><td>sp-job-1.tmpl</td><td>start of job script</td></tr>
043: * <tr><td>sp-job-2.tmpl</td><td>unused</td></tr>
044: * <tr><td>sp-job-3.tmpl</td><td>final portion of job script</td></tr>
045: * <tr><td>sp-master-1.tmpl</td><td>start of master script</td></tr>
046: * <tr><td>sp-master-2.tmpl</td><td>intermediary of master script</td></tr>
047: * <tr><td>sp-master-3.tmpl</td><td>final portion of master script</td></tr>
048: * <tr><td>sp-master-job.tmpl</td><td>Invocation of job from master</td></tr>
049: * </table>
050: *
051: * The following substitutions are available by default. Some substitutions
052: * are only available during job generation:<p>
053: *
054: * <table border="1">
055: * <tr><th>variable</th><th>purpose</th></tr>
056: * <tr><td>DAXLABEL</td><td>user-given label of the workflow</td></tr>
057: * <tr><td>DV</td><td>Job: fully-qualified DV of job</td></tr>
058: * <tr><td>FILELIST</td><td>Job: Name of file of output mappings</td></tr>
059: * <tr><td>HOME</td><td>JRE system property user.home</td></tr>
060: * <tr><td>JOBID</td><td>Job: the IDxxxxx of the current job</td></tr>
061: * <tr><td>JOBLOG</td><td>Job: the log file of the job</td></tr>
062: * <tr><td>JOBSCRIPT</td><td>Job: name of script file for job</td></tr>
063: * <tr><td>KICKSTART</td><td>if set, path to local kickstart</td><tr>
064: * <tr><td>LOGFILE</td><td>Name of master log file</td></tr>
065: * <tr><td>NOW</td><tr>Start time stamp of processing (compile time)</td></tr>
066: * <tr><td>REGISTER</td><td>0 or 1 for replica registration</td></tr>
067: * <tr><td>TR</td><td>Job: fully-qualified TR of job</td></tr>
068: * <tr><td>USER</td><td>JRE system property user.name</td></tr>
069: * </table>
070: *
071: * @author Jens-S. Vöckler
072: * @author Yong Zhao
073: * @version $Revision: 50 $
074: *
075: */
076: public class Scriptor {
077: /**
078: * the directory to put the scripts
079: */
080: private String m_dirName;
081:
082: /**
083: * the dag structure
084: */
085: private ADAG m_adag;
086:
087: /**
088: * name of the dag
089: */
090: private String m_dagName;
091:
092: /**
093: * replica catalog
094: */
095: private RCWrapper m_rc;
096:
097: /**
098: * site catalog (optional)
099: */
100: private SCWrapper m_sc;
101:
102: /**
103: * transformation catalog
104: */
105: private TCWrapper m_tc;
106:
107: /**
108: * the hash that holds all the lfn->pfn mapping
109: */
110: private HashMap m_filenameMap;
111:
112: /**
113: * the name of the master log file.
114: */
115: private String m_logFile;
116:
117: /**
118: * whether to register output files
119: */
120: private boolean m_register;
121:
122: /**
123: * path to kickstart
124: */
125: private String m_kickstart;
126:
127: /**
128: * buffered writer for control script file
129: */
130: private BufferedWriter m_master;
131:
132: /**
133: * Stores the reference to the logger.
134: */
135: private Logging m_log;
136:
137: /**
138: * holds the location where templates reside.
139: */
140: private File m_dataDir;
141:
142: /**
143: * holds the mapping for permissable substitutions.
144: */
145: private Map m_substitute = null;
146:
147: /**
148: * a private copy of this environment's notion of a line separator.
149: */
150: private final static String newline = System.getProperty(
151: "line.separator", "\r\n");
152:
153: /**
154: * Constructor
155: *
156: * @param dirName names the directory into which to produce the scripts.
157: * @param adag is the DAX as a parsed data structure in memory.
158: * @param rc is the replica catalog wrapper.
159: * @param sc is the site catalog wrapper, may be <code>null</code>.
160: * @param tc is the transformation catalog wrapper.
161: * @param fnMap is a map containing all filesnames in the DAG.
162: * @param dataDir is the location of $PEGASUS_HOME/share from properties.
163: */
164: public Scriptor(String dirName, ADAG adag, RCWrapper rc,
165: SCWrapper sc, TCWrapper tc, HashMap fnMap, File dataDir) {
166: m_dirName = dirName;
167: m_adag = adag;
168: m_dataDir = dataDir;
169:
170: // set dag name
171: m_dagName = adag.getName();
172: if (m_dagName == null)
173: m_dagName = m_dirName;
174:
175: m_rc = rc;
176: m_sc = sc;
177: m_tc = tc;
178: m_filenameMap = fnMap;
179:
180: m_logFile = m_dagName + ".log";
181: m_register = true;
182: m_kickstart = null;
183: if (m_sc != null) {
184: String kl = m_sc.getGridLaunch();
185: if (kl != null) {
186: File k = new File(kl);
187: if (k.exists())
188: m_kickstart = kl;
189: }
190: }
191: m_log = Logging.instance();
192:
193: // prepare substitutions
194: m_substitute = new TreeMap();
195: m_substitute.put("NOW", Currently.iso8601(false, true, false,
196: new Date()));
197: m_substitute.put("DAXLABEL", m_dagName);
198: m_substitute.put("USER", System.getProperty("user.name"));
199: m_substitute.put("HOME", System.getProperty("user.home"));
200: m_substitute.put("LOGFILE", m_logFile);
201: if (m_kickstart != null)
202: m_substitute.put("KICKSTART", m_kickstart);
203: m_substitute.put("REGISTER", m_register ? "1" : "0");
204: }
205:
206: /**
207: * Sets the flag indicating whether to register output files.
208: * @param b is a flag to set the registration state.
209: * @see #getRegister()
210: */
211: public void setRegister(boolean b) {
212: this .m_register = b;
213: addSubstitution("REGISTER", b ? "1" : "0");
214: }
215:
216: /**
217: * Gets the flag indicating whether to register output files.
218: * @return true, if output files are going to be registered.
219: * @see #setRegister(boolean)
220: */
221: public boolean getRegister() {
222: return this .m_register;
223: }
224:
225: /**
226: * Sets kickstart path, if the path is null, kickstart will not be used.
227: * @param kickstart the path to invoke kickstart
228: * @see #getKickstart()
229: */
230: public void setKickstart(String kickstart) {
231: m_kickstart = kickstart;
232: if (kickstart != null)
233: addSubstitution("KICKSTART", kickstart);
234: else
235: removeSubstitution("KICKSTART");
236: }
237:
238: /**
239: * Gets the current kickstart path. The location may be null.
240: * @return the path to kickstart, or <code>null</code>
241: * @see #setKickstart( String )
242: */
243: public String getKickstart() {
244: return this .m_kickstart;
245: }
246:
247: /**
248: * Inserts a substitution into the substitutable variables.
249: *
250: * @param key is the template variable name
251: * @param value is the replacement
252: * @return the previous setting, or <code>null</code>.
253: * @see #getSubstitution( String )
254: */
255: public String addSubstitution(String key, String value) {
256: return (String) m_substitute.put(key, value);
257: }
258:
259: /**
260: * Obtains the setting of a substitutable variable.
261: * @param key is the template variable name to query for.
262: * @return the current setting, or <code>null</code>, if the
263: * variable does not exist.
264: * @see #addSubstitution( String, String )
265: */
266: public String getSubstitution(String key) {
267: String result = null;
268:
269: if (m_substitute.containsKey(key)) {
270: result = (String) m_substitute.get(key);
271: if (result == null)
272: result = new String();
273: }
274:
275: return result;
276: }
277:
278: /**
279: * Removes a substition.
280: * @param key is the template variable name to query for.
281: * @return the current setting, or <code>null</code>, if the
282: * variable does not exist.
283: * @see #addSubstitution( String, String )
284: */
285: public String removeSubstitution(String key) {
286: return (String) m_substitute.remove(key);
287: }
288:
289: /**
290: * Writes the control script head, including functions for file
291: * registration.
292: *
293: * @return the name of the control (master) script.
294: * @throws IOException if writing to the master script somehow failes.
295: */
296: public String initializeControlScript() throws IOException {
297: // control script output filename
298: String controlScript = m_dagName + ".sh";
299: File controlFile = new File(m_dirName, controlScript);
300: String fullPath = controlFile.getAbsolutePath();
301:
302: // existence checks before overwriting
303: if (controlFile.exists()) {
304: m_log.log("planner", 0, "Warning: Master file " + fullPath
305: + " already exists, overwriting");
306: controlFile.delete();
307: }
308:
309: // open master for writing
310: m_master = new BufferedWriter(new FileWriter(controlFile));
311:
312: // copy template while substituting
313: m_log.log("planner", 1, "writing control script header");
314: copyFromTemplate(m_master, "sp-master-1.tmpl");
315:
316: // done
317: return controlScript;
318: }
319:
320: /**
321: * Adds scripts between stages.
322: * @exception IOException if adding to the master script fails for
323: * some reason.
324: */
325: public void intermediateControlScript() throws IOException {
326: m_log
327: .log("planner", 1,
328: "writing control script between stages");
329: copyFromTemplate(m_master, "sp-master-2.tmpl");
330: }
331:
332: /**
333: * Write the control script tail to the control file.
334: * @exception IOException if adding to the master script fails for
335: * some reason.
336: */
337: public void finalizeControlScript() throws IOException {
338: m_log.log("planner", 1, "writing control script tail");
339: copyFromTemplate(m_master, "sp-master-3.tmpl");
340:
341: // close master
342: m_master.flush();
343: m_master.close();
344: m_master = null;
345: }
346:
347: /**
348: * Converts a variable into the substituted value. Most of this is just
349: * a hash lookup, but some are more dynamic.
350: *
351: * @param key is the variable to replace
352: * @return the replacement string, which may be empty, never <code>null</code>.
353: */
354: private String convertVariable(String key) {
355: if (key.equals("NOW")) {
356: return Currently.iso8601(false, true, false, new Date());
357: } else {
358: return getSubstitution(key);
359: }
360: }
361:
362: /**
363: * Copies a template file into the open writer. During copy,
364: * certain substitutions may take place. The substitutable variables
365: * are dynamically adjusted from the main class.
366: *
367: * @param w is the writer open for writing.
368: * @param tfn is the template base file name.
369: * @throws IOException in case some io operation goes wrong.
370: */
371: public void copyFromTemplate(Writer w, String tfn)
372: throws IOException {
373: // determine location
374: File source = new File(m_dataDir, tfn);
375: if (source.exists()) {
376: // template exists, use it
377: LineNumberReader lnr = new LineNumberReader(new FileReader(
378: source));
379:
380: String line, key, value;
381: while ((line = lnr.readLine()) != null) {
382: StringBuffer sb = new StringBuffer(line);
383:
384: // substitute all substitutables
385: int circuitBreaker = 0;
386: for (int p1 = sb.indexOf("@@"); p1 != -1; p1 = sb
387: .indexOf("@@")) {
388: int p2 = sb.indexOf("@@", p1 + 2) + 2;
389: if (p2 == -1)
390: throw new IOException(
391: "unclosed @@var@@ element");
392: key = sb.substring(p1 + 2, p2 - 2);
393: if ((value = convertVariable(key)) == null) {
394: // does not exist
395: m_log
396: .log(
397: "planner",
398: 0,
399: "Warning: "
400: + source
401: + ":"
402: + lnr.getLineNumber()
403: + ": Requesting unknown substitution for "
404: + key);
405: value = new String();
406: } else {
407: // protocol substitution
408: m_log.log("planner", 3, "Substituting " + key
409: + " => " + value);
410: }
411: sb.replace(p1, p2, value);
412:
413: if (++circuitBreaker > 32) {
414: m_log.log("planner", 0, "Warning: "
415: + lnr.getLineNumber()
416: + ": circuit breaker triggered");
417: break;
418: }
419: }
420:
421: w.write(sb.toString());
422: w.write(newline);
423: }
424:
425: // free file handle resource
426: lnr.close();
427: } else {
428: // template does not exist
429: throw new IOException("template " + tfn + " not found");
430: }
431: }
432:
433: /**
434: * Processes each job in the adag. Also checks for input file
435: * existence, if necessary.
436: *
437: * @param jobID is the DAX-unique job id to generate a scripts for.
438: * @param checkInputFiles if set, checks in the filesystem for the
439: * existence of all input files into the job.
440: * @return the name of the job control script.
441: * @throws IOException for failure to write any job related files.
442: */
443: public String processJob(String jobID, boolean checkInputFiles)
444: throws IOException {
445: Logging.instance()
446: .log("planner", 0, "processing job: " + jobID);
447:
448: // get the job reference from ADAG
449: Job job = m_adag.getJob(jobID);
450:
451: // script file for this job
452: String scriptBase = job.getName() + "_" + jobID;
453: String scriptFile = scriptBase + ".sh";
454:
455: // file to hold the output file list
456: String outputList = scriptBase + ".lst";
457: File of = new File(m_dirName, outputList);
458: String outputFullPath = of.getAbsolutePath();
459: if (of.exists()) {
460: m_log.log("planner", 0, "Warning: output list file "
461: + outputList + " already exists, overwriting");
462: of.delete();
463: }
464:
465: // add to substitutions - temporarily
466: addSubstitution("JOBSCRIPT", scriptFile);
467: addSubstitution("FILELIST", outputList);
468: addSubstitution("JOBID", jobID);
469: addSubstitution("TR", Separator.combine(job.getNamespace(), job
470: .getName(), job.getVersion()));
471: addSubstitution("DV", Separator.combine(job.getDVNamespace(),
472: job.getDVName(), job.getDVVersion()));
473:
474: // create file with all mappings for just this job
475: BufferedWriter obw = new BufferedWriter(new FileWriter(of));
476: Map lfnMap = new HashMap(); // store mappings for job
477:
478: for (Iterator i = job.iterateUses(); i.hasNext();) {
479: Filename fn = (Filename) i.next();
480: String lfn = fn.getFilename();
481:
482: // look up LFN in hash
483: String pfn = (String) m_filenameMap.get(lfn);
484: if (pfn == null) {
485: // can't find the lfn in the filename list
486: m_log.log("planner", 0, "ERROR: LFN " + lfn
487: + "is not in the "
488: + "<filename> list, please check the DAX!");
489: return null;
490: } else {
491: lfnMap.put(lfn, pfn);
492: }
493:
494: // check if input files exist
495: if (checkInputFiles) {
496: if (fn.getLink() == LFN.INPUT) {
497: if (!(new File(pfn)).canRead()) {
498: m_log.log("planner", 0,
499: "Warning: Unable to read LFN " + lfn);
500: }
501: }
502: }
503:
504: // write the output file list entry: LFN PFN [abs]
505: if (fn.getLink() == LFN.OUTPUT) {
506: obw.write(lfn + " " + pfn + newline);
507: }
508: }
509:
510: // finish writing file of output files
511: obw.flush();
512: obw.close();
513:
514: // generate the script for this job
515: boolean result = generateJobScript(job, scriptFile, outputList,
516: lfnMap);
517: if (result) {
518: // OK: now add script invocation to master
519: m_log.log("planner", 1, "adding job " + jobID
520: + " to master script");
521: copyFromTemplate(m_master, "sp-master-job.tmpl");
522: } else {
523: m_log.log("planner", 0, "Warning: ignoring script "
524: + scriptFile);
525: }
526:
527: // always clean up
528: removeSubstitution("JOBSCRIPT");
529: removeSubstitution("FILELIST");
530: removeSubstitution("JOBID");
531: removeSubstitution("TR");
532: removeSubstitution("DV");
533:
534: return (result ? scriptFile : null);
535: }
536:
537: /**
538: * Extracts all profiles contained within the job description.
539: *
540: * @param job is the job description from the DAX
541: * @param lfnMap is the mapping to PFNs.
542: * @return a map of maps. The outer map is indexed by the lower-cased
543: * namespace identifier. The inner map is indexed by the key within
544: * the particular namespace. An empty map is possible.
545: */
546: private Map extractProfilesFromJob(Job job, Map lfnMap) {
547: Map result = new HashMap();
548: Map submap = null;
549:
550: for (Iterator i = job.iterateProfile(); i.hasNext();) {
551: org.griphyn.vdl.dax.Profile p = (org.griphyn.vdl.dax.Profile) i
552: .next();
553: String ns = p.getNamespace().trim().toLowerCase();
554: String key = p.getKey().trim();
555:
556: // recreate the vlaue
557: StringBuffer sb = new StringBuffer(8);
558: for (Iterator j = p.iterateLeaf(); j.hasNext();) {
559: Leaf l = (Leaf) j.next();
560: if (l instanceof PseudoText) {
561: sb.append(((PseudoText) l).getContent());
562: } else {
563: String lfn = ((Filename) l).getFilename();
564: sb.append((String) lfnMap.get(lfn));
565: }
566: }
567: String value = sb.toString().trim();
568:
569: // insert at the right place into the result map
570: if (result.containsKey(ns)) {
571: submap = (Map) result.get(ns);
572: } else {
573: result.put(ns, (submap = new HashMap()));
574: }
575: submap.put(key, value);
576: }
577:
578: return result;
579: }
580:
581: /**
582: * Combines profiles from two map of maps, with regards to priority.
583: *
584: * @param high is the higher priority profile
585: * @param low is the lower priority profile
586: * @return a new map with the combination of the two profiles
587: */
588: private Map combineProfiles(Map high, Map low) {
589: Set allKeys = new TreeSet(low.keySet());
590: allKeys.addAll(high.keySet());
591:
592: Map result = new HashMap();
593: for (Iterator i = allKeys.iterator(); i.hasNext();) {
594: String key = (String) i.next();
595: boolean h = high.containsKey(key);
596: boolean l = low.containsKey(key);
597: if (h && l) {
598: Map temp = new HashMap((Map) low.get(key));
599: temp.putAll((Map) high.get(key));
600: result.put(key, temp);
601: } else {
602: if (h)
603: result.put(key, high.get(key));
604: else
605: result.put(key, low.get(key));
606: }
607: }
608:
609: return result;
610: }
611:
612: /**
613: * Extracts the environment settings from the combined profiles.
614: *
615: * @param profiles is the combined profile map of maps
616: * @return a string with combined profiles, or <code>null</code>,
617: * if not applicable.
618: */
619: private String extractEnvironment(Map profiles) {
620: String result = null;
621:
622: if (profiles.containsKey("env")) {
623: StringBuffer sb = new StringBuffer();
624: Map env = (Map) profiles.get("env");
625: for (Iterator i = env.keySet().iterator(); i.hasNext();) {
626: String key = (String) i.next();
627: String value = (String) env.get(key);
628:
629: sb.append(key).append("='").append(value);
630: sb.append("'; export ").append(key).append(newline);
631: }
632: result = sb.toString();
633: }
634:
635: return result;
636: }
637:
638: /**
639: * Generates the script for each job.
640: *
641: * @param job is an ADAG job for which to generate the script.
642: * @param scriptFile is the basename of the script for the job.
643: * @param outputList is the name of a file containing output files.
644: * @param lfnMap is a map of LFN to PFN.
645: * @return true if all is well, false to signal an error
646: */
647: private boolean generateJobScript(Job job, String scriptFile,
648: String outputList, Map lfnMap) throws IOException {
649: String jobID = job.getID();
650: File f = new File(m_dirName, scriptFile);
651: String scriptFullPath = f.getAbsolutePath();
652: if (f.exists()) {
653: m_log.log("planner", 1, "Warning: Script file "
654: + scriptFile + " already exists, overwriting");
655: f.delete();
656: }
657:
658: // kickstart output file
659: // String kickLog = scriptFullPath.substring(0,scriptFullPath.length()-3) + ".out";
660: String kickLog = scriptFile.substring(0,
661: scriptFile.length() - 3)
662: + ".out";
663:
664: BufferedWriter bw = new BufferedWriter(new FileWriter(f));
665: copyFromTemplate(bw, "sp-job-1.tmpl");
666:
667: // full definition name of this job's transformation
668: String fqdn = Separator.combine(job.getNamespace(), job
669: .getName(), job.getVersion());
670:
671: // extract TR profiles
672: Map tr_profiles = extractProfilesFromJob(job, lfnMap);
673:
674: // lookup job in TC
675: List tc = m_tc.lookup(job.getNamespace(), job.getName(), job
676: .getVersion(), "local");
677: if (tc == null || tc.size() == 0) {
678: m_log.log("planner", 0, "ERROR: Transformation " + fqdn
679: + " on site \"local\" not found in TC");
680: return false;
681: } else if (tc.size() > 1) {
682: m_log.log("planner", 0, "Warning: Found " + tc.size()
683: + " matches for " + fqdn + " in TC, using first");
684: }
685: TransformationCatalogEntry tce = (TransformationCatalogEntry) tc
686: .get(0);
687:
688: // extract SC profiles
689: Map sc_profiles = (m_sc == null ? new HashMap() : m_sc
690: .getProfiles());
691:
692: // extract TC profiles
693: Map tc_profiles = m_tc.getProfiles(tce);
694:
695: // combine profiles by priority
696: Map temp = combineProfiles(tc_profiles, sc_profiles);
697: Map profiles = combineProfiles(temp, tr_profiles);
698:
699: // pfnHint has been deprecated !
700: if (profiles.containsKey("hints")) {
701: m_log.log("planner", 0,
702: "Warning: The hints profile namespace "
703: + "has been deprecated, ignoring keys "
704: + ((Map) profiles.get("hints")).keySet()
705: .toString());
706: }
707:
708: // assemble environment variables from profile
709: String executable = tce.getPhysicalTransformation();
710: String environment = extractEnvironment(profiles);
711:
712: // for web service
713: boolean service = profiles.containsKey("ws");
714: String invokews = null;
715: String wsenv = null;
716:
717: if (service) {
718: // lookup special web service invocation executable
719: tc = m_tc.lookup(null, "invokews", null, "local");
720: if (tc == null || tc.size() == 0) {
721: // not found
722: m_log.log("planner", 0,
723: "ERROR: Transformation invokews not found!");
724: return false;
725: } else if (tc.size() > 1) {
726: m_log.log("planner", 0, "Warning: Found " + tc.size()
727: + " matches for invokews in TC, using first");
728: }
729: tce = (TransformationCatalogEntry) tc.get(0);
730: invokews = tce.getPhysicalTransformation();
731:
732: // combine profiles by priority
733: temp = combineProfiles(m_tc.getProfiles(tce), sc_profiles);
734: // wsenv = extractEnvironment( combineProfiles( temp, tr_profiles ) );
735: wsenv = extractEnvironment(temp);
736: }
737:
738: // collect commandline arguments for invocation
739: StringBuffer argument = new StringBuffer();
740: for (Iterator i = job.iterateArgument(); i.hasNext();) {
741: Leaf l = (Leaf) i.next();
742: if (l instanceof PseudoText) {
743: argument.append(((PseudoText) l).getContent());
744: } else {
745: String lfn = ((Filename) l).getFilename();
746: argument.append(lfnMap.get(lfn));
747: }
748: }
749:
750: StringBuffer ks_arg = null;
751: if (m_kickstart != null) {
752: ks_arg = new StringBuffer(80);
753: ks_arg.append("-R local -l ").append(kickLog);
754: ks_arg.append(" -n \"").append(getSubstitution("TR"));
755: ks_arg.append("\" -N \"").append(getSubstitution("DV"));
756: ks_arg.append('"');
757: }
758:
759: // process stdin
760: Filename fn = job.getStdin();
761: if (fn != null) {
762: if (m_kickstart != null) {
763: ks_arg.append(" -i ").append(
764: (String) lfnMap.get(fn.getFilename()));
765: } else {
766: argument.append(" < ").append(
767: (String) lfnMap.get(fn.getFilename()));
768: }
769: }
770:
771: // process stdout
772: fn = job.getStdout();
773: if (fn != null) {
774: if (m_kickstart != null) {
775: ks_arg.append(" -o ").append(
776: (String) lfnMap.get(fn.getFilename()));
777: } else {
778: argument.append(" > ").append(
779: (String) lfnMap.get(fn.getFilename()));
780: }
781: }
782:
783: // process stderr
784: fn = job.getStderr();
785: if (fn != null) {
786: if (m_kickstart != null) {
787: ks_arg.append(" -e ").append(
788: (String) lfnMap.get(fn.getFilename()));
789: } else {
790: argument.append(" 2> ").append(
791: (String) lfnMap.get(fn.getFilename()));
792: }
793: }
794:
795: // environment of job
796: if (environment != null) {
797: bw.write("# regular job environment setup" + newline
798: + environment + newline);
799: }
800:
801: if (service) {
802: //
803: // web service invocation
804: //
805: Map in = (Map) profiles.get("ws");
806: Map out = new HashMap(in.size());
807: for (Iterator i = in.keySet().iterator(); i.hasNext();) {
808: String key = (String) i.next();
809: String value = (String) in.get(key);
810: out.put(key.trim().toLowerCase(), value.trim());
811: }
812:
813: // check that all required arguments are present
814: if (!(out.containsKey("porttype")
815: && out.containsKey("operation") && out
816: .containsKey("input"))) {
817: m_log.log("planner", 0,
818: "ERROR: You must specify portType, operation, and input "
819: + "for a web service invocation!");
820: return false;
821: }
822:
823: // extra environment for web service?
824: if (wsenv != null) {
825: bw.write("# extra WS invocation environment" + newline
826: + wsenv + newline);
827: }
828:
829: // invocation of web service
830: bw.write(invokews + " -I " + out.get("input"));
831: if (out.containsKey("output"))
832: bw.write(" -O " + out.get("output"));
833:
834: // rest of invocation
835: bw
836: .write(" -p " + out.get("porttype") + " -o "
837: + out.get("operation") + " " + executable
838: + newline);
839: } else {
840: //
841: // call the executable with argument in the script
842: //
843: if (m_kickstart != null)
844: bw.write(m_kickstart + " " + ks_arg.toString() + " ");
845:
846: bw.write(executable + " " + argument + newline);
847: }
848:
849: copyFromTemplate(bw, "sp-job-3.tmpl");
850:
851: // done
852: bw.flush();
853: bw.close();
854: return true;
855: }
856: }
|