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