/*
* 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.classes;
import org.griphyn.vdl.classes.*;
import java.util.*;
import java.io.Writer;
import java.io.IOException;
import java.io.Serializable;
/**
* This class captures the logical filename and its linkage. Also,
* some static methods allow to use the linkage constants outside
* the class.
*
* <code>LFN</code> extends the <code>Leaf</code> class by adding
* a filename and linkage type.
*
* @author Jens-S. Vöckler
* @author Yong Zhao
* @version $Revision$
*
* @see Leaf
* @see Text
* @see Use
*
* @see Value
* @see Scalar
* @see List
*/
public class LFN extends Leaf implements Cloneable, Serializable
{
/**
* Linkage type: no linkage, usually used for constants etc.
* It can also be used to indicate that the linkage is unknown.
* The NONE linkage does not participate in DAG construction.
*/
public static final int NONE = 0;
/**
* Linkage type: input file.
*/
public static final int INPUT = 1;
/**
* Linkage type: output file.
*/
public static final int OUTPUT = 2;
/**
* Linkage type: file is used as input and output. Please note that
* this linkage does not allow for DAG linking.
*/
public static final int INOUT = 3;
/**
* 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;
/**
* The linkage type of the logical file aids the linkage process.
*/
private int m_link = LFN.NONE;
/**
* Predicate to determine, if an integer is within the valid range for
* linkage types.
*
* @param x is the integer to test for in-intervall.
* @return true, if the integer satisfies {@link LFN#NONE}
* ≤ x ≤ {@link LFN#INOUT}, false otherwise.
*/
public static boolean isInRange( int x )
{
return ((x >= LFN.NONE) && (x <= LFN.INOUT));
}
/**
* Converts an integer into the symbolic linkage type represented by
* the constant.
*
* @param x is the integer with the linkage type to symbolically convert
* @return a string with the symbolic linkage name, or null, if the
* constant is out of range.
*/
public static String toString( int x )
{
switch ( x ) {
case LFN.NONE: return "none";
case LFN.INPUT: return "input";
case LFN.OUTPUT: return "output";
case LFN.INOUT: return "inout";
default: return null;
}
}
/**
* Marks a filename for registration in a replica catalog. If marked
* with true, the replica registration will not take place. This is
* useful for transient or non-important results. Regular, tracked
* files are marked with false.
*
* @see #m_dontTransfer
* @see #m_temporary
*/
private boolean m_dontRegister = false;
/**
* Transfer mode: The transfer of the file to the result collector
* is mandatory. Failure to transfer the file will make the workflow
* fail.
*/
public static final int XFER_MANDATORY = 0; // false
/**
* Transfer mode: The transfer of the file to the result collector
* is optional. Failure to transfer the file will <b>not</b> abort
* the workflow.
*/
public static final int XFER_OPTIONAL = 1;
/**
* Transfer mode: The file will not be transferred to the result
* collector.
*/
public static final int XFER_NOT = 2; // true
/**
* Predicate to determine, if an integer is within the valid range for
* transfer modes.
*
* @param x is the integer to test for in-intervall.
* @return true, if the integer satisfies {@link LFN#XFER_MANDATORY}
* ≤ x ≤ {@link LFN#XFER_NOT}, false otherwise.
*/
public static boolean transferInRange( int x )
{
return ((x >= LFN.XFER_MANDATORY) && (x <= LFN.XFER_NOT));
}
/**
* Converts an integer into the symbolic transfer mode represented by
* the constant.
*
* @param x is the integer with the linkage type to symbolically convert
* @return a string with the symbolic linkage name, or null, if the
* constant is out of range.
*/
public static String transferString( int x )
{
switch ( x ) {
case LFN.XFER_MANDATORY: return "true";
case LFN.XFER_OPTIONAL: return "optional";
case LFN.XFER_NOT: return "false";
default: return null;
}
}
/**
* Type of File: Denotes a data file. They are generally looked up in a replica
* catalog.
*/
public static final int TYPE_DATA = 0;
/**
* Type of File: Denotes an executable file. They are generally looked up in a
* transformation catalog.
*/
public static final int TYPE_EXECUTABLE = 1;
/**
* Type of File: Denotes a pattern. They are generally looked up in a
* pattern catalog.
*/
public static final int TYPE_PATTERN = 2;
/**
* Predicate to determine, if an integer is within the valid range for
* type
*
* @param x is the integer to test for in-intervall.
* @return true, if the integer satisfies {@link LFN#TYPE_DATA}
* ≤ x ≤ {@link LFN#TYPE_PATTERN}, false otherwise.
*/
public static boolean typeInRange( int x )
{
return ((x >= LFN.TYPE_DATA) && (x <= LFN.TYPE_PATTERN));
}
/**
* Converts an integer into the symbolic type mode represented by
* the constant.
*
* @param x is the integer with the linkage type to symbolically convert
* @return a string with the symbolic linkage name, or null, if the
* constant is out of range.
*/
public static String typeString( int x )
{
switch ( x ) {
case TYPE_DATA: return "data";
case TYPE_EXECUTABLE: return "executable";
case TYPE_PATTERN: return "pattern";
default: return null;
}
}
/**
* Converts a String into the corresponding integer value.
*
* @param x is the String to symbolically convert
* @return an integer with the value or -1 if not valid.
*/
public static int typeInt( String x )
{
int result = -1;
if( x == null ){
return result;
}
if( x.equalsIgnoreCase( "data" ) ){
result = TYPE_DATA;
}
else if( x.equalsIgnoreCase( "executable" ) ){
result = TYPE_EXECUTABLE;
}
else if( x.equalsIgnoreCase( "pattern" ) ){
result = TYPE_PATTERN;
}
return result;
}
/**
* Marks a filename for transfer to the result collector. If marked
* with true, 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. Regular, tracked files are marked with
* false. Optional transfers have a special mark.
*
* @see #m_dontRegister
* @see #m_temporary
*/
private int m_dontTransfer = 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;
/**
* The type of the filename, whether it refers to a data, pattern or executable.
*/
private int m_type = TYPE_DATA;
/**
* Creates and returns a copy of this object.
* @return a new instance.
*/
public Object clone()
{
return new LFN( this.m_filename, this.m_link, this.m_temporary,
this.m_dontRegister, this.m_dontTransfer,
this.m_optional );
}
/**
* ctor.
*/
public LFN()
{
super();
}
/**
* Default ctor: create an instance with a logical filename. The linkage
* defaults to {@link LFN#NONE}.
*
* @param filename is the logical filename to store.
*/
public LFN( String filename )
{
super();
this.m_filename = filename;
this.m_dontRegister = false;
this.m_dontTransfer = 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 LFN( String filename, int link )
throws IllegalArgumentException
{
super();
this.m_filename = filename;
this.m_dontRegister = false;
this.m_dontTransfer = XFER_MANDATORY;
if ( LFN.isInRange(link) )
this.m_link = link;
else
throw new IllegalArgumentException();
}
/**
* ctor: create a possibly 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 an expression for a temporary filename choice.
* If it is not null, the files will neither be marked for registration
* nor for transfer to the output collector.
* @throws IllegalArgumentException if the linkage does not match the
* legal range.
*/
public LFN( String filename, int link, String hint )
throws IllegalArgumentException
{
super();
this.m_filename = filename;
if ( (this.m_temporary = hint) == null ) {
this.m_dontRegister = false;
this.m_dontTransfer = XFER_MANDATORY;
} else {
this.m_dontRegister = true;
this.m_dontTransfer = XFER_NOT;
}
if ( LFN.isInRange(link) )
this.m_link = link;
else
throw new IllegalArgumentException();
}
/**
* ctor: Creates a filename given almost all specs. This is a backward
* compatible constructor, as it lacks access to the optional transfer
* attribute.
*
* @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.
* @throws IllegalArgumentException if the linkage does not match the
* legal range, or the transfer mode does not match its legal range.
* @since 1.21
*
* @deprecated
*/
public LFN( String filename, int link, String hint,
boolean dontRegister, int dontTransfer )
throws IllegalArgumentException
{
super();
this.m_filename = filename;
this.m_temporary = hint;
this.m_dontRegister = dontRegister;
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 almost all specs. This is a backward
* compatible constructor, as it lacks access to the optional transfer
* attribute.
*
* @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 optional whether the file is optional or required.
* @throws IllegalArgumentException if the linkage does not match the
* legal range, or the transfer mode does not match its legal range.
* @since 1.23
*
* @deprecated
*/
public LFN( String filename, int link, String hint,
boolean dontRegister, int dontTransfer, boolean optional )
throws IllegalArgumentException
{
super();
this.m_filename = filename;
this.m_temporary = hint;
this.m_dontRegister = dontRegister;
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");
}
//The new constructors that need to be added later, after the deprecation
//ends for the above constructors. Karan Oct 24, 2007
/**
* ctor: Creates a filename given almost all specs. This is a backward
* compatible constructor, as it lacks access to the optional transfer
* attribute.
*
* @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 register whether to to register with a replica catalog.
* @param transfer whether to transfer the file to the collector.
* @throws IllegalArgumentException if the linkage does not match the
* legal range, or the transfer mode does not match its legal range.
*/
// public LFN( String filename, int link, String hint,
// boolean register, int transfer )
// throws IllegalArgumentException
// {
// super();
// this.m_filename = filename;
// this.m_temporary = hint;
// this.m_dontRegister = !register;
// if ( LFN.transferInRange( transfer ) )
// this.m_dontTransfer = transfer;
// 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 almost all specs. This is a backward
* compatible constructor, as it lacks access to the optional transfer
* attribute.
*
* @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 register whether to to register with a replica catalog.
* @param transfer whether to transfer the file to the collector.
* @param optional whether the file is optional or required.
* @throws IllegalArgumentException if the linkage does not match the
* legal range, or the transfer mode does not match its legal range.
*/
// public LFN( String filename, int link, String hint,
// boolean register, int transfer, boolean optional )
// throws IllegalArgumentException
// {
// super();
// this.m_filename = filename;
// this.m_temporary = hint;
// this.m_dontRegister = !register;
// this.m_optional = optional;
// if ( LFN.transferInRange( transfer ) )
// this.m_dontTransfer = transfer;
// 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 almost all specs. This is a backward
* compatible constructor, as it lacks access to the optional transfer
* attribute.
*
* @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 optional whether the file is optional or required.
* @param type whether the file is data|executable|pattern
*
* @throws IllegalArgumentException if the linkage does not match the
* legal range, or the transfer mode does not match its legal range.
* @since 1.23
*/
public LFN( String filename, int link, String hint,
boolean dontRegister, int dontTransfer, boolean optional,
int type )
throws IllegalArgumentException
{
this( filename, link, hint, dontRegister, dontTransfer, optional );
if ( LFN.typeInRange( type ) )
this.m_type = type;
else
throw new IllegalArgumentException("Illegal File type");
}
// /**
// * @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>LFN</code> objects <i>default</i> to no linkage.
* @see #setLink(int)
*/
public int getLink()
{ return this.m_link; }
/**
* Accessor: Obtains the logical filename of the object.
*
* @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 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 predicate on registring with a replica
* catalog.
*
* @return false if the file will be registered with a replica catalog.
* @see #setRegister( boolean )
* @see #getRegister()
* @deprecated
* @since 1.21
*/
public boolean getDontRegister()
{ return this.m_dontRegister; }
/**
* 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; }
/**
* Accessor: Obtains the transfering mode.
*
* @return false if the file will be tranferred to an output collector.
*
* @deprecated
*
* @see #getTransfer()
* @see #setTransfer( int )
*
* @since 1.21
*/
public int getDontTransfer()
{ 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.23
*/
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;
}
// /**
// * @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 fn is the new logical filename.
* @see #getFilename()
*/
public void setFilename( String fn )
{
this.m_filename = fn;
}
/**
* 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 predicate on the type of the LFN
*
* @param type the type of LFN
*
*
* @see #getType( )
*
* @since 2.1
*/
public void setType( int type ){
if ( typeInRange( type ) ) {
this.m_type = type;
}
else{
throw new IllegalArgumentException( "Invalid LFN type " + type );
}
}
/**
* Accessor: Sets the predicate on registring with a replica catalog.
*
* @param dontRegister is false, if the file should be registered with a
* replica catalog.
* @see #getDontRegister()
* @since 1.21
* @deprecated
*
* @see #setRegister( boolean )
*/
public void setDontRegister( boolean dontRegister )
{ this.m_dontRegister = dontRegister; }
/**
* Accessor: Sets the transfer mode.
*
* @param transfer the transfer flag
*
* @exception IllegalArgumentException if the transfer mode is outside
* its legal range.
* @see #getTransfer( )
* @see LFN#XFER_MANDATORY
* @see LFN#XFER_OPTIONAL
* @see 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();
}
/**
* 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 #getDontTransfer( )
* @see LFN#XFER_MANDATORY
* @see LFN#XFER_OPTIONAL
* @see LFN#XFER_NOT
* @since 1.21
*/
public void setDontTransfer( int dontTransfer )
throws IllegalArgumentException
{
if ( LFN.transferInRange(dontTransfer) )
this.m_dontTransfer = dontTransfer;
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.23
*/
public void setOptional( boolean optional )
{ this.m_optional = optional; }
/**
* 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;
}
/**
* Predicate to determine, if the output can be abbreviated. Filenames
* can be abbreviated, if one of these two conditions are met: The
* hint is <code>null</code> and dontRegister is false and
* dontTransfer is mandatory, or the hint exists, and dontRegister
* is true and dontTransfer is no transfer.
*
* @param temp is the temporary hint
* @param dr is the value of dontRegister
* @param dt is the value of dontTransfer
* @param opt is whether a given file is optional or not
* @return true, if the filename can use abbreviated mode
*
*/
public static boolean abbreviatable( String temp, boolean dr, int dt,
boolean opt )
{
if ( opt ) return false;
else return ( ( temp == null && ! dr && dt == LFN.XFER_MANDATORY ) ||
( temp != null && dr && dt == LFN.XFER_NOT ) );
}
/**
* Convenience function to call the static test, if a filename can
* use the abbreviated notation.
*
* @return true, if abbreviatable notation is possible.
* @see #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.
*
* @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() ) {
// new mode, generate appendices
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();
}
/**
* Prints the current content onto the stream.
*
* @param stream is a stream opened and ready for writing. This can also
* be a string stream for efficient output.
* @throws IOException if something happens to the stream.
*/
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() ) {
// new mode, generate appendices
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 current element as XML output. This method
* converts the data into pretty-printed XML output meant for machine
* consumption.
*
* @param indent is a <code>String</code> of spaces used for pretty
* printing. The initial amount of spaces should be an empty string.
*
* @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 )
{
// slight over-allocation is without harm
StringBuffer result = new StringBuffer(128);
if ( indent != null ) result.append(indent);
result.append("<lfn file=\"").append(quote(this.m_filename,true));
result.append("\" link=\"").append(LFN.toString(this.m_link));
result.append("\" register=\"")
.append(Boolean.toString(!this.m_dontRegister));
result.append("\" transfer=\"")
.append(LFN.transferString(this.m_dontTransfer));
result.append("\" optional=\"")
.append(Boolean.toString(this.m_optional));
result.append( "\" type=\"" ).
append( LFN.typeString( this.m_type ) );
if ( this.m_temporary != null ) {
result.append("\" temporaryHint=\"");
result.append(quote(this.m_temporary,true));
}
result.append("\"/>");
if ( indent != null )
result.append( System.getProperty( "line.separator", "\r\n" ) );
return result.toString();
}
/**
* Dump the state of the current element as XML output. This function
* traverses all sibling classes as necessary, and converts the data
* into pretty-printed XML output. The stream interface should be able
* to handle large output efficiently, if you use a buffered writer.
*
* @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( "lfn" );
writeAttribute( stream, " file=\"", this.m_filename );
writeAttribute( stream, " link=\"", LFN.toString(this.m_link) );
writeAttribute( stream, " register=\"",
Boolean.toString(!this.m_dontRegister) );
writeAttribute( stream, " transfer=\"",
LFN.transferString(this.m_dontTransfer) );
writeAttribute( stream, " optional=\"",
Boolean.toString(this.m_optional) );
writeAttribute( stream, " type=\"",
LFN.typeString( this.m_type ) );
// null-safe
writeAttribute( stream, " temporaryHint=\"", this.m_temporary );
stream.write( "/>" );
if ( indent != null )
stream.write( System.getProperty( "line.separator", "\r\n" ) );
}
}