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.vdl.dax;
016:
017: import org.griphyn.vdl.dax.*;
018: import java.util.*;
019: import java.io.IOException;
020: import java.io.Writer;
021:
022: /**
023: * A <code>Profile</code> captures scheduler system and application
024: * environment specific stuff in a uniform fashion. Each profile
025: * declaration assigns a value to a key within a namespace. As of
026: * this writing, valid namespaces are
027: *
028: * <dl>
029: * <dt>vds</dt>
030: * <dd>Virtual Data System specific material.
031: * <dt>condor</dt>
032: * <dd>If the job runs in using the
033: * <a href="http://www.cs.wisc.edu/condor/">Condor</a/> scheduler,
034: * certain items like the "universe" or "requirments" can be set.
035: * Please note that currently the universe is provided as a hint
036: * to the logical transformation itself.</dd>
037: * <dt>dagman</dt>
038: * <dd>The job graph will usually be run by Condor DAGMan. Some issues,
039: * e.g. the number of retries, are specific to DAGMan and not Condor.</dd>
040: * <dt>env</dt>
041: * <dd>The Unix environment variables that are required for the job.</dd>
042: * </dl>
043: *
044: * In the future, more namespaces may be added.
045: *
046: * @author Jens-S. Vöckler
047: * @author Yong Zhao
048: * @version $Revision: 50 $
049: */
050: public class Profile extends DAX implements Cloneable {
051: /**
052: * The namespace of a profile. All profiles must mention their namespace
053: * in order to generate acceptable behaviour.
054: */
055: private String m_namespace;
056:
057: /**
058: * The identifier within a namespace. The meaning of the key can differ
059: * between namespaces. Within the unix namespace, it is the name of an
060: * environment variable. Within the condor namespace, it is a Condor
061: * submit file key.
062: */
063: private String m_key;
064:
065: /**
066: * The value to above keys. Any value passed down is an arbitrary mix
067: * of the three potential {@link Leaf} types. A profile value element
068: * only allows for {@link PseudoText} and {@link Filename} children in
069: * arbitrary number and order.
070: *
071: * @see Leaf
072: * @see PseudoText
073: * @see Filename
074: */
075: private ArrayList m_leafList;
076:
077: /**
078: * This value records which entity was responsible for setting the
079: * profile in the first place.
080: */
081: private String m_origin;
082:
083: /**
084: * Creates and returns a copy of this object.
085: * @return a new instance.
086: */
087: public Object clone() {
088: Profile result = new Profile(this .m_namespace, this .m_key);
089: for (int index = 0; index < this .m_leafList.size(); ++index) {
090: result.setLeaf(index, (Leaf) this .getLeaf(index).clone());
091: }
092: result.setOrigin(this .m_origin);
093: return result;
094: }
095:
096: /**
097: * Array ctor.
098: */
099: public Profile() {
100: this .m_leafList = new ArrayList();
101: this .m_origin = null;
102: }
103:
104: /**
105: * Standard ctor: set up everything except a value of the ns.key pair.
106: *
107: * @param namespace is the namespace within which to operate.
108: * @param key is an identifier unique within the namespace.
109: */
110: public Profile(String namespace, String key) {
111: this .m_leafList = new ArrayList();
112: this .m_namespace = namespace;
113: this .m_key = key;
114: this .m_origin = null;
115: }
116:
117: /**
118: * Convenience ctor: set up the first piece of the value in one go.
119: *
120: * @param namespace is the namespace within which to operate.
121: * @param key is an identifier unique within the namespace.
122: * @param firstChild is the first fragment of the value. Only
123: * <code>Leaf</code>s of type <code>Filename</code> or
124: * <code>PseudoText</code> are permissable.
125: *
126: * @see Leaf
127: * @see Filename
128: * @see PseudoText
129: */
130: public Profile(String namespace, String key, Leaf firstChild) {
131: this .m_leafList = new ArrayList();
132: this .m_leafList.add(firstChild);
133: this .m_namespace = namespace;
134: this .m_key = key;
135: this .m_origin = null;
136: }
137:
138: /**
139: * Convenience ctor: set up the first piece of the value in one go.
140: *
141: * @param namespace is the namespace within which to operate.
142: * @param key is an identifier unique within the namespace.
143: * @param children is a collection of fragments for the value. Only
144: * <code>Leaf</code>s of type <code>Filename</code> or
145: * <code>PseudoText</code> are permissable.
146: *
147: * @see Leaf
148: * @see Filename
149: * @see PseudoText
150: */
151: public Profile(String namespace, String key, Collection children) {
152: this .m_leafList = new ArrayList();
153: this .m_leafList.addAll(children);
154: this .m_namespace = namespace;
155: this .m_key = key;
156: this .m_origin = null;
157: }
158:
159: /**
160: * Accessor: Append a value fragment to this profile instance.
161: *
162: * @param vLeaf is the fragment to add. Note that only leaf values of
163: * <code>Filename</code> or <code>PseudoText</code> are allowed.
164: *
165: * @see Leaf
166: * @see PseudoText
167: * @see Filename
168: */
169: public void addLeaf(Leaf vLeaf) {
170: this .m_leafList.add(vLeaf);
171: }
172:
173: /**
174: * Accessor: Inserts a <code>Leaf</code> value into a specific position
175: * of the list of gathered values.
176: *
177: * @param index is the position to insert the item into
178: * @param vLeaf is the value to append to the list. Note that only leaf
179: * values of <code>Filename</code> or <code>PseudoText</code>
180: * are allowed.
181: * @throws IndexOutOfBoundsException if the value cannot be added.
182: * @see Leaf
183: * @see PseudoText
184: * @see Filename
185: */
186: public void addLeaf(int index, Leaf vLeaf)
187: throws IndexOutOfBoundsException {
188: this .m_leafList.add(index, vLeaf);
189: }
190:
191: /**
192: * Accessor: Enumerates the internal values that constitute the content
193: * of the <code>Profile</code> value.
194: *
195: * @return the iterator to the value fragment list.
196: * @deprecated Use the new Collection based interfaces
197: */
198: public Enumeration enumerateLeaf() {
199: return Collections.enumeration(this .m_leafList);
200: }
201:
202: /**
203: * Accessor: Obtains the <code>Leaf</code> at a certain position in the
204: * list of profile value fragments.
205: *
206: * @param index is the position in the list to obtain a value from
207: * @return The <code>Filename</code> or <code>PseudoText</code> at the position.
208: * @throws IndexOutOfBoundsException if the index points to an element
209: * in the list that does not contain any elments.
210: *
211: * @see Filename
212: * @see PseudoText
213: */
214: public Leaf getLeaf(int index) throws IndexOutOfBoundsException {
215: //-- check bound for index
216: if ((index < 0) || (index >= this .m_leafList.size()))
217: throw new IndexOutOfBoundsException();
218:
219: return (Leaf) this .m_leafList.get(index);
220: }
221:
222: /**
223: * Accessor: Gets an array of all values that constitute the current
224: * value content of a profile.
225: *
226: * @return an array with a mixture of either <code>PseudoText</code> or
227: * <code>Filename</code> values.
228: *
229: * @see Filename
230: * @see PseudoText
231: * @deprecated Use the new Collection based interfaces
232: */
233: public Leaf[] getLeaf() {
234: int size = this .m_leafList.size();
235: Leaf[] mLeaf = new Leaf[size];
236: System.arraycopy(this .m_leafList.toArray(new Leaf[0]), 0,
237: mLeaf, 0, size);
238: return mLeaf;
239: }
240:
241: /**
242: * Accessor: Obtains the number of profile value fragments.
243: *
244: * @return number of elements that an external array needs to be sized to.
245: */
246: public int getLeafCount() {
247: return this .m_leafList.size();
248: }
249:
250: /**
251: * Accessor: Gets an array of all values that constitute the current
252: * content. This list is read-only.
253: *
254: * @return an array with a mixture of either <code>PseudoText</code> or
255: * <code>Filename</code> values.
256: *
257: * @see PseudoText
258: * @see Filename
259: */
260: public java.util.List getLeafList() {
261: return Collections.unmodifiableList(this .m_leafList);
262: }
263:
264: /**
265: * Accessor: Gets the namespace value for the profile.
266: *
267: * @return the currently active namespace for this instance.
268: * @see #setNamespace(java.lang.String)
269: */
270: public String getNamespace() {
271: return this .m_namespace;
272: }
273:
274: /**
275: * Accessor: Obtains the originator for a profile.
276: *
277: * @return an arbitrary string at the moment.
278: * @see #setOrigin( java.lang.String )
279: */
280: public String getOrigin() {
281: return this .m_origin;
282: }
283:
284: /**
285: * Accessor: Gets the key identifier for the profile.
286: *
287: * @return the currently active key for this instance.
288: * @see #setKey(java.lang.String)
289: */
290: public String getKey() {
291: return this .m_key;
292: }
293:
294: /**
295: * Accessor: Enumerates the internal values that constitute the content
296: * of the <code>Scalar</code> element.
297: *
298: * @return an iterator to walk the list with.
299: */
300: public Iterator iterateLeaf() {
301: return this .m_leafList.iterator();
302: }
303:
304: /**
305: * Accessor: Enumerates the internal values that constitute the content
306: * of the <code>Leaf</code> element.
307: *
308: * @return a list iterator to walk the list with.
309: */
310: public ListIterator listIterateLeaf() {
311: return this .m_leafList.listIterator();
312: }
313:
314: /**
315: * Accessor: Enumerates the internal values that constitute the content
316: * of the <code>Leaf</code> element.
317: *
318: * @param start is the start index
319: * @return a list iterator to walk the list with.
320: */
321: public ListIterator listIterateLeaf(int start) {
322: return this .m_leafList.listIterator(start);
323: }
324:
325: /**
326: * Accessor: Removes all value fragments from the profile.
327: */
328: public void removeAllLeaf() {
329: this .m_leafList.clear();
330: }
331:
332: /**
333: * Accessor: Remove a single fragment from the list of value fragments.
334: * @param index is the position at which an element is to be removed.
335: * @return the object that was removed. The removed item is either an
336: * <code>Filename</code> or a <code>PseudoText</code>.
337: *
338: * @see Filename
339: * @see PseudoText
340: */
341: public Leaf removeLeaf(int index) {
342: return (Leaf) this .m_leafList.remove(index);
343: }
344:
345: /**
346: * Accessor: Overwrites a <code>Filename</code> or <code>PseudoText</code> value
347: * fragment at a certain position in the profile value fragment list.
348: *
349: * @param index position to overwrite an elment in.
350: * @param vLeaf is either a <code>Filename</code> or <code>PseudoText</code> object.
351: * @throws IndexOutOfBoundsException if the position pointed to is invalid.
352: *
353: * @see Filename
354: * @see PseudoText
355: */
356: public void setLeaf(int index, Leaf vLeaf)
357: throws IndexOutOfBoundsException {
358: //-- check bounds for index
359: if ((index < 0) || (index >= this .m_leafList.size())) {
360: throw new IndexOutOfBoundsException();
361: }
362: this .m_leafList.set(index, vLeaf);
363: }
364:
365: /**
366: * Accessor: Overwrites internal value fragments list with an external
367: * list representing a profile value.
368: *
369: * @param leafArray is the external list of <code>PseudoText</code> or
370: * <code>Filename</code> objects used to overwrite things.
371: * @see PseudoText
372: * @see Filename
373: * @deprecated Use the new Collection based interfaces
374: */
375: public void setLeaf(Leaf[] leafArray) {
376: this .m_leafList.clear();
377: this .m_leafList.addAll(Arrays.asList(leafArray));
378: }
379:
380: /**
381: * Accessor: Overwrites internal list with an external list representing
382: * a <code>Scalar</code> value.
383: *
384: * @param leaves is the external list of <code>PseudoText</code> or
385: * <code>Filename</code> objects used to overwrite things.
386: * @see PseudoText
387: * @see Filename
388: */
389: public void setLeaf(Collection leaves) {
390: this .m_leafList.clear();
391: this .m_leafList.addAll(leaves);
392: }
393:
394: /**
395: * Accessor: Sets the originator for a profile.
396: * @param origin is the new originator to use, may be <code>null</code>.
397: * @see #getOrigin()
398: */
399: public void setOrigin(String origin) {
400: this .m_origin = origin;
401: }
402:
403: /**
404: * Accessor: Adjusts a namespace value to a new state.
405: * @param namespace is the new namespace to use.
406: * @see #getNamespace()
407: */
408: public void setNamespace(String namespace) {
409: this .m_namespace = namespace;
410: }
411:
412: /**
413: * Accessor: Adjusts the identifier within a namespace.
414: * @param key is the new identifier to use from now on.
415: * @see #getKey()
416: */
417: public void setKey(String key) {
418: this .m_key = key;
419: }
420:
421: /**
422: * Converts the active state into something meant for human consumption.
423: * The method will be called when recursively traversing the instance
424: * tree.
425: *
426: * @param stream is a stream opened and ready for writing. This can also
427: * be a string stream for efficient output.
428: */
429: public void toString(Writer stream) throws IOException {
430: stream.write("profile ");
431: stream.write(escape(this .m_namespace));
432: stream.write("::");
433: stream.write(escape(this .m_key));
434: stream.write(" = ");
435:
436: for (int i = 0; i < this .m_leafList.size(); ++i) {
437: ((Leaf) this .m_leafList.get(i)).toString(stream);
438: }
439: }
440:
441: /**
442: * Dump the state of the current element as XML output. This function
443: * traverses all sibling classes as necessary, and converts the data
444: * into pretty-printed XML output. The stream interface should be able
445: * to handle large output efficiently.
446: *
447: * @param stream is a stream opened and ready for writing. This can also
448: * be a string stream for efficient output.
449: * @param indent is a <code>String</code> of spaces used for pretty
450: * printing. The initial amount of spaces should be an empty string.
451: * The parameter is used internally for the recursive traversal.
452: * @param namespace is the XML schema namespace prefix. If neither
453: * empty nor null, each element will be prefixed with this prefix,
454: * and the root element will map the XML namespace.
455: * @exception IOException if something fishy happens to the stream.
456: */
457: public void toXML(Writer stream, String indent, String namespace)
458: throws IOException {
459: String newline = System.getProperty("line.separator", "\r\n");
460: String tag = (namespace != null && namespace.length() > 0) ? namespace
461: + ":profile"
462: : "profile";
463:
464: // open tag
465: if (indent != null && indent.length() > 0)
466: stream.write(indent);
467: stream.write('<');
468: stream.write(tag);
469: writeAttribute(stream, " origin=\"", this .m_origin);
470: writeAttribute(stream, " namespace=\"", this .m_namespace);
471: writeAttribute(stream, " key=\"", this .m_key);
472: stream.write('>');
473: //NO: if ( indent != null ) stream.write( newline );
474:
475: // dump content
476: //NO: String newindent = indent==null ? null : indent+" ";
477: for (Iterator i = this .m_leafList.iterator(); i.hasNext();) {
478: //NO: ((Leaf) i.next()).shortXML( stream, newindent, namespace, 0x00 );
479: ((Leaf) i.next()).shortXML(stream, "", namespace, 0x00);
480: }
481:
482: // close tag
483: //NO: if ( indent != null && indent.length() > 0 ) stream.write( indent );
484: stream.write("</");
485: stream.write(tag);
486: stream.write('>');
487: if (indent != null)
488: stream.write(newline);
489: }
490: }
|