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: package org.griphyn.cPlanner.namespace;
016:
017: import java.util.Iterator;
018: import java.util.Map;
019: import java.util.TreeMap;
020:
021: import org.griphyn.cPlanner.classes.Profile;
022:
023: import org.griphyn.cPlanner.common.LogManager;
024: import org.griphyn.cPlanner.common.PegasusProperties;
025:
026: /**
027: * A Planner specific namespace. It defines profiles that are used to fine
028: * tune Pegasus behaviour on a per job basis if required.
029: *
030: * @author Karan Vahi
031: * @author Gaurang Mehta
032: * @version $Revision: 299 $
033: */
034:
035: public class VDS extends Namespace {
036:
037: /**
038: * The name of the namespace that this class implements.
039: */
040: public static final String NAMESPACE_NAME = Profile.VDS;
041:
042: /**
043: * The name of the key that sets a remote initial dir for a condor globus
044: * job.
045: */
046: public static final String REMOTE_INITIALDIR_KEY = "workdir";
047:
048: /**
049: * The name of the key that if set, determines the number of super jobs
050: * that are made corresponding to a logical transformation and an execution
051: * pool. It overrides the collapse key if set.
052: *
053: * @see #COLLAPSE_KEY
054: */
055: public static final String BUNDLE_KEY = "bundle";
056:
057: /**
058: * The name of the key that if set in the VDS namespace determines the
059: * number of jobs that are collapsed into the super job.
060: */
061: public static final String COLLAPSE_KEY = "collapse";
062:
063: /**
064: * The name of the key that determines the collapser executable to be used
065: * to run the merged/collapsed job.
066: */
067: public static final String COLLAPSER_KEY = "collapser";
068:
069: /**
070: * The name of the profile key in vds namespace that does the grouping.
071: */
072: public static final String GROUP_KEY = "group";
073:
074: /**
075: * The name of the profile key in vds namespace that does the labelling
076: * by default.
077: */
078: public static final String LABEL_KEY = "label";
079:
080: /**
081: * The name of the profile key that determines the launching executable
082: * to be used to launch a job on the grid.
083: */
084: public static final String GRIDSTART_KEY = "gridstart";
085:
086: /**
087: * The name of the profile key, that determines the arguments with which
088: * the GridStart that is used to launch a job on the remote site is invoked
089: * with. The arguments are appended to the ones constructed by default
090: * by the GridStart implementation.
091: */
092: public static final String GRIDSTART_ARGUMENTS_KEY = "gridstart.arguments";
093:
094: /**
095: * The deprecated change dir key.
096: * @see #CHANGE_DIR_KEY
097: */
098: public static final String DEPRECATED_CHANGE_DIR_KEY = "change_dir";
099:
100: /**
101: * The name of the profile key that triggers the kickstart to change directory
102: * before launching an executable instead of launching the executable from
103: * the directory where kickstart is being run.
104: */
105: public static final String CHANGE_DIR_KEY = "change.dir";
106:
107: /**
108: * The deprecated bundle stagein key.
109: * @see #CHANGE_DIR_KEY
110: */
111: public static final String DEPRECATED_BUNDLE_STAGE_IN_KEY = "bundle_stagein";
112:
113: /**
114: * The name of the key that determines the bundling parameter for the
115: * stagein transfer node.
116: */
117: public static final String BUNDLE_STAGE_IN_KEY = "bundle.stagein";
118:
119: /**
120: * The name of the key that determines the bundling parameter for the
121: * stageout transfer node.
122: */
123: public static final String BUNDLE_STAGE_OUT_KEY = "bundle.stageout";
124:
125: /**
126: * The name of the key that determines the number of chains of stagein
127: * nodes that are to be created per site.
128: */
129: public static final String CHAIN_STAGE_IN_KEY = "chain.stagein";
130:
131: /**
132: * The name of the profile key if associated with a job, results in an explicit
133: * transfer of the proxy from the submit host to the remote site, instead of
134: * banking upon CondorG to transfer the proxy.
135: */
136: public static final String TRANSFER_PROXY_KEY = "transfer.proxy";
137:
138: /**
139: * The name of the profile key, that when associated with transfer jobs
140: * determines the arguments with which the transfer executable is invoked.
141: */
142: public static final String TRANSFER_ARGUMENTS_KEY = "transfer.arguments";
143:
144: /**
145: * The name of the profile key when associated with a transformation in the
146: * transformation catalog gives expected runtime in seconds.
147: */
148: public static final String RUNTIME_KEY = "runtime";
149:
150: /**
151: * The name of the key, that denotes the style of the dag that is constructed.
152: * Possible styles can be
153: * -condor(glidein,flocking,submitting directly to condor pool)
154: * -globus(condorg)
155: */
156: public static final String STYLE_KEY = "style";
157:
158: /**
159: * The style indicating that the submit files are to be generated for
160: * a vanilla condor execution.
161: */
162: public static final String CONDOR_STYLE = "condor";
163:
164: /**
165: * The style indicating that the submit files are to be generated for
166: * a CondorG execution.
167: */
168: public static final String GLOBUS_STYLE = "globus";
169:
170: /**
171: * The style indicating that the submit files are to be generated for a
172: * glidein execution.
173: */
174: public static final String GLIDEIN_STYLE = "glidein";
175:
176: /**
177: * The name of the implementing namespace. It should be one of the valid
178: * namespaces always.
179: *
180: * @see Namespace#isNamespaceValid(String)
181: */
182: protected String mNamespace;
183:
184: /**
185: * The table containing the mapping of the deprecated keys to the newer keys.
186: */
187: protected static Map mDeprecatedTable = null;
188:
189: /**
190: * The default constructor.
191: * Note that the map is not allocated memory at this stage. It is done so
192: * in the overloaded construct function.
193: */
194: public VDS() {
195: mProfileMap = null;
196: mNamespace = NAMESPACE_NAME;
197: }
198:
199: /**
200: * The overloaded constructor.
201: *
202: * @param mp the initial map.
203: */
204: public VDS(Map mp) {
205: mProfileMap = new TreeMap(mp);
206: mNamespace = NAMESPACE_NAME;
207: }
208:
209: /**
210: * Returns the name of the namespace associated with the profile implementations.
211: *
212: * @return the namespace name.
213: * @see #NAMESPACE_NAME
214: */
215: public String namespaceName() {
216: return mNamespace;
217: }
218:
219: /**
220: * Constructs a new element of the format (key=value).
221: * It first checks if the map has been initialised or not. If not then
222: * allocates memory first. It converts the key to lower case before storing.
223: *
224: * @param key is the left-hand-side
225: * @param value is the right hand side
226: */
227: public void construct(String key, String value) {
228: if (mProfileMap == null)
229: mProfileMap = new TreeMap();
230: mProfileMap.put(key.toLowerCase(), value);
231: }
232:
233: /**
234: * This checks whether the key passed by the user is valid in the current
235: * namespace or not.
236: *
237: * @param key (left hand side)
238: * @param value (right hand side)
239: *
240: * @return Namespace.VALID_KEY
241: * @return Namespace.UNKNOWN_KEY
242: *
243: */
244: public int checkKey(String key, String value) {
245: int res = 0;
246:
247: if (key == null || key.length() < 2 || value == null
248: || value.length() < 1) {
249: res = MALFORMED_KEY;
250: return res;
251: }
252:
253: //convert key to lower case
254: key = key.toLowerCase();
255:
256: switch (key.charAt(0)) {
257:
258: case 'b':
259: if ((key.compareTo(BUNDLE_KEY) == 0)
260: || (key.compareTo(BUNDLE_STAGE_IN_KEY) == 0)
261: || (key.compareTo(BUNDLE_STAGE_OUT_KEY) == 0)) {
262: res = VALID_KEY;
263: } else if (key.compareTo(DEPRECATED_BUNDLE_STAGE_IN_KEY) == 0) {
264: res = DEPRECATED_KEY;
265: } else {
266: res = UNKNOWN_KEY;
267: }
268: break;
269:
270: case 'c':
271: if ((key.compareTo(COLLAPSE_KEY) == 0)
272: || (key.compareTo(COLLAPSER_KEY) == 0)
273: || (key.compareTo(CHANGE_DIR_KEY) == 0)
274: || (key.compareTo(CHAIN_STAGE_IN_KEY) == 0)) {
275: res = VALID_KEY;
276: } else if (key.compareTo(DEPRECATED_CHANGE_DIR_KEY) == 0) {
277: res = DEPRECATED_KEY;
278: } else {
279: res = UNKNOWN_KEY;
280: }
281: break;
282:
283: case 'g':
284: if (key.compareTo(GROUP_KEY) == 0
285: || key.compareTo(GRIDSTART_KEY) == 0
286: || key.compareTo(GRIDSTART_ARGUMENTS_KEY) == 0) {
287: res = VALID_KEY;
288: } else {
289: res = UNKNOWN_KEY;
290: }
291: break;
292:
293: case 'l':
294: if (key.compareTo(LABEL_KEY) == 0) {
295: res = VALID_KEY;
296: } else {
297: res = UNKNOWN_KEY;
298: }
299: break;
300:
301: case 'r':
302: if (key.compareTo(RUNTIME_KEY) == 0) {
303: res = VALID_KEY;
304: } else {
305: res = UNKNOWN_KEY;
306: }
307: break;
308:
309: case 's':
310: if (key.compareTo(STYLE_KEY) == 0) {
311: res = VALID_KEY;
312: } else {
313: res = UNKNOWN_KEY;
314: }
315:
316: break;
317:
318: case 't':
319: if ((key.compareTo(TRANSFER_PROXY_KEY) == 0)
320: || (key.compareTo(TRANSFER_ARGUMENTS_KEY) == 0)) {
321: res = VALID_KEY;
322: } else {
323: res = UNKNOWN_KEY;
324: }
325: break;
326:
327: case 'w':
328: if (key.compareTo(REMOTE_INITIALDIR_KEY) == 0) {
329: res = VALID_KEY;
330: } else {
331: res = UNKNOWN_KEY;
332: }
333: break;
334:
335: default:
336: res = UNKNOWN_KEY;
337: }
338:
339: return res;
340: }
341:
342: /**
343: * It puts in the namespace specific information specified in the properties
344: * file into the namespace. The name of the pool is also passed, as many of
345: * the properties specified in the properties file are on a per pool basis.
346: * This is used to load the appropriate collapser for the job.
347: * Any preexisting profile is preferred over the one in the property file.
348: *
349: * @param properties the <code>PegasusProperties</code> object containing
350: * all the properties that the user specified at various
351: * places (like .chimerarc, properties file, command line).
352: * @param pool the pool name where the job is scheduled to run.
353: *
354: * @see #COLLAPSER_KEY
355: * @see #TRANSFER_PROXY_KEY
356: */
357: public void checkKeyInNS(PegasusProperties properties, String pool) {
358: //get the value that might have been populated
359: //from other profile sources
360: String value = (String) get(this .COLLAPSER_KEY);
361: value = (value == null) ?
362: //load the global from the properties file
363: properties.getJobAggregator()
364: :
365: //prefer the existing one
366: value;
367:
368: //no strict type check required
369: //populate directly
370: this .construct(this .COLLAPSER_KEY, value);
371:
372: value = (String) get(this .TRANSFER_PROXY_KEY);
373: value = (value == null) ?
374: //load the property from the properties file
375: Boolean.toString(properties.transferProxy())
376: :
377: //prefer the existing one
378: value;
379: //no strict type check required
380: //populate directly
381: this .construct(this .TRANSFER_PROXY_KEY, value);
382:
383: value = (String) get(this .TRANSFER_ARGUMENTS_KEY);
384: value = (value == null) ?
385: //load the property from the properties file
386: properties.getTransferArguments()
387: :
388: //prefer the existing one
389: value;
390:
391: if (value != null) {
392: //no strict type check required
393: //populate directly
394: this .construct(this .TRANSFER_ARGUMENTS_KEY, value);
395: }
396:
397: }
398:
399: /**
400: * Merge the profiles in the namespace in a controlled manner.
401: * In case of intersection, the new profile value overrides, the existing
402: * profile value.
403: *
404: * @param profiles the <code>Namespace</code> object containing the profiles.
405: */
406: public void merge(Namespace profiles) {
407: //check if we are merging profiles of same type
408: if (!(profiles instanceof VDS)) {
409: //throw an error
410: throw new IllegalArgumentException(
411: "Profiles mismatch while merging");
412: }
413: String key;
414: for (Iterator it = profiles.getProfileKeyIterator(); it
415: .hasNext();) {
416: //construct directly. bypassing the checks!
417: key = (String) it.next();
418: this .construct(key, (String) profiles.get(key));
419: }
420: }
421:
422: /**
423: * Singleton access to the deprecated table that holds the deprecated keys,
424: * and the keys that replace them.
425: *
426: * @return Map
427: */
428: public java.util.Map deprecatedTable() {
429: if (mDeprecatedTable == null) {
430: // only initialize once and only once, as needed.
431: mDeprecatedTable = new java.util.TreeMap();
432: mDeprecatedTable.put(DEPRECATED_BUNDLE_STAGE_IN_KEY,
433: BUNDLE_STAGE_IN_KEY);
434: mDeprecatedTable.put(DEPRECATED_CHANGE_DIR_KEY,
435: CHANGE_DIR_KEY);
436: }
437:
438: return mDeprecatedTable;
439: }
440:
441: /**
442: * Converts the contents of the map into the string that can be put in the
443: * Condor file for printing.
444: *
445: * @return the textual description.
446: */
447: public String toString() {
448: StringBuffer st = new StringBuffer();
449: String key = null;
450: String value = null;
451: if (mProfileMap == null)
452: return "";
453:
454: Iterator it = mProfileMap.keySet().iterator();
455: while (it.hasNext()) {
456: key = (String) it.next();
457: value = (String) mProfileMap.get(key);
458: st.append(key).append(" = ").append(value).append("\n");
459: }
460:
461: return st.toString();
462: }
463:
464: /**
465: * Warns about an unknown profile key and constructs it anyway.
466: * Constructs a new RSL element of the format (key=value).
467: *
468: * @param key is the left-hand-side
469: * @param value is the right hand side
470: */
471: public void unknownKey(String key, String value) {
472: mLogger.log("unknown profile " + mNamespace + "." + key
473: + ", using anyway", LogManager.DEBUG_MESSAGE_LEVEL);
474: construct(key, value);
475: }
476:
477: /**
478: * Returns true if the namespace contains a mapping
479: * for the specified key. More formally, returns true
480: * if and only if this map contains at a mapping for a
481: * key k such that (key==null ? k==null : key.equals(k)).
482: * (There can be at most one such mapping.)
483: * It also returns false if the map does not exist.
484: *
485: * @param key The key that you want to search for
486: * in the namespace.
487: *
488: * @return boolean
489: */
490: public boolean containsKey(Object key) {
491: return (mProfileMap == null) ? false : mProfileMap
492: .containsKey(key);
493: }
494:
495: /**
496: * Returns the value to which this namespace maps the specified key.
497: * Returns null if the map contains no mapping for this key. A return value
498: * of null does not necessarily indicate that the map contains no mapping for
499: * the key; it's also possible that the map explicitly maps the key to null.
500: * The containsKey operation may be used to distinguish these two cases.
501: *
502: * @param key The key whose value you want.
503: *
504: * @return the object
505: */
506: public Object get(Object key) {
507: return (mProfileMap == null) ? null : mProfileMap.get(key);
508: }
509:
510: /**
511: * Returns a boolean value, that a particular key is mapped to in this
512: * namespace. If the key is mapped to a non boolean
513: * value or the key is not populated in the namespace false is returned.
514: *
515: * @param key The key whose boolean value you desire.
516: *
517: * @return boolean
518: */
519: public boolean getBooleanValue(Object key) {
520: boolean value = false;
521: if (mProfileMap != null && mProfileMap.containsKey(key)) {
522: value = Boolean.valueOf((String) mProfileMap.get(key))
523: .booleanValue();
524: }
525: return value;
526: }
527:
528: /**
529: * Returns a String value, that a particular key is mapped to in this
530: * namespace. If is not populated in the namespace null is returned.
531: *
532: * @param key The key whose boolean value you desire.
533: *
534: * @return String if key is in the namespace
535: * null otherwise.
536: */
537: public String getStringValue(Object key) {
538:
539: return containsKey(key) ? get(key).toString() : null;
540: }
541:
542: /**
543: * Returns a copy of the current namespace object
544: *
545: * @return the Cloned object
546: */
547: public Object clone() {
548: return (mProfileMap == null) ? new VDS() : new VDS(
549: this.mProfileMap);
550: }
551:
552: }
|