/* * This file or a portion of this file is licensed under the terms of * the Globus Toolkit Public License, found in file ../GTPL, or at * http://www.globus.org/toolkit/download/license.html. This notice must * appear in redistributions of this file, with or without modification. * * Redistributions of this Software, with or without modification, must * reproduce the GTPL in: (1) the Software, or (2) the Documentation or * some other similar material which is provided with the Software (if * any). * * Copyright 1999-2004 University of Chicago and The University of * Southern California. All rights reserved. */ package org.griphyn.vdl.dax; import edu.isi.pegasus.common.util.Separator; import org.griphyn.vdl.dax.*; import org.griphyn.vdl.classes.LFN; import java.util.*; import java.io.Writer; import java.io.IOException; /** * This class defines the specifics of a job to run in an abstract manner. * All filename references still refer to logical files. All references * transformations also refer to logical transformtions, though through * <code>Profile</code> physical location hints can be passed. * * @author Jens-S. Vöckler * @author Yong Zhao * @version $Revision$ * * @see Profile * @see Filename */ public class Job extends DAX implements Cloneable { /** * Each transformation and derivation resides in a namespace. Mind * that namespaces are currently flat. If you need to impose any kind * of hierarchy, please do so yourself, e.g. use periods between * hierarchy intifiers. The namespace is part of the key identifying * a logical transformation. */ private String m_namespace = null; /** * Each transformation and derivation can be identified by a name. * For a transformation, this is part of the logical transformation * name. Derivations can be anonymous, and not use a name. */ private String m_name = null; /** * Each transformation and derivation has a version associated with * their definition. While a version number is mandatory for transformation, * being part of the logical transformation key, a derivation can * remain anonymous without version. */ private String m_version = null; /** * DVs are dynamically mapped to TR. This variable records the namespace * of the chosen DV. */ private String m_dv_namespace = null; /** * DVs are dynamically mapped to TR. This variable records the name * of the chosen DV. */ private String m_dv_name = null; /** * DVs are dynamically mapped to TR. This variable records the version * of the chosen DV. */ private String m_dv_version = null; /** * Each job also gets a unique id to refer to it from references. * @see Child */ private String m_id = null; /** * A compound transformation may be nested. For purposes of display * and grouping, it is feasible to record the compound transformation * chain. This is an optional argument. */ private String m_chain = null; /** * stdin is a {@link Filename} which must be of input linkage. * Alternatively, it may be unused (null). */ private Filename m_stdin = null; /** * stdout is a {@link Filename} which must be of output linkage. * Alternatively, it may be unused (null). */ private Filename m_stdout = null; /** * stderr is a {@link Filename} which must be of output linkage. * Alternatively, it may be unused (null). */ private Filename m_stderr = null; /** * The level is set by the topological sort. It is optional. */ private int m_level = -1; /** * The argument list describes the command line arguments as sum of * strings and filename references. Each element is a <code>Leaf</code>, * which is either implemented by a <code>Filename</code> or * <code>PseudoText</code> instance. * * @see Leaf * @see Filename * @see PseudoText */ private ArrayList m_argumentList; /** * The profile list encapsulates scheduler specific data in a * generic structure. * * @see Profile */ private ArrayList m_profileList; /** * The uses list contains all filenames that were originally part * of the linkage via the actual arguments and formal argument defaults. * * @see Filename */ private ArrayList m_usesList; /** * Creates and returns a copy of this object. * @return a new instance, semi-deep copy */ public Object clone() { Job result = new Job( this.m_namespace, this.m_name, this.m_version, this.m_id, this.m_dv_namespace, this.m_dv_name, this.m_dv_version ); result.setChain( this.getChain() ); result.setStdin( this.getStdin() ); result.setStdout( this.getStdout() ); result.setStderr( this.getStderr() ); for ( int index=0; index < this.m_argumentList.size(); ++index ) { result.setArgument( index, (Leaf) this.getArgument(index).clone() ); } for ( int index=0; index < this.m_profileList.size(); ++index ) { result.setProfile( index, (Profile) this.getProfile(index).clone() ); } for ( int index=0; index < this.m_usesList.size(); ++index ) { result.setUses( index, (Filename) this.getUses(index).clone() ); } result.setLevel( this.getLevel() ); return result; } /** * Default ctor: Note that a job must be named. */ public Job() { this.m_argumentList = new ArrayList(); this.m_profileList = new ArrayList(); this.m_usesList = new ArrayList(); } /** * Convenience ctor. Any job must be named. The job id will be * assembled from the name. * * @param namespace is the namespace that the TR resides in. * @param name is the name of the job as logical TR identifier. * @param version is a version information string of the TR. * @param id is a short DAX-unique ID to distinguish this job * from other jobs in the same DAG. * @see org.griphyn.vdl.classes.Transformation */ public Job( String namespace, String name, String version, String id ) { this.m_namespace = namespace; this.m_name = name; this.m_version = version; this.m_id = id; this.m_argumentList = new ArrayList(); this.m_profileList = new ArrayList(); this.m_usesList = new ArrayList(); } /** * Convenience ctor. Any job must be named. The job id will be * assembled from the name. * * @param namespace is the namespace that the TR resides in. * @param name is the name of the job as logical TR identifier. * @param version is a version information string of the TR. * @param id is a short DAX-unique ID to distinguish this job * from other jobs in the same DAG. * @param dv_namespace is the namespace of the DV for this job. * @param dv_name is the name of the DV that produced this job. * @param dv_version is the version of the DV for this job. * @see org.griphyn.vdl.classes.Transformation */ public Job( String namespace, String name, String version, String id, String dv_namespace, String dv_name, String dv_version ) { this.m_namespace = namespace; this.m_name = name; this.m_version = version; this.m_id = id; this.m_dv_namespace = dv_namespace; this.m_dv_name = dv_name; this.m_dv_version = dv_version; this.m_argumentList = new ArrayList(); this.m_profileList = new ArrayList(); this.m_usesList = new ArrayList(); } /** * Accessor: Adds an argument to the list of arguments * * @param vArgument is an argument fragment to append to the command line * arguments. * * @see Leaf */ public void addArgument( Leaf vArgument ) { this.m_argumentList.add(vArgument); } /** * Accessor: Inserts an argument at an arbitrary place into the list. * Each component in this vector with an index greater or equal to the * specified index is shifted upward to have an index one greater than * the value it had previously. * * @param index is the position to insert an argument * @param vArgument is the argument fragment to insert at the * specified place. * @exception IndexOutOfBounds if the argument does not fit into the list. * @see #setArgument( int, Leaf ) * @see #getArgument( int ) * @see Leaf */ public void addArgument( int index, Leaf vArgument ) throws IndexOutOfBoundsException { this.m_argumentList.add(index, vArgument); } /** * Compares two strings, each of which may be null. * @param a is the first string * @param b is the other string to compare to * @return true, if both strings are null, or both strings match. */ private boolean matchWithNull( String a, String b ) { return ( a == null ? ( b == null ) : a.equals(b) ); } /** * Accessor: Appends a profile definition to the list of profiles. This * method provides extra magic, ensuring unique namespace and key * identifiers in the profile list. If the ns:id of the profile to add * already exists in the list, the list entry will be overwritten with * the new version.<p> * * FIXME: The profile should carry a state to signal appending or * replacing. * * @param vProfile is the profile to append to remembered profiles. * @return <code>false</code> for a new elements, and <code>true</code>, * if an existing element was overwritten. * @see Profile */ public boolean addProfile( Profile vProfile ) { boolean result = false; // the list is not sorted (and should not be sorted), thus linear search for ( Iterator i=this.m_profileList.iterator(); i.hasNext(); ) { Profile p = (Profile) i.next(); if ( matchWithNull( p.getNamespace(), vProfile.getNamespace() ) && matchWithNull( p.getKey(), vProfile.getKey() ) ) { // element of this name exists, remove i.remove(); result = true; } } this.m_profileList.add(vProfile); return result; } /** * Accessor: Inserts a profile definition at an arbitrary position * into the list of profiles. Each component in this vector with an * index greater or equal to the specified index is shifted upward to * have an index one greater than the value it had previously. * * @param index is the position to insert the definitions into. * @param vProfile is the profile to append to remembered profiles. * @exception IndexOutOfBounds if the argument does not fit into the list. * @see #setProfile( int, Profile ) * @see #getProfile( int ) * @see Profile */ public void addProfile( int index, Profile vProfile ) throws IndexOutOfBoundsException { this.m_profileList.add(index, vProfile); } /** * Accessor: Appends a filename to the list of used filenames. * * @param filename is the LFN to append to remembered filenames. * @exception IndexOutOfBounds if the argument does not fit into the list. * @see Filename */ public void addUses( Filename filename ) { this.m_usesList.add(filename); } /** * Accessor: Inserts a logical filename at an arbitrary position * into the list of used filenames. Each component in this vector with an * index greater or equal to the specified index is shifted upward to * have an index one greater than the value it had previously. * * @param index is the position to insert the definitions into. * @param filename is the LFN to append to remembered filenames. * @exception IndexOutOfBounds if the argument does not fit into the list. * @see #setUses( int, Filename ) * @see #getUses( int ) * @see Filename */ public void addUses( int index, Filename filename ) throws IndexOutOfBoundsException { this.m_profileList.add(index, filename); } /** * Accessor: Provides an iterator for the argument fragment list. * * @return the iterator for the commandline argument fragments. * @see Leaf * @see java.util.Enumeration * @deprecated Use the new Collection based interfaces */ public Enumeration enumerateArgument() { return Collections.enumeration(this.m_argumentList); } /** * Accessor: Provides an iterator for the <code>Profile</code> list. * * @return the iterator for the <code>Profile</code> list. * @see Profile * @see java.util.Enumeration * @deprecated Use the new Collection based interfaces */ public Enumeration enumerateProfile() { return Collections.enumeration(this.m_profileList); } /** * Accessor: Provides an iterator for the used <code>Filename</code> list. * * @return the iterator for the <code>Filename</code> list. * @see Filename * @see java.util.Enumeration * @deprecated Use the new Collection based interfaces */ public Enumeration enumerateUses() { return Collections.enumeration(this.m_usesList); } /** * Accessor: Obtains an argument fragment from an arbitrary position. * * @param index is the place to look up the element at. * @return the argument fragment at the specified place. * @throws IndexOutOfBoundsException if the referenced position does * not exist. * @see #addArgument( int, Leaf ) * @see #setArgument( int, Leaf ) * @see Leaf */ public Leaf getArgument(int index) throws IndexOutOfBoundsException { //-- check bound for index if ((index < 0) || (index >= this.m_argumentList.size())) throw new IndexOutOfBoundsException(); return (Leaf) this.m_argumentList.get(index); } /** * Accessor: Obtains the complete commandline arguments * * @return an array with all commandline argument fragments inside. * @see #setArgument( Leaf[] ) * @see Leaf * @deprecated Use the new Collection based interfaces */ public Leaf[] getArgument() { int size = this.m_argumentList.size(); Leaf[] mArray = new Leaf[size]; System.arraycopy( this.m_argumentList.toArray(new Leaf[0]), 0, mArray, 0, size ); return mArray; } /** * Accessor: Obtains the count of fragments in the argument list. * * @return the number of arguments in the commandline argument list. * @see Leaf */ public int getArgumentCount() { return this.m_argumentList.size(); } /** * Accessor: Gets an array of all values that constitute the current * argument line. This list is read-only. * * @return an array with a mixture of either <code>PseudoText</code> or * <code>Filename</code> values. * @see #setArgument( Collection ) * @see PseudoText * @see Filename */ public java.util.List getArgumentList() { return Collections.unmodifiableList(this.m_argumentList); } /** * Accessor: Obtains the XML list attribute which contains the * chain of compound transformations that lead to this job. * * @return the chain, which may be empty or even <code>null</code>. * @see #setChain( String ) */ public String getChain() { return this.m_chain; } /** * Accessor: Obtains the unique ID of this job. The ID will be used * in references in the dependency list. * * @return The unique id from this job. * @see #setID( String ) * @see Child */ public String getID() { return this.m_id; } /** * Accessor: Obtains the current name of the job. * * @return the name as logical TR string for this job. * @see #setName( String ) */ public String getName() { return this.m_name; } /** * Accessor: Obtains the current namespace that is used for the * definition. Note that a namespace is part of the key for any * logical transformation. * * @return the namespace the definition resides in, or null, if * no namespace was defined. * @see #setNamespace(java.lang.String) */ public String getNamespace() { return this.m_namespace; } /** * Accessor: Obtains the current namespace from the DV that created * this job. Note that a namespace is part of the key for any DV. * * @return the namespace the DV resides in, or null, if no namespace * was defined. * @see #setDVNamespace(java.lang.String) * @see #setDV( String, String, String ) */ public String getDVNamespace() { return this.m_dv_namespace; } /** * Accessor: Obtains the current name from the DV that created * this job. Note that a name is part of the key for any DV. * * @return the name the DV resides in. * @see #setDVName(java.lang.String) * @see #setDV( String, String, String ) */ public String getDVName() { return this.m_dv_name; } /** * Accessor: Obtains the current version from the DV that created * this job. Note that a version is part of the key triple for any * DV. * * @return the version the DV resides in, or null, if no version * was defined. * @see #setDVVersion(java.lang.String) * @see #setDV( String, String, String ) */ public String getDVVersion() { return this.m_dv_version; } /** * Accessor: Obtains the current setting of stdin redirection. * * @return a filename which will be associated with stdin, * or <code>null</code>, if unset. * @see #setStdin( Filename ) */ public Filename getStdin() { return this.m_stdin; } /** * Accessor * * @see #setLevel(int) */ public int getLevel() { return this.m_level; } /** * Accessor. * * @param level * @see #getLevel() */ public void setLevel( int level ) { this.m_level = level; } /** * Accessor: Obtains the current setting of stdout redirection. * * @return a filename which will be associated with stdout, * or <code>null</code>, if unset. * @see #setStdout( Filename ) */ public Filename getStdout() { return this.m_stdout; } /** * Accessor: Obtains the current setting of stderr redirection. * * @return a filename which will be associated with stderr, * or <code>null</code>, if unset. * @see #setStderr( Filename ) */ public Filename getStderr() { return this.m_stderr; } /** * Accessor: Obtains an <code>Profile</code> at an arbitrary position. * * @param index is the place to look up the element at. * @exception IndexOutOfBoundsException if the referenced position does not exist. * @see #addProfile( int, Profile ) * @see #setProfile( int, Profile ) * @see Profile */ public Profile getProfile(int index) throws IndexOutOfBoundsException { //-- check bounds for index if ((index < 0) || (index >= this.m_profileList.size())) throw new IndexOutOfBoundsException(); return (Profile) this.m_profileList.get(index); } /** * Accessor: Obtains all profiles. * * @return an array with all profiles inside. * @see #setProfile( Profile[] ) * @see Profile * @deprecated Use the new Collection based interfaces */ public Profile[] getProfile() { int size = this.m_argumentList.size(); Profile[] mArray = new Profile[size]; System.arraycopy( this.m_profileList.toArray(new Profile[0]), 0, mArray, 0, size ); return mArray; } /** * Accessor: Counts the number of profile specifications known to this job. * * @return the number of profiles * @see Profile */ public int getProfileCount() { return this.m_profileList.size(); } /** * Accessor: Obtain a read-only copy of the list of all * <code>Profile</code> specifications. * * @return a collection containing the scheduler specific environment * options for the job. * @see #setProfile( Collection ) * @see Profile */ public java.util.List getProfileList() { return Collections.unmodifiableList(this.m_profileList); } /** * Accessor: Obtains an <code>Filename</code> at an arbitrary position. * * @param index is the place to look up the element at. * @exception IndexOutOfBoundsException if the referenced position does not exist. * @see #addUses( int, Filename ) * @see #setUses( int, Filename ) * @see Filename */ public Filename getUses(int index) throws IndexOutOfBoundsException { //-- check bounds for index if ((index < 0) || (index >= this.m_usesList.size())) throw new IndexOutOfBoundsException(); return (Filename) this.m_usesList.get(index); } /** * Accessor: Obtain a copy of the list of all <code>Filename</code> * specifications, that were part of the arguments that generated * this job. * * @return an array containing the used filenames for the job. * @see #setUses( Filename[] ) * @see Filename * @deprecated Use the new Collection based interfaces */ public Filename[] getUses() { int size = this.m_usesList.size(); Filename[] mArray = new Filename[size]; System.arraycopy( this.m_usesList.toArray(new Filename[0]), 0, mArray, 0, size ); return mArray; } /** * Accessor: Counts the number of argument-referenced logical filenames * known to this job. * * @return the number of LFNs. * @see Filename */ public int getUsesCount() { return this.m_usesList.size(); } /** * Accessor: Obtain a copy of the list of all <code>Filename</code> * specifications, that were part of the arguments that generated * this job. This list is read-only. * * @return an array containing the used filenames for the job. * @see #setUses( Collection ) * @see Filename */ public java.util.List getUsesList() { return Collections.unmodifiableList(this.m_usesList); } /** * Accessor: Obtains the current version of the definition. A version * is an integral part of a logical transformation. * * @return the version number of this definition, or null, if no * version number was defined. * @see #setVersion(java.lang.String) */ public String getVersion() { return this.m_version; } /** * Accessor: Provides an iterator to the internal list of all * commandline argument elements. * * @return an iterator to walk the list with. */ public Iterator iterateArgument() { return this.m_argumentList.iterator(); } /** * Accessor: Provides an iterator to the internal list of all * profiles. * * @return an iterator to walk the list with. */ public Iterator iterateProfile() { return this.m_profileList.iterator(); } /** * Accessor: Provides an iterator to the internal list of used * filenames. * * @return an iterator to walk the list with. */ public Iterator iterateUses() { return this.m_usesList.iterator(); } /** * Accessor: Provides a list iterator to the internal list of all * commandline argument elements. * * @return a list iterator to walk the list with. */ public ListIterator listIterateArgument() { return this.m_argumentList.listIterator(); } /** * Accessor: Provides a list iterator to the internal list of all * commandline argument elements. * * @param start is the start index * @return a list iterator to walk the list with. */ public ListIterator listIterateArgument(int start) { return this.m_argumentList.listIterator(start); } /** * Accessor: Provides a list iterator to the internal list of all * profiles. * * @return a list iterator to walk the list with. */ public ListIterator listIterateProfile() { return this.m_profileList.listIterator(); } /** * Accessor: Provides a list iterator to the internal list of all * profiles. * * @param start is the start index * @return a list iterator to walk the list with. */ public ListIterator listIterateProfile(int start) { return this.m_profileList.listIterator(start); } /** * Accessor: Provides a list iterator to the internal list of all * used filenames. * * @return a list iterator to walk the list with. */ public ListIterator listIterateUses() { return this.m_usesList.listIterator(); } /** * Accessor: Provides a list iterator to the internal list of all * used filenames. * * @param start is the start index * @return a list iterator to walk the list with. */ public ListIterator listIterateUses(int start) { return this.m_usesList.listIterator(start); } /** * Accessor: Removes all commandline arguments pieces. */ public void removeAllArgument() { this.m_argumentList.clear(); } /** * Accessor: Removes all profile declarations. * @see Profile */ public void removeAllProfile() { this.m_profileList.clear(); } /** * Accessor: Removes all known <code>Filename</code>s. * @see Filename */ public void removeAllUses() { this.m_usesList.clear(); } /** * Accessor: Removes a commandline argument fragment from the * commandline. Each component in this vector with an index greater or * equal to the specified index is shifted downward to have an index * one smaller than the value it had previously. The size of this * vector is decreased by 1. * * @param index is the position to remove the argument fragment from. * @return the removed fragment. * @exception ArrayIndexOutOfBoundsException if the index was invalid. * @see Leaf */ public Leaf removeArgument(int index) { return (Leaf) this.m_argumentList.remove(index); } /** * Accessor: Removes a profile. Each component in this vector with an * index greater or equal to the specified index is shifted downward * to have an index one smaller than the value it had previously. The * size of this vector is decreased by 1. * * @param index is the position to remove the profile from. * @return the removed Profile. * @exception ArrayIndexOutOfBoundsException if the index was invalid. * @see Profile */ public Profile removeProfile(int index) { return (Profile) this.m_profileList.remove(index); } /** * Accessor: Removes a used filename from the list of * argument-referenced LFNs. Each component in this vector with an * index greater or equal to the specified index is shifted downward * to have an index one smaller than the value it had previously. The * size of this vector is decreased by 1. * * @param index is the position to remove the filename from. * @return the removed Filename * @exception ArrayIndexOutOfBoundsException if the index was invalid. * @see Filename */ public Filename removeUses(int index) { return (Filename) this.m_usesList.remove(index); } /** * Accessor: Overwrites an commandline argument fragment with a new one. * * @param index is the position to overwrite the element at * @param vArgument is the new commandline argument fragment. * @exception IndexOutOfBoundsException if the position does not exist. * @see Leaf * @see #addArgument( int, Leaf ) * @see #getArgument( int ) */ public void setArgument(int index, Leaf vArgument) throws IndexOutOfBoundsException { //-- check bounds for index if ((index < 0) || (index >= this.m_argumentList.size())) throw new IndexOutOfBoundsException(); this.m_argumentList.set(index, vArgument); } /** * Accessor: Replace the commandline arguments with a new commandline * argument fragment list. * * @param argumentArray is the new commandline argument array. * @see #getArgument() * @see Leaf * @deprecated Use the new Collection based interfaces */ public void setArgument(Leaf[] argumentArray) { this.m_argumentList.clear(); this.m_argumentList.addAll( Arrays.asList(argumentArray) ); } /** * Accessor: Replace the commandline arguments with a new commandline * argument fragment list. * * @param arguments is the new commandline argument collection. * @see #getArgumentList() * @see Leaf */ public void setArgument(java.util.Collection arguments) { this.m_argumentList.clear(); this.m_argumentList.addAll(arguments); } /** * Accessor: Sets the current name of the job. If the job ID was * not set previously, it will be set to the job name. * FIXME: We need to use the primary key triple for logical TR! * * @param name the new name as logical TR string for this job. * @see #getName() */ public void setName( String name) { if ( this.m_id == null ) this.m_id = name; this.m_name = name; } /** * Accessor: Sets or overwrites the TR namespace identifier. * * @param namespace * @see #getNamespace() */ public void setNamespace(String namespace) { this.m_namespace = namespace; } /** * Accessor: Sets or overwrites the DV namespace identifier. * * @param namespace * @see #getDVNamespace() * @see #setDV( String, String, String ) */ public void setDVNamespace(String namespace) { this.m_dv_namespace = namespace; } /** * Accessor: Sets or overwrites the DV name identifier. * * @param name * @see #getDVName() * @see #setDV( String, String, String ) */ public void setDVName(String name) { this.m_dv_name = name; } /** * Accessor: Sets or overwrites the DV version identifier. * * @param version * @see #getDVVersion() * @see #setDV( String, String, String ) */ public void setDVVersion(String version) { this.m_dv_version = version; } /** * Accessor: Sets or overwrites the DV FQDN triple. * * @param namespace is the DV's namespace, may be null * @param name is the DV name, should not be null * @param version is the DV version, may be null * @see #getDVNamespace() * @see #getDVName() * @see #getDVVersion() * @see #setDVNamespace( String ) * @see #setDVName( String ) * @see #setDVVersion( String ) */ public void setDV( String namespace, String name, String version) { this.m_dv_namespace = namespace; this.m_dv_name = name; this.m_dv_version = version; } /** * Accessor: Sets the XML list attribute which contains the * chain of compound transformations that lead to this job. * * @param chain is the chain, which may be empty or even <code>null</code>. * @see #getChain( ) */ public void setChain( String chain ) { this.m_chain = chain.trim(); } /** * Accessor: Sets the unique ID of this job. The ID will be used * in references in the dependency list. Please do not use this * function. * * @param id is the new unique id for this job. * @see #getID() * @see Child */ public void setID( String id ) { this.m_id = id; } /** * Accessor: Sets or releases the stdin redirection. * * @param f is a filename which will be associated with stdin, * or <code>null</code> to release redirection. * @see #getStdin() */ public void setStdin( Filename f ) { this.m_stdin = f; } /** * Accessor: Sets or releases the stdout redirection. * * @param f is a filename which will be associated with stdout, * or <code>null</code> to unset. * @see #getStdout() */ public void setStdout( Filename f ) { this.m_stdout = f; } /** * Accessor: Sets or releases the stderr redirection. * * @param f is a filename which will be associated with stderr, * or <code>null</code> to unset. * @see #getStderr() */ public void setStderr( Filename f ) { this.m_stderr = f; } /** * Accessor: Overwrites a profile with a new profile * * @param index is the position to overwrite the profile at. * @param vProfile is the new profile to use in overwriting. * @exception IndexOutOfBoundsException if the position does not exist. * @see Profile * @see #addProfile( int, Profile ) * @see #getProfile( int ) */ public void setProfile(int index, Profile vProfile) throws IndexOutOfBoundsException { //-- check bounds for index if ((index < 0) || (index >= this.m_profileList.size())) throw new IndexOutOfBoundsException(); this.m_profileList.set(index, vProfile); } /** * Accessor: Replace the internal profile list with a new list. * * @param profileArray is the new list of profiles to use for the job. * @see #getProfile() * @see Profile * @deprecated Use the new Collection based interfaces */ public void setProfile( Profile[] profileArray ) { this.m_profileList.clear(); this.m_profileList.addAll( Arrays.asList(profileArray) ); } /** * Accessor: Replace the internal profile list with a new list. * * @param profiles is the new list of profiles to use for the job. * @see #getProfileList() * @see Profile */ public void setProfile( java.util.Collection profiles ) { this.m_profileList.clear(); this.m_profileList.addAll(profiles); } /** * Accessor: Overwrites a used filename with a new LFN. * * @param index is the position to overwrite the LFN at. * @param vFilename is the new LFN to use in overwriting. * @exception IndexOutOfBoundsException if the position does not exist. * @see #addUses( int, Filename ) * @see #getUses( int ) * @see Filename */ public void setUses(int index, Filename vFilename) throws IndexOutOfBoundsException { //-- check bounds for index if ((index < 0) || (index >= this.m_usesList.size())) throw new IndexOutOfBoundsException(); this.m_usesList.set(index, vFilename); } /** * Accessor: Replace the internal list of used LFNs with a new list. * * @param filenameArray is the new list of argument-referenced * filenames to use for the job. * @see #getUses() * @see Filename * @deprecated Use the new Collection based interfaces */ public void setUses(Filename[] filenameArray) { this.m_usesList.clear(); this.m_usesList.addAll( Arrays.asList(filenameArray) ); } /** * Accessor: Replace the internal list of used LFNs with a new list. * * @param filenames is a new collection of argument-referenced * filenames to use for the job. * @see #getUsesList() * @see Filename */ public void setUses(java.util.Collection filenames) { this.m_usesList.clear(); this.m_usesList.addAll(filenames); } /** * Accessor: Sets the version of the definition. * * @param version * @see #getVersion() */ public void setVersion(String version) { this.m_version = version; } /** * Converts the active state into something meant for human consumption. * The method will be called when recursively traversing the instance * tree. * * @param stream is a stream opened and ready for writing. This can also * be a string stream for efficient output. */ public void toString( Writer stream ) throws IOException { String newline = System.getProperty( "line.separator", "\r\n" ); stream.write( " job " ); if ( this.m_namespace != null ) { stream.write( this.m_namespace ); stream.write( Separator.NAMESPACE ); } stream.write( this.m_name ); if ( this.m_version != null ) { stream.write( Separator.NAME ); stream.write( this.m_version ); } stream.write( " {" ); stream.write( newline ); // FIXME: assumes an indentation level stream.write( " id=" ); stream.write( this.m_id ); stream.write( ';' ); stream.write( newline ); // concat all command line fragments into one big string. if ( this.getArgumentCount() > 0 ) { stream.write( " argument=" ); for ( Iterator i=this.m_argumentList.iterator(); i.hasNext(); ) { // casting will print a mixed content string or Filename element ((Leaf) i.next()).toString(stream); } stream.write( ';' ); stream.write( newline ); } // profiles to be dumped next for ( Iterator i=this.m_profileList.iterator(); i.hasNext(); ) { stream.write( " " ); ((Profile) i.next()).toString(stream); stream.write( ';' ); stream.write( newline ); } // finally any bound stdio descriptor // FIXME: really need to dump a Filename element! if ( this.m_stdin != null ) { stream.write( " stdin=" ); this.m_stdin.toString(stream); stream.write( ';' ); stream.write( newline ); } if ( this.m_stdout != null ) { stream.write( " stdout=" ); this.m_stdout.toString(stream); stream.write( ';' ); stream.write(newline); } if ( this.m_stderr != null ) { stream.write( " stderr=" ); this.m_stderr.toString(stream); stream.write(';'); stream.write( newline ); } // argument-referenced filenames for the job, which may not appear // in the argument list nor the profile for ( Iterator i=this.m_usesList.iterator(); i.hasNext(); ) { stream.write( " uses=" ); ((Filename) i.next()).toString(stream); stream.write( ';' ); stream.write( newline ); } // finish job stream.write( " }" ); stream.write( newline ); } /** * Helper: Formats the attributes of any {@link Filename} instance, * or inherited instances. * * @param tag is the name of the element to use when formating. * @param indent is the indentation of the element, may be null. * @param namespace is an optional namespace to use in the tag. * @param f is an instance of a <code>Filename</code> object. * @param full denotes the full attributes set, or just the stdio * attributes set if false. * * @return the XML-formatted attributes without the element tags. */ private String formatFilename( String tag, String indent, String namespace, Filename f, boolean full ) { StringBuffer result = new StringBuffer( full ? 128 : 80 ); if ( namespace != null && namespace.length() > 0 ) tag = namespace + ":" + tag; if ( indent != null && indent.length() > 0 ) result.append( indent ); result.append('<').append(tag); result.append(" file=\"").append(quote(f.getFilename(),true)).append('"'); result.append(" link=\"").append(LFN.toString(f.getLink())).append('"'); if ( full ) { result.append(" register=\"") .append(Boolean.toString( f.getRegister())).append('"'); result.append(" transfer=\"") .append(LFN.transferString( f.getTransfer() )).append('"'); result.append(" type=\"") .append(LFN.typeString( f.getType() )).append('"'); if( f.getOptional() ) result.append( " optional=\"" ).append( f.getOptional() ).append( "\"" ); if ( f.getTemporary() != null ) result.append(" temporaryHint=\"") .append(quote(f.getTemporary(),true)).append('"'); } else { result.append(" varname=\"").append(f.getVariable()).append('"'); } // add newline and done result.append("/>"); if ( indent != null ) result.append( System.getProperty( "line.separator", "\r\n" ) ); return result.toString(); } /** * Dump the state of the current element as XML output. This function * traverses all sibling classes as necessary, and converts the data * into pretty-printed XML output. The stream interface should be able * to handle large output efficiently. * * @param stream is a stream opened and ready for writing. This can also * be a string stream for efficient output. * @param indent is a <code>String</code> of spaces used for pretty * printing. The initial amount of spaces should be an empty string. * The parameter is used internally for the recursive traversal. * @param namespace is the XML schema namespace prefix. If neither * empty nor null, each element will be prefixed with this prefix, * and the root element will map the XML namespace. */ public void toXML( Writer stream, String indent, String namespace ) throws IOException { String newline = System.getProperty( "line.separator", "\r\n" ); String tag = ( namespace != null && namespace.length() > 0 ) ? namespace + ":job" : "job"; String tag2 = ( namespace != null && namespace.length() > 0 ) ? namespace + ":argument" : "argument"; // open tag if ( indent != null && indent.length() > 0 ) stream.write( indent ); stream.write( '<' ); stream.write( tag ); writeAttribute( stream, " id=\"", this.m_id ); // open tag: print TR writeAttribute( stream, " namespace=\"", this.m_namespace ); writeAttribute( stream, " name=\"", this.m_name ); writeAttribute( stream, " version=\"", this.m_version ); // misc. attributes like the search tree depth if ( this.m_level != -1 ) writeAttribute( stream, " level=\"", Integer.toString(this.m_level) ); if ( this.m_chain != null && this.m_chain.length() > 0 ) writeAttribute( stream, " compound=\"", this.m_chain ); // still opening tag: print DV, if available if ( this.m_dv_name != null ) { writeAttribute( stream, " dv-namespace=\"", this.m_dv_namespace ); writeAttribute( stream, " dv-name=\"", this.m_dv_name ); writeAttribute( stream, " dv-version=\"", this.m_dv_version ); } // open tag: finish opening tag stream.write( '>' ); if ( indent != null ) stream.write( newline ); // concat all command line fragments into one big string. String newindent = indent==null ? null : indent + " "; if ( this.getArgumentCount() > 0 ) { if ( newindent != null ) stream.write( newindent ); stream.write( '<' ); stream.write( tag2 ); stream.write( '>' ); for ( Iterator i=this.m_argumentList.iterator(); i.hasNext(); ) { // casting will print a mixed content string or Filename element ((Leaf) i.next()).shortXML( stream, "", namespace, 0x00 ); } stream.write( "</" ); stream.write( tag2 ); stream.write( '>' ); if ( indent != null ) stream.write( newline ); } // profiles to be dumped next for ( Iterator i=this.m_profileList.iterator(); i.hasNext(); ) { ((Profile) i.next()).toXML( stream, newindent, namespace ); } // finally any bound stdio descriptor // FIXME: really need to dump a Filename element! if ( this.m_stdin != null ) stream.write( formatFilename( "stdin", newindent, namespace, this.m_stdin, false) ); if ( this.m_stdout != null ) stream.write( formatFilename( "stdout", newindent, namespace, this.m_stdout, false) ); if ( this.m_stderr != null ) stream.write( formatFilename( "stderr", newindent, namespace, this.m_stderr, false) ); // VDL referenced Filenames to be dumped next for ( Iterator i=this.m_usesList.iterator(); i.hasNext(); ) { stream.write( formatFilename( "uses", newindent, namespace, (Filename) i.next(), true) ); } // finish job if ( indent != null && indent.length() > 0 ) stream.write( indent ); stream.write( "</" ); stream.write( tag ); stream.write( '>' ); if ( indent != null ) stream.write( newline ); } }