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 edu.isi.pegasus.planner.client;
017:
018: import edu.isi.pegasus.planner.ranking.GetDAX;
019: import edu.isi.pegasus.planner.ranking.Rank;
020: import edu.isi.pegasus.planner.ranking.Ranking;
021:
022: import org.griphyn.cPlanner.classes.PegasusBag;
023: import org.griphyn.cPlanner.classes.PlannerOptions;
024:
025: import org.griphyn.cPlanner.common.LogManager;
026: import org.griphyn.cPlanner.common.PegasusProperties;
027:
028: import org.griphyn.cPlanner.toolkit.Executable;
029:
030: import org.griphyn.cPlanner.poolinfo.SiteFactory;
031: import org.griphyn.cPlanner.poolinfo.SiteFactoryException;
032: import org.griphyn.cPlanner.poolinfo.PoolInfoProvider;
033:
034: import org.griphyn.common.catalog.TransformationCatalog;
035: import org.griphyn.common.catalog.transformation.TransformationFactory;
036:
037: import gnu.getopt.LongOpt;
038: import gnu.getopt.Getopt;
039:
040: import java.util.StringTokenizer;
041: import java.util.Collection;
042: import java.util.List;
043: import java.util.LinkedList;
044: import java.util.Iterator;
045:
046: import java.io.File;
047: import java.io.FileWriter;
048: import java.io.PrintWriter;
049: import java.io.IOException;
050: import java.util.Date;
051:
052: import org.griphyn.cPlanner.toolkit.CPlanner;
053:
054: import org.griphyn.common.util.FactoryException;
055: import org.griphyn.common.catalog.transformation.Mapper;
056:
057: /**
058: * A client that ranks the DAX'es corresponding to the request id.
059: *
060: *
061: * @author Karan Vahi
062: * @version $Revision: 446 $
063: */
064: public class RankDAX extends Executable {
065:
066: /**
067: * The base directory where the ranked daxes are kept.
068: */
069: private String mBaseDir;
070:
071: /**
072: * The list of grid sites where the daxes can run.
073: */
074: private List mSites;
075:
076: /**
077: * The output file that lists the daxes in sorted order.
078: */
079: private String mOutputFile;
080:
081: /**
082: * The request id to get the daxes.
083: */
084: private String mRequestID;
085:
086: /**
087: * The bag of objects that Pegasus requires.
088: */
089: private PegasusBag mBag;
090:
091: /**
092: * The options to be passed ahead to pegasus plan.
093: */
094: private PlannerOptions mPlannerOptions;
095:
096: /**
097: * The top n workflows to execute and put in the rankings file
098: */
099: private int mTopNum;
100:
101: /**
102: * The default constructor.
103: */
104: public RankDAX() {
105: super ();
106: mBag = new PegasusBag();
107: mBag.add(PegasusBag.PEGASUS_LOGMANAGER, mLogger);
108: mBag.add(PegasusBag.PEGASUS_PROPERTIES, mProps);
109: mTopNum = Integer.MAX_VALUE;
110: }
111:
112: /**
113: * The main program for the CPlanner.
114: *
115: *
116: * @param args the main arguments passed to the planner.
117: */
118: public static void main(String[] args) {
119:
120: RankDAX me = new RankDAX();
121: int result = 0;
122: double starttime = new Date().getTime();
123: double execTime = -1;
124:
125: try {
126: me.executeCommand(args);
127: } catch (FactoryException fe) {
128: me.log(fe.convertException(),
129: LogManager.FATAL_MESSAGE_LEVEL);
130: result = 2;
131: } catch (RuntimeException rte) {
132: //catch all runtime exceptions including our own that
133: //are thrown that may have chained causes
134: me.log(convertException(rte),
135: LogManager.FATAL_MESSAGE_LEVEL);
136: rte.printStackTrace();
137: result = 1;
138: } catch (Exception e) {
139: //unaccounted for exceptions
140: me.log(e.getMessage(), LogManager.FATAL_MESSAGE_LEVEL);
141: result = 3;
142: } finally {
143: double endtime = new Date().getTime();
144: execTime = (endtime - starttime) / 1000;
145: }
146:
147: // warn about non zero exit code
148: if (result != 0) {
149: me.log("Non-zero exit-code " + result,
150: LogManager.WARNING_MESSAGE_LEVEL);
151: } else {
152: //log the time taken to execute
153: me.log("Time taken to execute is " + execTime + " seconds",
154: LogManager.INFO_MESSAGE_LEVEL);
155: }
156:
157: System.exit(result);
158: }
159:
160: /**
161: * Parses the command line arguments using GetOpt and sets the class
162: * member variables.
163: *
164: * @param args the arguments passed by the user at command line.
165: *
166: *
167: */
168: public void parseCommandLineArguments(String[] args) {
169: LongOpt[] longOptions = generateValidOptions();
170:
171: Getopt g = new Getopt("rank-dax", args, "vhr:d:s:o:r:f:t:",
172: longOptions, false);
173: g.setOpterr(false);
174:
175: int option = 0;
176: int level = 0;
177: while ((option = g.getopt()) != -1) {
178: //System.out.println("Option tag " + (char)option);
179: switch (option) {
180:
181: case 'd': //base directory
182: mBaseDir = g.getOptarg();
183: break;
184:
185: case 's': //comma separated list of sites
186: mSites = this .generateList(g.getOptarg());
187: break;
188:
189: case 'o': //the output file where the ranked list is kept
190: mOutputFile = g.getOptarg();
191: break;
192:
193: case 'r': //the request id
194: mRequestID = g.getOptarg();
195: break;
196:
197: case 'v': //sets the verbosity level
198: level++;
199: break;
200:
201: case 'f'://the options to be passed to pegasus-plan
202: mPlannerOptions = new CPlanner()
203: .parseCommandLineArguments(g.getOptarg().split(
204: "\\s"));
205: mBag.add(PegasusBag.PLANNER_OPTIONS, mPlannerOptions);
206: break;
207:
208: case 't'://rank top t
209: mTopNum = new Integer(g.getOptarg()).intValue();
210: break;
211:
212: case 'h':
213: printShortHelp();
214: System.exit(0);
215: break;
216:
217: default: //same as help
218: printShortHelp();
219: for (int i = 0; i < args.length; i++)
220: System.out.println(args[i]);
221: throw new RuntimeException(
222: "Incorrect option or option usage " + option);
223:
224: }
225: }
226: if (level > 0) {
227: mLogger.setLevel(level);
228: }
229: }
230:
231: /**
232: * Executes the command on the basis of the options specified.
233: *
234: * @param args the command line options.
235: */
236: public void executeCommand(String[] args) {
237: parseCommandLineArguments(args);
238:
239: if (mRequestID == null || mPlannerOptions == null) {
240: mLogger
241: .log(
242: "\nNeed to specify the request id and options that are to be passed to planner.",
243: LogManager.INFO_MESSAGE_LEVEL);
244:
245: this .printShortVersion();
246: return;
247: }
248:
249: //override the sites if any are set in the forward options
250: mPlannerOptions.setExecutionSites(mSites);
251:
252: //load the site catalog using the factory
253: PoolInfoProvider sCatalog = SiteFactory.loadInstance(mProps,
254: false);
255: mBag.add(PegasusBag.SITE_CATALOG, sCatalog);
256:
257: //load the transformation catalog using the factory
258: TransformationCatalog tCatalog = TransformationFactory
259: .loadInstance(mProps);
260: mBag.add(PegasusBag.TRANSFORMATION_CATALOG, tCatalog);
261:
262: //initialize the transformation mapper
263: mBag.add(PegasusBag.TRANSFORMATION_MAPPER, Mapper
264: .loadTCMapper(mProps.getTCMapperMode()));
265:
266: //write out the daxes to the directory
267: File dir = new File(mBaseDir, mRequestID);
268: Collection daxes;
269: GetDAX getDax = new GetDAX();
270: try {
271: log("Writing daxes to directory " + dir,
272: LogManager.DEBUG_MESSAGE_LEVEL);
273: getDax.connect(mProps);
274: daxes = getDax.get(mRequestID, dir.getAbsolutePath());
275: mLogger.log("Number of DAX'es retrieved " + daxes.size(),
276: LogManager.DEBUG_MESSAGE_LEVEL);
277: mLogger.logCompletion("Writing daxes to directory " + dir,
278: LogManager.DEBUG_MESSAGE_LEVEL);
279: } finally {
280: getDax.close();
281: getDax = null;
282: }
283:
284: //now rank the daxes
285: Rank rank = new Rank();
286: rank.initialize(mBag, (List) mSites, mRequestID);
287: Collection rankings = rank.rank(daxes);
288:
289: //write out the rankings file
290: File f = null;
291: if (mOutputFile == null) {
292: mLogger.log(
293: "Output file not specified. Writing out ranked file in dir "
294: + dir, LogManager.DEBUG_MESSAGE_LEVEL);
295: f = new File(dir, "ranked_daxes.txt");
296: } else {
297: f = new File(mOutputFile);
298: }
299:
300: log("Writing out the ranking file " + f,
301: LogManager.DEBUG_MESSAGE_LEVEL);
302: try {
303: writeOutRankings(f, rankings);
304: } catch (IOException ioe) {
305: throw new RuntimeException("Unable to write to file " + f,
306: ioe);
307: }
308: }
309:
310: /**
311: * Writes out the ranking to the file. If the file is null then it is written
312: * out to a file named ranked_daxes.txt in the directory where the daxes
313: * reside
314: *
315: * @param file String
316: * @param rankings Collection
317: *
318: * @throws IOException
319: */
320: protected void writeOutRankings(File file,
321: Collection<Ranking> rankings) throws IOException {
322:
323: //do a sanity check on the directory for the file specified
324: File dir = file.getParentFile();
325: sanityCheck(dir);
326:
327: //write out the ranked daxes.
328: PrintWriter pw = new PrintWriter(new FileWriter(file));
329: int i = 1;
330: for (Iterator it = rankings.iterator(); it.hasNext()
331: && i <= mTopNum; i++) {
332: pw.println(it.next());
333: pw.println(mPlannerOptions.toOptions());
334: }
335: pw.close();
336:
337: }
338:
339: /**
340: * Checks the destination location for existence, if it can
341: * be created, if it is writable etc.
342: *
343: * @param dir is the new base directory to optionally create.
344: *
345: * @throws IOException in case of error while writing out files.
346: */
347: protected static void sanityCheck(File dir) throws IOException {
348: if (dir.exists()) {
349: // location exists
350: if (dir.isDirectory()) {
351: // ok, isa directory
352: if (dir.canWrite()) {
353: // can write, all is well
354: return;
355: } else {
356: // all is there, but I cannot write to dir
357: throw new IOException(
358: "Cannot write to existing directory "
359: + dir.getPath());
360: }
361: } else {
362: // exists but not a directory
363: throw new IOException("Destination " + dir.getPath()
364: + " already "
365: + "exists, but is not a directory.");
366: }
367: } else {
368: // does not exist, try to make it
369: if (!dir.mkdirs()) {
370: throw new IOException("Unable to create directory "
371: + dir.getPath());
372: }
373: }
374: }
375:
376: /**
377: * Loads all the properties that would be needed by the Toolkit classes.
378: * Empty implementation.
379: */
380: public void loadProperties() {
381:
382: }
383:
384: /**
385: * This method is used to print the long version of the command.
386: */
387: public void printLongVersion() {
388: printShortHelp();
389: }
390:
391: /**
392: * This is used to print the short version of the command.
393: */
394: public void printShortVersion() {
395: printShortHelp();
396: }
397:
398: /**
399: * This is used to print the short version of the command.
400: */
401: public void printShortHelp() {
402: StringBuffer text = new StringBuffer();
403: text
404: .append("\n")
405: .append(
406: " $Id: RankDAX.java 446 2007-12-21 20:25:50Z vahi $ ")
407: .append("\n")
408: .append(getGVDSVersion())
409: .append("\n")
410: .append(
411: "Usage : rank-dax [-Dprop [..]] -r <request id> -f <options to pegasus-plan> -d <base directory> ")
412: .append("\n")
413: .append(
414: " [-s site[,site[..]]] [-o <output file>] [-t execute top t] [-v] [-h]");
415:
416: System.out.println(text.toString());
417:
418: }
419:
420: /**
421: * It generates the LongOpt which contain the valid options that the command
422: * will accept.
423: *
424: * @return array of <code>LongOpt</code> objects , corresponding to the valid
425: * options
426: */
427: public LongOpt[] generateValidOptions() {
428: LongOpt[] longopts = new LongOpt[8];
429:
430: longopts[0] = new LongOpt("dir", LongOpt.REQUIRED_ARGUMENT,
431: null, 'd');
432: longopts[1] = new LongOpt("sites", LongOpt.REQUIRED_ARGUMENT,
433: null, 's');
434: longopts[2] = new LongOpt("output", LongOpt.REQUIRED_ARGUMENT,
435: null, 'o');
436: longopts[3] = new LongOpt("verbose", LongOpt.NO_ARGUMENT, null,
437: 'v');
438: longopts[4] = new LongOpt("help", LongOpt.NO_ARGUMENT, null,
439: 'h');
440: longopts[5] = new LongOpt("request-id",
441: LongOpt.OPTIONAL_ARGUMENT, null, 'r');
442: longopts[6] = new LongOpt("forward", LongOpt.REQUIRED_ARGUMENT,
443: null, 'f');
444: longopts[7] = new LongOpt("top", LongOpt.REQUIRED_ARGUMENT,
445: null, 't');
446:
447: return longopts;
448: }
449:
450: /**
451: * Generates a List by parsing a comma separated string.
452: *
453: * @param str the comma separted String.
454: *
455: * @return List containing the parsed values, in case of a null string
456: * an empty List is returned.
457: */
458: private List generateList(String str) {
459: List l = new LinkedList();
460:
461: //check for null
462: if (str == null) {
463: return l;
464: }
465:
466: for (StringTokenizer st = new StringTokenizer(str, ","); st
467: .hasMoreElements();) {
468: l.add(st.nextToken().trim());
469: }
470:
471: return l;
472: }
473:
474: }
|