/* * 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 org.griphyn.vdl.dax.*; import java.util.*; import java.io.IOException; import java.io.Writer; /** * A <code>Profile</code> captures scheduler system and application * environment specific stuff in a uniform fashion. Each profile * declaration assigns a value to a key within a namespace. As of * this writing, valid namespaces are * * <dl> * <dt>vds</dt> * <dd>Virtual Data System specific material. * <dt>condor</dt> * <dd>If the job runs in using the * <a href="http://www.cs.wisc.edu/condor/">Condor</a/> scheduler, * certain items like the "universe" or "requirments" can be set. * Please note that currently the universe is provided as a hint * to the logical transformation itself.</dd> * <dt>dagman</dt> * <dd>The job graph will usually be run by Condor DAGMan. Some issues, * e.g. the number of retries, are specific to DAGMan and not Condor.</dd> * <dt>env</dt> * <dd>The Unix environment variables that are required for the job.</dd> * </dl> * * In the future, more namespaces may be added. * * @author Jens-S. Vöckler * @author Yong Zhao * @version $Revision$ */ public class Profile extends DAX implements Cloneable { /** * The namespace of a profile. All profiles must mention their namespace * in order to generate acceptable behaviour. */ private String m_namespace; /** * The identifier within a namespace. The meaning of the key can differ * between namespaces. Within the unix namespace, it is the name of an * environment variable. Within the condor namespace, it is a Condor * submit file key. */ private String m_key; /** * The value to above keys. Any value passed down is an arbitrary mix * of the three potential {@link Leaf} types. A profile value element * only allows for {@link PseudoText} and {@link Filename} children in * arbitrary number and order. * * @see Leaf * @see PseudoText * @see Filename */ private ArrayList m_leafList; /** * This value records which entity was responsible for setting the * profile in the first place. */ private String m_origin; /** * Creates and returns a copy of this object. * @return a new instance. */ public Object clone() { Profile result = new Profile( this.m_namespace, this.m_key ); for ( int index=0; index < this.m_leafList.size(); ++index ) { result.setLeaf( index, (Leaf) this.getLeaf(index).clone() ); } result.setOrigin( this.m_origin ); return result; } /** * Array ctor. */ public Profile() { this.m_leafList = new ArrayList(); this.m_origin = null; } /** * Standard ctor: set up everything except a value of the ns.key pair. * * @param namespace is the namespace within which to operate. * @param key is an identifier unique within the namespace. */ public Profile( String namespace, String key ) { this.m_leafList = new ArrayList(); this.m_namespace = namespace; this.m_key = key; this.m_origin = null; } /** * Convenience ctor: set up the first piece of the value in one go. * * @param namespace is the namespace within which to operate. * @param key is an identifier unique within the namespace. * @param firstChild is the first fragment of the value. Only * <code>Leaf</code>s of type <code>Filename</code> or * <code>PseudoText</code> are permissable. * * @see Leaf * @see Filename * @see PseudoText */ public Profile( String namespace, String key, Leaf firstChild ) { this.m_leafList = new ArrayList(); this.m_leafList.add(firstChild); this.m_namespace = namespace; this.m_key = key; this.m_origin = null; } /** * Convenience ctor: set up the first piece of the value in one go. * * @param namespace is the namespace within which to operate. * @param key is an identifier unique within the namespace. * @param children is a collection of fragments for the value. Only * <code>Leaf</code>s of type <code>Filename</code> or * <code>PseudoText</code> are permissable. * * @see Leaf * @see Filename * @see PseudoText */ public Profile( String namespace, String key, Collection children ) { this.m_leafList = new ArrayList(); this.m_leafList.addAll(children); this.m_namespace = namespace; this.m_key = key; this.m_origin = null; } /** * Accessor: Append a value fragment to this profile instance. * * @param vLeaf is the fragment to add. Note that only leaf values of * <code>Filename</code> or <code>PseudoText</code> are allowed. * * @see Leaf * @see PseudoText * @see Filename */ public void addLeaf( Leaf vLeaf ) { this.m_leafList.add(vLeaf); } /** * Accessor: Inserts a <code>Leaf</code> value into a specific position * of the list of gathered values. * * @param index is the position to insert the item into * @param vLeaf is the value to append to the list. Note that only leaf * values of <code>Filename</code> or <code>PseudoText</code> * are allowed. * @throws IndexOutOfBoundsException if the value cannot be added. * @see Leaf * @see PseudoText * @see Filename */ public void addLeaf( int index, Leaf vLeaf ) throws IndexOutOfBoundsException { this.m_leafList.add(index, vLeaf); } /** * Accessor: Enumerates the internal values that constitute the content * of the <code>Profile</code> value. * * @return the iterator to the value fragment list. * @deprecated Use the new Collection based interfaces */ public Enumeration enumerateLeaf() { return Collections.enumeration(this.m_leafList); } /** * Accessor: Obtains the <code>Leaf</code> at a certain position in the * list of profile value fragments. * * @param index is the position in the list to obtain a value from * @return The <code>Filename</code> or <code>PseudoText</code> at the position. * @throws IndexOutOfBoundsException if the index points to an element * in the list that does not contain any elments. * * @see Filename * @see PseudoText */ public Leaf getLeaf(int index) throws IndexOutOfBoundsException { //-- check bound for index if ((index < 0) || (index >= this.m_leafList.size())) throw new IndexOutOfBoundsException(); return (Leaf) this.m_leafList.get(index); } /** * Accessor: Gets an array of all values that constitute the current * value content of a profile. * * @return an array with a mixture of either <code>PseudoText</code> or * <code>Filename</code> values. * * @see Filename * @see PseudoText * @deprecated Use the new Collection based interfaces */ public Leaf[] getLeaf() { int size = this.m_leafList.size(); Leaf[] mLeaf = new Leaf[size]; System.arraycopy( this.m_leafList.toArray(new Leaf[0]), 0, mLeaf, 0, size ); return mLeaf; } /** * Accessor: Obtains the number of profile value fragments. * * @return number of elements that an external array needs to be sized to. */ public int getLeafCount() { return this.m_leafList.size(); } /** * Accessor: Gets an array of all values that constitute the current * content. This list is read-only. * * @return an array with a mixture of either <code>PseudoText</code> or * <code>Filename</code> values. * * @see PseudoText * @see Filename */ public java.util.List getLeafList() { return Collections.unmodifiableList(this.m_leafList); } /** * Accessor: Gets the namespace value for the profile. * * @return the currently active namespace for this instance. * @see #setNamespace(java.lang.String) */ public String getNamespace() { return this.m_namespace; } /** * Accessor: Obtains the originator for a profile. * * @return an arbitrary string at the moment. * @see #setOrigin( java.lang.String ) */ public String getOrigin() { return this.m_origin; } /** * Accessor: Gets the key identifier for the profile. * * @return the currently active key for this instance. * @see #setKey(java.lang.String) */ public String getKey() { return this.m_key; } /** * Accessor: Enumerates the internal values that constitute the content * of the <code>Scalar</code> element. * * @return an iterator to walk the list with. */ public Iterator iterateLeaf() { return this.m_leafList.iterator(); } /** * Accessor: Enumerates the internal values that constitute the content * of the <code>Leaf</code> element. * * @return a list iterator to walk the list with. */ public ListIterator listIterateLeaf() { return this.m_leafList.listIterator(); } /** * Accessor: Enumerates the internal values that constitute the content * of the <code>Leaf</code> element. * * @param start is the start index * @return a list iterator to walk the list with. */ public ListIterator listIterateLeaf(int start) { return this.m_leafList.listIterator(start); } /** * Accessor: Removes all value fragments from the profile. */ public void removeAllLeaf() { this.m_leafList.clear(); } /** * Accessor: Remove a single fragment from the list of value fragments. * @param index is the position at which an element is to be removed. * @return the object that was removed. The removed item is either an * <code>Filename</code> or a <code>PseudoText</code>. * * @see Filename * @see PseudoText */ public Leaf removeLeaf( int index ) { return (Leaf) this.m_leafList.remove(index); } /** * Accessor: Overwrites a <code>Filename</code> or <code>PseudoText</code> value * fragment at a certain position in the profile value fragment list. * * @param index position to overwrite an elment in. * @param vLeaf is either a <code>Filename</code> or <code>PseudoText</code> object. * @throws IndexOutOfBoundsException if the position pointed to is invalid. * * @see Filename * @see PseudoText */ public void setLeaf(int index, Leaf vLeaf) throws IndexOutOfBoundsException { //-- check bounds for index if ((index < 0) || (index >= this.m_leafList.size())) { throw new IndexOutOfBoundsException(); } this.m_leafList.set(index, vLeaf); } /** * Accessor: Overwrites internal value fragments list with an external * list representing a profile value. * * @param leafArray is the external list of <code>PseudoText</code> or * <code>Filename</code> objects used to overwrite things. * @see PseudoText * @see Filename * @deprecated Use the new Collection based interfaces */ public void setLeaf(Leaf[] leafArray) { this.m_leafList.clear(); this.m_leafList.addAll( Arrays.asList(leafArray) ); } /** * Accessor: Overwrites internal list with an external list representing * a <code>Scalar</code> value. * * @param leaves is the external list of <code>PseudoText</code> or * <code>Filename</code> objects used to overwrite things. * @see PseudoText * @see Filename */ public void setLeaf(Collection leaves) { this.m_leafList.clear(); this.m_leafList.addAll(leaves); } /** * Accessor: Sets the originator for a profile. * @param origin is the new originator to use, may be <code>null</code>. * @see #getOrigin() */ public void setOrigin( String origin ) { this.m_origin = origin; } /** * Accessor: Adjusts a namespace value to a new state. * @param namespace is the new namespace to use. * @see #getNamespace() */ public void setNamespace( String namespace ) { this.m_namespace = namespace; } /** * Accessor: Adjusts the identifier within a namespace. * @param key is the new identifier to use from now on. * @see #getKey() */ public void setKey( String key ) { this.m_key = key; } /** * 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 { stream.write( "profile " ); stream.write( escape(this.m_namespace) ); stream.write( "::" ); stream.write( escape(this.m_key) ); stream.write( " = " ); for ( int i=0; i<this.m_leafList.size(); ++i ) { ((Leaf) this.m_leafList.get(i)).toString(stream); } } /** * 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 { String newline = System.getProperty( "line.separator", "\r\n" ); String tag = ( namespace != null && namespace.length() > 0 ) ? namespace + ":profile" : "profile"; // open tag if ( indent != null && indent.length() > 0 ) stream.write( indent ); stream.write( '<' ); stream.write( tag ); writeAttribute( stream, " origin=\"", this.m_origin ); writeAttribute( stream, " namespace=\"", this.m_namespace ); writeAttribute( stream, " key=\"", this.m_key ); stream.write( '>' ); //NO: if ( indent != null ) stream.write( newline ); // dump content //NO: String newindent = indent==null ? null : indent+" "; for ( Iterator i=this.m_leafList.iterator(); i.hasNext(); ) { //NO: ((Leaf) i.next()).shortXML( stream, newindent, namespace, 0x00 ); ((Leaf) i.next()).shortXML( stream, "", namespace, 0x00 ); } // close tag //NO: if ( indent != null && indent.length() > 0 ) stream.write( indent ); stream.write( "</" ); stream.write( tag ); stream.write( '>' ); if ( indent != null ) stream.write( newline ); } }