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.dax;
017:
018: import org.griphyn.vdl.dax.*;
019: import java.util.*;
020: import java.io.Writer;
021: import java.io.IOException;
022:
023: /**
024: * This class captures the parent-child relationship between any two
025: * nodes in a directed acyclic graph. For ease of external
026: * transportation, the graph is flattened into this two-level form.
027: * Please note that this presentation is slightly less powerful than the
028: * true DAGMan form, because for each child, there can be multiple
029: * parents, but multiple children cannot be grouped.
030: *
031: * @author Jens-S. Vöckler
032: * @author Yong Zhao
033: * @version $Revision: 50 $
034: */
035: public class Child extends DAX implements Cloneable {
036: /**
037: * Captures the list of parent nodes for this child node.
038: */
039: private HashSet m_parentSet;
040:
041: /**
042: * Captures the element for which we are constructing dependencies.
043: */
044: private String m_this Child = null;
045:
046: /**
047: * Creates and returns a copy of this object.
048: * @return a new instance.
049: */
050: public Object clone() {
051: Child result = new Child(this .m_this Child);
052: for (Iterator i = this .m_parentSet.iterator(); i.hasNext();) {
053: result.addParent((String) i.next());
054: }
055:
056: return result;
057: }
058:
059: /**
060: * Default ctor: Constructs a child node w/o any parents
061: */
062: public Child() {
063: this .m_parentSet = new HashSet();
064: }
065:
066: /**
067: * Ctor: Constructs a child node.
068: *
069: * @param child is the job ID of the child node.
070: */
071: public Child(String child) {
072: this .m_this Child = child;
073: this .m_parentSet = new HashSet();
074: }
075:
076: /**
077: * Ctor: Constructs a child node.
078: *
079: * @param child is the job reference of the child node.
080: */
081: public Child(Job child) {
082: this .m_this Child = child.getID();
083: this .m_parentSet = new HashSet();
084: }
085:
086: /**
087: * Convenience ctor: Constructs a child node with one parent.
088: */
089: public Child(String child, String parent) {
090: this .m_this Child = child;
091: this .m_parentSet = new HashSet();
092: this .m_parentSet.add(parent);
093: }
094:
095: /**
096: * Convenience ctor: Constructs a child node with one parent.
097: */
098: public Child(Job child, Job parent) {
099: this .m_this Child = child.getID();
100: this .m_parentSet = new HashSet();
101: this .m_parentSet.add(parent.getID());
102: }
103:
104: /**
105: * Accessor: Adds a parent job id as dependency to the list of parents.
106: *
107: * @param parent is the parent id to add, <b>not</b> the parent reference.
108: * @see Job
109: */
110: public void addParent(String parent) {
111: this .m_parentSet.add(parent);
112: }
113:
114: /**
115: * Accessor: Adds a parent job id as dependency to the list of parents.
116: *
117: * @param parent is the parent reference to add
118: * @see Job
119: */
120: public void addParent(Job parent) {
121: this .m_parentSet.add(parent.getID());
122: }
123:
124: /**
125: * Accessor: Provides an iterator for the parent list.
126: *
127: * @return the iterator for all dependencies.
128: * @see Job
129: */
130: public Iterator iterateParent() {
131: return this .m_parentSet.iterator();
132: }
133:
134: /**
135: * Accessor: Obtains the child identifier.
136: *
137: * @return the name of the current child, or <code>null</code>, if
138: * the element is hollow.
139: * @see #setChild( String )
140: */
141: public String getChild() {
142: return this .m_this Child;
143: }
144:
145: /**
146: * Accessor: Obtains a parent, iff it is in the bag.
147: *
148: * @param name is the parent id to look up.
149: * @return true if the parent is know, false otherwise.
150: */
151: public boolean getParent(String name) {
152: return this .m_parentSet.contains(name);
153: }
154:
155: // /**
156: // * Accessor: Obtains the complete parental dependencies (one level).
157: // *
158: // * @return an array with all parent IDs inside.
159: // * @see Job
160: // */
161: // public String[] getParent()
162: // {
163: // int size = this.m_parentSet.size();
164: // String[] mArray = new String[size];
165: // for (Iterator i=this.m_parentSet.iterator(); i.hasNext(); ) {
166: // mArray[index] = (String) i.next();
167: // }
168: // return mArray;
169: // }
170:
171: /**
172: * Accessor: Obtains the count of parental dependencies.
173: *
174: * @return the number of parents.
175: * @see Job
176: */
177: public int getParentCount() {
178: return this .m_parentSet.size();
179: }
180:
181: /**
182: * Accessor: Removes all parental dependencies.
183: * @see Job
184: */
185: public void removeAllParent() {
186: this .m_parentSet.clear();
187: }
188:
189: /**
190: * Accessor: Removes a parent name from the bag.
191: *
192: * @param name is the name of the parent ID to remove.
193: * @return true, if the parent was removed, false, if it was not present.
194: * @see Job
195: * @see java.util.HashSet#remove(Object)
196: */
197: public boolean removeParent(String name) {
198: return this .m_parentSet.remove(name);
199: }
200:
201: /**
202: * Accessor: Sets the identifier for this dependency child.
203: *
204: * @param id is the job identifier.
205: * @see #getChild()
206: */
207: public void setChild(String id) {
208: this .m_this Child = id;
209: }
210:
211: /**
212: * Accessor: Sets the identifier for this dependency child.
213: *
214: * @param job is a job reference.
215: * @see #getChild()
216: */
217: public void setChild(Job job) {
218: this .m_this Child = job.getID();
219: }
220:
221: /**
222: * Updates the identifiers for child and parents from a mapping.
223: * @param mapping is the mapping between old and new identifier
224: * @return a new instance with mapped identifiers. If none of the
225: * old identifiers in mapping are in the child, the result is the
226: * same as a {@link #clone()}.
227: */
228: public Child updateChild(java.util.Map mapping) {
229: Child result = null;
230: if (mapping.containsKey(this .m_this Child)) {
231: // child name itself needs mapping
232: result = new Child((String) mapping.get(this .m_this Child));
233: } else {
234: // child name can be copied
235: result = new Child(this .m_this Child);
236: }
237:
238: for (Iterator i = this .m_parentSet.iterator(); i.hasNext();) {
239: String parent = (String) i.next();
240: if (mapping.containsKey(parent)) {
241: result.addParent((String) mapping.get(parent));
242: } else {
243: result.addParent(parent);
244: }
245: }
246:
247: return result;
248: }
249:
250: /**
251: * Converts the active state into something meant for human consumption.
252: * The method will be called when recursively traversing the instance
253: * tree.
254: *
255: * @param stream is a stream opened and ready for writing. This can also
256: * be a string stream for efficient output.
257: */
258: public void toString(Writer stream) throws IOException {
259: // only do anything for children with parents!
260: if (this .m_parentSet.size() > 0) {
261: stream.write(" ");
262: stream.write("CHILD ");
263: stream.write(escape(this .m_this Child));
264: stream.write(" PARENT");
265: for (Iterator i = this .m_parentSet.iterator(); i.hasNext();) {
266: stream.write(' ');
267: stream.write(escape((String) i.next()));
268: }
269: stream.write(System.getProperty("line.separator", "\r\n"));
270: }
271: }
272:
273: /**
274: * Dump the state of the current element as XML output. This function
275: * traverses all sibling classes as necessary, and converts the data
276: * into pretty-printed XML output. The stream interface should be able
277: * to handle large output efficiently.
278: *
279: * @param stream is a stream opened and ready for writing. This can also
280: * be a string stream for efficient output.
281: * @param indent is a <code>String</code> of spaces used for pretty
282: * printing. The initial amount of spaces should be an empty string.
283: * The parameter is used internally for the recursive traversal.
284: * @param namespace is the XML schema namespace prefix. If neither
285: * empty nor null, each element will be prefixed with this prefix,
286: * and the root element will map the XML namespace.
287: * @exception IOException if something fishy happens to the stream.
288: */
289: public void toXML(Writer stream, String indent, String namespace)
290: throws IOException {
291: // only do anything for children with parents!
292: if (this .m_parentSet.size() > 0) {
293: String newline = System.getProperty("line.separator",
294: "\r\n");
295: String tag = (namespace != null && namespace.length() > 0) ? namespace
296: + ":child"
297: : "child";
298: String tag2 = (namespace != null && namespace.length() > 0) ? namespace
299: + ":parent"
300: : "parent";
301:
302: // open tag
303: if (indent != null && indent.length() > 0)
304: stream.write(indent);
305: stream.write('<');
306: stream.write(tag);
307: writeAttribute(stream, " ref=\"", this .m_this Child);
308: stream.write('>');
309: if (indent != null)
310: stream.write(newline);
311:
312: String newindent = indent == null ? null : indent + " ";
313: for (Iterator i = this .m_parentSet.iterator(); i.hasNext();) {
314: if (indent != null && indent.length() > 0)
315: stream.write(newindent);
316: stream.write('<');
317: stream.write(tag2);
318: writeAttribute(stream, " ref=\"", (String) i.next());
319: stream.write("/>");
320: if (indent != null)
321: stream.write(newline);
322: }
323:
324: if (indent != null && indent.length() > 0)
325: stream.write(indent);
326: stream.write("</");
327: stream.write(tag);
328: stream.write('>');
329: if (indent != null)
330: stream.write(newline);
331: }
332: }
333: }
|