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: */package org.griphyn.cPlanner.code.gridstart;
015:
016: import org.griphyn.cPlanner.code.GridStart;
017: import org.griphyn.cPlanner.code.POSTScript;
018:
019: import org.griphyn.cPlanner.classes.ADag;
020: import org.griphyn.cPlanner.classes.SubInfo;
021: import org.griphyn.cPlanner.classes.AggregatedJob;
022:
023: import org.griphyn.cPlanner.common.PegasusProperties;
024:
025: import org.griphyn.cPlanner.namespace.VDS;
026: import org.griphyn.cPlanner.namespace.Dagman;
027:
028: import org.griphyn.common.util.DynamicLoader;
029:
030: import java.util.Map;
031: import java.util.HashMap;
032: import org.griphyn.cPlanner.classes.PegasusBag;
033:
034: /**
035: * An abstract factory class to load the appropriate type of GridStart
036: * implementations, and their corresponding POSTScript classes.
037: * This factory class is different from other factories, in the sense that it
038: * must be instantiated first and intialized first before calling out to any
039: * of the Factory methods.
040: *
041: *
042: * @author Karan Vahi
043: * @version $Revision: 410 $
044: */
045:
046: public class GridStartFactory {
047:
048: /**
049: * The package name where the implementations of this interface reside
050: * by default.
051: */
052: public static final String DEFAULT_PACKAGE_NAME = "org.griphyn.cPlanner.code.gridstart";
053:
054: /**
055: * The corresponding short names for the implementations.
056: */
057: public static String[] GRIDSTART_SHORT_NAMES = { "kickstart",
058: "none" };
059:
060: /**
061: * The index in the constant arrays for NoGridStart.
062: */
063: public static final int KICKSTART_INDEX = 0;
064:
065: /**
066: * The index in the constant arrays for NoGridStart.
067: */
068: public static final int NO_GRIDSTART_INDEX = 1;
069:
070: /**
071: * The postscript mode in which post scripts are added only for essential
072: * jobs.
073: */
074: public static final String ESSENTIAL_POST_SCRIPT_SCOPE = "essential";
075:
076: /**
077: * The postscript mode in which post scripts are added only for all
078: * jobs.
079: */
080: public static final String ALL_POST_SCRIPT_SCOPE = "all";
081:
082: /**
083: * The known gridstart implementations.
084: */
085: public static String[] GRIDSTART_IMPLEMENTING_CLASSES = {
086: "Kickstart", "NoGridStart" };
087:
088: //
089:
090: /**
091: * A table that associates POSTScript implementing classes with their
092: * SHORT_NAMES.
093: */
094: private static Map POSTSCRIPT_IMPLEMENTING_CLASS_TABLE;
095:
096: /**
097: * Initializes the <code>POSTScript</code> implementation table, associating
098: * short names for the POSTScript with the name of the classes itself.
099: */
100: static {
101: POSTSCRIPT_IMPLEMENTING_CLASS_TABLE = new HashMap(8);
102: //not really the best way. should have avoided creating objects
103: //but then too many constants everywhere.
104: associate(new ExitPOST());
105: associate(new ExitCode());
106: associate(new UserPOSTScript());
107: associate(new NoPOSTScript());
108: }
109:
110: /**
111: * Associates a shortname with the classname.
112: *
113: * @param ps the <code>POSTScript</code> implementation.
114: */
115: private static void associate(POSTScript ps) {
116: POSTSCRIPT_IMPLEMENTING_CLASS_TABLE.put(ps.shortDescribe(), ps
117: .getClass().getName());
118: }
119:
120: /**
121: * Associates a shortname with the classname.
122: *
123: * @param shortName the shortName for the POSTScript implementation
124: * @param className the fully qualified className of the implementing class.
125: */
126: private static void associate(String shortName, String className) {
127: POSTSCRIPT_IMPLEMENTING_CLASS_TABLE.put(shortName, className);
128: }
129:
130: /**
131: * Returns the name of the implementing POSTSCript class.
132: *
133: * @param shortName the shortName for the POSTScript implementation
134: *
135: * @return the className the fully qualified className of the implementing class,
136: * else null.
137: */
138: private static String implementingPOSTScriptClass(String shortName) {
139: Object obj = POSTSCRIPT_IMPLEMENTING_CLASS_TABLE.get(shortName);
140: return (obj == null) ? null : (String) obj;
141: }
142:
143: /**
144: * The postscript mode. Whether to add postscripts for the jobs or not.
145: * At present just two modes supported
146: * all add postscripts for jobs where kickstart is present.
147: * none do not add postscripts to anyjob
148: */
149: private String mPostScriptScope;
150:
151: /**
152: * A table that maps short names of <code>POSTScript</code> implementations
153: * with the implementations themselves.
154: */
155: private Map mPOSTScriptImplementationTable;
156:
157: /**
158: * A table that maps short names of <code>GridStart</code> implementations
159: * with the implementations themselves.
160: */
161: private Map mGridStartImplementationTable;
162:
163: /**
164: * The bag of objects used for initialization.
165: */
166: private PegasusBag mBag;
167:
168: /**
169: * The properties object holding all the properties.
170: */
171: private PegasusProperties mProps;
172:
173: /**
174: * The submit directory where the submit files are being generated for
175: * the workflow.
176: */
177: private String mSubmitDir;
178:
179: /**
180: * The workflow object.
181: */
182: private ADag mDAG;
183:
184: /**
185: * A boolean indicating that the factory has been initialized.
186: */
187: private boolean mInitialized;
188:
189: /**
190: * The default constructor.
191: */
192: public GridStartFactory() {
193: mGridStartImplementationTable = new HashMap(3);
194: mPOSTScriptImplementationTable = new HashMap(3);
195: mInitialized = false;
196: }
197:
198: /**
199: * Initializes the factory with known GridStart implementations.
200: *
201: * @param bag the bag of objects that is used for initialization.
202: * @param dag the concrete dag so far.
203: */
204: public void initialize(PegasusBag bag, ADag dag) {
205: mBag = bag;
206: mProps = bag.getPegasusProperties();
207: mSubmitDir = bag.getPlannerOptions().getSubmitDirectory();
208: mDAG = dag;
209: mPostScriptScope = mProps.getPOSTScriptScope();
210:
211: //load all the known implementations and initialize them
212: for (int i = 0; i < GRIDSTART_IMPLEMENTING_CLASSES.length; i++) {
213: //load via reflection just once
214: registerGridStart(GRIDSTART_SHORT_NAMES[i], this
215: .loadGridStart(bag, dag,
216: GRIDSTART_IMPLEMENTING_CLASSES[i]));
217: }
218:
219: mInitialized = true;
220: }
221:
222: /**
223: * Loads the appropriate gridstart implementation for a job on the basis of
224: * the value of the GRIDSTART_KEY in the VDS namepsace. If no value is
225: * specified then the value in the properties file is picked up.
226: *
227: * @param job the job for which we want the gridstart handle.
228: * @param gridStartPath the path to the gridstart from the site catalog.
229: *
230: * @return a handle to appropriate GridStart implementation.
231: *
232: * @see org.griphyn.cPlanner.namespace.VDS#GRIDSTART_KEY
233: * @see org.griphyn.cPlanner.common.PegasusProperties#getGridStart()
234: *
235: * @throws GridStartFactoryException that nests any error that
236: * might occur during the instantiation of the implementation.
237: */
238: public GridStart loadGridStart(SubInfo job, String gridStartPath)
239: throws GridStartFactoryException {
240:
241: //sanity checks first
242: if (!mInitialized) {
243: throw new GridStartFactoryException(
244: "GridStartFactory needs to be initialized first before using");
245: }
246: GridStart gs = null;
247: if (gridStartPath == null || job.isMPIJob()) {
248: //return NoGridStart implementation
249: gs = (GridStart) this
250: .gridStart(GRIDSTART_SHORT_NAMES[NO_GRIDSTART_INDEX]);
251: } else {
252: //determine the short name of GridStart implementation
253: //on the basis of any profile associated or from the properties file
254: String shortName = (job.vdsNS
255: .containsKey(VDS.GRIDSTART_KEY)) ?
256: //pick the one associated in profiles
257: (String) job.vdsNS.get(VDS.GRIDSTART_KEY)
258: :
259: //pick the one in the properties file
260: mProps.getGridStart();
261:
262: //try loading on the basis of short name from the cache
263: Object obj = this .gridStart(shortName);
264:
265: if (obj == null) {
266: //load via reflection and register in the cache
267: obj = this .loadGridStart(mBag, mDAG, shortName);
268: this .registerGridStart(shortName, (GridStart) obj);
269: }
270: gs = (GridStart) obj;
271: }
272: return gs;
273: }
274:
275: /**
276: * Loads the appropriate POST Script implementation for a job on the basis of
277: * the value of the VDS profile GRIDSTART_KEY, and the DAGMan profile
278: * POST_SCRIPT_KEY in the VDS namepsace. If no value is
279: * specified then the value in the properties file is picked up.
280: *
281: * @param job the job for which we want the gridstart handle.
282: * @param gridStart the <code>GridStart</code> for which we want to load
283: * the POSTSCRIPT implementation.
284: *
285: * @return a handle to appropriate POSTScript implementation.
286: *
287: * @see org.griphyn.cPlanner.namespace.VDS#GRIDSTART_KEY
288: * @see org.griphyn.cPlanner.namespace.Dagman#POST_SCRIPT_KEY
289: * @see org.griphyn.cPlanner.common.PegasusProperties#getGridStart()
290: *
291: * @throws GridStartFactoryException that nests any error that
292: * might occur during the instantiation of the implementation.
293: */
294: public POSTScript loadPOSTScript(SubInfo job, GridStart gridStart)
295: throws GridStartFactoryException {
296:
297: //sanity checks first
298: if (!mInitialized) {
299: throw new GridStartFactoryException(
300: "GridStartFactory needs to be initialized first before using");
301: }
302:
303: if (gridStart == null) {
304: throw new GridStartFactoryException(
305: "POSTScript can only be instantiated if supplied a GridStart implementation");
306: }
307:
308: //figure out the postscript type. the scope takes precedence
309: String postScriptType;
310: if (mPostScriptScope.equals(this .ALL_POST_SCRIPT_SCOPE)
311: || (mPostScriptScope
312: .equals(this .ESSENTIAL_POST_SCRIPT_SCOPE) && job
313: .getJobType() != SubInfo.REPLICA_REG_JOB)) {
314: //we need to apply some postscript
315: //let us figure out the type of postscript to instantiate
316: Object profileValue = job.dagmanVariables
317: .get(Dagman.POST_SCRIPT_KEY);
318: postScriptType = (profileValue == null) ?
319: //get the default associated with gridstart
320: gridStart.defaultPOSTScript()
321: :
322: //use the one specified in profiles/properties
323: (String) profileValue;
324:
325: } else {
326: //mode is none , make sure to remove post key and the arguments
327: postScriptType = NoPOSTScript.SHORT_NAME;
328: }
329:
330: //try loading on the basis of postscript type from the cache
331: Object obj = this .postScript(postScriptType);
332:
333: POSTScript ps = null;
334: if (obj == null) {
335: //determine the className for postScriptType
336: String className = this
337: .implementingPOSTScriptClass(postScriptType);
338:
339: if (className == null) {
340: //so this is a user specified postscript
341: className = this
342: .implementingPOSTScriptClass(UserPOSTScript.SHORT_NAME);
343: }
344:
345: //load via reflection and register in the cache
346: obj = this .loadPOSTScript(mProps, mSubmitDir, mProps
347: .getPOSTScriptPath(postScriptType), className);
348: this .registerPOSTScript(postScriptType, (POSTScript) obj);
349: }
350: ps = (POSTScript) obj;
351:
352: return ps;
353: }
354:
355: /**
356: * Loads the implementing class corresponding to the class. If the package
357: * name is not specified with the class, then class is assumed to be
358: * in the DEFAULT_PACKAGE. The properties object passed should not be null.
359: *
360: * @param bag the bag of initialization objects
361: * @param dag the concrete dag so far.
362: * @param className the name of the class that implements the mode. It is the
363: * name of the class, not the complete name with package. That
364: * is added by itself.
365: *
366: * @return the instance of the class implementing this interface.
367: *
368: * @throws GridStartFactoryException that nests any error that
369: * might occur during the instantiation of the implementation.
370: *
371: * @see #DEFAULT_PACKAGE_NAME
372: */
373: private GridStart loadGridStart(PegasusBag bag, ADag dag,
374: String className) throws GridStartFactoryException {
375:
376: //prepend the package name
377: className = (className.indexOf('.') == -1) ?
378: //pick up from the default package
379: DEFAULT_PACKAGE_NAME + "." + className
380: :
381: //load directly
382: className;
383:
384: //try loading the class dynamically
385: GridStart gs = null;
386: try {
387: DynamicLoader dl = new DynamicLoader(className);
388: gs = (GridStart) dl.instantiate(new Object[0]);
389: gs.initialize(bag, dag);
390: } catch (Exception e) {
391: throw new GridStartFactoryException(
392: "Instantiating GridStart ", className, e);
393: }
394:
395: return gs;
396: }
397:
398: /**
399: * Loads the implementing class corresponding to the class. If the package
400: * name is not specified with the class, then class is assumed to be
401: * in the DEFAULT_PACKAGE. The properties object passed should not be null.
402: *
403: *
404: * @param properties the <code>PegasusProperties</code> object containing all
405: * the properties required by Pegasus.
406: * @param submitDir the submit directory where the submit file for the job
407: * has to be generated.
408: * @param path the path to the postscript on the submit host.
409: * @param className the name of the class that implements the mode. It is the
410: * name of the class, not the complete name with package. That
411: * is added by itself.
412: *
413: * @return the instance of the class implementing this interface.
414: *
415: * @throws GridStartFactoryException that nests any error that
416: * might occur during the instantiation of the implementation.
417: *
418: * @see #DEFAULT_PACKAGE_NAME
419: */
420: private POSTScript loadPOSTScript(PegasusProperties properties,
421: String submitDir, String path, String className)
422: throws GridStartFactoryException {
423:
424: //prepend the package name
425: className = (className.indexOf('.') == -1) ?
426: //pick up from the default package
427: DEFAULT_PACKAGE_NAME + "." + className
428: :
429: //load directly
430: className;
431:
432: //try loading the class dynamically
433: POSTScript ps = null;
434: try {
435: DynamicLoader dl = new DynamicLoader(className);
436: ps = (POSTScript) dl.instantiate(new Object[0]);
437: ps.initialize(properties, path, submitDir);
438: } catch (Exception e) {
439: throw new GridStartFactoryException(
440: "Instantiating GridStart ", className, e);
441: }
442:
443: return ps;
444: }
445:
446: /**
447: * Returns the cached implementation of <code>POSTScript</code>
448: * from the implementing class table.
449: *
450: * @param type the short name for a <code>POSTScript</code> implementation
451: *
452: * @return implementation the object class implementing that style, else null
453: */
454: private POSTScript postScript(String type) {
455: Object obj = mPOSTScriptImplementationTable.get(type
456: .toLowerCase());
457: return (obj == null) ? null : (POSTScript) obj;
458: }
459:
460: /**
461: * Inserts an entry into the implementing class table. The name is
462: * converted to lower case before being stored.
463: *
464: * @param name the short name for a <code>POSTScript</code> implementation
465: * @param implementation the object of the class implementing that style.
466: */
467: private void registerPOSTScript(String name,
468: POSTScript implementation) {
469: mPOSTScriptImplementationTable.put(name.toLowerCase(),
470: implementation);
471: }
472:
473: /**
474: * Returns the cached implementation of GridStart from the implementing
475: * class table.
476: *
477: * @param name the short name for a GridStart implementation
478: *
479: * @return implementation the object of the class implementing that style, else null
480: */
481: private GridStart gridStart(String name) {
482: Object obj = mGridStartImplementationTable.get(name
483: .toLowerCase());
484: return (obj == null) ? null : (GridStart) obj;
485: }
486:
487: /**
488: * Inserts an entry into the implementing class table. The name is
489: * converted to lower case before being stored.
490: *
491: * @param name the short name for a GridStart implementation
492: * @param implementation the object of the class implementing that style.
493: */
494: private void registerGridStart(String name, GridStart implementation) {
495: mGridStartImplementationTable.put(name.toLowerCase(),
496: implementation);
497: }
498:
499: }
|