/*
* 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 org.griphyn.vdl.classes.LFN;
import java.util.Vector;
import java.io.Writer;
import java.io.IOException;
/**
* This class captures the logical filename and its linkage. Also,
* some static methods allow to use the linkage constants outside
* the class.<p>
*
* <code>Filename</code> extends the <code>Leaf</code> class by adding a
* filename, linkage type, temporary pattern, and management attributes.
*
* @author Jens-S. Vöckler
* @author Yong Zhao
* @version $Revision$
*
* @see Leaf
* @see PseudoText
*/
public class Filename extends Leaf implements Cloneable
{
/**
* The filename is the logical name of the file. With the help of
* the replica location service (RLS), the physical filename is
* determined by the concrete planner.
*/
private String m_filename = null;
/**
* The linkage type of the logical file aids the linkage process.
*/
private int m_link = LFN.NONE;
/**
* Marks a filename for registration in a replica catalog. If
* marked with false, the replica registration will not take place.
* This is useful for transient or non-important results.
*
* @see #m_dontTransfer
* @see #m_temporary
*/
private boolean m_dontRegister = false;
/**
* Marks a filename for transfer to the result collector. If
* marked with false, the file is usually a temporary file, and will
* not be transferred to the output collector. Inter-pool transfers
* may still happen in multi-pool mode. In optional mode, failure to
* transfer due to missing source file will not be fatal.
*
* @see #m_dontRegister
* @see #m_temporary
*/
private int m_dontTransfer = LFN.XFER_MANDATORY;
/**
* If a filename is marked transient, the higher level planners might
* have some notion where to place it, or how to name it. Lower level
* planners are not necessarily required to follow this hint.
*
* @see #m_dontRegister
* @see #m_dontTransfer
*/
private String m_temporary = null;
/**
* If a filename is marked as optional, it's non-existence must not
* stop a workflow. Regular files, however, are not optional.
*/
private boolean m_optional = false;
/*
* Records the VDL variable that was responsible for generating this
* logical filename.
*/
private String m_variable = null;
/**
* The type of the filename, whether it refers to a data, pattern or executable.
*/
private int m_type = LFN.TYPE_DATA;
/**
* Creates and returns a copy of this object.
* @return a new instance.
*/
public Object clone()
{
return new Filename( this.m_filename, this.m_link, this.m_temporary,
this.m_dontRegister, this.m_dontTransfer,
this.m_variable, this.m_optional );
}
/**
* Default ctor: create a hollow instance which needs to be filled
* with content.
*/
public Filename()
{
super();
}
/**
* Default ctor: create an instance with a logical filename. The linkage
* defaults to {@link org.griphyn.vdl.classes.LFN#NONE}.
*
* @param filename is the logical filename to store.
*/
public Filename( String filename )
{
super();
this.m_filename = filename;
this.m_dontRegister = false;
this.m_dontTransfer = LFN.XFER_MANDATORY;
}
/**
* ctor: create a file with a name and linkage.
*
* @param filename is the logical filename to store.
* @param link is the linkage of the file to remember.
* @throws IllegalArgumentException if the linkage does not match the
* legal range.
*/
public Filename( String filename, int link )
throws IllegalArgumentException
{
super();
this.m_filename = filename;
this.m_dontRegister = false;
this.m_dontTransfer = LFN.XFER_MANDATORY;
if ( LFN.isInRange(link) )
this.m_link = link;
else
throw new IllegalArgumentException();
}
/**
* ctor: create a transient file with a name, linkage and hint.
*
* @param filename is the logical filename to store.
* @param link is the linkage of the file to remember.
* @param hint is the transient filename. If null, the file is regular,
* if set, the file is assumed to be neither registered not transferred.
* @exception IllegalArgumentException if the linkage does not match the
* legal range.
*/
public Filename( String filename, int link, String hint )
throws IllegalArgumentException
{
super();
this.m_filename = filename;
this.m_temporary = hint;
if ( (this.m_temporary = hint) == null ) {
this.m_dontRegister = false;
this.m_dontTransfer = LFN.XFER_MANDATORY;
} else {
this.m_dontRegister = true;
this.m_dontTransfer = LFN.XFER_NOT;
}
if ( LFN.isInRange(link) )
this.m_link = link;
else
throw new IllegalArgumentException();
}
/**
* ctor: Creates a filename given all specs.
*
* @param filename is the logical filename to store.
* @param link is the linkage of the file to remember.
* @param hint is an expression for a temporary filename choice.
* @param dontRegister whether to to register with a replica catalog.
* @param dontTransfer whether to transfer the file to the collector.
* @param variable is the variable that is responsible for this LFN.
* @throws IllegalArgumentException if the linkage does not match the
* legal range, or the transfer mode does not match its legal range.
* @since 1.6
*/
public Filename( String filename, int link, String hint,
boolean dontRegister, int dontTransfer,
String variable )
throws IllegalArgumentException
{
super();
this.m_filename = filename;
this.m_temporary = hint;
this.m_dontRegister = dontRegister;
this.m_variable = variable;
if ( LFN.transferInRange(dontTransfer) )
this.m_dontTransfer = dontTransfer;
else
throw new IllegalArgumentException("Illegal transfer mode");
if ( LFN.isInRange(link) )
this.m_link = link;
else
throw new IllegalArgumentException("Illegal linkage type");
}
/**
* ctor: Creates a filename given all specs.
*
* @param filename is the logical filename to store.
* @param link is the linkage of the file to remember.
* @param hint is an expression for a temporary filename choice.
* @param dontRegister whether to to register with a replica catalog.
* @param dontTransfer whether to transfer the file to the collector.
* @param variable is the variable that is responsible for this LFN.
* @param optional records the optionality of a given file.
* @throws IllegalArgumentException if the linkage does not match the
* legal range, or the transfer mode does not match its legal range.
* @since 1.8
*/
public Filename( String filename, int link, String hint,
boolean dontRegister, int dontTransfer,
String variable, boolean optional )
throws IllegalArgumentException
{
super();
this.m_filename = filename;
this.m_temporary = hint;
this.m_dontRegister = dontRegister;
this.m_variable = variable;
this.m_optional = optional;
if ( LFN.transferInRange(dontTransfer) )
this.m_dontTransfer = dontTransfer;
else
throw new IllegalArgumentException("Illegal transfer mode");
if ( LFN.isInRange(link) )
this.m_link = link;
else
throw new IllegalArgumentException("Illegal linkage type");
}
/**
* convenience ctor: create a DAX filename from a VDLx filename.
* @param lfn is a VDLx logical filename.
*/
public Filename( LFN lfn )
throws IllegalArgumentException
{
super();
this.m_filename = lfn.getFilename();
this.m_link = lfn.getLink();
this.m_temporary = lfn.getTemporary();
this.m_dontRegister = !lfn.getRegister();
this.m_dontTransfer = lfn.getTransfer();
this.m_optional = lfn.getOptional();
this.m_type = lfn.getType();
}
// /**
// * @deprecated Use the finer control of {@link #getDontRegister}
// * and {@link #getDontTransfer}.
// *
// * @return true, if the current filename instance points to
// * a transient (dontRegister, dontTransfer) file. False for all other
// * cases.
// */
// public boolean getIsTransient()
// {
// return ( this.m_dontRegister && this.m_dontTransfer );
// }
/**
* Accessor: Obtains the linkage type from the object.
*
* @return the linkage type of the current object. Note that
* <code>Filename</code> constructor defaults to no linkage.
* @see #setLink(int)
*/
public int getLink()
{ return this.m_link; }
/**
* Accessor: Obtains the logical filename for this instance.
*
* @return the logical filename.
* @see #setFilename( java.lang.String )
*/
public String getFilename()
{ return this.m_filename; }
/**
* Accessor: Obtains the predicate on registring with a replica
* catalog.
*
* @return false if the file will be registered with a replica catalog.
*
* @deprecated
*
* @see #getRegister( )
* @since 1.6
*/
public boolean getDontRegister()
{ return this.m_dontRegister; }
/**
* Accessor: Obtains the predicate on registring with a replica
* catalog.
*
* @return true if the file will be registered with a replica catalog.
*
* @see #setRegister( boolean )
*
* @since 2.1
*/
public boolean getRegister()
{ return !this.m_dontRegister; }
/**
* Accessor: Returns the predicate on the type of the LFN
*
* @return the type of LFN
*
*
* @see #setType( int )
* @since 2.1
*/
public int getType( ){
return this.m_type;
}
/**
* Accessor: Obtains the transfer mode.
*
* @return false if the file will be tranferred to an output collector.
*
* @deprecated
* @see #getTransfer()
*
* @since 1.6
*/
public int getDontTransfer()
{ return this.m_dontTransfer; }
/**
* Accessor: Obtains the transfering mode.
*
* @return true if the file will be tranferred to an output collector.
*
* @see #setTransfer( int )
* @since 2.1
*/
public int getTransfer()
{ return this.m_dontTransfer; }
/**
* Acessor: Obtains the optionality of the file.
*
* @return false, if the file is required, or true, if it is optional.
* @see #setOptional( boolean )
* @since 1.8
*/
public boolean getOptional()
{ return this.m_optional; }
/**
* Accessor: Obtains the file name suggestion for a transient file.
* If a filename is marked transient, the higher level planners might
* have some notion where to place it, or how to name it. Lower level
* planners are not necessarily required to follow this hint.
*
* @return the transient name suggestion of the file. The current
* settings will always be returned, regardless of the transiency
* state of the file.
* @see #setTemporary(String)
*/
public String getTemporary()
{ return this.m_temporary; }
/**
* Accessor: Obtains the responsible variable.
*
* @return the variable responsible for setting this LFN.
* @see #setVariable( String )
* @since 1.7
*/
public String getVariable()
{ return this.m_variable; }
// /**
// * @deprecated Use the finer control of {@link #setDontRegister} and
// * {@link #setDontTranfer} for transiency control.
// *
// * @param transient is the transience state of this filename instance.
// * dontRegister and dontTransfer will both be set to the value of
// * transient.
// *
// * @see #getIsTransient()
// */
// public void setIsTransient( boolean isTransient )
// { this.m_dontRegister = this.m_dontTransfer = isTransient; }
/**
* Accessor: Sets the linkage type.
*
* @param link is the new linkage type to use. Please note that it
* must match the range of legal values.
* @throws IllegalArgumentException if the range is beyong legal values.
* @see #getLink()
*/
public void setLink( int link )
throws IllegalArgumentException
{
if ( LFN.isInRange(link) )
this.m_link = link;
else
throw new IllegalArgumentException();
}
/**
* Accessor: Sets the filename
*
* @param name is the new logical filename.
* @see #getFilename()
*/
public void setFilename( String name )
{ this.m_filename = name; }
/**
* Accessor: Sets the predicate on registring with a replica catalog.
*
* @param dontRegister is false, if the file should be registered with a
* replica catalog.
*
* @deprecated
*
* @see #setRegister(boolean)
*
* @since 1.6
*/
public void setDontRegister( boolean dontRegister )
{ this.m_dontRegister = dontRegister; }
/**
* Accessor: Sets the predicate on registring with a replica catalog.
*
* @param register is true, if the file should be registered with a
* replica catalog.
*
*
* @see #getRegister( )
* @since 2.1
*/
public void setRegister( boolean register )
{ this.m_dontRegister = !register; }
/**
* Accessor: Sets the transfer mode.
*
* @param dontTransfer is false, if the file should be transferred to
* the output collector.
* @exception IllegalArgumentException if the transfer mode is outside
* its legal range.
*
* @deprecated
*
* @see #setTransfer(int)
* @see org.griphyn.vdl.classes.LFN#XFER_MANDATORY
* @see org.griphyn.vdl.classes.LFN#XFER_OPTIONAL
* @see org.griphyn.vdl.classes.LFN#XFER_NOT
* @since 1.6
*/
public void setDontTransfer( int dontTransfer )
throws IllegalArgumentException
{
if ( LFN.transferInRange(dontTransfer) )
this.m_dontTransfer = dontTransfer;
else
throw new IllegalArgumentException();
}
/**
* Accessor: Sets the transfer mode.
*
* @param transfer the transfer flag
*
* @exception IllegalArgumentException if the transfer mode is outside
* its legal range.
* @see #getTransfer( )
* @see org.griphyn.vdl.classes.LFN#XFER_MANDATORY
* @see org.griphyn.vdl.classes.LFN#XFER_OPTIONAL
* @see org.griphyn.vdl.classes.LFN#XFER_NOT
*
* @since 2.1
*/
public void setTransfer( int transfer )
throws IllegalArgumentException
{
if ( LFN.transferInRange( transfer ) )
this.m_dontTransfer = transfer;
else
throw new IllegalArgumentException();
}
/**
* Acessor: Sets the optionality of the file.
*
* @param optional false, if the file is required, or true, if it is
* optional.
* @see #getOptional()
* @since 1.8
*/
public void setOptional( boolean optional )
{ this.m_optional = optional; }
/**
* Accessor: Sets the predicate on the type of the LFN
*
* @param type the type of LFN
*
*
* @see #getType( )
*
* @since 2.1
*/
public void setType( int type ){
if ( LFN.typeInRange( type ) ) {
this.m_type = type;
}
else{
throw new IllegalArgumentException( "Invalid LFN type " + type );
}
}
/**
* Accessor: Sets a file name suggestion for a transient file. If a
* filename is marked transient, the higher level planners might have
* some notion where to place it, or how to name it. Lower level
* planners are not necessarily required to follow this hint.
*
* @param name is a transient name suggestion for this filename instance.
* No automatic marking of transiency will be done!
* @see #getTemporary()
*/
public void setTemporary( String name )
{
this.m_temporary = name;
}
/**
* Accessor: Sets the responsible variable.
*
* @param variable the variable responsible for setting this LFN.
* @see #getVariable()
* @since 1.7
*/
public void setVariable( String variable )
{ this.m_variable = variable; }
/**
* Convenience function to call the static test, if a filename can
* use the abbreviated notation.
*
* @return true, if abbreviatable notation is possible.
* @see org.griphyn.vdl.classes.LFN#abbreviatable( String, boolean, int, boolean )
*/
private boolean abbreviatable()
{
return LFN.abbreviatable( this.m_temporary,
this.m_dontRegister,
this.m_dontTransfer,
this.m_optional );
}
/**
* Convert the logical filename and linkage into something human
* readable. The output is also slightly nudged towards machine
* parsability. This method overwrites the inherited methods since it
* appears to be faster to do it this way.<p>
*
* @return a textual description of the element and its attributes.
*/
public String toString()
{
// slight over-allocation is without harm
StringBuffer result = new StringBuffer( this.m_filename.length() + 32 );
result.append( "@{" );
result.append( LFN.toString(this.m_link) );
result.append( ":\"" );
result.append( escape(this.m_filename) );
if ( this.m_temporary != null ) {
result.append( "\":\"" );
result.append( escape(this.m_temporary) );
}
result.append('"');
if ( ! abbreviatable() ) {
result.append( '|' );
if ( this.m_optional ) result.append('o');
if ( ! this.m_dontRegister ) result.append('r');
if ( this.m_dontTransfer != LFN.XFER_NOT )
result.append( this.m_dontTransfer == LFN.XFER_OPTIONAL ? 'T' : 't');
}
result.append( '}' );
return result.toString();
}
/**
* 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( "@{" );
stream.write( LFN.toString(this.m_link) );
stream.write( ":\"" );
stream.write( escape(this.m_filename) ); // risk NullPointerException
if ( this.m_temporary != null ) {
stream.write( "\":\"" );
stream.write( escape(this.m_temporary) );
}
stream.write( '"' );
if ( ! abbreviatable() ) {
stream.write( '|' );
if ( this.m_optional ) stream.write('o');
if ( ! this.m_dontRegister ) stream.write('r');
if ( this.m_dontTransfer != LFN.XFER_NOT )
stream.write( this.m_dontTransfer == LFN.XFER_OPTIONAL ? 'T' : 't');
}
stream.write( "}" );
}
/**
* Dumps the state of the filename as PlainFilenameType or
* StdioFilenameType without the transiency information.
*
* @param indent is a <code>String</code> of spaces used for pretty
* printing. The initial amount of spaces should be an empty string.
* @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.
* @param flag 0x01: also dump the linkage information, 0x02: also
* dump optionality
*
* @return a String which contains the state of the current class
* and its siblings using XML. Note that these strings might become large. */
public String shortXML( String indent, String namespace, int flag )
{
// slight over-allocation is without harm
StringBuffer result = new StringBuffer( this.m_filename.length() + 32 );
if ( indent != null ) result.append(indent);
result.append('<');
if ( namespace != null && namespace.length() > 0 )
result.append(namespace).append(':');
result.append("filename file=\"").append(quote(this.m_filename,true));
if ( this.m_variable != null && this.m_variable.length() > 0 )
result.append("\" varname=\"").append(quote(this.m_variable,true));
if ( (flag & 0x01) == 0x01 )
result.append("\" link=\"").append(LFN.toString(this.m_link));
if ( (flag & 0x02) == 0x02 && this.m_optional )
result.append("\" optional=\"true\"");
result.append("\"/>");
return result.toString();
}
/**
* Dumps the state of the current element as XML output. This method
* converts the data into pretty-printed XML output meant for machine
* consumption. This method overwrites the inherited methods since it
* appears to be faster to do it this way.<p>
*
* @param indent is a <code>String</code> of spaces used for pretty
* printing. The initial amount of spaces should be an empty string.
* @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.
*
* @return a String which contains the state of the current class
* and its siblings using XML. Note that these strings might become large.
*/
public String toXML( String indent, String namespace )
{
// slight over-allocation is without harm
StringBuffer result = new StringBuffer( this.m_filename.length() + 128 );
if ( indent != null ) result.append(indent);
result.append('<');
if ( namespace != null && namespace.length() > 0 )
result.append(namespace).append(':');
result.append("filename file=\"").append(quote(this.m_filename,true));
result.append("\" link=\"").append(LFN.toString(this.m_link));
result.append("\" register=\"")
.append(Boolean.toString( this.getRegister() ));
result.append("\" transfer=\"")
.append(LFN.transferString( this.getTransfer() ));
result.append("\" optional=\"")
.append(Boolean.toString(this.m_optional));
result.append( "\" type=\"" ).
append( LFN.typeString( this.getType() ));
if ( this.m_temporary != null ) {
result.append("\" temporaryHint=\"");
result.append(quote(this.m_temporary,true));
}
result.append("\"/>");
return result.toString();
}
/**
* Dumps the state of the filename as PlainFilenameType or
* StdioFilenameType without the transiency information.
*
* @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.
* @param flag if 0x01, dump linkage, if 0x02 is set, dump optionality.
* @exception IOException if something fishy happens to the stream.
*/
public void shortXML( Writer stream, String indent, String namespace,
int flag )
throws IOException
{
// if ( indent != null && indent.length() > 0 ) stream.write( indent );
stream.write( '<' );
if ( namespace != null && namespace.length() > 0 ) {
stream.write( namespace );
stream.write( ':' );
}
stream.write( "filename" );
writeAttribute( stream, " file=\"", this.m_filename );
if ( this.m_variable != null && this.m_variable.length() > 0 )
writeAttribute( stream, " varname=\"", this.m_variable );
if ( (flag & 0x01) == 0x01 )
writeAttribute( stream, " link=\"", LFN.toString(this.m_link) );
if ( (flag & 0x02) == 0x02 && this.m_optional )
stream.write( " optional=\"true\"" );
stream.write( "/>" );
}
/**
* 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
{
// if ( indent != null && indent.length() > 0 ) stream.write( indent );
stream.write( '<' );
if ( namespace != null && namespace.length() > 0 ) {
stream.write( namespace );
stream.write( ':' );
}
stream.write( "filename" );
writeAttribute( stream, " varname=\"", this.m_variable );
writeAttribute( stream, " file=\"", this.m_filename );
writeAttribute( stream, " link=\"", LFN.toString(this.m_link) );
writeAttribute( stream, " register=\"",
Boolean.toString( this.getRegister() ) );
writeAttribute( stream, " dontTransfer=\"",
LFN.transferString( this.getTransfer() ) );
writeAttribute( stream, " optional=\"",
Boolean.toString(this.m_optional) );
writeAttribute( stream, " type=\"",
LFN.typeString( this.getType() ) );
if ( this.m_temporary != null )
writeAttribute( stream, " temporaryHint=\"", this.m_temporary );
stream.write( "/>" );
}
}