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: * <code>Use</code> is employed to reference bound actual arguments. Note
026: * that actual arguments are either of type <code>Scalar</code> or
027: * of type <code>List</code>. Each argument has a preferred linkage that
028: * is optionally repeated in this usage class.
029: *
030: * <code>Use</code> extends the base class <code>Leaf</code> by adding
031: * most attributes of all siblings.
032: *
033: * @author Jens-S. Vöckler
034: * @author Yong Zhao
035: * @version $Revision: 50 $
036: *
037: * @see Leaf
038: * @see Text
039: * @see LFN
040: *
041: * @see Value
042: * @see Scalar
043: * @see List
044: */
045: public class Use extends Leaf implements Cloneable, Serializable {
046: /**
047: * The linkage type when refering to an argument that contains a filename.
048: * Legal values range from <code>LFN#NONE</code> to <code>LFN#INOUT</code>.
049: * The initial value is used to flag the non-initialized state.
050: *
051: * @see LFN#NONE
052: * @see LFN#INPUT
053: * @see LFN#OUTPUT
054: * @see LFN#INOUT
055: * @see LFN#isInRange(int)
056: */
057: private int m_link = -1;
058:
059: /**
060: * Stores the name of the bound variable from the actual argument.
061: * This must not be empty. A value must be filled in to reach a valid
062: * object state.
063: */
064: private String m_name;
065:
066: /**
067: * Stores the prefix string to be used when rendering a <code>List</code>.
068: * Unused for <code>Scalar</code> content.
069: *
070: * @see Value
071: * @see Scalar
072: * @see List
073: */
074: private String m_prefix;
075:
076: /**
077: * Stores the separator string used when rendering a <code>List</code>.
078: * Unused for <code>Scalar</code> content.
079: *
080: * @see Value
081: * @see Scalar
082: * @see List
083: */
084: private String m_separator;
085:
086: /**
087: * Stores the suffix string to terminate a <code>List</code> rendering with.
088: * Unused for <code>Scalar</code> content.
089: *
090: * @see Value
091: * @see Scalar
092: * @see List
093: */
094: private String m_suffix;
095:
096: /**
097: * Creates and returns a copy of this object.
098: * @return a new instance.
099: */
100: public Object clone() {
101: Use result = new Use(this .m_name, this .m_prefix,
102: this .m_separator, this .m_suffix);
103: result.setAnyLink(this .m_link);
104: return result;
105: }
106:
107: /**
108: * Default ctor. Creates an empty object that is not valid due
109: * to the lack of a bound variable name. To be used by the SAX
110: * parser.
111: */
112: public Use() {
113: super ();
114: this .m_separator = " "; // default per XML Schema
115: this .m_prefix = this .m_suffix = "";
116: }
117:
118: /**
119: * Convenience ctor. Creates an empty object with a bound argument
120: * name. This ctor should be used by outside applications to assure
121: * proper initialization of the bound argument name.
122: *
123: * @param name is the name of the bound argument to remember.
124: */
125: public Use(String name) {
126: super ();
127: this .m_name = name;
128: this .m_separator = " "; // default per XML Schema
129: this .m_prefix = this .m_suffix = "";
130: }
131:
132: /**
133: * Convenience ctor. Creates an object with a bound argument name.
134: * This ctor should be used by outside applications to assure proper
135: * initialization of the bound argument name.
136: *
137: * @param name is the name of the bound argument to remember.
138: * @param prefix is a prefix when rendering list content into a string.
139: * @param separator is a string to be placed between list elements when
140: * rendering a list.
141: * @param suffix is a suffix when rendering list content into a string.
142: *
143: * @see Scalar
144: * @see List
145: */
146: public Use(String name, String prefix, String separator,
147: String suffix) {
148: super ();
149: this .m_name = name;
150: this .m_prefix = prefix;
151: this .m_separator = separator;
152: this .m_suffix = suffix;
153: }
154:
155: /**
156: * Convenience ctor. Creates an object with a bound argument name.
157: * This ctor should be used by outside applications to assure proper
158: * initialization of the bound argument name.
159: *
160: * @param name is the name of the bound argument to remember.
161: * @param link is the linkage type of the bound argument for type checking.
162: * @throws IllegalArgumentException if the linkage is not
163: * within the legal range between {@link LFN#NONE} and
164: * {@link LFN#INOUT}.
165: */
166: public Use(String name, int link) throws IllegalArgumentException {
167: super ();
168: this .m_name = name;
169: this .m_separator = " "; // default per XML Schema
170: this .m_prefix = this .m_suffix = "";
171: if (LFN.isInRange(link))
172: this .m_link = link;
173: else
174: throw new IllegalArgumentException();
175: }
176:
177: /**
178: * Accessor: Obtains the current state of the linkage.
179: *
180: * @return the linkage value. The returned value might be -1 to indicate
181: * that the linkage was not initialized. Note that -1 is an out of range
182: * value for linkage.
183: * @see #setLink(int)
184: */
185: public int getLink() {
186: return this .m_link;
187: }
188:
189: /**
190: * Accessor: Obtains the name of the bound actual argument.
191: *
192: * @return the bound name. A misconfigured object might return an empty
193: * or null string.
194: * @see #setName(String)
195: */
196: public String getName() {
197: return this .m_name;
198: }
199:
200: /**
201: * Accessor: Obtains the current prefix rendering information. The
202: * prefix is used in {@link List} rendering as front bracket.
203: *
204: * @return the prefix rendering string, which might be null or empty.
205: * @see #setPrefix(String)
206: */
207: public String getPrefix() {
208: return this .m_prefix;
209: }
210:
211: /**
212: * Accessor: Obtains the current separator rendering information. The
213: * separator is used in {@link List} rendering as element separator.
214: *
215: * @return the separator rendering string, which might be null or empty.
216: * @see #setSeparator(String)
217: */
218: public String getSeparator() {
219: return this .m_separator;
220: }
221:
222: /**
223: * Accessor: Obtains the current suffix rendering information. The
224: * suffix is used in {@link List} rendering as rear bracket.
225: *
226: * @return the suffix rendering string, which might be null or empty.
227: * @see #setSuffix(String)
228: */
229: public String getSuffix() {
230: return this .m_suffix;
231: }
232:
233: /**
234: * Accessor: Sets the linkage of the bound argument.
235: * @param link is the linkage value as integer within the range.
236: * @throws IllegalArgumentException if the linkage is not
237: * within the legal range between {@link LFN#NONE} and
238: * {@link LFN#INOUT}.
239: * @see #getLink()
240: * @see LFN#NONE
241: * @see LFN#INPUT
242: * @see LFN#OUTPUT
243: * @see LFN#INOUT
244: * @see LFN#isInRange(int)
245: */
246: public void setLink(int link) throws IllegalArgumentException {
247: if (LFN.isInRange(link))
248: this .m_link = link;
249: else
250: throw new IllegalArgumentException();
251: }
252:
253: private void setAnyLink(int link) {
254: this .m_link = link;
255: }
256:
257: /**
258: * Accessor: Sets or overwrites the name of the bound argument.
259: * Do not use empty or null strings here.
260: *
261: * @param name is the new variable name to remember.
262: * @see #getName()
263: */
264: public void setName(String name) {
265: this .m_name = name;
266: }
267:
268: /**
269: * Accessor: Sets or overwrites the current prefix rendering information.
270: * The prefix is used in {@link List} rendering as front bracket.
271: *
272: * @param prefix is a rendering string, which might be null or empty.
273: * @see #getPrefix()
274: */
275: public void setPrefix(String prefix) {
276: this .m_prefix = prefix;
277: }
278:
279: /**
280: * Accessor: Sets or overwrites the current separator rendering information.
281: * The separator is used between {@link List} element during rendering.
282: *
283: * @param separator is a rendering string, which might be null or empty.
284: * @see #getSeparator()
285: */
286: public void setSeparator(String separator) {
287: this .m_separator = separator;
288: }
289:
290: /**
291: * Accessor: Sets or overwrites the current suffix rendering information.
292: * The suffix is used in {@link List} rendering as rear bracket.
293: *
294: * @param suffix is a rendering string, which might be null or empty.
295: * @see #getSuffix()
296: */
297: public void setSuffix(String suffix) {
298: this .m_suffix = suffix;
299: }
300:
301: /**
302: * Dump content of this instance representation into a stream.<p>
303: * FIXME: The rendering information is not dumped into the non-XML output.
304: *
305: * @param stream is a stream opened and ready for writing. This can
306: * also be a string stream for efficient output. The stream interface
307: * should be able to handle large elements efficiently.
308: * @exception IOException if something fishy happens to the stream.
309: */
310: public void toString(Writer stream) throws IOException {
311: boolean has_fix = (this .m_prefix != null
312: && this .m_prefix.length() > 0 || this .m_suffix != null
313: && this .m_suffix.length() > 0);
314: boolean has_sep = (this .m_separator == null || !this .m_separator
315: .equals(" "));
316:
317: if (has_fix || has_sep) {
318: // must use the tedious version
319: stream.write("${");
320: if (has_fix) {
321: // this is the ${pre:sep:suf|link:id} version
322: stream.write('"');
323: if (this .m_prefix != null)
324: stream.write(escape(this .m_prefix));
325: stream.write("\":\"");
326: if (this .m_separator != null)
327: stream.write(escape(this .m_separator));
328: stream.write("\":\"");
329: if (this .m_suffix != null)
330: stream.write(escape(this .m_suffix));
331: stream.write("\"|");
332: } else if (has_sep) {
333: // this is the ${sep|link:id} version, mind that " " is IMPLIED!
334: // thus, ${""|link:id} is the output for any null separator, while
335: // ${link:id} will be the output for a space separator.
336: stream.write('"');
337: if (this .m_separator != null)
338: stream.write(escape(this .m_separator));
339: stream.write("\"|");
340: }
341:
342: if (LFN.isInRange(this .m_link)) {
343: stream.write(LFN.toString(this .m_link)); // no need to escape()
344: stream.write(':');
345: }
346: stream.write(escape(this .m_name));
347: stream.write('}');
348: } else if (LFN.isInRange(this .m_link)) {
349: // use the type-casting version
350: stream.write('(');
351: stream.write(LFN.toString(this .m_link)); // no need to escape()
352: stream.write(')');
353: stream.write(escape(this .m_name));
354: } else {
355: // can use minimal version
356: stream.write(escape(this .m_name));
357: }
358: }
359:
360: /**
361: * Dump the state of the current element as XML output. This function
362: * traverses all sibling classes as necessary, and converts the data
363: * into pretty-printed XML output. The stream interface should be able
364: * to handle large output efficiently, if you use a buffered writer.
365: *
366: * @param stream is a stream opened and ready for writing. This can also
367: * be a string stream for efficient output.
368: * @param indent is a <code>String</code> of spaces used for pretty
369: * printing. The initial amount of spaces should be an empty string.
370: * The parameter is used internally for the recursive traversal.
371: * If a <code>null</code> value is specified, no indentation nor
372: * linefeeds will be generated.
373: * @param namespace is the XML schema namespace prefix. If neither
374: * empty nor null, each element will be prefixed with this prefix,
375: * and the root element will map the XML namespace.
376: * @exception IOException if something fishy happens to the stream.
377: */
378: public void toXML(Writer stream, String indent, String namespace)
379: throws IOException {
380: if (indent != null && indent.length() > 0)
381: stream.write(indent);
382: stream.write('<');
383: if (namespace != null && namespace.length() > 0) {
384: stream.write(namespace);
385: stream.write(':');
386: }
387: stream.write("use");
388: writeAttribute(stream, " name=\"", this .m_name);
389: if (LFN.isInRange(this .m_link))
390: writeAttribute(stream, " link=\"", LFN
391: .toString(this .m_link));
392: if (this .m_prefix != null && this .m_prefix.length() > 0)
393: writeAttribute(stream, " prefix=\"", this .m_prefix);
394:
395: // If the separator is empty, write it. We may not need to write it,
396: // if the separator is a space.
397: if (this .m_separator == null || !this .m_separator.equals(" ")) {
398: stream.write(" separator=\"");
399: if (this .m_separator != null)
400: stream.write(quote(this .m_separator, true));
401: stream.write('\"');
402: }
403:
404: if (this .m_suffix != null && this .m_suffix.length() > 0)
405: writeAttribute(stream, " suffix=\"", this .m_suffix);
406:
407: stream.write("/>");
408: if (indent != null)
409: stream.write(System.getProperty("line.separator", "\r\n"));
410: }
411: }
|