0001: /*
0002: * This file or a portion of this file is licensed under the terms of
0003: * the Globus Toolkit Public License, found in file ../GTPL, or at
0004: * http://www.globus.org/toolkit/download/license.html. This notice must
0005: * appear in redistributions of this file, with or without modification.
0006: *
0007: * Redistributions of this Software, with or without modification, must
0008: * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
0009: * some other similar material which is provided with the Software (if
0010: * any).
0011: *
0012: * Copyright 1999-2004 University of Chicago and The University of
0013: * Southern California. All rights reserved.
0014: */
0015:
0016: package org.griphyn.vdl.dax;
0017:
0018: import org.griphyn.common.util.Separator;
0019: import org.griphyn.vdl.dax.*;
0020: import org.griphyn.vdl.classes.LFN;
0021: import java.util.*;
0022: import java.io.Writer;
0023: import java.io.IOException;
0024:
0025: /**
0026: * This class defines the specifics of a job to run in an abstract manner.
0027: * All filename references still refer to logical files. All references
0028: * transformations also refer to logical transformtions, though through
0029: * <code>Profile</code> physical location hints can be passed.
0030: *
0031: * @author Jens-S. Vöckler
0032: * @author Yong Zhao
0033: * @version $Revision: 366 $
0034: *
0035: * @see Profile
0036: * @see Filename
0037: */
0038: public class Job extends DAX implements Cloneable {
0039: /**
0040: * Each transformation and derivation resides in a namespace. Mind
0041: * that namespaces are currently flat. If you need to impose any kind
0042: * of hierarchy, please do so yourself, e.g. use periods between
0043: * hierarchy intifiers. The namespace is part of the key identifying
0044: * a logical transformation.
0045: */
0046: private String m_namespace = null;
0047:
0048: /**
0049: * Each transformation and derivation can be identified by a name.
0050: * For a transformation, this is part of the logical transformation
0051: * name. Derivations can be anonymous, and not use a name.
0052: */
0053: private String m_name = null;
0054:
0055: /**
0056: * Each transformation and derivation has a version associated with
0057: * their definition. While a version number is mandatory for transformation,
0058: * being part of the logical transformation key, a derivation can
0059: * remain anonymous without version.
0060: */
0061: private String m_version = null;
0062:
0063: /**
0064: * DVs are dynamically mapped to TR. This variable records the namespace
0065: * of the chosen DV.
0066: */
0067: private String m_dv_namespace = null;
0068:
0069: /**
0070: * DVs are dynamically mapped to TR. This variable records the name
0071: * of the chosen DV.
0072: */
0073: private String m_dv_name = null;
0074:
0075: /**
0076: * DVs are dynamically mapped to TR. This variable records the version
0077: * of the chosen DV.
0078: */
0079: private String m_dv_version = null;
0080:
0081: /**
0082: * Each job also gets a unique id to refer to it from references.
0083: * @see Child
0084: */
0085: private String m_id = null;
0086:
0087: /**
0088: * A compound transformation may be nested. For purposes of display
0089: * and grouping, it is feasible to record the compound transformation
0090: * chain. This is an optional argument.
0091: */
0092: private String m_chain = null;
0093:
0094: /**
0095: * stdin is a {@link Filename} which must be of input linkage.
0096: * Alternatively, it may be unused (null).
0097: */
0098: private Filename m_stdin = null;
0099:
0100: /**
0101: * stdout is a {@link Filename} which must be of output linkage.
0102: * Alternatively, it may be unused (null).
0103: */
0104: private Filename m_stdout = null;
0105:
0106: /**
0107: * stderr is a {@link Filename} which must be of output linkage.
0108: * Alternatively, it may be unused (null).
0109: */
0110: private Filename m_stderr = null;
0111:
0112: /**
0113: * The level is set by the topological sort. It is optional.
0114: */
0115: private int m_level = -1;
0116:
0117: /**
0118: * The argument list describes the command line arguments as sum of
0119: * strings and filename references. Each element is a <code>Leaf</code>,
0120: * which is either implemented by a <code>Filename</code> or
0121: * <code>PseudoText</code> instance.
0122: *
0123: * @see Leaf
0124: * @see Filename
0125: * @see PseudoText
0126: */
0127: private ArrayList m_argumentList;
0128:
0129: /**
0130: * The profile list encapsulates scheduler specific data in a
0131: * generic structure.
0132: *
0133: * @see Profile
0134: */
0135: private ArrayList m_profileList;
0136:
0137: /**
0138: * The uses list contains all filenames that were originally part
0139: * of the linkage via the actual arguments and formal argument defaults.
0140: *
0141: * @see Filename
0142: */
0143: private ArrayList m_usesList;
0144:
0145: /**
0146: * Creates and returns a copy of this object.
0147: * @return a new instance, semi-deep copy
0148: */
0149: public Object clone() {
0150: Job result = new Job(this .m_namespace, this .m_name,
0151: this .m_version, this .m_id, this .m_dv_namespace,
0152: this .m_dv_name, this .m_dv_version);
0153:
0154: result.setChain(this .getChain());
0155: result.setStdin(this .getStdin());
0156: result.setStdout(this .getStdout());
0157: result.setStderr(this .getStderr());
0158:
0159: for (int index = 0; index < this .m_argumentList.size(); ++index) {
0160: result.setArgument(index, (Leaf) this .getArgument(index)
0161: .clone());
0162: }
0163: for (int index = 0; index < this .m_profileList.size(); ++index) {
0164: result.setProfile(index, (Profile) this .getProfile(index)
0165: .clone());
0166: }
0167: for (int index = 0; index < this .m_usesList.size(); ++index) {
0168: result.setUses(index, (Filename) this .getUses(index)
0169: .clone());
0170: }
0171:
0172: result.setLevel(this .getLevel());
0173: return result;
0174: }
0175:
0176: /**
0177: * Default ctor: Note that a job must be named.
0178: */
0179: public Job() {
0180: this .m_argumentList = new ArrayList();
0181: this .m_profileList = new ArrayList();
0182: this .m_usesList = new ArrayList();
0183: }
0184:
0185: /**
0186: * Convenience ctor. Any job must be named. The job id will be
0187: * assembled from the name.
0188: *
0189: * @param namespace is the namespace that the TR resides in.
0190: * @param name is the name of the job as logical TR identifier.
0191: * @param version is a version information string of the TR.
0192: * @param id is a short DAX-unique ID to distinguish this job
0193: * from other jobs in the same DAG.
0194: * @see org.griphyn.vdl.classes.Transformation
0195: */
0196: public Job(String namespace, String name, String version, String id) {
0197: this .m_namespace = namespace;
0198: this .m_name = name;
0199: this .m_version = version;
0200: this .m_id = id;
0201: this .m_argumentList = new ArrayList();
0202: this .m_profileList = new ArrayList();
0203: this .m_usesList = new ArrayList();
0204: }
0205:
0206: /**
0207: * Convenience ctor. Any job must be named. The job id will be
0208: * assembled from the name.
0209: *
0210: * @param namespace is the namespace that the TR resides in.
0211: * @param name is the name of the job as logical TR identifier.
0212: * @param version is a version information string of the TR.
0213: * @param id is a short DAX-unique ID to distinguish this job
0214: * from other jobs in the same DAG.
0215: * @param dv_namespace is the namespace of the DV for this job.
0216: * @param dv_name is the name of the DV that produced this job.
0217: * @param dv_version is the version of the DV for this job.
0218: * @see org.griphyn.vdl.classes.Transformation
0219: */
0220: public Job(String namespace, String name, String version,
0221: String id, String dv_namespace, String dv_name,
0222: String dv_version) {
0223: this .m_namespace = namespace;
0224: this .m_name = name;
0225: this .m_version = version;
0226: this .m_id = id;
0227: this .m_dv_namespace = dv_namespace;
0228: this .m_dv_name = dv_name;
0229: this .m_dv_version = dv_version;
0230: this .m_argumentList = new ArrayList();
0231: this .m_profileList = new ArrayList();
0232: this .m_usesList = new ArrayList();
0233: }
0234:
0235: /**
0236: * Accessor: Adds an argument to the list of arguments
0237: *
0238: * @param vArgument is an argument fragment to append to the command line
0239: * arguments.
0240: *
0241: * @see Leaf
0242: */
0243: public void addArgument(Leaf vArgument) {
0244: this .m_argumentList.add(vArgument);
0245: }
0246:
0247: /**
0248: * Accessor: Inserts an argument at an arbitrary place into the list.
0249: * Each component in this vector with an index greater or equal to the
0250: * specified index is shifted upward to have an index one greater than
0251: * the value it had previously.
0252: *
0253: * @param index is the position to insert an argument
0254: * @param vArgument is the argument fragment to insert at the
0255: * specified place.
0256: * @exception IndexOutOfBounds if the argument does not fit into the list.
0257: * @see #setArgument( int, Leaf )
0258: * @see #getArgument( int )
0259: * @see Leaf
0260: */
0261: public void addArgument(int index, Leaf vArgument)
0262: throws IndexOutOfBoundsException {
0263: this .m_argumentList.add(index, vArgument);
0264: }
0265:
0266: /**
0267: * Compares two strings, each of which may be null.
0268: * @param a is the first string
0269: * @param b is the other string to compare to
0270: * @return true, if both strings are null, or both strings match.
0271: */
0272: private boolean matchWithNull(String a, String b) {
0273: return (a == null ? (b == null) : a.equals(b));
0274: }
0275:
0276: /**
0277: * Accessor: Appends a profile definition to the list of profiles. This
0278: * method provides extra magic, ensuring unique namespace and key
0279: * identifiers in the profile list. If the ns:id of the profile to add
0280: * already exists in the list, the list entry will be overwritten with
0281: * the new version.<p>
0282: *
0283: * FIXME: The profile should carry a state to signal appending or
0284: * replacing.
0285: *
0286: * @param vProfile is the profile to append to remembered profiles.
0287: * @return <code>false</code> for a new elements, and <code>true</code>,
0288: * if an existing element was overwritten.
0289: * @see Profile
0290: */
0291: public boolean addProfile(Profile vProfile) {
0292: boolean result = false;
0293:
0294: // the list is not sorted (and should not be sorted), thus linear search
0295: for (Iterator i = this .m_profileList.iterator(); i.hasNext();) {
0296: Profile p = (Profile) i.next();
0297: if (matchWithNull(p.getNamespace(), vProfile.getNamespace())
0298: && matchWithNull(p.getKey(), vProfile.getKey())) {
0299: // element of this name exists, remove
0300: i.remove();
0301: result = true;
0302: }
0303: }
0304: this .m_profileList.add(vProfile);
0305: return result;
0306: }
0307:
0308: /**
0309: * Accessor: Inserts a profile definition at an arbitrary position
0310: * into the list of profiles. Each component in this vector with an
0311: * index greater or equal to the specified index is shifted upward to
0312: * have an index one greater than the value it had previously.
0313: *
0314: * @param index is the position to insert the definitions into.
0315: * @param vProfile is the profile to append to remembered profiles.
0316: * @exception IndexOutOfBounds if the argument does not fit into the list.
0317: * @see #setProfile( int, Profile )
0318: * @see #getProfile( int )
0319: * @see Profile
0320: */
0321: public void addProfile(int index, Profile vProfile)
0322: throws IndexOutOfBoundsException {
0323: this .m_profileList.add(index, vProfile);
0324: }
0325:
0326: /**
0327: * Accessor: Appends a filename to the list of used filenames.
0328: *
0329: * @param filename is the LFN to append to remembered filenames.
0330: * @exception IndexOutOfBounds if the argument does not fit into the list.
0331: * @see Filename
0332: */
0333: public void addUses(Filename filename) {
0334: this .m_usesList.add(filename);
0335: }
0336:
0337: /**
0338: * Accessor: Inserts a logical filename at an arbitrary position
0339: * into the list of used filenames. Each component in this vector with an
0340: * index greater or equal to the specified index is shifted upward to
0341: * have an index one greater than the value it had previously.
0342: *
0343: * @param index is the position to insert the definitions into.
0344: * @param filename is the LFN to append to remembered filenames.
0345: * @exception IndexOutOfBounds if the argument does not fit into the list.
0346: * @see #setUses( int, Filename )
0347: * @see #getUses( int )
0348: * @see Filename
0349: */
0350: public void addUses(int index, Filename filename)
0351: throws IndexOutOfBoundsException {
0352: this .m_profileList.add(index, filename);
0353: }
0354:
0355: /**
0356: * Accessor: Provides an iterator for the argument fragment list.
0357: *
0358: * @return the iterator for the commandline argument fragments.
0359: * @see Leaf
0360: * @see java.util.Enumeration
0361: * @deprecated Use the new Collection based interfaces
0362: */
0363: public Enumeration enumerateArgument() {
0364: return Collections.enumeration(this .m_argumentList);
0365: }
0366:
0367: /**
0368: * Accessor: Provides an iterator for the <code>Profile</code> list.
0369: *
0370: * @return the iterator for the <code>Profile</code> list.
0371: * @see Profile
0372: * @see java.util.Enumeration
0373: * @deprecated Use the new Collection based interfaces
0374: */
0375: public Enumeration enumerateProfile() {
0376: return Collections.enumeration(this .m_profileList);
0377: }
0378:
0379: /**
0380: * Accessor: Provides an iterator for the used <code>Filename</code> list.
0381: *
0382: * @return the iterator for the <code>Filename</code> list.
0383: * @see Filename
0384: * @see java.util.Enumeration
0385: * @deprecated Use the new Collection based interfaces
0386: */
0387: public Enumeration enumerateUses() {
0388: return Collections.enumeration(this .m_usesList);
0389: }
0390:
0391: /**
0392: * Accessor: Obtains an argument fragment from an arbitrary position.
0393: *
0394: * @param index is the place to look up the element at.
0395: * @return the argument fragment at the specified place.
0396: * @throws IndexOutOfBoundsException if the referenced position does
0397: * not exist.
0398: * @see #addArgument( int, Leaf )
0399: * @see #setArgument( int, Leaf )
0400: * @see Leaf
0401: */
0402: public Leaf getArgument(int index) throws IndexOutOfBoundsException {
0403: //-- check bound for index
0404: if ((index < 0) || (index >= this .m_argumentList.size()))
0405: throw new IndexOutOfBoundsException();
0406:
0407: return (Leaf) this .m_argumentList.get(index);
0408: }
0409:
0410: /**
0411: * Accessor: Obtains the complete commandline arguments
0412: *
0413: * @return an array with all commandline argument fragments inside.
0414: * @see #setArgument( Leaf[] )
0415: * @see Leaf
0416: * @deprecated Use the new Collection based interfaces
0417: */
0418: public Leaf[] getArgument() {
0419: int size = this .m_argumentList.size();
0420: Leaf[] mArray = new Leaf[size];
0421: System.arraycopy(this .m_argumentList.toArray(new Leaf[0]), 0,
0422: mArray, 0, size);
0423: return mArray;
0424: }
0425:
0426: /**
0427: * Accessor: Obtains the count of fragments in the argument list.
0428: *
0429: * @return the number of arguments in the commandline argument list.
0430: * @see Leaf
0431: */
0432: public int getArgumentCount() {
0433: return this .m_argumentList.size();
0434: }
0435:
0436: /**
0437: * Accessor: Gets an array of all values that constitute the current
0438: * argument line. This list is read-only.
0439: *
0440: * @return an array with a mixture of either <code>PseudoText</code> or
0441: * <code>Filename</code> values.
0442: * @see #setArgument( Collection )
0443: * @see PseudoText
0444: * @see Filename
0445: */
0446: public java.util.List getArgumentList() {
0447: return Collections.unmodifiableList(this .m_argumentList);
0448: }
0449:
0450: /**
0451: * Accessor: Obtains the XML list attribute which contains the
0452: * chain of compound transformations that lead to this job.
0453: *
0454: * @return the chain, which may be empty or even <code>null</code>.
0455: * @see #setChain( String )
0456: */
0457: public String getChain() {
0458: return this .m_chain;
0459: }
0460:
0461: /**
0462: * Accessor: Obtains the unique ID of this job. The ID will be used
0463: * in references in the dependency list.
0464: *
0465: * @return The unique id from this job.
0466: * @see #setID( String )
0467: * @see Child
0468: */
0469: public String getID() {
0470: return this .m_id;
0471: }
0472:
0473: /**
0474: * Accessor: Obtains the current name of the job.
0475: *
0476: * @return the name as logical TR string for this job.
0477: * @see #setName( String )
0478: */
0479: public String getName() {
0480: return this .m_name;
0481: }
0482:
0483: /**
0484: * Accessor: Obtains the current namespace that is used for the
0485: * definition. Note that a namespace is part of the key for any
0486: * logical transformation.
0487: *
0488: * @return the namespace the definition resides in, or null, if
0489: * no namespace was defined.
0490: * @see #setNamespace(java.lang.String)
0491: */
0492: public String getNamespace() {
0493: return this .m_namespace;
0494: }
0495:
0496: /**
0497: * Accessor: Obtains the current namespace from the DV that created
0498: * this job. Note that a namespace is part of the key for any DV.
0499: *
0500: * @return the namespace the DV resides in, or null, if no namespace
0501: * was defined.
0502: * @see #setDVNamespace(java.lang.String)
0503: * @see #setDV( String, String, String )
0504: */
0505: public String getDVNamespace() {
0506: return this .m_dv_namespace;
0507: }
0508:
0509: /**
0510: * Accessor: Obtains the current name from the DV that created
0511: * this job. Note that a name is part of the key for any DV.
0512: *
0513: * @return the name the DV resides in.
0514: * @see #setDVName(java.lang.String)
0515: * @see #setDV( String, String, String )
0516: */
0517: public String getDVName() {
0518: return this .m_dv_name;
0519: }
0520:
0521: /**
0522: * Accessor: Obtains the current version from the DV that created
0523: * this job. Note that a version is part of the key triple for any
0524: * DV.
0525: *
0526: * @return the version the DV resides in, or null, if no version
0527: * was defined.
0528: * @see #setDVVersion(java.lang.String)
0529: * @see #setDV( String, String, String )
0530: */
0531: public String getDVVersion() {
0532: return this .m_dv_version;
0533: }
0534:
0535: /**
0536: * Accessor: Obtains the current setting of stdin redirection.
0537: *
0538: * @return a filename which will be associated with stdin,
0539: * or <code>null</code>, if unset.
0540: * @see #setStdin( Filename )
0541: */
0542: public Filename getStdin() {
0543: return this .m_stdin;
0544: }
0545:
0546: /**
0547: * Accessor
0548: *
0549: * @see #setLevel(int)
0550: */
0551: public int getLevel() {
0552: return this .m_level;
0553: }
0554:
0555: /**
0556: * Accessor.
0557: *
0558: * @param level
0559: * @see #getLevel()
0560: */
0561: public void setLevel(int level) {
0562: this .m_level = level;
0563: }
0564:
0565: /**
0566: * Accessor: Obtains the current setting of stdout redirection.
0567: *
0568: * @return a filename which will be associated with stdout,
0569: * or <code>null</code>, if unset.
0570: * @see #setStdout( Filename )
0571: */
0572: public Filename getStdout() {
0573: return this .m_stdout;
0574: }
0575:
0576: /**
0577: * Accessor: Obtains the current setting of stderr redirection.
0578: *
0579: * @return a filename which will be associated with stderr,
0580: * or <code>null</code>, if unset.
0581: * @see #setStderr( Filename )
0582: */
0583: public Filename getStderr() {
0584: return this .m_stderr;
0585: }
0586:
0587: /**
0588: * Accessor: Obtains an <code>Profile</code> at an arbitrary position.
0589: *
0590: * @param index is the place to look up the element at.
0591: * @exception IndexOutOfBoundsException if the referenced position does not exist.
0592: * @see #addProfile( int, Profile )
0593: * @see #setProfile( int, Profile )
0594: * @see Profile
0595: */
0596: public Profile getProfile(int index)
0597: throws IndexOutOfBoundsException {
0598: //-- check bounds for index
0599: if ((index < 0) || (index >= this .m_profileList.size()))
0600: throw new IndexOutOfBoundsException();
0601:
0602: return (Profile) this .m_profileList.get(index);
0603: }
0604:
0605: /**
0606: * Accessor: Obtains all profiles.
0607: *
0608: * @return an array with all profiles inside.
0609: * @see #setProfile( Profile[] )
0610: * @see Profile
0611: * @deprecated Use the new Collection based interfaces
0612: */
0613: public Profile[] getProfile() {
0614: int size = this .m_argumentList.size();
0615: Profile[] mArray = new Profile[size];
0616: System.arraycopy(this .m_profileList.toArray(new Profile[0]), 0,
0617: mArray, 0, size);
0618: return mArray;
0619: }
0620:
0621: /**
0622: * Accessor: Counts the number of profile specifications known to this job.
0623: *
0624: * @return the number of profiles
0625: * @see Profile
0626: */
0627: public int getProfileCount() {
0628: return this .m_profileList.size();
0629: }
0630:
0631: /**
0632: * Accessor: Obtain a read-only copy of the list of all
0633: * <code>Profile</code> specifications.
0634: *
0635: * @return a collection containing the scheduler specific environment
0636: * options for the job.
0637: * @see #setProfile( Collection )
0638: * @see Profile
0639: */
0640: public java.util.List getProfileList() {
0641: return Collections.unmodifiableList(this .m_profileList);
0642: }
0643:
0644: /**
0645: * Accessor: Obtains an <code>Filename</code> at an arbitrary position.
0646: *
0647: * @param index is the place to look up the element at.
0648: * @exception IndexOutOfBoundsException if the referenced position does not exist.
0649: * @see #addUses( int, Filename )
0650: * @see #setUses( int, Filename )
0651: * @see Filename
0652: */
0653: public Filename getUses(int index) throws IndexOutOfBoundsException {
0654: //-- check bounds for index
0655: if ((index < 0) || (index >= this .m_usesList.size()))
0656: throw new IndexOutOfBoundsException();
0657:
0658: return (Filename) this .m_usesList.get(index);
0659: }
0660:
0661: /**
0662: * Accessor: Obtain a copy of the list of all <code>Filename</code>
0663: * specifications, that were part of the arguments that generated
0664: * this job.
0665: *
0666: * @return an array containing the used filenames for the job.
0667: * @see #setUses( Filename[] )
0668: * @see Filename
0669: * @deprecated Use the new Collection based interfaces
0670: */
0671: public Filename[] getUses() {
0672: int size = this .m_usesList.size();
0673: Filename[] mArray = new Filename[size];
0674: System.arraycopy(this .m_usesList.toArray(new Filename[0]), 0,
0675: mArray, 0, size);
0676: return mArray;
0677: }
0678:
0679: /**
0680: * Accessor: Counts the number of argument-referenced logical filenames
0681: * known to this job.
0682: *
0683: * @return the number of LFNs.
0684: * @see Filename
0685: */
0686: public int getUsesCount() {
0687: return this .m_usesList.size();
0688: }
0689:
0690: /**
0691: * Accessor: Obtain a copy of the list of all <code>Filename</code>
0692: * specifications, that were part of the arguments that generated
0693: * this job. This list is read-only.
0694: *
0695: * @return an array containing the used filenames for the job.
0696: * @see #setUses( Collection )
0697: * @see Filename
0698: */
0699: public java.util.List getUsesList() {
0700: return Collections.unmodifiableList(this .m_usesList);
0701: }
0702:
0703: /**
0704: * Accessor: Obtains the current version of the definition. A version
0705: * is an integral part of a logical transformation.
0706: *
0707: * @return the version number of this definition, or null, if no
0708: * version number was defined.
0709: * @see #setVersion(java.lang.String)
0710: */
0711: public String getVersion() {
0712: return this .m_version;
0713: }
0714:
0715: /**
0716: * Accessor: Provides an iterator to the internal list of all
0717: * commandline argument elements.
0718: *
0719: * @return an iterator to walk the list with.
0720: */
0721: public Iterator iterateArgument() {
0722: return this .m_argumentList.iterator();
0723: }
0724:
0725: /**
0726: * Accessor: Provides an iterator to the internal list of all
0727: * profiles.
0728: *
0729: * @return an iterator to walk the list with.
0730: */
0731: public Iterator iterateProfile() {
0732: return this .m_profileList.iterator();
0733: }
0734:
0735: /**
0736: * Accessor: Provides an iterator to the internal list of used
0737: * filenames.
0738: *
0739: * @return an iterator to walk the list with.
0740: */
0741: public Iterator iterateUses() {
0742: return this .m_usesList.iterator();
0743: }
0744:
0745: /**
0746: * Accessor: Provides a list iterator to the internal list of all
0747: * commandline argument elements.
0748: *
0749: * @return a list iterator to walk the list with.
0750: */
0751: public ListIterator listIterateArgument() {
0752: return this .m_argumentList.listIterator();
0753: }
0754:
0755: /**
0756: * Accessor: Provides a list iterator to the internal list of all
0757: * commandline argument elements.
0758: *
0759: * @param start is the start index
0760: * @return a list iterator to walk the list with.
0761: */
0762: public ListIterator listIterateArgument(int start) {
0763: return this .m_argumentList.listIterator(start);
0764: }
0765:
0766: /**
0767: * Accessor: Provides a list iterator to the internal list of all
0768: * profiles.
0769: *
0770: * @return a list iterator to walk the list with.
0771: */
0772: public ListIterator listIterateProfile() {
0773: return this .m_profileList.listIterator();
0774: }
0775:
0776: /**
0777: * Accessor: Provides a list iterator to the internal list of all
0778: * profiles.
0779: *
0780: * @param start is the start index
0781: * @return a list iterator to walk the list with.
0782: */
0783: public ListIterator listIterateProfile(int start) {
0784: return this .m_profileList.listIterator(start);
0785: }
0786:
0787: /**
0788: * Accessor: Provides a list iterator to the internal list of all
0789: * used filenames.
0790: *
0791: * @return a list iterator to walk the list with.
0792: */
0793: public ListIterator listIterateUses() {
0794: return this .m_usesList.listIterator();
0795: }
0796:
0797: /**
0798: * Accessor: Provides a list iterator to the internal list of all
0799: * used filenames.
0800: *
0801: * @param start is the start index
0802: * @return a list iterator to walk the list with.
0803: */
0804: public ListIterator listIterateUses(int start) {
0805: return this .m_usesList.listIterator(start);
0806: }
0807:
0808: /**
0809: * Accessor: Removes all commandline arguments pieces.
0810: */
0811: public void removeAllArgument() {
0812: this .m_argumentList.clear();
0813: }
0814:
0815: /**
0816: * Accessor: Removes all profile declarations.
0817: * @see Profile
0818: */
0819: public void removeAllProfile() {
0820: this .m_profileList.clear();
0821: }
0822:
0823: /**
0824: * Accessor: Removes all known <code>Filename</code>s.
0825: * @see Filename
0826: */
0827: public void removeAllUses() {
0828: this .m_usesList.clear();
0829: }
0830:
0831: /**
0832: * Accessor: Removes a commandline argument fragment from the
0833: * commandline. Each component in this vector with an index greater or
0834: * equal to the specified index is shifted downward to have an index
0835: * one smaller than the value it had previously. The size of this
0836: * vector is decreased by 1.
0837: *
0838: * @param index is the position to remove the argument fragment from.
0839: * @return the removed fragment.
0840: * @exception ArrayIndexOutOfBoundsException if the index was invalid.
0841: * @see Leaf
0842: */
0843: public Leaf removeArgument(int index) {
0844: return (Leaf) this .m_argumentList.remove(index);
0845: }
0846:
0847: /**
0848: * Accessor: Removes a profile. Each component in this vector with an
0849: * index greater or equal to the specified index is shifted downward
0850: * to have an index one smaller than the value it had previously. The
0851: * size of this vector is decreased by 1.
0852: *
0853: * @param index is the position to remove the profile from.
0854: * @return the removed Profile.
0855: * @exception ArrayIndexOutOfBoundsException if the index was invalid.
0856: * @see Profile
0857: */
0858: public Profile removeProfile(int index) {
0859: return (Profile) this .m_profileList.remove(index);
0860: }
0861:
0862: /**
0863: * Accessor: Removes a used filename from the list of
0864: * argument-referenced LFNs. Each component in this vector with an
0865: * index greater or equal to the specified index is shifted downward
0866: * to have an index one smaller than the value it had previously. The
0867: * size of this vector is decreased by 1.
0868: *
0869: * @param index is the position to remove the filename from.
0870: * @return the removed Filename
0871: * @exception ArrayIndexOutOfBoundsException if the index was invalid.
0872: * @see Filename
0873: */
0874: public Filename removeUses(int index) {
0875: return (Filename) this .m_usesList.remove(index);
0876: }
0877:
0878: /**
0879: * Accessor: Overwrites an commandline argument fragment with a new one.
0880: *
0881: * @param index is the position to overwrite the element at
0882: * @param vArgument is the new commandline argument fragment.
0883: * @exception IndexOutOfBoundsException if the position does not exist.
0884: * @see Leaf
0885: * @see #addArgument( int, Leaf )
0886: * @see #getArgument( int )
0887: */
0888: public void setArgument(int index, Leaf vArgument)
0889: throws IndexOutOfBoundsException {
0890: //-- check bounds for index
0891: if ((index < 0) || (index >= this .m_argumentList.size()))
0892: throw new IndexOutOfBoundsException();
0893:
0894: this .m_argumentList.set(index, vArgument);
0895: }
0896:
0897: /**
0898: * Accessor: Replace the commandline arguments with a new commandline
0899: * argument fragment list.
0900: *
0901: * @param argumentArray is the new commandline argument array.
0902: * @see #getArgument()
0903: * @see Leaf
0904: * @deprecated Use the new Collection based interfaces
0905: */
0906: public void setArgument(Leaf[] argumentArray) {
0907: this .m_argumentList.clear();
0908: this .m_argumentList.addAll(Arrays.asList(argumentArray));
0909: }
0910:
0911: /**
0912: * Accessor: Replace the commandline arguments with a new commandline
0913: * argument fragment list.
0914: *
0915: * @param arguments is the new commandline argument collection.
0916: * @see #getArgumentList()
0917: * @see Leaf
0918: */
0919: public void setArgument(java.util.Collection arguments) {
0920: this .m_argumentList.clear();
0921: this .m_argumentList.addAll(arguments);
0922: }
0923:
0924: /**
0925: * Accessor: Sets the current name of the job. If the job ID was
0926: * not set previously, it will be set to the job name.
0927: * FIXME: We need to use the primary key triple for logical TR!
0928: *
0929: * @param name the new name as logical TR string for this job.
0930: * @see #getName()
0931: */
0932: public void setName(String name) {
0933: if (this .m_id == null)
0934: this .m_id = name;
0935: this .m_name = name;
0936: }
0937:
0938: /**
0939: * Accessor: Sets or overwrites the TR namespace identifier.
0940: *
0941: * @param namespace
0942: * @see #getNamespace()
0943: */
0944: public void setNamespace(String namespace) {
0945: this .m_namespace = namespace;
0946: }
0947:
0948: /**
0949: * Accessor: Sets or overwrites the DV namespace identifier.
0950: *
0951: * @param namespace
0952: * @see #getDVNamespace()
0953: * @see #setDV( String, String, String )
0954: */
0955: public void setDVNamespace(String namespace) {
0956: this .m_dv_namespace = namespace;
0957: }
0958:
0959: /**
0960: * Accessor: Sets or overwrites the DV name identifier.
0961: *
0962: * @param name
0963: * @see #getDVName()
0964: * @see #setDV( String, String, String )
0965: */
0966: public void setDVName(String name) {
0967: this .m_dv_name = name;
0968: }
0969:
0970: /**
0971: * Accessor: Sets or overwrites the DV version identifier.
0972: *
0973: * @param version
0974: * @see #getDVVersion()
0975: * @see #setDV( String, String, String )
0976: */
0977: public void setDVVersion(String version) {
0978: this .m_dv_version = version;
0979: }
0980:
0981: /**
0982: * Accessor: Sets or overwrites the DV FQDN triple.
0983: *
0984: * @param namespace is the DV's namespace, may be null
0985: * @param name is the DV name, should not be null
0986: * @param version is the DV version, may be null
0987: * @see #getDVNamespace()
0988: * @see #getDVName()
0989: * @see #getDVVersion()
0990: * @see #setDVNamespace( String )
0991: * @see #setDVName( String )
0992: * @see #setDVVersion( String )
0993: */
0994: public void setDV(String namespace, String name, String version) {
0995: this .m_dv_namespace = namespace;
0996: this .m_dv_name = name;
0997: this .m_dv_version = version;
0998: }
0999:
1000: /**
1001: * Accessor: Sets the XML list attribute which contains the
1002: * chain of compound transformations that lead to this job.
1003: *
1004: * @param chain is the chain, which may be empty or even <code>null</code>.
1005: * @see #getChain( )
1006: */
1007: public void setChain(String chain) {
1008: this .m_chain = chain.trim();
1009: }
1010:
1011: /**
1012: * Accessor: Sets the unique ID of this job. The ID will be used
1013: * in references in the dependency list. Please do not use this
1014: * function.
1015: *
1016: * @param id is the new unique id for this job.
1017: * @see #getID()
1018: * @see Child
1019: */
1020: public void setID(String id) {
1021: this .m_id = id;
1022: }
1023:
1024: /**
1025: * Accessor: Sets or releases the stdin redirection.
1026: *
1027: * @param f is a filename which will be associated with stdin,
1028: * or <code>null</code> to release redirection.
1029: * @see #getStdin()
1030: */
1031: public void setStdin(Filename f) {
1032: this .m_stdin = f;
1033: }
1034:
1035: /**
1036: * Accessor: Sets or releases the stdout redirection.
1037: *
1038: * @param f is a filename which will be associated with stdout,
1039: * or <code>null</code> to unset.
1040: * @see #getStdout()
1041: */
1042: public void setStdout(Filename f) {
1043: this .m_stdout = f;
1044: }
1045:
1046: /**
1047: * Accessor: Sets or releases the stderr redirection.
1048: *
1049: * @param f is a filename which will be associated with stderr,
1050: * or <code>null</code> to unset.
1051: * @see #getStderr()
1052: */
1053: public void setStderr(Filename f) {
1054: this .m_stderr = f;
1055: }
1056:
1057: /**
1058: * Accessor: Overwrites a profile with a new profile
1059: *
1060: * @param index is the position to overwrite the profile at.
1061: * @param vProfile is the new profile to use in overwriting.
1062: * @exception IndexOutOfBoundsException if the position does not exist.
1063: * @see Profile
1064: * @see #addProfile( int, Profile )
1065: * @see #getProfile( int )
1066: */
1067: public void setProfile(int index, Profile vProfile)
1068: throws IndexOutOfBoundsException {
1069: //-- check bounds for index
1070: if ((index < 0) || (index >= this .m_profileList.size()))
1071: throw new IndexOutOfBoundsException();
1072:
1073: this .m_profileList.set(index, vProfile);
1074: }
1075:
1076: /**
1077: * Accessor: Replace the internal profile list with a new list.
1078: *
1079: * @param profileArray is the new list of profiles to use for the job.
1080: * @see #getProfile()
1081: * @see Profile
1082: * @deprecated Use the new Collection based interfaces
1083: */
1084: public void setProfile(Profile[] profileArray) {
1085: this .m_profileList.clear();
1086: this .m_profileList.addAll(Arrays.asList(profileArray));
1087: }
1088:
1089: /**
1090: * Accessor: Replace the internal profile list with a new list.
1091: *
1092: * @param profiles is the new list of profiles to use for the job.
1093: * @see #getProfileList()
1094: * @see Profile
1095: */
1096: public void setProfile(java.util.Collection profiles) {
1097: this .m_profileList.clear();
1098: this .m_profileList.addAll(profiles);
1099: }
1100:
1101: /**
1102: * Accessor: Overwrites a used filename with a new LFN.
1103: *
1104: * @param index is the position to overwrite the LFN at.
1105: * @param vFilename is the new LFN to use in overwriting.
1106: * @exception IndexOutOfBoundsException if the position does not exist.
1107: * @see #addUses( int, Filename )
1108: * @see #getUses( int )
1109: * @see Filename
1110: */
1111: public void setUses(int index, Filename vFilename)
1112: throws IndexOutOfBoundsException {
1113: //-- check bounds for index
1114: if ((index < 0) || (index >= this .m_usesList.size()))
1115: throw new IndexOutOfBoundsException();
1116:
1117: this .m_usesList.set(index, vFilename);
1118: }
1119:
1120: /**
1121: * Accessor: Replace the internal list of used LFNs with a new list.
1122: *
1123: * @param filenameArray is the new list of argument-referenced
1124: * filenames to use for the job.
1125: * @see #getUses()
1126: * @see Filename
1127: * @deprecated Use the new Collection based interfaces
1128: */
1129: public void setUses(Filename[] filenameArray) {
1130: this .m_usesList.clear();
1131: this .m_usesList.addAll(Arrays.asList(filenameArray));
1132: }
1133:
1134: /**
1135: * Accessor: Replace the internal list of used LFNs with a new list.
1136: *
1137: * @param filenames is a new collection of argument-referenced
1138: * filenames to use for the job.
1139: * @see #getUsesList()
1140: * @see Filename
1141: */
1142: public void setUses(java.util.Collection filenames) {
1143: this .m_usesList.clear();
1144: this .m_usesList.addAll(filenames);
1145: }
1146:
1147: /**
1148: * Accessor: Sets the version of the definition.
1149: *
1150: * @param version
1151: * @see #getVersion()
1152: */
1153: public void setVersion(String version) {
1154: this .m_version = version;
1155: }
1156:
1157: /**
1158: * Converts the active state into something meant for human consumption.
1159: * The method will be called when recursively traversing the instance
1160: * tree.
1161: *
1162: * @param stream is a stream opened and ready for writing. This can also
1163: * be a string stream for efficient output.
1164: */
1165: public void toString(Writer stream) throws IOException {
1166: String newline = System.getProperty("line.separator", "\r\n");
1167:
1168: stream.write(" job ");
1169: if (this .m_namespace != null) {
1170: stream.write(this .m_namespace);
1171: stream.write(Separator.NAMESPACE);
1172: }
1173: stream.write(this .m_name);
1174: if (this .m_version != null) {
1175: stream.write(Separator.NAME);
1176: stream.write(this .m_version);
1177: }
1178:
1179: stream.write(" {");
1180: stream.write(newline);
1181:
1182: // FIXME: assumes an indentation level
1183: stream.write(" id=");
1184: stream.write(this .m_id);
1185: stream.write(';');
1186: stream.write(newline);
1187:
1188: // concat all command line fragments into one big string.
1189: if (this .getArgumentCount() > 0) {
1190: stream.write(" argument=");
1191: for (Iterator i = this .m_argumentList.iterator(); i
1192: .hasNext();) {
1193: // casting will print a mixed content string or Filename element
1194: ((Leaf) i.next()).toString(stream);
1195: }
1196: stream.write(';');
1197: stream.write(newline);
1198: }
1199:
1200: // profiles to be dumped next
1201: for (Iterator i = this .m_profileList.iterator(); i.hasNext();) {
1202: stream.write(" ");
1203: ((Profile) i.next()).toString(stream);
1204: stream.write(';');
1205: stream.write(newline);
1206: }
1207:
1208: // finally any bound stdio descriptor
1209: // FIXME: really need to dump a Filename element!
1210: if (this .m_stdin != null) {
1211: stream.write(" stdin=");
1212: this .m_stdin.toString(stream);
1213: stream.write(';');
1214: stream.write(newline);
1215: }
1216: if (this .m_stdout != null) {
1217: stream.write(" stdout=");
1218: this .m_stdout.toString(stream);
1219: stream.write(';');
1220: stream.write(newline);
1221: }
1222: if (this .m_stderr != null) {
1223: stream.write(" stderr=");
1224: this .m_stderr.toString(stream);
1225: stream.write(';');
1226: stream.write(newline);
1227: }
1228:
1229: // argument-referenced filenames for the job, which may not appear
1230: // in the argument list nor the profile
1231: for (Iterator i = this .m_usesList.iterator(); i.hasNext();) {
1232: stream.write(" uses=");
1233: ((Filename) i.next()).toString(stream);
1234: stream.write(';');
1235: stream.write(newline);
1236: }
1237:
1238: // finish job
1239: stream.write(" }");
1240: stream.write(newline);
1241: }
1242:
1243: /**
1244: * Helper: Formats the attributes of any {@link Filename} instance,
1245: * or inherited instances.
1246: *
1247: * @param tag is the name of the element to use when formating.
1248: * @param indent is the indentation of the element, may be null.
1249: * @param namespace is an optional namespace to use in the tag.
1250: * @param f is an instance of a <code>Filename</code> object.
1251: * @param full denotes the full attributes set, or just the stdio
1252: * attributes set if false.
1253: *
1254: * @return the XML-formatted attributes without the element tags.
1255: */
1256: private String formatFilename(String tag, String indent,
1257: String namespace, Filename f, boolean full) {
1258: StringBuffer result = new StringBuffer(full ? 128 : 80);
1259: if (namespace != null && namespace.length() > 0)
1260: tag = namespace + ":" + tag;
1261: if (indent != null && indent.length() > 0)
1262: result.append(indent);
1263: result.append('<').append(tag);
1264: result.append(" file=\"").append(quote(f.getFilename(), true))
1265: .append('"');
1266: result.append(" link=\"").append(LFN.toString(f.getLink()))
1267: .append('"');
1268:
1269: if (full) {
1270: result.append(" register=\"").append(
1271: Boolean.toString(f.getRegister())).append('"');
1272: result.append(" transfer=\"").append(
1273: LFN.transferString(f.getTransfer())).append('"');
1274: result.append(" type=\"").append(
1275: LFN.typeString(f.getType())).append('"');
1276:
1277: if (f.getTemporary() != null)
1278: result.append(" temporaryHint=\"").append(
1279: quote(f.getTemporary(), true)).append('"');
1280: } else {
1281: result.append(" varname=\"").append(f.getVariable())
1282: .append('"');
1283: }
1284:
1285: // add newline and done
1286: result.append("/>");
1287: if (indent != null)
1288: result.append(System.getProperty("line.separator", "\r\n"));
1289: return result.toString();
1290: }
1291:
1292: /**
1293: * Dump the state of the current element as XML output. This function
1294: * traverses all sibling classes as necessary, and converts the data
1295: * into pretty-printed XML output. The stream interface should be able
1296: * to handle large output efficiently.
1297: *
1298: * @param stream is a stream opened and ready for writing. This can also
1299: * be a string stream for efficient output.
1300: * @param indent is a <code>String</code> of spaces used for pretty
1301: * printing. The initial amount of spaces should be an empty string.
1302: * The parameter is used internally for the recursive traversal.
1303: * @param namespace is the XML schema namespace prefix. If neither
1304: * empty nor null, each element will be prefixed with this prefix,
1305: * and the root element will map the XML namespace.
1306: */
1307: public void toXML(Writer stream, String indent, String namespace)
1308: throws IOException {
1309: String newline = System.getProperty("line.separator", "\r\n");
1310: String tag = (namespace != null && namespace.length() > 0) ? namespace
1311: + ":job"
1312: : "job";
1313: String tag2 = (namespace != null && namespace.length() > 0) ? namespace
1314: + ":argument"
1315: : "argument";
1316:
1317: // open tag
1318: if (indent != null && indent.length() > 0)
1319: stream.write(indent);
1320: stream.write('<');
1321: stream.write(tag);
1322: writeAttribute(stream, " id=\"", this .m_id);
1323:
1324: // open tag: print TR
1325: writeAttribute(stream, " namespace=\"", this .m_namespace);
1326: writeAttribute(stream, " name=\"", this .m_name);
1327: writeAttribute(stream, " version=\"", this .m_version);
1328:
1329: // misc. attributes like the search tree depth
1330: if (this .m_level != -1)
1331: writeAttribute(stream, " level=\"", Integer
1332: .toString(this .m_level));
1333: if (this .m_chain != null && this .m_chain.length() > 0)
1334: writeAttribute(stream, " compound=\"", this .m_chain);
1335:
1336: // still opening tag: print DV, if available
1337: if (this .m_dv_name != null) {
1338: writeAttribute(stream, " dv-namespace=\"",
1339: this .m_dv_namespace);
1340: writeAttribute(stream, " dv-name=\"", this .m_dv_name);
1341: writeAttribute(stream, " dv-version=\"", this .m_dv_version);
1342: }
1343:
1344: // open tag: finish opening tag
1345: stream.write('>');
1346: if (indent != null)
1347: stream.write(newline);
1348:
1349: // concat all command line fragments into one big string.
1350: String newindent = indent == null ? null : indent + " ";
1351: if (this .getArgumentCount() > 0) {
1352: if (newindent != null)
1353: stream.write(newindent);
1354: stream.write('<');
1355: stream.write(tag2);
1356: stream.write('>');
1357: for (Iterator i = this .m_argumentList.iterator(); i
1358: .hasNext();) {
1359: // casting will print a mixed content string or Filename element
1360: ((Leaf) i.next()).shortXML(stream, "", namespace, 0x00);
1361: }
1362: stream.write("</");
1363: stream.write(tag2);
1364: stream.write('>');
1365: if (indent != null)
1366: stream.write(newline);
1367: }
1368:
1369: // profiles to be dumped next
1370: for (Iterator i = this .m_profileList.iterator(); i.hasNext();) {
1371: ((Profile) i.next()).toXML(stream, newindent, namespace);
1372: }
1373:
1374: // finally any bound stdio descriptor
1375: // FIXME: really need to dump a Filename element!
1376: if (this .m_stdin != null)
1377: stream.write(formatFilename("stdin", newindent, namespace,
1378: this .m_stdin, false));
1379: if (this .m_stdout != null)
1380: stream.write(formatFilename("stdout", newindent, namespace,
1381: this .m_stdout, false));
1382: if (this .m_stderr != null)
1383: stream.write(formatFilename("stderr", newindent, namespace,
1384: this .m_stderr, false));
1385:
1386: // VDL referenced Filenames to be dumped next
1387: for (Iterator i = this .m_usesList.iterator(); i.hasNext();) {
1388: stream.write(formatFilename("uses", newindent, namespace,
1389: (Filename) i.next(), true));
1390: }
1391:
1392: // finish job
1393: if (indent != null && indent.length() > 0)
1394: stream.write(indent);
1395: stream.write("</");
1396: stream.write(tag);
1397: stream.write('>');
1398: if (indent != null)
1399: stream.write(newline);
1400: }
1401: }
|