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.classes;
016:
017: import org.griphyn.vdl.classes.*;
018: import java.util.*;
019: import java.io.IOException;
020: import java.io.Writer;
021: import java.io.Serializable;
022:
023: /**
024: * A class to encapsulate a command line argument line. The command line
025: * is separated into a list of distinct fragments. Each fragment can only
026: * be of type <code>Use</code> or <code>Text</code>.
027: *
028: * @author Jens-S. Vöckler
029: * @author Yong Zhao
030: * @version $Revision: 50 $
031: *
032: * @see Leaf
033: * @see Text
034: * @see Use
035: */
036: public class Argument extends VDL implements Serializable {
037: /**
038: * Throws this message, if neither <text> nor <use>
039: * elements are tried to be added.
040: */
041: private static final String c_error_message = "Only \"text\" and \"use\" elements are allowed inside an \"argument\".";
042:
043: /**
044: * The command line consists of an ordered list of <code>Leaf</code>
045: * pieces, which in their sum create the commandline. Any value passed
046: * down is an arbitrary mix of the three potential <code>Leaf</code>
047: * types. Each element only allows for <code>Text</code> and
048: * <code>Use</code> children in arbitrary number and order.
049: *
050: * @see Leaf
051: * @see Text
052: * @see Use
053: */
054: private ArrayList m_leafList;
055:
056: /**
057: * Each <code>Argument</code> is a fragment of the complete command
058: * line. Each such group (of fragments) can be given a name. Special
059: * names of the stdio handles refer to these handles.
060: */
061: private String m_name;
062:
063: /**
064: * Array ctor.
065: */
066: public Argument() {
067: this .m_leafList = new ArrayList();
068: }
069:
070: /**
071: * Standard ctor: Constructs a named <code>Argument</code> group.
072: *
073: * @param name is the identifier for the argument group.
074: */
075: public Argument(String name) {
076: this .m_name = name;
077: this .m_leafList = new ArrayList();
078: }
079:
080: /**
081: * Convenience ctor: Constructs a name argument group, and enters the
082: * first (and possibly only) fragment into the group.
083: *
084: * @param name is the unique identifier for the argument group.
085: * @param firstChild is the element to place into the argument group. Only
086: * <code>Leaf</code>s of type <code>Use</code> or <code>Text</code>
087: * are permissable.
088: *
089: * @see Leaf
090: * @see Use
091: * @see Text
092: */
093: public Argument(String name, Leaf firstChild) {
094: this .m_name = name;
095: this .m_leafList = new ArrayList();
096: this .m_leafList.add(firstChild);
097: }
098:
099: /**
100: * Accessor: Appends a commandline fragment to the current group.
101: *
102: * @param vLeaf is the fragment to add. Note that only leaf values of
103: * <code>Use</code> or <code>Text</code> are allowed.
104: * @throws IndexOutOfBoundsException if the value cannot be added.
105: * @throws IllegalArgumentException if the value type is neither
106: * <code>Use</code> nor <code>Text</code>.
107: * @see Leaf
108: * @see Text
109: * @see Use
110: */
111: public void addLeaf(Leaf vLeaf) throws IndexOutOfBoundsException,
112: IllegalArgumentException {
113: if (vLeaf instanceof Text || vLeaf instanceof Use)
114: this .m_leafList.add(vLeaf);
115: else
116: throw new java.lang.IllegalArgumentException(
117: c_error_message);
118: }
119:
120: /**
121: * Accessor: Inserts a <code>Leaf</code> value into a specific position
122: * of this commandline group.
123: *
124: * @param index is the position to insert the item into
125: * @param vLeaf is the value to append to the list. Note that only leaf
126: * values of <code>Use</code> or <code>Text</code> are allowed.
127: * @throws IndexOutOfBoundsException if the value cannot be added.
128: * @throws IllegalArgumentException if the value type is neither
129: * <code>Use</code> nor <code>Text</code>.
130: *
131: * @see Text
132: * @see Use
133: */
134: public void addLeaf(int index, Leaf vLeaf)
135: throws IndexOutOfBoundsException, IllegalArgumentException {
136: if (vLeaf instanceof Text || vLeaf instanceof Use)
137: this .m_leafList.add(index, vLeaf);
138: else
139: throw new java.lang.IllegalArgumentException(
140: c_error_message);
141: }
142:
143: /**
144: * Accessor: Enumerates the internal values that constitute the content
145: * this commandline group.
146: *
147: * @return the iterator to the commandline group internal list.
148: * @deprecated Use the new Collection based interfaces
149: */
150: public Enumeration enumerateLeaf() {
151: return Collections.enumeration(this .m_leafList);
152: }
153:
154: /**
155: * Accessor: Obtains the <code>Leaf</code> at a certain position in the
156: * commandline argument group.
157: *
158: * @param index is the position in the list to obtain a value from
159: * @return The <code>Use</code> or <code>Text</code> at the position.
160: * @throws IndexOutOfBoundsException if the index points to an element
161: * in the list that does not contain any elments.
162: *
163: * @see Use
164: * @see Text
165: */
166: public Leaf getLeaf(int index) throws IndexOutOfBoundsException {
167: //-- check bound for index
168: if ((index < 0) || (index >= this .m_leafList.size()))
169: throw new IndexOutOfBoundsException();
170:
171: return (Leaf) this .m_leafList.get(index);
172: }
173:
174: /**
175: * Accessor: Gets an array of all values that constitute the current
176: * value content of this commandline group. This array is a copy to
177: * avoid write-through modifications.
178: *
179: * @return an array with a mixture of either <code>Text</code> or
180: * <code>Use</code> values.
181: *
182: * @see Use
183: * @see Text
184: * @deprecated Use the new Collection based interfaces
185: */
186: public Leaf[] getLeaf() {
187: int size = this .m_leafList.size();
188: Leaf[] mLeaf = new Leaf[size];
189: System.arraycopy(this .m_leafList.toArray(new Leaf[0]), 0,
190: mLeaf, 0, size);
191: return mLeaf;
192: }
193:
194: /**
195: * Accessor: Obtains the size of the commandline group.
196: *
197: * @return number of elements that an external array needs to be sized to.
198: */
199: public int getLeafCount() {
200: return this .m_leafList.size();
201: }
202:
203: /**
204: * Accessor: Gets an array of all values that constitute the current
205: * content. This list is read-only.
206: *
207: * @return an array with a mixture of either <code>Text</code> or
208: * <code>LFN</code> values.
209: *
210: * @see LFN
211: * @see Text
212: */
213: public java.util.List getLeafList() {
214: return Collections.unmodifiableList(this .m_leafList);
215: }
216:
217: /**
218: * Accessor: Obtains the current name of this commandline group.
219: *
220: * @return the name of this commandline group.
221: * @see #setName(java.lang.String)
222: */
223: public String getName() {
224: return this .m_name;
225: }
226:
227: /**
228: * Accessor: Enumerates the internal values that constitute the content
229: * of the <code>Scalar</code> element.
230: *
231: * @return an iterator to walk the list with.
232: */
233: public Iterator iterateLeaf() {
234: return this .m_leafList.iterator();
235: }
236:
237: /**
238: * Accessor: Enumerates the internal values that constitute the content
239: * of the <code>Scalar</code> element.
240: *
241: * @return an enumeration to walk the list with.
242: */
243: public ListIterator listIterateLeaf() {
244: return this .m_leafList.listIterator();
245: }
246:
247: /**
248: * Accessor: Enumerates the internal values that constitute the content
249: * of the <code>Scalar</code> element.
250: *
251: * @param start is the start index
252: * @return an enumeration to walk the list with.
253: */
254: public ListIterator listIterateLeaf(int start) {
255: return this .m_leafList.listIterator(start);
256: }
257:
258: /**
259: * Accessor: Removes all values from this commandline group.
260: */
261: public void removeAllLeaf() {
262: this .m_leafList.clear();
263: }
264:
265: /**
266: * Accessor: Removes a specific fragment from this commandline group.
267: * @param index is the position at which an element is to be removed.
268: * @return the object that was removed. The removed item is either an
269: * <code>Use</code> or a <code>Text</code>.
270: *
271: * @see Use
272: * @see Text
273: */
274: public Leaf removeLeaf(int index) {
275: return (Leaf) this .m_leafList.remove(index);
276: }
277:
278: /**
279: * Accessor: Overwrites a <code>Use</code> or <code>Text</code> value
280: * fragment at a certain position in this command line group.
281: *
282: * @param index position to overwrite an elment in.
283: * @param vLeaf is either a <code>Use</code> or <code>Text</code> object.
284: * @throws IndexOutOfBoundsException if the position pointed to is invalid.
285: * @throws IllegalArgumentException if the added element is of the
286: * incorrect <code>Leaf</code> type.
287: *
288: * @see Use
289: * @see Text
290: */
291: public void setLeaf(int index, Leaf vLeaf)
292: throws IndexOutOfBoundsException, IllegalArgumentException {
293: //-- check bounds for index
294: if ((index < 0) || (index >= this .m_leafList.size())) {
295: throw new IndexOutOfBoundsException();
296: }
297: if (vLeaf instanceof Text || vLeaf instanceof Use)
298: this .m_leafList.set(index, vLeaf);
299: else
300: throw new IllegalArgumentException(c_error_message);
301: } //-- void setLeaf(int, Leaf)
302:
303: /**
304: * Accessor: Replaces the commandline group with another group value.
305: * Warning: The replacements are not checked for being of the correct
306: * leaf types.
307: *
308: * @param leafArray is the external list of <code>Text</code> or
309: * <code>Use</code> objects used to overwrite things.
310: * @see Text
311: * @see Use
312: * @deprecated Use the new Collection based interfaces
313: */
314: public void setLeaf(Leaf[] leafArray) {
315: this .m_leafList.clear();
316: this .m_leafList.addAll(Arrays.asList(leafArray));
317: }
318:
319: /**
320: * Accessor: Overwrites internal list with an external list representing
321: * a <code>Scalar</code> value.
322: *
323: * @param leaves is the external list of <code>Text</code> or
324: * <code>LFN</code> objects used to overwrite things.
325: * @see Text
326: * @see LFN
327: */
328: public void setLeaf(Collection leaves) {
329: this .m_leafList.clear();
330: this .m_leafList.addAll(leaves);
331: }
332:
333: /**
334: * Accessor: Replaces or sets the current identifier for this
335: * commandline group.
336: * @param name is the new identifier to use for this commandline group.
337: * @see #getName()
338: */
339: public void setName(String name) {
340: this .m_name = name;
341: }
342:
343: /**
344: * Converts the commandline group into textual format for human
345: * consumption.
346: *
347: * @param stream is a stream opened and ready for writing. This can also
348: * be a string stream for efficient output.
349: * @exception IOException if something fishy happens to the stream.
350: */
351: public void toString(Writer stream) throws IOException {
352: stream.write("argument");
353: if (this .m_name != null) {
354: stream.write(' ');
355: stream.write(escape(this .m_name));
356: }
357:
358: stream.write(" = ");
359: for (Iterator i = this .m_leafList.iterator(); i.hasNext();) {
360: ((Leaf) i.next()).toString(stream);
361: }
362: }
363:
364: /**
365: * Dump the state of the current element as XML output. This function
366: * traverses all sibling classes as necessary, and converts the data
367: * into pretty-printed XML output. The stream interface should be able
368: * to handle large output efficiently, if you use a buffered writer.
369: *
370: * @param stream is a stream opened and ready for writing. This can also
371: * be a string stream for efficient output.
372: * @param indent is a <code>String</code> of spaces used for pretty
373: * printing. The initial amount of spaces should be an empty string.
374: * The parameter is used internally for the recursive traversal.
375: * If a <code>null</code> value is specified, no indentation nor
376: * linefeeds will be generated.
377: * @param namespace is the XML schema namespace prefix. If neither
378: * empty nor null, each element will be prefixed with this prefix,
379: * and the root element will map the XML namespace.
380: * @exception IOException if something fishy happens to the stream.
381: */
382: public void toXML(Writer stream, String indent, String namespace)
383: throws IOException {
384: String newline = System.getProperty("line.separator", "\r\n");
385: String tag = (namespace != null && namespace.length() > 0) ? namespace
386: + ":argument"
387: : "argument";
388:
389: // open tag
390: if (indent != null && indent.length() > 0)
391: stream.write(indent);
392: stream.write('<');
393: stream.write(tag);
394: writeAttribute(stream, " name=\"", this .m_name); // null-safe
395: stream.write('>');
396: if (indent != null)
397: stream.write(newline);
398:
399: // dump content
400: String newindent = indent == null ? null : indent + " ";
401: for (Iterator i = this .m_leafList.iterator(); i.hasNext();) {
402: ((Leaf) i.next()).toXML(stream, newindent, namespace);
403: }
404:
405: // close tag
406: if (indent != null && indent.length() > 0)
407: stream.write(indent);
408: stream.write("</");
409: stream.write(tag);
410: stream.write('>');
411: if (indent != null)
412: stream.write(newline);
413: }
414: }
|