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.cPlanner.selector.site;
017:
018: import org.griphyn.cPlanner.classes.GridFTPServer;
019: import org.griphyn.cPlanner.classes.PegasusFile;
020: import org.griphyn.cPlanner.classes.SubInfo;
021:
022: import org.griphyn.cPlanner.common.LogManager;
023: import org.griphyn.cPlanner.common.PegasusProperties;
024:
025: import org.griphyn.cPlanner.poolinfo.PoolInfoProvider;
026:
027: import java.io.BufferedReader;
028: import java.io.File;
029: import java.io.FileWriter;
030: import java.io.IOException;
031: import java.io.InputStream;
032: import java.io.InputStreamReader;
033: import java.io.PrintWriter;
034:
035: import java.util.HashMap;
036: import java.util.Iterator;
037: import java.util.List;
038: import java.util.Map;
039: import java.util.StringTokenizer;
040: import org.griphyn.cPlanner.partitioner.graph.Adapter;
041: import org.griphyn.cPlanner.classes.ADag;
042: import org.griphyn.cPlanner.classes.PegasusBag;
043:
044: /**
045: * This is the class that implements a call-out to a site selector which
046: * is an application or executable script. In order to use the site
047: * selector implemented by this class, the property
048: * <code>pegasus.selector.site</code> must be set to value
049: * <code>NonJavaCallout</code>.<p>
050: *
051: * This site selector implements a <code>popen()</code> like call to an
052: * external application that conforms to the API laid out here. The name
053: * of the application to run is specified by the property
054: * <code>pegasus.selector.site.path</code>. Its value points to a locally
055: * available application.<p>
056: *
057: * If the external executable requires certain environment variables to
058: * be set for execution, these can be specified in the property files,
059: * using the prefix <code>pegasus.selector.site.env</code>. The name of the
060: * environment variable is obtained by stripping the prefix. For
061: * example, to set the variable PATH to a certain value, use the
062: * following entry in your user property file:<p>
063: *
064: * <pre>
065: * pegasus.selector.site.env.PATH = /usr/bin:/bin:/usr/X11R6/bin
066: * </pre>
067: *
068: * The site selector populates the environment of the external
069: * application with the following default properties, which can
070: * be overwritten by user-specified properties:<p>
071: *
072: * <table border="1">
073: * <tr align="left"><th>key</th><th>value</th></tr>
074: * <tr align="left"><th>PEGASUS_HOME</th>
075: * <td>As set by the system</td></tr>
076: * <tr align="left"><th>CLASSPATH</th>
077: * <td>From <tt>java.class.path</tt></td></tr>
078: * <tr align="left"><th>JAVA_HOME</th>
079: * <td>From <tt>java.home</tt></td></tr>
080: * <tr align="left"><th>USER</th>
081: * <td>From <tt>user.name</tt>, if present</td></tr>
082: * <tr align="left"><th>LOGNAME</th>
083: * <td>From <tt>user.name</tt>, if present</td></tr>
084: * <tr align="left"><th>HOME</th>
085: * <td>From <tt>user.home</tt>, if present</td></tr>
086: * <tr align="left"><th>TMP</th>
087: * <td>From <tt>java.io.tmpdir</tt>, if present</td></tr>
088: * <tr align="left"><th>TZ</th>
089: * <td>From <tt>user.timezone</tt>, if present</td></tr>
090: * </table><p>
091: *
092: * The user can specify the environment variables, by specifying the
093: * properties with the prefix pegasus.selector.site.env. prefix. for e.g user
094: * can override the default user.name property by setting the property
095: * pegasus.selector.site.env.user.home .<p>
096: *
097: * The external application is invoked with one commandline argument.
098: * This argument is the name of a temporary file. The temporary file is
099: * created for each invocation anew by the site selecting caller. Being
100: * temporary, the file is deleted after the site selector returns with
101: * success. The deletion of the file is governed by the property
102: * pegasus.selector.site.keep.tmp. It can have a tristate value with the valid
103: * values being
104: * <pre>
105: * ALWAYS
106: * NEVER
107: * ONERROR
108: * </pre>
109: * <p>
110: *
111: * The external application is expected to write one line to stdout.
112: * The line starts with the string <code>SOLUTION:</code>, followed
113: * by the chosen site handle. Optionally, separated by a colon, the
114: * name of a jobmanager for the site can be provided by the site
115: * selector. Two examples for successful site selections are:<p>
116: *
117: * <pre>
118: * SOLUTION:mysite:my.job.mgr/jobmanager-batch
119: * SOLUTION:siteY
120: * </pre>
121: *
122: * Note, these are two examples. The site selector only returns one line
123: * with the appropriate solution. If no site is found to be eligble, the
124: * poolhandle should be set to NONE by the site selector. <p>
125: *
126: * The temporary file is the corner stone of the communication between
127: * the site selecting caller and the external site selector. It is a
128: * collection of key-value pairs. Each pair is separated by an equals
129: * (=) sign, and stands on a line of its own. There are no multi-line
130: * values permitted.<p>
131: *
132: * The following pairs are generated for the siteselector temporary file:<p>
133: *
134: * <table border="1">
135: * <tr align="left"><th>#</th><th>key</th><th>value</th></tr>
136: * <tr align="left"><th>1</th><th>version</th>
137: * <td>The version of the site selector API, currently 2.0</td></tr>
138: * <tr align="left"><th>1</th><th>transformation</th>
139: * <td>The fully-qualified definition identifier for the TR, ns::id:vs.</td></tr>
140: * <tr align="left"><th>1</th><th>derivation</th>
141: * <td>The fully-qualified definition identifier for the DV, ns::id:vs.</td></tr>
142: * <tr align="left"><th>1</th><th>job.level</th>
143: * <td>The job's depth in the DFS tree of the workflow DAG</td></tr>
144: * <tr align="left"><th>1</th><th>job.id</th>
145: * <td>The job's ID, as used in the DAX file.</td></tr>
146: * <tr align="left"><th>N</th><th>resource.id</th>
147: * <td>A pool handle, followed by a whitespace, followed by a gridftp server.
148: * Typically, each gridftp server is enumerated once, so you may have multiple
149: * occurances of the same site.</td></tr>
150: * <tr align="left"><th>M</th><th>input.lfn</th>
151: * <td>An input LFN, optionally followed by a whitespace and filesize.</td></tr>
152: * <tr align="left"><th>1</th><th>wf.name</th>
153: * <td>The label of the DAX, as found in the DAX's root element.</td></tr>
154: * <tr align="left"><th>1</th><th>wf.index</th>
155: * <td>The DAX index, which is incremented for each partition.</td></tr>
156: * <tr align="left"><th>1</th><th>wf.time</th>
157: * <td>The <i>mtime</i> of the workflow.</td></tr>
158: * <tr align="left"><th>1</th><th>wf.manager</th>
159: * <td>The name of the workflow manager to be used, e.g. <tt>dagman</tt>.</td></tr>
160: * <tr align="left"><th>1</th><th>vo.name</th>
161: * <td>unused at present, name of the virtual organization who runs this WF.</td></tr>
162: * <tr align="left"><th>1</th><th>vo.group</th>
163: * <td>unused at present, usage not clear .</td></tr>
164: * </table><p>
165: *
166: * In order to detect malfunctioning site selectors, a timeout is
167: * attached with each site selector, see property
168: * <code>pegasus.selector.site.timeout</code>. By default, a site selector
169: * is given up upon after 60 s.<p>
170: *
171: * @author Karan Vahi
172: * @author Jens Vöckler
173: *
174: * @version $Revision: 298 $
175: *
176: * @see java.lang.Runtime
177: * @see java.lang.Process
178: */
179: public class NonJavaCallout extends AbstractPerJob {
180:
181: /**
182: * The prefix to be used while creating a temporary file to pass to
183: * the external siteselector.
184: */
185: public static final String PREFIX_TEMPORARY_FILE = "pegasus";
186:
187: /**
188: * The suffix to be used while creating a temporary file to pass to
189: * the external siteselector.
190: */
191: public static final String SUFFIX_TEMPORARY_FILE = null;
192:
193: /**
194: * The prefix of the property names that specify the environment
195: * variables that need to be set before calling out to the site
196: * selector.
197: */
198: public static final String PREFIX_PROPERTIES = "pegasus.selector.site.env.";
199:
200: /**
201: * The prefix that the site selector writes out on its stdout to
202: * designate that it is sending a solution.
203: */
204: public static final String SOLUTION_PREFIX = "SOLUTION:";
205:
206: /**
207: * The version number associated with this API of non java callout
208: * site selection.
209: */
210: public static final String VERSION = "2.0";
211:
212: //tristate variables for keeping the temporary files generated
213:
214: /**
215: * The state denoting never to keep the temporary files.
216: */
217: public static final int KEEP_NEVER = 0;
218:
219: /**
220: * The state denoting to keep the temporary files only in case of error.
221: */
222: public static final int KEEP_ONERROR = 1;
223:
224: /**
225: * The state denoting always to keep the temporary files.
226: */
227: public static final int KEEP_ALWAYS = 2;
228:
229: /**
230: * The description of the site selector.
231: */
232: private static final String mDescription = "External call-out to a site-selector application";
233:
234: /**
235: * The map that contains the environment variables including the
236: * default ones that are set while calling out to the site selector
237: * unless they are overridden by the values set in the properties
238: * file.
239: */
240: private Map mEnvVar;
241:
242: /**
243: * The timeout value in seconds after which to timeout, in the case
244: * where the external site selector does nothing (nothing on stdout
245: * nor stderr).
246: */
247: private int mTimeout;
248:
249: /**
250: * The tristate value for whether keeping the temporary files generated or
251: * not.
252: */
253: private int mKeepTMP;
254:
255: /**
256: * The path to the site selector.
257: */
258: private String mSiteSelectorPath;
259:
260: /**
261: * The abstract DAG.
262: */
263: private ADag mAbstractDag;
264:
265: /**
266: * The default constructor.
267: */
268: public NonJavaCallout() {
269: super ();
270: // set the default timeout to 60 seconds
271: mTimeout = 60;
272: //default would be onerror
273: mKeepTMP = KEEP_ONERROR;
274: }
275:
276: /**
277: * Initializes the site selector.
278: *
279: * @param bag the bag of objects that is useful for initialization.
280: *
281: */
282: public void initialize(PegasusBag bag) {
283: super .initialize(bag);
284: mTimeout = mProps.getSiteSelectorTimeout();
285: mSiteSelectorPath = mProps.getSiteSelectorPath();
286:
287: // load the environment variables from the properties file
288: // and the default values.
289: this .loadEnvironmentVariables();
290: //get the value from the properties file.
291: mKeepTMP = getKeepTMPValue(mProps.getSiteSelectorKeep());
292: }
293:
294: /**
295: * Maps the jobs in the workflow to the various grid sites.
296: * The jobs are mapped by setting the site handle for the jobs.
297: *
298: * @param workflow the workflow.
299: *
300: * @param sites the list of <code>String</code> objects representing the
301: * execution sites that can be used.
302: */
303: public void mapWorkflow(ADag workflow, List sites) {
304: mAbstractDag = workflow;
305: mapWorkflow(Adapter.convert(workflow), sites);
306: }
307:
308: /**
309: * Returns a brief description of the site selection technique
310: * implemented by this class.
311: *
312: * @return a self-description of this site selector.
313: */
314: public String description() {
315: return mDescription;
316: }
317:
318: /**
319: * Calls out to the external site selector. The method converts a
320: * <code>SubInfo</code> object into an API-compliant temporary file.
321: * The file's name is provided as single commandline argument to the
322: * site selector executable when it is invoked. The executable,
323: * representing the external site selector, provides its answer
324: * on <i>stdout</i>. The answer is captures, and returned.
325: *
326: * @param job is a representation of the DAX compute job whose site of
327: * execution need to be determined.
328: *
329: * @param sites the list of <code>String</code> objects representing the
330: * execution sites that can be used.
331: *
332: *
333: *
334: * FIXME: Some site selector return an empty string on failures. Also:
335: * NONE could be a valid site name.
336: *
337: * @see org.griphyn.cPlanner.classes.SubInfo
338: */
339: public void mapJob(SubInfo job, List sites) {
340: Runtime rt = Runtime.getRuntime();
341:
342: // prepare the temporary file that needs to be sent to the
343: // Site Selector via command line.
344: File ipFile = prepareInputFile(job, sites);
345:
346: // sanity check
347: if (ipFile == null) {
348: job.setSiteHandle(null);
349: return;
350: }
351:
352: // prepare the environment to call out the site selector
353: String command = this .mSiteSelectorPath;
354: if (command == null) {
355: // delete the temporary file generated
356: ipFile.delete();
357: throw new RuntimeException(
358: "Site Selector: Please set the path to the external site "
359: + "selector in the properties! ");
360: }
361:
362: try {
363: command += " " + ipFile.getAbsolutePath();
364:
365: // get hold of all the environment variables that are to be set
366: String[] envArr = this .getEnvArrFromMap();
367: mLogger.log("Calling out to site selector " + command,
368: LogManager.DEBUG_MESSAGE_LEVEL);
369: Process p = rt.exec(command, envArr);
370:
371: // set up to read subprogram output
372: InputStream is = p.getInputStream();
373: InputStreamReader isr = new InputStreamReader(is);
374: BufferedReader br = new BufferedReader(isr);
375:
376: // set up to read subprogram error
377: InputStream er = p.getErrorStream();
378: InputStreamReader err = new InputStreamReader(er);
379: BufferedReader ebr = new BufferedReader(err);
380:
381: // pipe the process stdout and stderr to standard stdout/stderr
382: // FIXME: Really? I thought we want to capture stdout?
383: String s = null;
384: String se = null;
385:
386: // set the variable to check if the timeout needs to be set or not
387: boolean notTimeout = (mTimeout <= 0);
388:
389: boolean stdout = false;
390: boolean stderr = false;
391: int time = 0;
392: while (((stdout = br.ready()) || (stderr = ebr.ready()))
393: || notTimeout || time < mTimeout) {
394:
395: if (!(stdout || stderr)) {
396: // nothing on either streams
397: // sleep for some time
398: try {
399: time += 5;
400: mLogger.log("main thread going to sleep "
401: + time, LogManager.DEBUG_MESSAGE_LEVEL);
402: Thread.sleep(5000);
403: mLogger.log("main thread woken up",
404: LogManager.DEBUG_MESSAGE_LEVEL);
405: } catch (InterruptedException e) {
406: // do nothing
407: // we potentially loose time here.
408: }
409: } else {
410: // we hearing something from selector
411: // reset the time counter
412: time = 0;
413:
414: if (stdout) {
415: s = br.readLine();
416: mLogger.log("[Site Selector stdout] " + s,
417: LogManager.DEBUG_MESSAGE_LEVEL);
418:
419: // parse the string to get the output
420: if (parseStdOut(job, s)) {
421: break;
422: }
423:
424: }
425:
426: if (stderr) {
427: se = ebr.readLine();
428: mLogger.log("[Site Selector stderr] " + se,
429: LogManager.ERROR_MESSAGE_LEVEL);
430: }
431: }
432: } // while
433:
434: // close the streams
435: br.close();
436: ebr.close();
437:
438: if (time >= mTimeout) {
439: mLogger.log("External Site Selector timeout after "
440: + mTimeout + " seconds",
441: LogManager.ERROR_MESSAGE_LEVEL);
442: p.destroy();
443: // no use closing the streams as it would be probably hung
444: job.setSiteHandle(null);
445: return;
446: }
447:
448: // the site selector seems to have worked without any errors
449: // delete the temporary file that was generated only if the
450: // process exited with a status of 0
451: // FIXME: Who is going to clean up after us?
452: int status = p.waitFor();
453: if (status != 0) {
454: // let the user know site selector exited with non zero
455: mLogger.log("Site Selector exited with non zero exit "
456: + "status " + status,
457: LogManager.DEBUG_MESSAGE_LEVEL);
458: }
459: //delete the temporary file on basis of keep value
460: if ((status == 0 && mKeepTMP < KEEP_ALWAYS)
461: || (status != 0 && mKeepTMP == KEEP_NEVER)) {
462: //deleting the file
463: if (!ipFile.delete())
464: mLogger.log("Unable to delete temporary file "
465: + ipFile.getAbsolutePath(),
466: LogManager.WARNING_MESSAGE_LEVEL);
467: }
468:
469: } catch (IOException e) {
470: mLogger.log("[Site selector] " + e.getMessage(),
471: LogManager.ERROR_MESSAGE_LEVEL);
472: } catch (InterruptedException e) {
473: mLogger.log("Waiting for site selector to exit: "
474: + e.getMessage(), LogManager.ERROR_MESSAGE_LEVEL);
475: }
476:
477: return;
478: }
479:
480: /**
481: * Writes job knowledge into the temporary file passed to the external
482: * site selector. The job knowledge derives from the contents of the
483: * DAX job's <code>SubInfo</code> record, and the a list of site
484: * candidates. The format of the file is laid out in the class's
485: * introductory documentation.
486: *
487: * @param job is a representation of the DAX compute job whose site of
488: * execution need to be determined.
489: *
490: * @param pools is a list of site candidates. The items of the list are
491: * <code>String</code> objects.
492: *
493: * @return the temporary input file was successfully prepared. A value
494: * of <code>null</code> implies that an error occured while writing
495: * the file.
496: *
497: * @see #getTempFilename()
498: */
499: private File prepareInputFile(SubInfo job, List pools) {
500: File f = new File(this .getTempFilename());
501: PrintWriter pw;
502:
503: try {
504: pw = new PrintWriter(new FileWriter(f));
505:
506: // write out the version of the api
507: pw.println("version=" + this .VERSION);
508:
509: // fw.write("\nvds_job_name=" + job.jobName);
510: pw.println("transformation=" + job.getCompleteTCName());
511: pw.println("derivation=" + job.getCompleteDVName());
512:
513: // write out the job id and level as gotten from dax
514: pw.println("job.level=" + job.level);
515: pw.println("job.id=" + job.logicalId);
516:
517: //at present Pegasus always asks to schedule compute jobs
518: //User should be able to specify through vdl or the pool config file.
519: //Karan Feb 10 3:00 PM PDT
520: //pw.println("vds_scheduler_preference=regular");
521:
522: // write down the list of exec Pools and their corresponding grid
523: // ftp servers
524: if (pools.isEmpty()) {
525: // just write out saying illustrating no exec pool or grid ftp
526: // server passed to site selector. Upto the selector to do what
527: // it wants.
528:
529: // FIXME: We need to define this part of the interface. If there
530: // are not site candidates, should it ever reach this part of
531: // the code? If now, insert assertion and abort here. If yes, we
532: // need to define this case! But just silently write the below
533: // will not site will with our set of site selectors.
534: pw.println("resource.id=NONE NONE");
535: } else {
536: String st, pool;
537: for (Iterator i = pools.iterator(); i.hasNext();) {
538: pool = (String) i.next();
539: st = "resource.id=" + pool + " ";
540:
541: // get handle to pool config
542: List l = mSCHandle.getGridFTPServers(pool);
543: if (l == null || l.isEmpty()) {
544: // FIXME: How hard should this error be?
545: mLogger.log("Site " + pool + " has no grid ftp"
546: + "servers associated with it",
547: LogManager.WARNING_MESSAGE_LEVEL);
548: // append a NONE grid ftp server
549: pw.println(st + "NONE");
550: } else {
551: for (Iterator j = l.iterator(); j.hasNext();) {
552: pw
553: .println(st
554: + ((GridFTPServer) j.next())
555: .getInfo(GridFTPServer.GRIDFTP_URL));
556: }
557: }
558: } // for
559: }
560:
561: // write the input files
562: for (Iterator i = job.inputFiles.iterator(); i.hasNext();)
563: pw.println("input.lfn="
564: + ((PegasusFile) i.next()).getLFN());
565:
566: // write workflow related metadata
567: if (this .mAbstractDag != null) {
568: pw
569: .println("wf.name="
570: + mAbstractDag.dagInfo.nameOfADag);
571: pw.println("wf.index=" + mAbstractDag.dagInfo.index);
572: // pw.println("workflow.time=" + mAbstractDag.dagInfo.time??);
573: // FIXME: Try File.lastModified() on the DAX file
574:
575: // should actually be picked up from the properties file
576: pw.println("wf.manager=" + "dagman");
577: }
578:
579: // uninitialized values
580: pw.println("vo.name=" + "NONE");
581: pw.println("vo.group=" + "NONE");
582:
583: // done
584: pw.flush();
585: pw.close();
586:
587: } catch (IOException e) {
588: mLogger.log("While writing to the temporary file :"
589: + e.getMessage(), LogManager.ERROR_MESSAGE_LEVEL);
590: return null;
591:
592: } catch (Exception ex) {
593: //an unknown exception
594: mLogger.log(
595: "Unknown error while writing to the temp file :"
596: + ex.getMessage(),
597: LogManager.ERROR_MESSAGE_LEVEL);
598: return null;
599: }
600:
601: return f;
602: }
603:
604: /**
605: * Extracts the chosen site from the site selector's answer. Parses
606: * the <i>stdout</i> sent by the selector, to see, if the execution
607: * pool and the jobmanager were sent or not.
608: *
609: * @param job the job that has to be mapped.
610: * @param s is the stdout received from the site selector.
611: *
612: * @return boolean indicating if the stdout was succesfully parsed and
613: * job populated.
614: *
615: *
616: */
617: private boolean parseStdOut(SubInfo job, String s) {
618: String val = null;
619:
620: s = s.trim();
621: boolean result = false;
622: if (s.startsWith(SOLUTION_PREFIX)) {
623: s = s.substring(SOLUTION_PREFIX.length());
624:
625: StringTokenizer st = new StringTokenizer(s, ":");
626:
627: while (st.hasMoreTokens()) {
628: result = true;
629: job.setSiteHandle((String) st.nextToken());
630:
631: job.setJobManager(st.hasMoreTokens() ? st.nextToken()
632: : null);
633: }
634: }
635:
636: // HMMM: String.indexOf() functions can be used in Jens HO.
637: return result;
638: }
639:
640: /**
641: * Creates a temporary file and obtains its name. This method returns
642: * the absolute path to a temporary file in the system's TEMP
643: * directory. The file is guarenteed to be unique for the current
644: * invocation of the virtual machine.
645: *
646: * FIXME: However, since we return a filename and not an opened file, race
647: * conditions are still possible.
648: *
649: * @return the absolute path of a newly created temporary file.
650: */
651: private String getTempFilename() {
652: File f = null;
653: try {
654: f = File.createTempFile(PREFIX_TEMPORARY_FILE,
655: SUFFIX_TEMPORARY_FILE);
656: return f.getAbsolutePath();
657: } catch (IOException e) {
658: throw new RuntimeException(
659: "Unable to get handle to a temporary file :"
660: + e.getMessage());
661: }
662: }
663:
664: /**
665: * Initializes the internal hash that collects environment variables.
666: * These variables are set up to run the external helper application.
667: * Environment variables come from two source.
668: *
669: * <ol>
670: * <li>Default environment variables, fixed, hard-coded.
671: * <li>User environment variables, from properties.
672: * </ol>
673: */
674: private void loadEnvironmentVariables() {
675: // load the default environment variables
676: String value = null;
677: mEnvVar = new HashMap();
678: mEnvVar.put("PEGASUS_HOME", mProps.getPegasusHome());
679: mEnvVar.put("CLASSPATH", mProps.getProperty("java.class.path"));
680: mEnvVar.put("JAVA_HOME", mProps.getProperty("java.home"));
681:
682: // set $LOGNAME and $USER if corresponding property set in JVM
683: if ((value = mProps.getProperty("user.name")) != null) {
684: mEnvVar.put("USER", value);
685: mEnvVar.put("LOGNAME", value);
686: }
687:
688: // set the $HOME if user.home is set
689: if ((value = mProps.getProperty("user.home")) != null)
690: mEnvVar.put("HOME", value);
691:
692: // set the $TMP if java.io.tmpdir is set
693: if ((value = mProps.getProperty("java.io.tmpdir")) != null)
694: mEnvVar.put("TMP", value);
695:
696: // set $TZ if user.timezone is set
697: if ((value = mProps.getProperty("user.timezone")) != null)
698: mEnvVar.put("TZ", value);
699:
700: // get hold of the environment variables that user might have set
701: // and put them in the map overriding the variables already set.
702: mEnvVar.putAll(mProps.matchingSubset(PREFIX_PROPERTIES, false));
703: }
704:
705: /**
706: * Generates an array of environment variables. The variables are kept
707: * in an internal map. Converts the environment variables in the map
708: * to the array format.
709: *
710: * @return array of enviroment variables set, or <code>null</code> if
711: * the map is empty.
712: * @see #loadEnvironmentVariables()
713: */
714: private String[] getEnvArrFromMap() {
715: String result[] = null;
716:
717: // short-cut
718: if (mEnvVar == null || mEnvVar.isEmpty())
719: return result;
720: else
721: result = new String[mEnvVar.size()];
722:
723: Iterator it = mEnvVar.entrySet().iterator();
724: int i = 0;
725: while (it.hasNext()) {
726: Map.Entry entry = (Map.Entry) it.next();
727: result[i] = entry.getKey() + "=" + entry.getValue();
728: i++;
729: }
730:
731: return result;
732: }
733:
734: /**
735: * Returns the int value corresponding to the string value passed.
736: *
737: * @param value the string value for keeping the temporary files.
738: *
739: * @return the corresponding int value.
740: * @see #KEEP_ALWAYS
741: * @see #KEEP_NEVER
742: * @see #KEEP_ONERROR
743: */
744: private int getKeepTMPValue(String value) {
745: //default value is keep on error
746: int val = KEEP_ONERROR;
747:
748: //sanity check of the string value
749: if (value == null || value.length() == 0) {
750: //return the default value
751: return val;
752: }
753: value = value.trim();
754: if (value.equalsIgnoreCase("always"))
755: val = KEEP_ALWAYS;
756: if (value.equalsIgnoreCase("never"))
757: val = KEEP_NEVER;
758:
759: return val;
760: }
761:
762: /**
763: * The main program that allows you to test.
764: * FIXME: Test programs should have prefix Test.....java
765: *
766: * @param args the arguments
767: *
768: */
769: public static void main(String[] args) {
770: LogManager.getInstance().setLevel(
771: LogManager.DEBUG_MESSAGE_LEVEL);
772:
773: NonJavaCallout nj = new NonJavaCallout();
774:
775: SubInfo s = new SubInfo();
776: s.logicalName = "test";
777: s.namespace = "pegasus";
778: s.version = "1.01";
779: s.jobName = "test_ID00001";
780:
781: List pools = new java.util.ArrayList();
782: pools.add("isi-condor");
783: pools.add("isi-lsf");
784:
785: nj.mapJob(s, pools);
786: System.out.println("Exec Pool return by site selector is "
787: + s.getSiteHandle());
788: }
789:
790: }
|