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: * This class implements the list argument type used for parameters passed
025: * to transformations from derivations.
026: *
027: * @author Jens-S. Vöckler
028: * @author Yong Zhao
029: * @version $Revision: 50 $
030: *
031: * @see Value
032: * @see Scalar
033: */
034: public class List extends Value implements Cloneable, Serializable {
035: /**
036: * A list is just an ordered bunch of {@link Scalar}.
037: */
038: private ArrayList m_scalarList;
039:
040: /**
041: * Creates and returns a copy of this object.
042: * @return a new instance.
043: */
044: public Object clone() {
045: List result = new List();
046: for (int index = 0; index < this .m_scalarList.size(); ++index) {
047: result.addScalar((Scalar) this .getScalar(index).clone());
048: }
049: return result;
050: }
051:
052: /**
053: * Default ctor.
054: */
055: public List() {
056: super ();
057: this .m_scalarList = new ArrayList();
058: }
059:
060: /**
061: * Convenience ctor: Initializes the list, and stores the given
062: * {@link Scalar} as first child into the list.
063: *
064: * @param firstChild is the first element in the list
065: */
066: public List(Scalar firstChild) {
067: super ();
068: this .m_scalarList = new ArrayList();
069: this .m_scalarList.add(firstChild);
070: }
071:
072: /**
073: * Accessor: Obtains the value type of this class. By using the abstract
074: * method in the parent class, <code>List</code> objects can be
075: * distinguished from <code>Scalar</code> objects without using the
076: * <code>instanceof</code> operator.
077: *
078: * @return the fixed value of being a scalar.
079: * @see Value#LIST
080: */
081: public int getContainerType() {
082: return Value.LIST;
083: }
084:
085: /**
086: * This method determines which container is being used in the abstract
087: * base class in order to kludgy statements when printing debug info.
088: *
089: * @return the symblic identifier for the type of the Value.
090: */
091: public String getSymbolicType() {
092: // always
093: return new String("List");
094: }
095:
096: /**
097: * Accessor: Appends as <code>Scalar</code> value to the list.
098: *
099: * @param vScalar is the <code>Scalar</code> to append to the list.
100: * @throws IndexOutOfBoundsException if the value cannot be added.
101: * @see Scalar
102: */
103: public void addScalar(Scalar vScalar)
104: throws IndexOutOfBoundsException {
105: this .m_scalarList.add(vScalar);
106: }
107:
108: /**
109: * Accessor: Insert a <code>Scalar</code> at a specific position.
110: *
111: * @param index is the position to insert the item into
112: * @param vScalar is the <code>Scalar</code> to append to the list.
113: * @throws IndexOutOfBoundsException if the value cannot be added.
114: * @see Scalar
115: */
116: public void addScalar(int index, Scalar vScalar)
117: throws IndexOutOfBoundsException {
118: this .m_scalarList.add(index, vScalar);
119: }
120:
121: /**
122: * Accessor: constructs the iterator for the <code>List</code> items.
123: *
124: * @return an enumeration to walk the list with.
125: * @deprecated Use the new Collection based interfaces
126: */
127: public Enumeration enumerateScalar() {
128: return Collections.enumeration(this .m_scalarList);
129: }
130:
131: /**
132: * Determines all LFN instances of a given scalar that match the
133: * specified linkage. This is a higher-level method employing the
134: * given API.
135: *
136: * @param linkage is the linkage to check for, -1 for all filenames.
137: * @return a set of logical filename instances that match the linkage
138: * and were part of the scalar. The result may be an empty set, if no
139: * such result were to be found.
140: *
141: * @see Scalar#getAllLFN( int )
142: * @see LFN
143: */
144: public java.util.List getAllLFN(int linkage) {
145: java.util.List result = new ArrayList();
146:
147: for (Iterator i = this .iterateScalar(); i.hasNext();)
148: result.addAll(((Scalar) i.next()).getAllLFN(linkage));
149:
150: return result;
151: }
152:
153: /**
154: * Determines all LFN instances of a given scalar that match the
155: * specified linkage. This is a higher-level method employing the
156: * given API. Note that also linkage of NONE will not be found in
157: * wildcard search mode.
158: *
159: * @param linkage is the linkage to check for, -1 for all filenames.
160: * @return a set of all logical filenames that match the linkage and
161: * were part of the scalar. The result may be an empty set, if no such
162: * result were to be found. For a linkage of -1, complete LFNs will be
163: * returned, for any other linkage, just the filename will be
164: * returned.
165: *
166: * @see Scalar#getLFNList( int )
167: * @see Derivation#getLFNList( int )
168: * @see LFN
169: */
170: public java.util.List getLFNList(int linkage) {
171: java.util.List result = new ArrayList();
172:
173: for (Iterator i = this .iterateScalar(); i.hasNext();)
174: result.addAll(((Scalar) i.next()).getLFNList(linkage));
175:
176: return result;
177: }
178:
179: /**
180: * Determines if the list contains an LFN of the specified linkage.
181: * The logic uses short-circuit evaluation, thus finding things is
182: * faster than not finding things. Searching a list is a potentially
183: * expensive method.
184: *
185: * @param filename is the name of the LFN
186: * @param linkage is the linkage to check for, -1 for any linkage type.
187: * @return true if the LFN is contained in the scalar, false otherwise.
188: *
189: * @see org.griphyn.vdl.classes.LFN
190: * @see Scalar#containsLFN( String, int )
191: */
192: public boolean containsLFN(String filename, int linkage) {
193: for (Iterator i = this .iterateScalar(); i.hasNext();)
194: if (((Scalar) i.next()).containsLFN(filename, linkage))
195: return true;
196:
197: // not found
198: return false;
199: }
200:
201: /**
202: * Accessor: Obtains the value of a specific item in the list.
203: *
204: * @param index is the position of which to obtain the value of.
205: * @return The {@link Scalar} at the specified position.
206: * @throws IndexOutOfBoundsException if the index points to an element
207: * that is beyond the list boundaries.
208: */
209: public Scalar getScalar(int index) throws IndexOutOfBoundsException {
210: //-- check bound for index
211: if ((index < 0) || (index >= this .m_scalarList.size()))
212: throw new IndexOutOfBoundsException();
213:
214: return (Scalar) this .m_scalarList.get(index);
215: }
216:
217: /**
218: * Accessor: Gets an array of all <code>Scalar</code>s in the list.
219: *
220: * @return an array of <code>Scalar</code>s.
221: * @see Scalar
222: * @deprecated Use the new Collection based interfaces
223: */
224: public Scalar[] getScalar() {
225: int size = this .m_scalarList.size();
226: Scalar[] mScalar = new Scalar[size];
227: System.arraycopy(this .m_scalarList.toArray(new Scalar[0]), 0,
228: mScalar, 0, size);
229: return mScalar;
230: }
231:
232: /**
233: * Accessor: Obtains the element count of the internal list
234: *
235: * @return number of elements in the internal list
236: */
237: public int getScalarCount() {
238: return this .m_scalarList.size();
239: }
240:
241: /**
242: * Accessor: Gets an array of all <code>Scalar</code>s in the list.
243: * This list is read-only.
244: *
245: * @return an array of <code>Scalar</code>s.
246: * @see Scalar
247: */
248: public java.util.List getScalarList() {
249: return Collections.unmodifiableList(this .m_scalarList);
250: }
251:
252: /**
253: * Accessor: constructs the iterator for the <code>List</code> items.
254: *
255: * @return an enumeration to walk the list with.
256: */
257: public Iterator iterateScalar() {
258: return this .m_scalarList.iterator();
259: }
260:
261: /**
262: * Accessor: constructs the iterator for the <code>List</code> items.
263: *
264: * @return an enumeration to walk the list with.
265: */
266: public ListIterator listIterateScalar() {
267: return this .m_scalarList.listIterator();
268: }
269:
270: /**
271: * Accessor: constructs the iterator for the <code>List</code> items.
272: * @param start is the starting position for the sub-iteration.
273: * @return an enumeration to walk the list with.
274: */
275: public ListIterator listIterateScalar(int start) {
276: return this .m_scalarList.listIterator(start);
277: }
278:
279: /**
280: * Accessor: Removes all elements in the <code>List</code>.
281: */
282: public void removeAllScalar() {
283: this .m_scalarList.clear();
284: }
285:
286: /**
287: * Accessor: Removes a single element from the <code>List</code>. Each
288: * component in this vector with an index greater or equal to the
289: * specified index is shifted downward to have an index one smaller
290: * than the value it had previously. The size of this vector is
291: * decreased by 1.
292: *
293: * @param index is the position at which an element is to be removed.
294: * @return the {@link Scalar} that was removed.
295: * @throws ArrayIndexOutOfBoundsException if the index was invalid.
296: */
297: public Scalar removeScalar(int index) {
298: return (Scalar) this .m_scalarList.remove(index);
299: }
300:
301: /**
302: * Accessor: Overwrite an element at a given position.
303: *
304: * @param index is the position to use. It must be within the list.
305: * @param vScalar is the new value to replace the element with.
306: * @throws IndexOutOfBoundsException if the position is outside the list.
307: */
308: public void setScalar(int index, Scalar vScalar)
309: throws IndexOutOfBoundsException {
310: //-- check bounds for index
311: if ((index < 0) || (index >= this .m_scalarList.size())) {
312: throw new IndexOutOfBoundsException();
313: }
314: this .m_scalarList.set(index, vScalar);
315: } //-- void setScalar(int, Scalar)
316:
317: /**
318: * Accessor: Replaces all elements with a new list of {@link Scalar}s.
319: *
320: * @param scalarArray is the list to replace the original list with.
321: * @deprecated Use the new Collection based interfaces
322: */
323: public void setScalar(Scalar[] scalarArray) {
324: //-- copy array
325: this .m_scalarList.clear();
326: this .m_scalarList.addAll(Arrays.asList(scalarArray));
327: }
328:
329: /**
330: * Accessor: Replaces all elements with a new list of {@link Scalar}s.
331: *
332: * @param scalars is the list to replace the original list with.
333: */
334: public void setScalar(Collection scalars) {
335: this .m_scalarList.clear();
336: this .m_scalarList.addAll(scalars);
337: }
338:
339: /**
340: * Dumps the list and all its contents into a string. The list will
341: * be terminated by brackets, elements separated by komma, space.
342: * Elements itself will be dumped by recursive calls to the element
343: * specific method of the same name.
344: *
345: * @param stream is a stream opened and ready for writing. This can also
346: * be a string stream for efficient output.
347: * @exception IOException if something fishy happens to the stream.
348: */
349: public void toString(Writer stream) throws IOException {
350: stream.write("[ ");
351: for (Iterator i = this .m_scalarList.iterator(); i.hasNext();) {
352: ((Scalar) i.next()).toString(stream);
353: if (i.hasNext())
354: stream.write(", ");
355: }
356: stream.write(" ]");
357: }
358:
359: /**
360: * Dump the state of the current element as XML output. This function
361: * traverses all sibling classes as necessary, and converts the data
362: * into pretty-printed XML output. The stream interface should be able
363: * to handle large output efficiently, if you use a buffered writer.
364: *
365: * @param stream is a stream opened and ready for writing. This can also
366: * be a string stream for efficient output.
367: * @param indent is a <code>String</code> of spaces used for pretty
368: * printing. The initial amount of spaces should be an empty string.
369: * The parameter is used internally for the recursive traversal.
370: * @param namespace is the XML schema namespace prefix. If neither
371: * empty nor null, each element will be prefixed with this prefix,
372: * and the root element will map the XML namespace.
373: * @exception IOException if something fishy happens to the stream.
374: */
375: public void toXML(Writer stream, String indent, String namespace)
376: throws IOException {
377: String newline = System.getProperty("line.separator", "\r\n");
378: String tag = (namespace != null && namespace.length() > 0) ? namespace
379: + ":list"
380: : "list";
381:
382: // open tag
383: if (indent != null && indent.length() > 0)
384: stream.write(indent);
385: stream.write('<');
386: stream.write(tag);
387: stream.write('>');
388: if (indent != null)
389: stream.write(newline);
390:
391: // dump content
392: String newindent = indent == null ? null : indent + " ";
393: for (Iterator i = this .m_scalarList.iterator(); i.hasNext();) {
394: // FIXME: If we cast to Value, we can have lists in lists
395: ((Scalar) i.next()).toXML(stream, newindent, namespace);
396: }
397:
398: // close tag
399: if (indent != null && indent.length() > 0)
400: stream.write(indent);
401: stream.write("</");
402: stream.write(tag);
403: stream.write('>');
404: if (indent != null)
405: stream.write(newline);
406: }
407: }
|