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.common.util.Currently;
018: import org.griphyn.vdl.classes.*;
019: import org.griphyn.vdl.util.*;
020: import java.util.*;
021: import java.io.*;
022:
023: /**
024: * This class implements the container to carry any number of
025: * <code>Transformation</code> and <code>Derivation</code> instances.
026: * In addition, it captures some attributes from the root element of
027: * the XML document.
028: *
029: * @author Jens-S. Vöckler
030: * @author Yong Zhao
031: * @version $Revision: 50 $
032: *
033: * @see Definition
034: * @see Transformation
035: * @see Derivation
036: */
037: public class Definitions extends VDL implements Serializable {
038: /**
039: * The "official" namespace URI of the VDLx schema.
040: */
041: public static final String SCHEMA_NAMESPACE = "http://www.griphyn.org/chimera/VDL";
042:
043: /**
044: * The "not-so-official" location URL of the VDLx schema definition.
045: */
046: public static final String SCHEMA_LOCATION = "http://www.griphyn.org/chimera/vdl-1.24.xsd";
047:
048: // attributes of "definitions" element
049: /**
050: * Capture the global namespace given to all child elements that
051: * do not set their own namespace definition.
052: */
053: private String m_vdlns;
054:
055: /**
056: * Capture the version of the XML document.
057: */
058: private String m_version;
059:
060: /**
061: * children are either {@link Transformation}s or {@link Derivation}s,
062: * both of which are {@link Derivation}s.
063: */
064: private ArrayList m_definitionList;
065:
066: /**
067: * ctor. It is strongly suggested that you set the namespace and
068: * version of the object before adding any other {@link Definition}
069: * objects.
070: */
071: public Definitions() {
072: this .m_definitionList = new ArrayList();
073: this .m_vdlns = null;
074: this .m_version = null;
075: }
076:
077: /**
078: * ctor: Create a new container, using the given namespace. It is
079: * highly recommended that you set the version number before you add
080: * any {@link Definition} instance.
081: *
082: * @param vdlns is the namespace to use for elements w/o namespace.
083: */
084: public Definitions(String vdlns) {
085: this .m_definitionList = new ArrayList();
086: this .m_vdlns = vdlns;
087: this .m_version = null;
088: }
089:
090: /**
091: * ctor: Create a new container, using a namespace and version.
092: *
093: * @param vdlns is the namespace to propagate to children w/o namespace.
094: * @param version is a version of the XML document used to transport
095: * the data.
096: */
097: public Definitions(String vdlns, String version) {
098: this .m_definitionList = new ArrayList();
099: this .m_vdlns = vdlns;
100: this .m_version = version;
101: }
102:
103: /**
104: * updating old Use.linkage with new Use.linkage. This table uses
105: * the old/stored linkage in the top row, and the new/found linkage
106: * in the first column. (-) denotes no action to be taken, and #
107: * an illegal combination.<p>
108: * <pre>
109: * | -1 | NONE| IN | OUT | IO
110: * ----+-----+-----+-----+-----+----
111: * -1 | (-) | (-) | (-) | (-) | (-)
112: * NONE| NONE| (-) | # | # | #
113: * IN| IN | # | (-) | IO | (-)
114: * OUT| OUT | # | IO | (-) | (-)
115: * IO| IO | # | IO | IO | (-)
116: * ----+-----+-----+-----+-----+----
117: * </pre>
118: * The table uses -1 for no action to do, and -2 for an illegal state.
119: */
120: private int m_state[][] = { { -1, -1, -1, -1, -1 }, // newlink == -1
121: { 0, -1, -2, -2, -2 }, // newlink == NONE
122: { 1, -2, -1, 3, -1 }, // newlink == IN
123: { 2, -2, 3, -1, -1 }, // newlink == OUT
124: { 3, -2, 3, 3, -1 } };
125:
126: /**
127: * Checks the linkage of a transformation between a declared, previously
128: * used and currently used variable of the same name.
129: *
130: * @param use is a table of previously used variables and their linkage
131: * @param u is the variable at the "cursor position".
132: * @param tr is the transformation to be checked.
133: */
134: private void checkLinkage(Map use, Use u, Transformation tr) {
135: if (use.containsKey(u.getName())) {
136: // key exists, check/modify linkage
137: int linkage = ((Integer) use.get(u.getName())).intValue();
138: int newlink = u.getLink();
139: int result = this .m_state[newlink + 1][linkage + 1];
140: if (result == -2) {
141: // illegal combination of linkages, usually NONE w/ I,O,IO
142: throw new IncompatibleLinkageException(
143: "Transformation " + tr.shortID()
144: + "uses variable " + u.getName()
145: + " with incompatibles linkages");
146: } else if (result > -1) {
147: // store new result
148: use.put(u.getName(), new Integer(result));
149: }
150: } else {
151: // key does not exist, add
152: use.put(u.getName(), new Integer(u.getLink()));
153: }
154: }
155:
156: /**
157: * Clean-up definition and perform abstract type checks before
158: * submitting them into the document.
159: *
160: * @exception IllegalArgumentException will be thrown if the
161: * <code>Definition</code> is neither a <code>Derivation</code> nor a
162: * <code>Transformation</code>. This should not happen.
163: * @exception UndeclaredVariableException will be thrown, if
164: * a <code>Transformation</code> uses a bound variable via <code>Use</code>,
165: * but fails to declare the formal argument with <code>Declare</code>.
166: * @exception IncompatibleLinkageException will be thrown, if
167: * the declared linkage of a formal argument is incompatible with the
168: * usage of such a bound variable within a <code>Transformation</code>.
169: * @exception IllegalTransformationException will be thrown, if
170: * the <code>Transformation</code> has simultaneously <code>Call</code>
171: * and <code>Argument</code> items. This exception is bound to vanish
172: * with the next major re-design.
173: *
174: * @see Transformation
175: * @see Derivation
176: * @see Use
177: * @see Declare
178: */
179: protected void sanitizeDefinition(Definition d)
180: throws IllegalArgumentException,
181: IncompatibleLinkageException, UndeclaredVariableException,
182: IllegalTransformationException {
183: String newline = System.getProperty("line.separator", "\r\n");
184:
185: // update definition with namespace and version, if necessary
186: // Note: results may still be null
187: if (d.getNamespace() == null && this .m_vdlns != null)
188: d.setNamespace(this .m_vdlns);
189: if (d.getVersion() == null && this .m_version != null)
190: d.setVersion(this .m_version);
191:
192: switch (d.getType()) {
193: case Definition.TRANSFORMATION:
194: Transformation tr = (Transformation) d;
195: HashMap use = new HashMap();
196:
197: // a TR must not be simultaneously simple and compound
198: if (tr.getArgumentCount() > 0 && tr.getCallCount() > 0)
199: throw new IllegalTransformationException("TR "
200: + tr.identify()
201: + " is simultaneously simple and compound"
202: + newline + tr.toXML("\t", null));
203:
204: //
205: // collect all unique bindings of class Use
206: //
207: if (tr.isSimple()) {
208: // collect from Argument list
209: for (Iterator e = tr.iterateArgument(); e.hasNext();) {
210: for (Iterator f = ((Argument) e.next())
211: .iterateLeaf(); f.hasNext();) {
212: Leaf l = (Leaf) f.next();
213: if (l instanceof Use)
214: checkLinkage(use, (Use) l, tr);
215: }
216: }
217: } else {
218: // collect from Call list, this is slightly more complex...
219: // only 3..4 nested for loops, why do you worry...
220: for (Iterator e = tr.iterateCall(); e.hasNext();) {
221: for (Iterator f = ((Call) e.next()).iteratePass(); f
222: .hasNext();) {
223: Value v = (Value) ((Pass) f.next()).getValue();
224: switch (v.getContainerType()) {
225: case Value.SCALAR:
226: for (Iterator g = ((Scalar) v)
227: .iterateLeaf(); g.hasNext();) {
228: Leaf l = (Leaf) g.next();
229: if (l instanceof Use)
230: checkLinkage(use, (Use) l, tr);
231: }
232: break;
233: case Value.LIST:
234: for (Iterator h = ((List) v)
235: .iterateScalar(); h.hasNext();) {
236: for (Iterator g = ((Scalar) h.next())
237: .iterateLeaf(); g.hasNext();) {
238: Leaf l = (Leaf) g.next();
239: if (l instanceof Use)
240: checkLinkage(use, (Use) l, tr);
241: }
242: }
243: break;
244: }
245: }
246: }
247: }
248: // collect from Profile list
249: for (Iterator e = tr.iterateProfile(); e.hasNext();) {
250: for (Iterator f = ((Profile) e.next()).iterateLeaf(); f
251: .hasNext();) {
252: Leaf l = (Leaf) f.next();
253: if (l instanceof Use)
254: checkLinkage(use, (Use) l, tr);
255: }
256: }
257:
258: // check usages against all declared and temporary variables. Also
259: // check linkage. Note that the declared variables must have a
260: // linkage. It is permissable to declare variables, but not use
261: // them.
262: for (Iterator i = use.keySet().iterator(); i.hasNext();) {
263: String name = (String) i.next();
264:
265: // check that the used variable is declared
266: Declare dec = (Declare) tr.getDeclare(name);
267: Local local = (Local) tr.getLocal(name);
268: if (dec == null && local == null)
269: throw new UndeclaredVariableException("variable "
270: + name + " is used, but not declared"
271: + newline + tr.toXML("\t", null));
272:
273: // match up linkages. Note that a use linkage of -1 means
274: // that we don't have any information on the used linkage.
275: int dLinkage = (dec == null ? local.getLink() : dec
276: .getLink());
277: int uLinkage = ((Integer) use.get(name)).intValue();
278: if (uLinkage > -1) {
279: if (dLinkage == LFN.NONE && uLinkage != LFN.NONE
280: || dLinkage == LFN.INPUT
281: && uLinkage != LFN.INPUT
282: || dLinkage == LFN.OUTPUT
283: && uLinkage != LFN.OUTPUT
284: || dLinkage == LFN.INOUT
285: && uLinkage == LFN.NONE)
286: throw new IncompatibleLinkageException(
287: "variable " + name
288: + " uses incompatible linkages"
289: + newline
290: + tr.toXML("\t", null));
291: }
292: }
293: break;
294: case Definition.DERIVATION:
295: Derivation dv = (Derivation) d;
296:
297: if (dv.getUsesspace() == null) {
298: if (this .m_vdlns != null) {
299: // either default uses namespace to vdlns
300: dv.setUsesspace(this .m_vdlns);
301: } else if (d.getNamespace() != null) {
302: // or default uses namespace to derivation namespace
303: dv.setUsesspace(d.getNamespace());
304: }
305: }
306:
307: // nothing really to check for derivations
308: // note: Do *not* check here, if a DV has a matching TR, because
309: // in the future, TR will be stored in distributed database(s).
310: break;
311:
312: default:
313: // this must not happen
314: throw new IllegalArgumentException("Definition "
315: + d.identify() + " is neither TR nor DV");
316: }
317: }
318:
319: /**
320: * Accessor: Appends a {@link Definition} to the container. The
321: * namespace and version information will be, in case they are
322: * missing, updated from the definitions namespace and version
323: * respectively.
324: *
325: * @param d is the {@link Transformation} or {@link Derivation}
326: * to append to the internal container.
327: * @throws IndexOutOfBoundsException if the definition does not fit into
328: * the container.
329: */
330: public void addDefinition(Definition d)
331: throws IndexOutOfBoundsException {
332: this .sanitizeDefinition(d);
333: this .m_definitionList.add(d);
334: }
335:
336: /**
337: * Accessor: Inserts a {@link Definition} at a particular place. The
338: * namespace and version information will be, in case they are
339: * missing, updated from the definitions namespace and version
340: * respectively.<p>
341: *
342: * Each component in this vector with an index greater or equal to the
343: * specified index is shifted upward to have an index one greater than
344: * the value it had previously.
345: *
346: * @param index is the position to insert a {@link Definition}
347: * @param d is the {@link Transformation} or {@link Derivation}
348: * to append to the internal container.
349: * @throws IndexOutOfBoundsException if the definition does not fit into
350: * the container.
351: */
352: public void addDefinition(int index, Definition d)
353: throws IndexOutOfBoundsException {
354: this .sanitizeDefinition(d);
355: this .m_definitionList.add(index, d);
356: }
357:
358: /**
359: * Accessor: Search the database for the existence of a Definition with
360: * the same primary keys and type as the parameter.
361: * @param d is the Definition to search for
362: * @return the position of the selfsame Definition, or -1 if not found.
363: */
364: public int positionOfDefinition(Definition d) {
365: int n = 0;
366: for (Iterator i = this .m_definitionList.iterator(); i.hasNext(); ++n) {
367: if (d.equals(i.next()))
368: return n;
369: }
370: return -1;
371: }
372:
373: /**
374: * Accessor: Provides an iterator for the list of {@link Transformation}
375: * and {@link Derivation}.
376: *
377: * @return the iterator to traverse the container of {@link Definition}s.
378: * @see java.util.Enumeration
379: * @deprecated Use the new Collection based interfaces
380: */
381: public Enumeration enumerateDefinition() {
382: return Collections.enumeration(this .m_definitionList);
383: }
384:
385: /**
386: * Obtains a vector of all definition instances that share the same
387: * instance type. Please note that the definitions below may change
388: * after the vector is obtained.
389: *
390: * @return a vector with all {@link Transformation} or {@link Derivation}
391: * objects. The vector may have zero size, if no such instances exist.
392: */
393: public java.util.List getDefinitionOfAKind(int type) {
394: ArrayList result = new ArrayList();
395: for (Iterator i = this .m_definitionList.iterator(); i.hasNext();) {
396: Definition d = (Definition) i.next();
397: if (d.getType() == type) {
398: result.add(d);
399: }
400: }
401:
402: return result;
403: }
404:
405: /**
406: * Accessor: Obtains a <code>Definition</code> at a particular place
407: * in this container.
408: *
409: * @param index is the place to look up the element.
410: * @return the <code>Definition</code> at the specified place.
411: * @throws IndexOutOfBoundsException if the referenced position does
412: * not exist.
413: * @see Definition
414: */
415: public Definition getDefinition(int index)
416: throws IndexOutOfBoundsException {
417: //-- check bound for index
418: if ((index < 0) || (index >= this .m_definitionList.size()))
419: throw new IndexOutOfBoundsException();
420:
421: return (Definition) this .m_definitionList.get(index);
422: }
423:
424: /**
425: * Accessor: Obtains all {@link Definition}s available.
426: * This array is a copy to avoid write-through modifications.
427: *
428: * @return an array containing either a {@link Transformation}
429: * or {@link Derivation} at each position.
430: * @deprecated Use the new Collection based interfaces
431: */
432: public Definition[] getDefinition() {
433: int size = this .m_definitionList.size();
434: Definition[] mDefinition = new Definition[size];
435: System.arraycopy(this .m_definitionList
436: .toArray(new Definition[0]), 0, mDefinition, 0, size);
437: return mDefinition;
438: }
439:
440: /**
441: * Accessor: Counts the number of {@link Transformation} and
442: * {@link Derivation} definitions.
443: * @return item count.
444: */
445: public int getDefinitionCount() {
446: return this .m_definitionList.size();
447: }
448:
449: /**
450: * Accessor: Obtains all {@link Definition}s available.
451: * This list is read-only.
452: *
453: * @return an array containing either a {@link Transformation}
454: * or {@link Derivation} at each position.
455: */
456: public java.util.List getDefinitionList() {
457: return Collections.unmodifiableList(this .m_definitionList);
458: }
459:
460: /**
461: * Accessor: Obtains the document namespace.
462: * @return the namespace of the document, or null, if not used.
463: * @see #setVdlns(java.lang.String)
464: */
465: public String getVdlns() {
466: return this .m_vdlns;
467: }
468:
469: /** Accessor: Obtains the document version number.
470: *
471: * @return the version number from the document header, or null,
472: * if unset. Since the version number is a required attribute,
473: * it should never return null, only an empty string.
474: */
475: public String getVersion() {
476: return this .m_version;
477: }
478:
479: /**
480: * Accessor: Provides an iterator for the list of {@link Transformation}
481: * and {@link Derivation} references.
482: *
483: * @return a list iterator to traverse the container of {@link Definition}s.
484: * @see java.util.ListIterator
485: */
486: public Iterator iterateDefinition() {
487: return this .m_definitionList.iterator();
488: }
489:
490: /**
491: * Accessor: Provides an iterator for the list of {@link Transformation}
492: * and {@link Derivation} references.
493: *
494: * @return a list iterator to traverse the container of {@link Definition}s.
495: * @see java.util.ListIterator
496: */
497: public ListIterator listIterateDefinition() {
498: return this .m_definitionList.listIterator();
499: }
500:
501: /**
502: * Accessor: Provides an iterator for the list of {@link Transformation}
503: * and {@link Derivation} references.
504: *
505: * @param start is the starting point of the iteration.
506: * @return a list iterator to traverse the container of {@link Definition}s.
507: * @see java.util.ListIterator
508: */
509: public ListIterator listIterateDefinition(int start) {
510: return this .m_definitionList.listIterator(start);
511: }
512:
513: /**
514: * Accessor: Removes all definitions we know about.
515: * @see Definition
516: */
517: public void removeAllDefinition() {
518: this .m_definitionList.clear();
519: }
520:
521: /**
522: * Accessor: Removes a definition. Each component in this vector with
523: * an index greater or equal to the specified index is shifted
524: * downward to have an index one smaller than the value it had
525: * previously. The size of this vector is decreased by 1.
526: *
527: * @param index is the position to remove the argument fragment from.
528: * @return the removed Definition.
529: * @exception ArrayIndexOutOfBoundsException if the index was invalid.
530: * @see Definition
531: */
532: public Definition removeDefinition(int index) {
533: return (Definition) this .m_definitionList.remove(index);
534: }
535:
536: /**
537: * Accessor: Removes a definition named by its reference. Removes the
538: * first occurrence of the specified element in this Vector.
539: *
540: * @param d is a definition instance that originated from this list.
541: * @return true, if the first occurance of the element was deleted,
542: * false, if there was nothing found to be removed.
543: * @see Definition
544: */
545: public boolean removeDefinition(Definition d) {
546: return this .m_definitionList.remove(d);
547: }
548:
549: /**
550: * Accessor: Sets the component at the specified index of this vector
551: * to be the specified object. The previous component at that position
552: * is discarded. The index must be a value greater than or equal to 0
553: * and less than the current size of the vector.
554: *
555: * @param index is the postion at which to replace a {@link Definition}.
556: * @param d is either a {@link Transformation} or
557: * {@link Derivation} to use for replacement.
558: * @throws IndexOutOfBoundsException if the index was invalid.
559: */
560: public Definition setDefinition(int index, Definition d)
561: throws IndexOutOfBoundsException {
562: //-- check bounds for index
563: if ((index < 0) || (index >= this .m_definitionList.size())) {
564: throw new IndexOutOfBoundsException();
565: }
566:
567: this .sanitizeDefinition(d);
568: return (Definition) this .m_definitionList.set(index, d);
569: }
570:
571: /**
572: * Accessor: Replace all {@link Definition}s with a new list.
573: *
574: * @param definitionArray is an array of possibly mixed
575: * {@link Transformation} and {@link Derivation} elements.
576: * @deprecated Use the new Collection based interfaces
577: */
578: public void setDefinition(Definition[] definitionArray) {
579: this .m_definitionList.clear();
580: this .m_definitionList.addAll(Arrays.asList(definitionArray));
581: }
582:
583: /**
584: * Accessor: Replace all {@link Definition}s with a new list.
585: *
586: * @param definitions is an collection of possibly mixed
587: * {@link Transformation} and {@link Derivation} elements.
588: */
589: public void setDefinition(Collection definitions) {
590: this .m_definitionList.clear();
591: this .m_definitionList.addAll(definitions);
592: }
593:
594: /**
595: * Accessor: Sets the document default namespace.
596: *
597: * @param vdlns is the new namespace to use. Note that the change will
598: * <b>not</b> be propagated to contained elememts.
599: * @see #getVdlns()
600: */
601: public void setVdlns(String vdlns) {
602: this .m_vdlns = vdlns;
603: }
604:
605: /**
606: * Accessor: Replaces the version number of the document.
607: *
608: * @param version is the new version number.
609: * @see #getVersion()
610: */
611: public void setVersion(String version) {
612: this .m_version = version;
613: }
614:
615: /**
616: * Dumps the content of the given element into a string. This function
617: * traverses all sibling classes as necessary and converts the
618: * data into textual output.
619: *
620: * @param stream is a stream opened and ready for writing. This can also
621: * be a string stream for efficient output.
622: * @exception IOException if something fishy happens to the stream.
623: */
624: public void toString(Writer stream) throws IOException {
625: for (Iterator i = this .m_definitionList.iterator(); i.hasNext();) {
626: ((Definition) i.next()).toString(stream);
627: }
628: }
629:
630: /**
631: * Writes the header of the XML output. The output contains the special
632: * strings to start an XML document, some comments, and the root element.
633: * The latter points to the XML schema via XML Instances.
634: *
635: * @param stream is a stream opened and ready for writing. This can also
636: * be a string stream for efficient output.
637: * @param indent is a <code>String</code> of spaces used for pretty
638: * printing. The initial amount of spaces should be an empty string.
639: * The parameter is used internally for the recursive traversal.
640: * @param namespace is the XML schema namespace prefix. If neither
641: * empty nor null, each element will be prefixed with this prefix,
642: * and the root element will map the XML namespace.
643: * @exception IOException if something fishy happens to the stream.
644: */
645: public void writeXMLHeader(Writer stream, String indent,
646: String namespace) throws IOException {
647: String newline = System.getProperty("line.separator", "\r\n");
648:
649: if (indent != null && indent.length() > 0)
650: stream.write(indent);
651: stream.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
652: stream.write(newline);
653:
654: if (indent != null && indent.length() > 0)
655: stream.write(indent);
656: stream.write("<!-- generated: ");
657: stream.write(Currently.iso8601(false));
658: stream.write(" -->");
659: stream.write(newline);
660:
661: if (indent != null && indent.length() > 0)
662: stream.write(indent);
663: stream.write("<!-- generated by: ");
664: stream.write(System.getProperties().getProperty("user.name",
665: "unknown"));
666: stream.write(" [");
667: stream.write(System.getProperties().getProperty("user.region",
668: "??"));
669: stream.write("] -->");
670: stream.write(newline);
671:
672: // start root element
673: if (indent != null && indent.length() > 0)
674: stream.write(indent);
675: stream.write('<');
676: if (namespace != null && namespace.length() > 0) {
677: stream.write(namespace);
678: stream.write(':');
679: }
680: stream.write("definitions xmlns");
681: if (namespace != null && namespace.length() > 0) {
682: stream.write(':');
683: stream.write(namespace);
684: }
685: stream.write("=\"");
686: stream.write(SCHEMA_NAMESPACE);
687: stream
688: .write("\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"");
689: stream.write(SCHEMA_NAMESPACE);
690: stream.write(' ');
691: stream.write(SCHEMA_LOCATION);
692: stream.write('"');
693:
694: writeAttribute(stream, " vdlns=\"", this .m_vdlns);
695: writeAttribute(stream, " version=\"", this .m_version);
696:
697: stream.write('>');
698: if (indent != null)
699: stream.write(newline);
700: }
701:
702: /**
703: * Dump the state of the current element as XML output. This function
704: * traverses all sibling classes as necessary, and converts the data
705: * into pretty-printed XML output. The stream interface should be able
706: * to handle large output efficiently, if you use a buffered writer.
707: *
708: * @param stream is a stream opened and ready for writing. This can also
709: * be a string stream for efficient output.
710: * @param indent is a <code>String</code> of spaces used for pretty
711: * printing. The initial amount of spaces should be an empty string.
712: * The parameter is used internally for the recursive traversal.
713: * @param namespace is the XML schema namespace prefix. If neither
714: * empty nor null, each element will be prefixed with this prefix,
715: * and the root element will map the XML namespace.
716: * @exception IOException if something fishy happens to the stream.
717: */
718: public void toXML(Writer stream, String indent, String namespace)
719: throws IOException {
720: // write prefix
721: writeXMLHeader(stream, indent, namespace);
722:
723: // optionally write content
724: if (this .m_definitionList.size() > 0) {
725: String newindent = indent == null ? null : indent + " ";
726: for (Iterator i = this .m_definitionList.iterator(); i
727: .hasNext();) {
728: ((Definition) i.next()).toXML(stream, newindent,
729: namespace);
730: }
731: }
732:
733: // finish document
734: if (indent != null && indent.length() > 0)
735: stream.write(indent);
736: stream.write("</");
737: if (namespace != null && namespace.length() > 0) {
738: stream.write(namespace);
739: stream.write(':');
740: }
741: stream.write("definitions>");
742: stream.write(System.getProperty("line.separator", "\r\n"));
743: stream.flush(); // this is the only time we flush
744: }
745: }
|