/* * 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 edu.isi.pegasus.planner.invocation; import edu.isi.pegasus.common.util.Currently; import java.util.*; import java.net.InetAddress; import java.io.Writer; import java.io.IOException; /** * This class is the container for an invocation record. The record * itself contains information about the job or jobs that ran, the total * usage, and information about central files that were used. * * @author Jens-S. Vöckler * @author Yong Zhao * @version $Revision$ */ public class InvocationRecord extends Invocation // implements Cloneable { /** * The "official" namespace URI of the invocation record schema. */ public static final String SCHEMA_NAMESPACE = "http://pegasus.isi.edu/schema/invocation"; /** * The "not-so-official" location URL of the invocation record definition. */ public static final String SCHEMA_LOCATION = "http://pegasus.isi.edu/schema/iv-2.1.xsd"; /** * protocol version information. */ private String m_version; /** * start of gridlaunch timestamp. */ private Date m_start; /** * total duration of call. */ private double m_duration; /** * Name of the: Transformation that produced this invocation. */ private String m_transformation; /** * Name of the Derivation that produced this invocation. */ private String m_derivation; /** * Records the physical memory on the remote machine, if available. */ private long m_pmem = -1; /** * process id of gridlaunch itself. */ private int m_pid; /** * host address where gridlaunch ran (primary interface). */ private InetAddress m_hostaddr; /** * Symbolic hostname where gridlaunch ran (primary interface). */ private String m_hostname; /** * Symbolic name of primary interface we used to determine host-name and -address. */ private String m_interface; /** * numerical user id of the effective user. */ private int m_uid; /** * symbolical user name of the effective user. */ private String m_user; /** * numerical group id of the effective user. */ private int m_gid; /** * symbolical group name of the effective user. */ private String m_group; /** * Working directory at startup. */ private WorkingDir m_cwd; /** * Architectural information. */ private Architecture m_uname; /** * Total resource consumption by gridlaunch and all siblings. */ private Usage m_usage; /** * Job records: prejob, main job, postjob */ private List m_job; /** * Array with stat() and fstat() information about various files. */ private List m_stat; /** * Resource, site or pool at which the jobs was run. */ private String m_resource; /** * Workflow label, currently optional? */ private String m_wf_label; /** * Workflow timestamp to make the label more unique. */ private Date m_wf_stamp; /** * Environment settings. */ private Environment m_environment; /** * Currently active umask while kickstart was executing. This * is available with new kickstart, older version will have -1 * at this API point. */ private int m_umask = -1; /** * The Machine object capturing machine information. */ private Machine m_machine; /** * Accessor * * @see #setUMask(int) */ public int getUMask() { return this.m_umask; } /** * Accessor. * * @param umask * @see #getUMask() */ public void setUMask( int umask ) { this.m_umask = umask; } /** * Default c'tor: Construct a hollow shell and allow further * information to be added later. */ public InvocationRecord() { m_stat = new ArrayList(5); m_job = new ArrayList(3); m_environment = null; } /** * Accessor * * @see #setVersion(String) */ public String getVersion() { return this.m_version; } /** * Accessor. * * @param version * @see #getVersion() */ public void setVersion( String version ) { this.m_version = version; } /** * Accessor * * @see #setStart(Date) */ public Date getStart() { return this.m_start; } /** * Accessor. * * @param start * @see #getStart() */ public void setStart( Date start ) { this.m_start = start; } /** * Accessor * * @see #setDuration(double) */ public double getDuration() { return this.m_duration; } /** * Accessor. * * @param duration * @see #getDuration() */ public void setDuration( double duration ) { this.m_duration = duration; } /** * Accessor. * * @param machine * @see #getMachine() */ public void setMachine( Machine machine ) { this.m_machine = machine; } /** * Accessor. * * @return machine * @see #setMachine(org.griphyn.vdl.invocation.Machine) */ public Machine getMachine( ) { return this.m_machine; } /** * Accessor * * @see #setTransformation(String) */ public String getTransformation() { return this.m_transformation; } /** * Accessor. * * @param transformation * @see #getTransformation() */ public void setTransformation( String transformation ) { this.m_transformation = transformation; } /** * Accessor * * @see #setDerivation(String) */ public String getDerivation() { return this.m_derivation; } /** * Accessor. * * @param derivation * @see #getDerivation() */ public void setDerivation( String derivation ) { this.m_derivation = derivation; } /** * Accessor * * @see #setPID(int) */ public int getPID() { return this.m_pid; } /** * Accessor. * * @param pid * @see #getPID() */ public void setPID( int pid ) { this.m_pid = pid; } /** * Accessor * * @see #setHostAddress(InetAddress) */ public InetAddress getHostAddress() { return this.m_hostaddr; } /** * Accessor. * * @param hostaddr * @see #getHostAddress() */ public void setHostAddress( InetAddress hostaddr ) { this.m_hostaddr = hostaddr; } /** * Accessor * * @see #setHostname(String) */ public String getHostname() { return this.m_hostname; } /** * Accessor. * * @param hostname * @see #getHostname() */ public void setHostname( String hostname ) { this.m_hostname = hostname; } /** * Accessor. * * @see #setInterface(String) */ public String getInterface() { return this.m_interface; } /** * Accessor. * * @param p_interface * @see #getInterface() */ public void setInterface( String p_interface ) { this.m_interface = p_interface; } /** * Accessor * * @see #setUID(int) */ public int getUID() { return this.m_uid; } /** * Accessor. * * @param uid * @see #getUID() */ public void setUID( int uid ) { this.m_uid = uid; } /** * Accessor * * @see #setUser(String) */ public String getUser() { return this.m_user; } /** * Accessor. * * @param user * @see #getUser() */ public void setUser( String user ) { this.m_user = user; } /** * Accessor * * @see #setGID(int) */ public int getGID() { return this.m_gid; } /** * Accessor. * * @param gid * @see #getGID() */ public void setGID( int gid ) { this.m_gid = gid; } /** * Accessor * * @see #setGroup(String) */ public String getGroup() { return this.m_group; } /** * Accessor. * * @param group * @see #getGroup() */ public void setGroup( String group ) { this.m_group = group; } /** * Accessor * * @see #setUsage(Usage) */ public Usage getUsage() { return this.m_usage; } /** * Accessor. * * @param usage * @see #getUsage() */ public void setUsage( Usage usage ) { this.m_usage = usage; } /** * Accessor * * @see #setArchitecture(Architecture) */ public Architecture getArchitecture() { return this.m_uname; } /** * Accessor. * * @param uname * @see #getArchitecture() */ public void setArchitecture( Architecture uname ) { this.m_uname = uname; } /** * Accessor * * @see #setResource( String ) */ public String getResource() { return this.m_resource; } /** * Accessor. * * @param resource * @see #getResource() */ public void setResource( String resource ) { this.m_resource = resource; } /** * Accessor * * @see #setWorkflowLabel( String ) */ public String getWorkflowLabel() { return this.m_wf_label; } /** * Accessor. * * @param label * @see #getWorkflowLabel() */ public void setWorkflowLabel( String label ) { this.m_wf_label = label; } /** * Accessor * * @see #setWorkflowTimestamp( Date ) */ public Date getWorkflowTimestamp() { return this.m_wf_stamp; } /** * Accessor. * * @param stamp * @see #getResource() */ public void setWorkflowTimestamp( Date stamp ) { this.m_wf_stamp = stamp; } /** * Accessor * * @see #setEnvironment(Environment) */ public Environment getEnvironment() { return this.m_environment; } /** * Accessor. * * @param environment * @see #getEnvironment() */ public void setEnvironment( Environment environment ) { this.m_environment = environment; } // /** // * Parses an ISO 8601 timestamp? // * // * @param stamp // * @see #getResource() // */ // public void setWorkflowTimestamp( String stamp ) // { this.m_wf_stamp = stamp; } /** * Accessor: Appends a job to the list of jobs. * * @param job is the job to append to the list. */ public void addJob( Job job ) { this.m_job.add(job); } /** * Accessor: Inserts a Job into a specific position of the job list. * * @param index is the position to insert the item into * @param job is the job to insert into the list. */ public void addJob( int index, Job job ) { this.m_job.add( index, job ); } /** * Accessor: Obtains a job at a certain position in the job list. * * @param index is the position in the list to obtain a job from * @return the job at that position. * @throws IndexOutOfBoundsException if the index points to an element * in the list that does not contain any elments. */ public Job getJob( int index ) throws IndexOutOfBoundsException { //-- check bound for index if ((index < 0) || (index >= this.m_job.size())) throw new IndexOutOfBoundsException(); return (Job) this.m_job.get(index); } /** * Accessor: Obtains the size of the job list. * * @return number of elements that an external array needs to be sized to. */ public int getJobCount() { return this.m_job.size(); } /** * Accessor: Gets an array of all values that constitute the current * content. This list is read-only. * * @return a list of jobs. */ public java.util.List getJobList() { return Collections.unmodifiableList(this.m_job); } /** * Accessor: Enumerates the internal values that constitute the content * of the job list. * * @return an iterator to walk the list with. */ public Iterator iterateJob() { return this.m_job.iterator(); } /** * Accessor: Enumerates the internal values that constitute the content * of the job list. * * @return a list iterator to walk the list with. */ public ListIterator listIterateJob() { return this.m_job.listIterator(); } /** * Accessor: Removes all values from the job list. */ public void removeAllJob() { this.m_job.clear(); } /** * Accessor: Removes a specific job from the job list. * @param index is the position at which an element is to be removed. * @return the job that was removed. */ public Job removeJob( int index ) { return (Job) this.m_job.remove(index); } /** * Accessor: Overwrites a job at a certain position. * * @param index position to overwrite an elment in. * @param job is the Job to replace with. * @throws IndexOutOfBoundsException if the position pointed to is invalid. */ public void setJob( int index, Job job ) throws IndexOutOfBoundsException { //-- check bounds for index if ((index < 0) || (index >= this.m_job.size())) { throw new IndexOutOfBoundsException(); } this.m_job.set(index, job); } /** * Accessor: Overwrites internal list with an external list * representing jobs. * * @param jobs is the external list of job to overwrite with. */ public void setJob( Collection jobs ) { this.m_job.clear(); this.m_job.addAll(jobs); } /** * Accessor: Appends a stat to the list of stats. * * @param stat is the stat to append to the list. */ public void addStatCall( StatCall stat ) { this.m_stat.add(stat); } /** * Accessor: Inserts a StatCall into a specific position of the stat list. * * @param index is the position to insert the item into * @param stat is the stat to insert into the list. */ public void addStatCall( int index, StatCall stat ) { this.m_stat.add( index, stat ); } /** * Accessor: Obtains a stat at a certain position in the stat list. * * @param index is the position in the list to obtain a stat from * @return the stat at that position. * @throws IndexOutOfBoundsException if the index points to an element * in the list that does not contain any elments. */ public StatCall getStatCall( int index ) throws IndexOutOfBoundsException { //-- check bound for index if ((index < 0) || (index >= this.m_stat.size())) throw new IndexOutOfBoundsException(); return (StatCall) this.m_stat.get(index); } /** * Accessor: Obtains the size of the stat list. * * @return number of elements that an external array needs to be sized to. */ public int getStatCount() { return this.m_stat.size(); } /** * Accessor: Gets an array of all values that constitute the current * content. This list is read-only. * * @return a list of stats. */ public java.util.List getStatList() { return Collections.unmodifiableList(this.m_stat); } /** * Accessor: Enumerates the internal values that constitute the content * of the stat list. * * @return an iterator to walk the list with. */ public Iterator iterateStatCall() { return this.m_stat.iterator(); } /** * Accessor: Enumerates the internal values that constitute the content * of the stat list. * * @return a list iterator to walk the list with. */ public ListIterator listIterateStatCall() { return this.m_stat.listIterator(); } /** * Accessor: Removes all values from the stat list. */ public void removeAllStatCall() { this.m_stat.clear(); } /** * Accessor: Removes a specific stat from the stat list. * @param index is the position at which an element is to be removed. * @return the stat that was removed. */ public StatCall removeStatCall( int index ) { return (StatCall) this.m_stat.remove(index); } /** * Accessor: Overwrites a stat at a certain position. * * @param index position to overwrite an elment in. * @param stat is the StatCall to replace with. * @throws IndexOutOfBoundsException if the position pointed to is invalid. */ public void setStatCall( int index, StatCall stat ) throws IndexOutOfBoundsException { //-- check bounds for index if ((index < 0) || (index >= this.m_stat.size())) { throw new IndexOutOfBoundsException(); } this.m_stat.set(index, stat); } /** * Accessor: Overwrites internal list with an external list * representing stats. * * @param stats is the external list of stat to overwrite with. */ public void setStatCall( Collection stats ) { this.m_stat.clear(); this.m_stat.addAll(stats); } /** * Accessor * * @see #setWorkingDirectory(WorkingDir) * @see #setWorkingDirectory(String) */ public WorkingDir getWorkingDirectory() { return this.m_cwd; } /** * Accessor. * * @param cwd * @see #getWorkingDirectory() * @see #setWorkingDirectory(WorkingDir) */ public void setWorkingDirectory( String cwd ) { this.m_cwd = new WorkingDir(cwd); } /** * Accessor. * * @param cwd * @see #getWorkingDirectory() * @see #setWorkingDirectory(String) */ public void setWorkingDirectory( WorkingDir cwd ) { this.m_cwd = cwd; } /** * Accessor. * * @return the recorded physical memory in byte, or -1 if not available. * @see #setPhysicalMemory( long ) */ public long getPhysicalMemory() { return this.m_pmem; } /** * Accessor. * * @param pmem * @see #getPhysicalMemory() */ public void setPhysicalMemory( long pmem ) { this.m_pmem = pmem; } /** * 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 { throw new IOException( "method not implemented, please contact vds-support@griphyn.org" ); } /** * Writes the header of the XML output. The output contains the special * strings to start an XML document, some comments, and the root element. * The latter points to the XML schema via XML Instances. * * @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. * @exception IOException if something fishy happens to the stream. */ public void writeXMLHeader( Writer stream, String indent, String namespace ) throws IOException { String newline = System.getProperty( "line.separator", "\r\n" ); // intro if ( indent != null && indent.length() > 0 ) stream.write( indent ); stream.write( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" ); stream.write( newline ); // when was this document generated if ( indent != null && indent.length() > 0 ) stream.write( indent ); stream.write( "<!-- generated: " ); stream.write( Currently.iso8601(false) ); stream.write( " -->" ); stream.write( newline ); // who generated this document if ( indent != null && indent.length() > 0 ) stream.write( indent ); stream.write( "<!-- generated by: " ); stream.write( System.getProperties().getProperty("user.name", "unknown") ); stream.write( " [" ); stream.write( System.getProperties().getProperty("user.region","??") ); stream.write( "] -->" ); stream.write( newline ); // root element with elementary attributes if ( indent != null && indent.length() > 0 ) stream.write( indent ); stream.write( '<' ); if ( namespace != null && namespace.length() > 0 ) { stream.write( namespace ); stream.write( ':' ); } stream.write( "invocation xmlns" ); if ( namespace != null && namespace.length() > 0 ) { stream.write( ':' ); stream.write( namespace ); } stream.write( "=\""); stream.write( SCHEMA_NAMESPACE ); stream.write( "\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"" ); stream.write( SCHEMA_NAMESPACE ); stream.write( ' ' ); stream.write( SCHEMA_LOCATION ); stream.write( "\""); writeAttribute( stream, " version=\"", this.m_version ); writeAttribute( stream, " start=\"", Currently.iso8601(false,true,true,this.m_start) ); writeAttribute( stream, " duration=\"", Double.toString(this.m_duration) ); if ( this.m_transformation != null && this.m_transformation.length() > 0 ) writeAttribute( stream, " transformation=\"", this.m_transformation ); if ( this.m_derivation != null && this.m_derivation.length() > 0 ) writeAttribute( stream, " derivation=\"", this.m_derivation ); if ( this.m_pmem != -1 ) writeAttribute( stream, " ram=\"", Long.toString(this.m_pmem) ); writeAttribute( stream, " pid=\"", Integer.toString( this.m_pid ) ); if ( this.m_resource != null && this.m_resource.length() > 0 ) writeAttribute( stream, " resource=\"", this.m_resource ); if ( this.m_wf_label != null && this.m_wf_label.length() > 0 ) writeAttribute( stream, " wf-label=\"", this.m_wf_label ); if ( this.m_wf_stamp != null ) writeAttribute( stream, " wf-stamp=\"", Currently.iso8601(false,true,true,this.m_wf_stamp) ); writeAttribute( stream, " hostaddr=\"", this.m_hostaddr.getHostAddress() ); if ( this.m_hostname != null && this.m_hostname.length() > 0 ) writeAttribute( stream, " hostname=\"", this.m_hostname ); writeAttribute( stream, " uid=\"", Integer.toString( this.m_uid ) ); if ( this.m_user != null && this.m_user.length() > 0 ) writeAttribute( stream, " user=\"", this.m_user ); writeAttribute( stream, " gid=\"", Integer.toString( this.m_gid ) ); if ( this.m_group != null && this.m_group.length() > 0 ) writeAttribute( stream, " group=\"", this.m_group ); stream.write( '>' ); if ( indent != null ) stream.write( newline ); } /** * 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. * @exception IOException if something fishy happens to the stream. */ public void toXML( Writer stream, String indent, String namespace ) throws IOException { // write prefix writeXMLHeader( stream, indent, namespace ); // part 1: jobs String newindent = indent==null ? null : indent+" "; for ( Iterator i=this.m_job.iterator(); i.hasNext(); ) { ((Job) i.next()).toXML( stream, newindent, namespace ); } // part 2: cwd and total usage m_cwd.toXML( stream, newindent, namespace ); m_usage.toXML( stream, newindent, namespace ); m_uname.toXML( stream, newindent, namespace ); //machine if not null if( m_machine != null ){ m_machine.toXML( stream, indent, namespace ); } // part 3: statcall records for ( Iterator i=this.m_stat.iterator(); i.hasNext(); ) { ((StatCall) i.next()).toXML( stream, newindent, namespace ); } // part 4: environment and resourcs if ( m_environment != null ) m_environment.toXML( stream, newindent, namespace ); // close tag if ( indent != null && indent.length() > 0 ) stream.write( indent ); stream.write( "</" ); if ( namespace != null && namespace.length() > 0 ) { stream.write( namespace ); stream.write( ':' ); } stream.write( "invocation>" ); stream.write( System.getProperty( "line.separator", "\r\n" ) ); stream.flush(); // this is the only time we flush } }