/* * 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.parser; import org.griphyn.vdl.parser.*; import edu.isi.pegasus.planner.invocation.CPU; import edu.isi.pegasus.planner.invocation.HasText; import edu.isi.pegasus.planner.invocation.JobStatus; import edu.isi.pegasus.planner.invocation.StatCall; import edu.isi.pegasus.planner.invocation.Architecture; import edu.isi.pegasus.planner.invocation.Machine; import edu.isi.pegasus.planner.invocation.StatInfo; import edu.isi.pegasus.planner.invocation.JobStatusSignal; import edu.isi.pegasus.planner.invocation.Regular; import edu.isi.pegasus.planner.invocation.ArgEntry; import edu.isi.pegasus.planner.invocation.ArgVector; import edu.isi.pegasus.planner.invocation.Proc; import edu.isi.pegasus.planner.invocation.Fifo; import edu.isi.pegasus.planner.invocation.Temporary; import edu.isi.pegasus.planner.invocation.EnvEntry; import edu.isi.pegasus.planner.invocation.MachineSpecific; import edu.isi.pegasus.planner.invocation.JobStatusSuspend; import edu.isi.pegasus.planner.invocation.Descriptor; import edu.isi.pegasus.planner.invocation.Task; import edu.isi.pegasus.planner.invocation.Load; import edu.isi.pegasus.planner.invocation.Environment; import edu.isi.pegasus.planner.invocation.Usage; import edu.isi.pegasus.planner.invocation.Boot; import edu.isi.pegasus.planner.invocation.MachineInfo; import edu.isi.pegasus.planner.invocation.Invocation; import edu.isi.pegasus.planner.invocation.InvocationRecord; import edu.isi.pegasus.planner.invocation.RAM; import edu.isi.pegasus.planner.invocation.WorkingDir; import edu.isi.pegasus.planner.invocation.Arguments; import edu.isi.pegasus.planner.invocation.JobStatusRegular; import edu.isi.pegasus.planner.invocation.ArgString; import edu.isi.pegasus.planner.invocation.Data; import edu.isi.pegasus.planner.invocation.Stamp; import edu.isi.pegasus.planner.invocation.Uname; import edu.isi.pegasus.planner.invocation.Swap; import edu.isi.pegasus.planner.invocation.Job; import edu.isi.pegasus.planner.invocation.Status; import edu.isi.pegasus.planner.invocation.Ignore; import edu.isi.pegasus.planner.invocation.JobStatusFailure; import org.griphyn.vdl.util.Logging; // Xerces import org.xml.sax.*; import org.xml.sax.helpers.DefaultHandler; import java.io.*; import java.util.*; import java.text.*; import java.net.InetAddress; import java.net.UnknownHostException; /** * This class uses the Xerces SAX2 parser to validate and parse an XML * document which contains information from kickstart generated * invocation record. * * @author Jens-S. Vöckler * @author Yong Zhao * @version $Revision$ * */ public class InvocationParser extends DefaultHandler { /** * Default parser is the Xerces parser. */ protected static final String vendorParserClass = "org.apache.xerces.parsers.SAXParser"; /** * Holds the instance of a {@link org.xml.sax.XMLReader} class. */ private XMLReader m_parser; /** * Holds the result, will be overwritten by each invocation of parse(). */ private InvocationRecord m_result; /** * Keep the location within the document */ private Locator m_location; /** * A Hashmap to forward resolve namespaces that were encountered * during parsing. */ private Map m_forward; /** * A Hashmap to reverse resolve namespaces that were encountered * during parsing. */ private Map m_reverse; /** * Parsing for ISO dates without milliseconds */ private SimpleDateFormat m_coarse; /** * Parsing for ISO dates with millisecond extension. */ private SimpleDateFormat m_fine; /** * Obtain our logger once for multiple uses. */ private Logging m_log; /** * Count the depths of elements in the document */ private int m_depth = 0; /** * A stack of namespaces? */ private Stack m_stack; /** * Sets a feature while capturing failed features right here. * * @param uri is the feature's URI to modify * @param flag is the new value to set. * @return true, if the feature could be set, false for an exception */ private boolean set( String uri, boolean flag ) { boolean result = false; try { this.m_parser.setFeature( uri, flag ); result = true; } catch ( SAXException se ) { Logging.instance().log( "default", 0, "Could not set parser feature " + se.getMessage() ); } return result; } /** * The class constructor. This function initializes the Xerces parser * and the features that enable schema validation. * * @param schemaLocation is the default location of the XML Schema * which this parser is capable of parsing. It may be null to use * the defaults provided in the document. */ public InvocationParser( String schemaLocation ) { this.m_forward = new HashMap(); this.m_reverse = new HashMap(); this.m_coarse = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssZ" ); this.m_fine = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ" ); this.m_log = Logging.instance(); try { m_parser = (XMLReader) Class.forName(vendorParserClass).newInstance(); m_parser.setContentHandler(this); // m_parser.setErrorHandler(this); m_parser.setErrorHandler( new VDLErrorHandler() ); set( "http://xml.org/sax/features/validation", true ); set( "http://apache.org/xml/features/validation/dynamic", true ); set( "http://apache.org/xml/features/validation/schema", true ); // time+memory consuming, see http://xml.apache.org/xerces2-j/features.html // set( "http://apache.org/xml/features/validation/schema-full-checking", true ); // Send XML Schema element default values via characters(). set( "http://apache.org/xml/features/validation/schema/element-default", true ); set( "http://apache.org/xml/features/validation/warn-on-duplicate-attdef", true ); // mysteriously, this one fails with recent Xerces // set( "http://apache.org/xml/features/validation/warn-on-undeclared-elemdef", true ); set( "http://apache.org/xml/features/warn-on-duplicate-entitydef", true ); set( "http://apache.org/xml/features/honour-all-schemaLocations", true ); // set the schema default location. if ( schemaLocation != null ) { setSchemaLocations( InvocationRecord.SCHEMA_NAMESPACE + ' ' + schemaLocation ); m_log.log("app", 2, "will use " + schemaLocation ); } else { m_log.log("app", 2, "will use document schema hint" ); } } catch (ClassNotFoundException e) { m_log.log( "defaut", 0, "The SAXParser class was not found: " + e); } catch (InstantiationException e) { m_log.log( "default", 0, "The SAXParser class could not be instantiated: " + e); } catch (IllegalAccessException e) { m_log.log( "default", 0, "The SAXParser class could not be accessed: " + e); } } /** * Sets the list of external real locations where the XML schema may * be found. Since this list can be determined at run-time through * properties etc., we expect this function to be called between * instantiating the parser, and using the parser * * @param list is a list of strings representing schema locations. The * content exists in pairs, one of the namespace URI, one of the * location URL. */ public void setSchemaLocations( String list ) { // schema location handling try { m_parser.setProperty( "http://apache.org/xml/properties/schema/external-schemaLocation", list ); } catch ( SAXException se ) { m_log.log( "default", 0, "The SAXParser reported an error: " + se ); } } /** * This function parses a XML source from an InputStream source, and * creates java class instances that correspond to different elements * in the XML source. * * @param reader is a bytestream opened for reading. * @return the records with the invocation information, or null on failure. */ public InvocationRecord parse( java.io.InputStream reader ) { try { // will change m_result m_parser.parse( new InputSource(reader) ); return m_result; } catch (SAXException e) { // e.printStackTrace( System.err ); m_log.log( "default", 0, "SAX Error: " + e.getMessage() ); } catch (IOException e) { m_log.log( "default", 0, "IO Error: " + e.getMessage() ); } return null; } /** * This function parses a XML source from the new Reader source, and * creates java class instances that correspond to different elements * in the XML source. * * @param reader is a character stream opened for reading. * @return the records with the invocation information, or null on failure. */ public InvocationRecord parse( java.io.Reader reader ) { try { // will change m_result m_parser.parse( new InputSource(reader) ); return m_result; } catch (SAXException e) { // e.printStackTrace( System.err ); m_log.log( "default", 0, "SAX Error: " + e.getMessage() ); } catch (IOException e) { m_log.log( "default", 0, "IO Error: " + e.getMessage() ); } return null; } // // here starts the implementation to the Interface // /** * Obtains the document locator from the parser. The document location * can be used to print debug information, i.e the current location * (line, column) in the document. * * @param locator is the externally set current position */ public void setDocumentLocator( Locator locator ) { this.m_location = locator; } private String full_where() { return ( "line " + m_location.getLineNumber() + ", col " + m_location.getColumnNumber() ); } private String where() { return ( m_location.getLineNumber() + ":" + m_location.getColumnNumber() ); } /** * This method specifies what to do when the parser is at the beginning * of the document. In this case, we simply print a message for debugging. */ public void startDocument() { this.m_depth = 0; this.m_stack = new Stack(); this.m_log.log( "parser", 1, "*** start of document ***" ); } /** * The parser comes to the end of the document. */ public void endDocument() { this.m_log.log( "parser", 1, "*** end of document ***" ); } /** * There is a prefix or namespace defined, put the prefix and its URI * in the HashMap. We can get the URI when the prefix is used here after. * * @param prefix the Namespace prefix being declared. * @param uri the Namespace URI the prefix is mapped to. */ public void startPrefixMapping( java.lang.String prefix, java.lang.String uri ) throws SAXException { String p = prefix == null ? null : new String(prefix); String u = uri == null ? null : new String(uri); m_log.log( "parser", 2, "adding \"" + p + "\" <=> " + u ); if ( ! this.m_forward.containsKey(p) ) this.m_forward.put(p, new Stack()); ((Stack) this.m_forward.get(p)).push(u); if ( ! this.m_reverse.containsKey(u) ) this.m_reverse.put(u, new Stack()); ((Stack) this.m_reverse.get(u)).push(p); } /** * Out of the reach of the prefix, remove it from the HashMap. * * @param prefix is the prefix that was being mapped previously. */ public void endPrefixMapping( java.lang.String prefix ) throws SAXException { String u = (String) ((Stack) this.m_forward.get(prefix)).pop(); String p = (String) ((Stack) this.m_reverse.get(u)).pop(); m_log.log( "parser", 2, "removed \"" + p + "\" <=> " + u ); } /** * Helper function to map prefixes correctly onto the elements. * * @param uri is the parser-returned URI that needs translation. * @return the correct prefix for the URI */ private String map( String uri ) { if ( uri == null || uri.length() == 0 ) return ""; Stack stack = (Stack) this.m_reverse.get(uri); String result = stack == null ? null : (String) stack.peek(); if ( result == null || result.length() == 0 ) return ""; else return result + ':'; } /** * This method defines the action to take when the parser begins to parse * an element. * * @param namespaceURI is the URI of the namespace for the element * @param localName is the element name without namespace * @param qName is the element name as it appears in the docment * @param atts has the names and values of all the attributes */ public void startElement( java.lang.String namespaceURI, java.lang.String localName, java.lang.String qName, Attributes atts ) throws SAXException { m_log.log( "parser", 3, "<" + map(namespaceURI) + localName + "> at " + where() ); // yup, one more element level m_depth++; java.util.List names = new java.util.ArrayList(); java.util.List values = new java.util.ArrayList(); for ( int i=0; i < atts.getLength(); ++i ) { String name = new String( atts.getLocalName(i) ); String value = new String( atts.getValue(i) ); m_log.log( "parser", 2, "attribute " + map(atts.getURI(i)) + name + "=\"" + value + "\"" ); names.add(name); values.add(value); } //System.out.println( "QNAME " + qName + " NAME " + names + "\t Values" + values ); Invocation parent = null; if ( ! m_stack.empty() ) { IVSElement peek = (IVSElement) m_stack.peek(); parent = (Invocation)peek.m_obj; } Invocation object = createObject( parent, qName, names, values ); if ( object != null ) m_stack.push( new IVSElement( qName, object ) ); else throw new SAXException( "empty element while parsing" ); } /** * The parser is at the end of an element. Each successfully and * completely parsed Definition will trigger a callback to the * registered DefinitionHandler. * * @param namespaceURI is the URI of the namespace for the element * @param localName is the element name without namespace * @param qName is the element name as it appears in the docment */ public void endElement( java.lang.String namespaceURI, java.lang.String localName, java.lang.String qName ) throws SAXException { // that's it for this level m_depth--; m_log.log( "parser", 3, "</" + map(namespaceURI) + localName + "> at " + where() ); IVSElement tos = (IVSElement) m_stack.pop(); if ( ! qName.equals(tos.m_name) ) { m_log.log( "default", 0, "assertion failure" ); System.exit(1); } if ( ! m_stack.empty() ) { // add pieces to lower levels IVSElement peek = (IVSElement) m_stack.peek(); if ( !setElementRelation( peek.m_name.charAt(0), peek.m_obj, tos.m_obj )){ m_log.log( "parser", 0, "Element " + tos.m_name + " does not fit into element " + peek.m_name ); //System.out.println( "Element " + tos.m_name + // " does not fit into element " + peek.m_name ); } } else { // run finalizer, if available // m_log.log( "default", 0, "How did I get here?" ); } } /** * This method is the callback function for characters in an element. * The element is expected to be of mixed content. * * @param ch are the characters from the XML document * @param start is the start position into the array * @param length is the amount of valid data in the array */ public void characters( char[] ch, int start, int length ) throws SAXException { String message = new String( ch, start, length ); if ( message.length() > 0 ) { if ( message.trim().length() == 0 ) m_log.log( "parser", 3, "Characters: \' \' x " + message.length() ); else m_log.log( "parser", 3, "Characters: \"" + message + "\"" ); // Insert text into the text carrying elements. These elements // must be capable to have text added repeatedly. if ( ! m_stack.empty() ) { IVSElement tos = (IVSElement) m_stack.peek(); if ( tos.m_obj instanceof HasText ) { HasText obj = (HasText) tos.m_obj; obj.appendValue(message); } } else { // run finalizer, if available m_log.log( "default", 0, "How did I get here II?" ); } } } /** * Currently, ignorable whitespace will be ignored. * * @param ch are the characters from the XML document * @param start is the start position into the array * @param length is the amount of valid data in the array */ public void ignorableWhitespace( char[] ch, int start, int length ) throws SAXException { // not implemented } /** * Receive a processing instruction. Currently, we are just printing * a debug message that we received a PI. * * @param target the processing instruction target * @param data the processing instruction data, or null if none was supplied. * The data does not include any whitespace separating it from the target. */ public void processingInstruction( java.lang.String target, java.lang.String data ) throws SAXException { m_log.log( "parser", 2, "processing instruction " + target + "=\"" + data + "\" was skipped!"); } /** * Receive a notification that an entity was skipped. Currently, we * are just printing a debug message to this fact. * * @param name The name of the skipped entity. If it is a parameter * entity, the name will begin with '%', and if it is the external DTD * subset, it will be the string "[dtd]". */ public void skippedEntity(java.lang.String name) throws SAXException { m_log.log( "parser", 2, "entity " + name + " was skipped!"); } // // =================================================== our own stuff === // /** * Small helper method to bundle repetitive parameters in a template * for reporting progress. * * @param subject is the name of the XML element that is being scrutinized. * @param name is then name of the element we are working with. * @param value is the attribute value. */ private void log( String subject, String name, String value ) { if ( value == null ) value = new String(); m_log.log( "filler", 3, subject + "." + name + "=\"" + value + "\"" ); } /** * Small helper method to bundle repetitive complaints in a template * for reporting progress. * * @param subject is the name of the XML element that is being scrutinized. * @param name is then name of the element we are working with. * @param value is the attribute value. */ private void complain( String subject, String name, String value ) { if ( value == null ) value = new String(); m_log.log( "default", 0, "ignoring " + subject + '@' + name + "=\"" + value + '"', true ); } /** * Small helper to parse the different date varieties and deal with * Java obnoxeity. * * @param date is an ISO 8601 timestamp * @return a date field * @exception ParseException thrown if the date cannot be parsed */ private Date parseDate( String date ) throws ParseException { // SimpleDataFormat stumbles over colon in time zone int size = date.length(); if ( date.charAt(size-3) == ':' ) { StringBuffer temp = new StringBuffer(date); temp.deleteCharAt(size-3); date = temp.toString(); } Date result; if ( date.indexOf('.') == -1 ) { // coarse grained timestamp result = m_coarse.parse(date); } else { // fine grained timestamp result = m_fine.parse(date); } SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ"); m_log.log( "filler", 3, "found date " + sdf.format(result) ); return result; } /** * Small helper method to set up the attributes for the job elements. * * @param job is the job to set up. * @param names is the list of attribute names * @param values is the list of attribute values */ private void setupJob( Job job, java.util.List names, java.util.List values ) throws NumberFormatException, ParseException { for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("start") ) { this.log( job.getTag(), name, value ); job.setStart( parseDate(value) ); } else if ( name.equals("duration") ) { this.log( job.getTag(), name, value ); job.setDuration( Double.parseDouble(value) ); } else if ( name.equals("pid") ) { this.log( job.getTag(), name, value ); job.setPID( (int) (Long.parseLong(value) & 0xFFFFFFFF) ); } else { this.complain( job.getTag(), name, value ); } } } /** * This method determines the actively parsed element, creates the * Java object that corresponds to the element, and sets the member * variables with the values of the attributes of the element. * * @param parent is the parent element * @param e is the name of the element * @param names is a list of attribute names, as strings. * @param values is a list of attribute values, to match the key list. * @return A new VDL Java object, which may only be partly constructed. * @exception IllegalArgumentException if the element name is too short. */ protected Invocation createObject( Invocation parent, String e, java.util.List names, java.util.List values ) throws IllegalArgumentException { if ( e == null || e.length() < 1 ) throw new IllegalArgumentException("illegal element length"); try { // postcondition: string has content w/ length > 0 switch ( e.charAt(0) ) { // // A // case 'a': if ( e.equals("arg") ) { ArgEntry entry = new ArgEntry(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("nr") ) { this.log( e, name, value ); entry.setPosition( Integer.parseInt(value) ); } else { this.complain( e, name, value ); } } return entry; } else if ( e.equals("arguments") ) { Arguments cli = new ArgString(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("executable") ) { this.log( e, name, value ); cli.setExecutable(value); } else { this.complain( e, name, value ); } } return cli; } else if ( e.equals("argument-vector") ) { Arguments cli = new ArgVector(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("executable") ) { this.log( e, name, value ); cli.setExecutable(value); } else { this.complain( e, name, value ); } } return cli; } // unknown return null; // // B // case 'b': if ( e.equals("boot") ) { Boot b = new Boot(); b.addAttributes(names, values); return b; } else if ( e.equals("basic") ) { MachineSpecific basic = new MachineSpecific("basic"); return basic; } // unknown return null; // // C // case 'c': if ( e.equals("cwd") ) { WorkingDir cwd = new WorkingDir(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); this.complain( e, name, value ); } return cwd; } else if ( e.equals("cleanup") ) { Job job = new Job(e); setupJob( job, names, values ); return job; } else if ( e.equals( "cpu" ) ){ CPU c = new CPU(); c.addAttributes(names, values); return c; } // unknown return null; // // D // case 'd': if ( e.equals("data") ) { Data data = new Data(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("truncated") ) { this.log( e, name, value ); data.setTruncated( Boolean.valueOf(value).booleanValue() ); } else { this.complain( e, name, value ); } } return data; } else if ( e.equals("descriptor") ) { Descriptor file = new Descriptor(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("number") ) { this.log( e, name, value ); file.setDescriptor( Integer.parseInt(value) ); } else { this.complain( e, name, value ); } } return file; } else if ( e.equals("darwin") ) { MachineSpecific darwin = new MachineSpecific("darwin"); return darwin; } // unknown return null; // // E // case 'e': if ( e.equals("env") ) { EnvEntry ee = new EnvEntry(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("key") ) { this.log( e, name, value ); ee.setKey( value ); } else { this.complain( e, name, value ); } } return ee; } else if ( e.equals("environment") ) { Environment env = new Environment(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); this.complain( e, name, value ); } return env; } // unknown return null; // // F // case 'f': if ( e.equals("file") ) { Regular file = new Regular(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("name") ) { this.log( e, name, value ); file.setFilename(value); } else { this.complain( e, name, value ); } } return file; } else if ( e.equals("fifo") ) { Fifo fifo = new Fifo(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("name") ) { this.log( e, name, value ); fifo.setFilename(value); } else if ( name.equals("descriptor") ) { this.log( e, name, value ); fifo.setDescriptor( Integer.parseInt(value) ); } else if ( name.equals("count") ) { this.log( e, name, value ); fifo.setCount( Integer.parseInt(value) ); } else if ( name.equals("rsize") ) { this.log( e, name, value ); fifo.setInputSize( Long.parseLong(value) ); } else if ( name.equals("wsize") ) { this.log( e, name, value ); fifo.setOutputSize( Long.parseLong(value) ); } else { this.complain( e, name, value ); } } return fifo; } else if ( e.equals("failure") ) { JobStatusFailure failed = new JobStatusFailure(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("error") ) { this.log( e, name, value ); failed.setError( Integer.parseInt(value) ); } else { this.complain( e, name, value ); } } return failed; } // unknown return null; // // H // case 'h': if ( e.equals("hard") ) { return new Ignore(); } // unknown return null; // // I // case 'i': if ( e.equals("invocation") ) { this.m_result = new InvocationRecord(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("version") ) { this.log( e, name, value ); m_result.setVersion( value ); } else if ( name.equals("start") ) { this.log( e, name, value ); m_result.setStart( parseDate(value) ); } else if ( name.equals("duration") ) { this.log( e, name, value ); m_result.setDuration( Double.parseDouble(value) ); } else if ( name.equals("transformation") ) { this.log( e, name, value ); m_result.setTransformation(value); } else if ( name.equals("derivation") ) { this.log( e, name, value ); m_result.setDerivation(value); } else if ( name.equals("host") || name.equals("hostaddr") ) { this.log( e, name, value ); m_result.setHostAddress( InetAddress.getByName(value) ); } else if ( name.equals("hostname") ) { this.log( e, name, value ); m_result.setHostname( value ); } else if ( name.equals("interface") ) { this.log( e, name, value ); m_result.setInterface( value ); } else if ( name.equals("resource") ) { this.log( e, name, value ); m_result.setResource( value ); } else if ( name.equals("ram" ) ) { this.log( e, name, value ); m_result.setPhysicalMemory( Long.parseLong(value) ); } else if ( name.equals("pid") ) { this.log( e, name, value ); m_result.setPID( (int) (Long.parseLong(value) & 0xFFFFFFFF) ); } else if ( name.equals("uid") ) { this.log( e, name, value ); m_result.setUID( (int) (Long.parseLong(value) & 0xFFFFFFFF) ); } else if ( name.equals("gid") ) { this.log( e, name, value ); m_result.setGID( (int) (Long.parseLong(value) & 0xFFFFFFFF) ); } else if ( name.equals("user") ) { this.log( e, name, value ); m_result.setUser( value ); } else if ( name.equals("group") ) { this.log( e, name, value ); m_result.setGroup( value ); } else if ( name.equals("schemaLocation") ) { // ignore root element schema location hint } else if ( name.equals("umask") ) { this.log( e, name, value ); m_result.setUMask( Integer.parseInt(value,8) ); } else if ( name.equals("wf-label") ) { this.log( e, name, value ); m_result.setWorkflowLabel( value ); } else if ( name.equals("wf-stamp") ) { this.log( e, name, value ); m_result.setWorkflowTimestamp( parseDate(value) ); } else { this.complain( e, name, value ); } } return this.m_result; } // unknown return null; // // L // case 'l': if ( e.equals("load") ) { Load l = new Load(); l.addAttributes( names, values ); return l; } else if ( e.equals("linux") ) { MachineSpecific linux = new MachineSpecific("linux"); return linux; } // unknown return null; // // M // case 'm': if ( e.equals("mainjob") ) { Job job = new Job(e); setupJob( job, names, values ); return job; } else if ( e.equals( "machine" ) ){ Machine machine = new Machine(); for ( int i=0; i< names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("page-size") ) { this.log( e, name, value ); machine.setPageSize( Long.parseLong(value) ); } else { this.complain( e, name, value ); } } return machine; } // unknown return null; // // P // case 'p': if ( e.equals("prejob") ) { Job job = new Job(e); setupJob( job, names, values ); return job; } else if ( e.equals("postjob") ) { Job job = new Job(e); setupJob( job, names, values ); return job; } else if ( e.equals( "proc") ){ Proc p = new Proc(); p.addAttributes( names, values ); return p; } // unknown return null; // // R // case 'r': if ( e.equals("regular") ) { JobStatusRegular regular = new JobStatusRegular(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("exitcode") ) { this.log( e, name, value ); regular.setExitCode( Short.parseShort(value) ); } else { this.complain( e, name, value ); } } return regular; } else if ( e.equals("resource") ) { // ignore return new Ignore(); } else if( e.equals( "ram" ) ) { RAM r = new RAM(); r.addAttributes( names, values ); return r; } // unknown return null; // // S // case 's': if ( e.equals("statcall") ) { StatCall statcall = new StatCall(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("error") ) { this.log( e, name, value ); statcall.setError( Integer.parseInt(value) ); } else if ( name.equals("id") ) { this.log( e, name, value ); statcall.setHandle(value); } else if ( name.equals("lfn") ) { this.log( e, name, value ); statcall.setLFN(value); } else { this.complain( e, name, value ); } } return statcall; } else if ( e.equals("statinfo") ) { StatInfo statinfo = new StatInfo(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); //System.out.println( name + " -> " + value ); if ( name.equals("mode") ) { this.log( e, name, value ); statinfo.setMode( Integer.parseInt(value,8) ); } else if ( name.equals("size") ) { this.log( e, name, value ); statinfo.setSize( Long.parseLong(value) ); } else if ( name.equals("inode") ) { this.log( e, name, value ); statinfo.setINode( (long)Double.parseDouble(value) ); } else if ( name.equals("nlink") ) { this.log( e, name, value ); statinfo.setLinkCount( Long.parseLong(value) ); } else if ( name.equals("blksize") ) { this.log( e, name, value ); statinfo.setBlockSize( Long.parseLong(value) ); } else if ( name.equals("blocks") ) { this.log( e, name, value ); statinfo.setBlocks( Long.parseLong(value) ); } else if ( name.equals("atime") ) { this.log( e, name, value ); statinfo.setAccessTime( parseDate(value) ); } else if ( name.equals("ctime") ) { this.log( e, name, value ); statinfo.setCreationTime( parseDate(value) ); } else if ( name.equals("mtime") ) { this.log( e, name, value ); statinfo.setModificationTime( parseDate(value) ); } else if ( name.equals("uid") ) { this.log( e, name, value ); statinfo.setUID( (int) (Long.parseLong(value) & 0xFFFFFFFF) ); } else if ( name.equals("user") ) { this.log( e, name, value ); statinfo.setUser( value ); } else if ( name.equals("gid") ) { this.log( e, name, value ); statinfo.setGID( (int) (Long.parseLong(value) & 0xFFFFFFFF) ); } else if ( name.equals("group") ) { this.log( e, name, value ); statinfo.setGroup( value ); } else { this.complain( e, name, value ); } } return statinfo; } else if ( e.equals("status") ) { Status status = new Status(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("raw") ) { this.log( e, name, value ); status.setStatus( Integer.parseInt(value) ); } else { this.complain( e, name, value ); } } return status; } else if ( e.equals("soft") ) { return new Ignore(); } else if ( e.equals("signalled") ) { JobStatusSignal signalled = new JobStatusSignal(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("signal") ) { this.log( e, name, value ); signalled.setSignalNumber( Short.parseShort(value) ); } else if ( name.equals("corefile") ) { this.log( e, name, value ); signalled.setCoreFlag( Boolean.valueOf(value).booleanValue() ); } else { this.complain( e, name, value ); } } return signalled; } else if ( e.equals("suspended") ) { JobStatusSuspend suspended = new JobStatusSuspend(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("signal") ) { this.log( e, name, value ); suspended.setSignalNumber( Short.parseShort(value) ); } else { this.complain( e, name, value ); } } return suspended; } else if ( e.equals("setup") ) { Job job = new Job(e); setupJob( job, names, values ); return job; } else if( e.equals( "stamp" ) ){ Stamp s = new Stamp(); return s; } else if( e.equals( "swap" ) ){ Swap s = new Swap(); s.addAttributes( names, values ); return s; } else if ( e.equals("sunos") ) { MachineSpecific sunos = new MachineSpecific("sunos"); return sunos; } // unknown return null; // // T // case 't': if ( e.equals("temporary") ) { Temporary file = new Temporary(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("name") ) { this.log( e, name, value ); file.setFilename(value); } else if ( name.equals("descriptor") ) { this.log( e, name, value ); file.setDescriptor( Integer.parseInt(value) ); } else { this.complain( e, name, value ); } } return file; } else if( e.equals( "task" ) ){ Task t = new Task(); t.addAttributes(names, values); return t; } // unknown return null; // // U // case 'u': if ( e.equals("usage") ) { Usage usage = new Usage(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("utime") ) { this.log( e, name, value ); usage.setUserTime( Double.parseDouble(value) ); } else if ( name.equals("stime") ) { this.log( e, name, value ); usage.setSystemTime( Double.parseDouble(value) ); } else if ( name.equals("minflt") ) { this.log( e, name, value ); usage.setMinorFaults( Integer.parseInt(value) ); } else if ( name.equals("majflt") ) { this.log( e, name, value ); usage.setMajorFaults( Integer.parseInt(value) ); } else if ( name.equals("nswap") ) { this.log( e, name, value ); usage.setSwaps( Integer.parseInt(value) ); } else if ( name.equals("nsignals") ) { this.log( e, name, value ); usage.setSignals( Integer.parseInt(value) ); } else if ( name.equals("nvcsw") ) { this.log( e, name, value ); usage.setVoluntarySwitches( Integer.parseInt(value) ); } else if ( name.equals("nivcsw") ) { this.log( e, name, value ); usage.setInvoluntarySwitches( Integer.parseInt(value) ); } else if ( name.equals("maxrss") ) { this.log( e, name, value ); usage.setMaximumRSS( Integer.parseInt(value) ); } else if ( name.equals("ixrss") ) { this.log( e, name, value ); usage.setSharedRSS( Integer.parseInt(value) ); } else if ( name.equals("idrss") ) { this.log( e, name, value ); usage.setUnsharedRSS( Integer.parseInt(value) ); } else if ( name.equals("isrss") ) { this.log( e, name, value ); usage.setStackRSS( Integer.parseInt(value) ); } else if ( name.equals("inblock") ) { this.log( e, name, value ); usage.setInputBlocks( Integer.parseInt(value) ); } else if ( name.equals("outblock") ) { this.log( e, name, value ); usage.setOutputBlocks( Integer.parseInt(value) ); } else if ( name.equals("msgsnd") ) { this.log( e, name, value ); usage.setSent( Integer.parseInt(value) ); } else if ( name.equals("msgrcv") ) { this.log( e, name, value ); usage.setReceived( Integer.parseInt(value) ); } else { this.complain( e, name, value ); } } return usage; } else if( e.equals( "uname" ) && parent instanceof Machine ){ Uname u = new Uname(); u.addAttributes(names, values); return u; } else if ( e.equals("uname") ) { Architecture uname = new Architecture(); for ( int i=0; i<names.size(); ++i ) { String name = (String) names.get(i); String value = (String) values.get(i); if ( name.equals("system") ) { this.log( e, name, value ); uname.setSystemName(value); } else if ( name.equals("archmode") ) { this.log( e, name, value ); uname.setArchMode(value); } else if ( name.equals("nodename") ) { this.log( e, name, value ); uname.setNodeName(value); } else if ( name.equals("release") ) { this.log( e, name, value ); uname.setRelease(value); } else if ( name.equals("machine") ) { this.log( e, name, value ); uname.setMachine(value); } else if ( name.equals("domainname") ) { this.log( e, name, value ); uname.setDomainName(value); } else { this.complain( e, name, value ); } } return uname; } // unknown return null; default: // FIXME: shouldn't this be an exception? m_log.log( "filler", 0, "Error: No rules defined for element " + e ); return null; } } catch ( NumberFormatException nfe ) { m_log.log( "filler", 0, "Error: Unable to parse a number: " + nfe.getMessage() + " at " + where() ); return null; } catch ( UnknownHostException uh ) { m_log.log( "filler", 0, "Error: Unable to parse a hostname: " + uh.getMessage() + " at " + where() ); return null; } catch ( ParseException pe ) { m_log.log( "filler", 0, "Error: Unable to parse a date: " + pe.getMessage() + " at " + where() ); return null; } } /** * This method sets the relations between the currently finished XML * element and its containing element in terms of Java objects. * Usually it involves adding the object to the parent's child object * list. * * @param initial is the first charactor of the parent element name * @param parent is a reference to the parent's Java object * @param child is the completed child object to connect to the parent * @return true if the element was added successfully, false, if the * child does not match into the parent. */ protected boolean setElementRelation( char initial, Invocation parent, Invocation child ) { switch ( initial ) { // // A // case 'a': if ( parent instanceof ArgVector && child instanceof ArgEntry ) { ArgVector args = (ArgVector) parent; ArgEntry entry = (ArgEntry) child; args.setValue( entry.getPosition(), entry.getValue() ); return true; } // unknown return false; // // C // case 'c': if ( parent instanceof Job ) { Job job = (Job) parent; if ( child instanceof Usage ) { job.setUsage((Usage) child); return true; } else if ( child instanceof Status ) { job.setStatus((Status) child); return true; } else if ( child instanceof StatCall ) { job.setExecutable((StatCall) child); return true; } else if ( child instanceof Arguments ) { job.setArguments((Arguments) child); return true; } } // unknown return false; // // E // case 'e': if ( parent instanceof Environment && child instanceof EnvEntry ) { ((Environment) parent).addEntry((EnvEntry) child); return true; } // unknown return false; // // I // case 'i': if ( parent instanceof InvocationRecord ) { InvocationRecord invocation = (InvocationRecord) parent; if ( child instanceof Job ) { invocation.addJob((Job) child); return true; } else if ( child instanceof Usage ) { invocation.setUsage((Usage) child); return true; } else if ( child instanceof StatCall ) { invocation.addStatCall((StatCall) child); return true; } else if ( child instanceof WorkingDir ) { invocation.setWorkingDirectory((WorkingDir) child); return true; } else if ( child instanceof Architecture ) { invocation.setArchitecture((Architecture) child); return true; } else if ( child instanceof Environment ) { invocation.setEnvironment((Environment) child); return true; } else if ( child instanceof Machine ) { Machine machine = (Machine) child; invocation.setMachine(machine); // convert uname object to Architecture object // reqd for Pegasus Bug 39 invocation.setArchitecture( machine.getUname().toArchitecture() ); return true; } } // unknown return false; // // mainjob // case 'm': if ( parent instanceof Job ) { Job job = (Job) parent; if ( child instanceof Usage ) { job.setUsage((Usage) child); return true; } else if ( child instanceof Status ) { job.setStatus((Status) child); return true; } else if ( child instanceof StatCall ) { job.setExecutable((StatCall) child); return true; } else if ( child instanceof Arguments ) { job.setArguments((Arguments) child); return true; } } else if ( parent instanceof Machine ) { Machine m = (Machine) parent; if ( child instanceof Stamp ) { m.setStamp( (Stamp) child ); return true; } else if ( child instanceof Uname ) { m.setUname( (Uname) child ); return true; } else if ( child instanceof MachineSpecific ) { m.setMachineSpecific( (MachineSpecific) child ); return true; } } else if ( parent instanceof MachineSpecific ) { MachineSpecific ms = (MachineSpecific) parent; if ( child instanceof RAM || child instanceof Swap || child instanceof Boot || child instanceof CPU || child instanceof Load || child instanceof Proc || child instanceof Task ) { ms.addMachineInfo( (MachineInfo) child ); return true; } } // unknown return false; // // P // case 'p': if ( parent instanceof Job ) { // both, prejob and postjob Job job = (Job) parent; if ( child instanceof Usage ) { job.setUsage((Usage) child); return true; } else if ( child instanceof Status ) { job.setStatus((Status) child); return true; } else if ( child instanceof StatCall ) { job.setExecutable((StatCall) child); return true; } else if ( child instanceof Arguments ) { job.setArguments((Arguments) child); return true; } } // unknown return false; // // R // case 'r': if ( parent instanceof Ignore && child instanceof Ignore ) { // ignore return true; } // unknown return false; // // S // case 's': if ( parent instanceof Status && child instanceof JobStatus ) { ((Status) parent).setJobStatus((JobStatus) child); return true; } else if ( parent instanceof StatCall ) { StatCall statcall = (StatCall) parent; if ( child instanceof edu.isi.pegasus.planner.invocation.File ) { statcall.setFile((edu.isi.pegasus.planner.invocation.File) child); return true; } else if ( child instanceof StatInfo ) { statcall.setStatInfo((StatInfo) child); return true; } else if ( child instanceof Data ) { statcall.setData((Data) child); return true; } } else if ( parent instanceof Job ) { // both, prejob and postjob Job job = (Job) parent; if ( child instanceof Usage ) { job.setUsage((Usage) child); return true; } else if ( child instanceof Status ) { job.setStatus((Status) child); return true; } else if ( child instanceof StatCall ) { job.setExecutable((StatCall) child); return true; } else if ( child instanceof Arguments ) { job.setArguments((Arguments) child); return true; } } // unknown return false; default: // FIXME: shouldn't this be an exception? m_log.log( "filler", 0, "Error: unable to join child to parent" ); return false; } } }