/*
* BioJava development code
*
* This code may be freely distributed and modified under the
* terms of the GNU Lesser General Public Licence. This should
* be distributed with the code. If you do not have a copy,
* see:
*
* http://www.gnu.org/copyleft/lesser.html
*
* Copyright for this code is held jointly by the individual
* authors. These should be listed in @author doc comments.
*
* For more information on the BioJava project and its aims,
* or to join the biojava-l mailing list, visit the home page
* at:
*
* http://www.biojava.org/
*
*/
package org.biojava.bio.seq.io.agave;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.Iterator;
import org.biojava.bio.Annotatable;
import org.biojava.bio.seq.ComponentFeature;
import org.biojava.bio.seq.Feature;
import org.biojava.bio.seq.FeatureHolder;
import org.biojava.bio.seq.Sequence;
import org.biojava.bio.seq.SimpleAssembly;
import org.biojava.bio.seq.StrandedFeature;
import org.biojava.bio.seq.impl.SimpleSequence;
/**
* Writes Sequence into AGAVE XML document. The AGAVE
* format is defined in agave.dtd which can be downloaded
* from http://www.agavexml.org.
*
* @author Hanning Ni
* @author Brian King
*/
public class AgaveWriter
{
/**
* Implements indenting for elements.
* @author Brian King
*/
protected class Indent
{
/** Base indent */
protected String mIndent = new String(INDENT);
/**
* Add a level of indentation
*/
public void
indent()
{
mIndent += INDENT;
}
/**
* Remove a level of indentation
*
*/
public void
unIndent()
{
int len = mIndent.length();
int iLen = INDENT.length();
if(len >= iLen)
{
mIndent = mIndent.substring(0, len - iLen);
}
}
/**
* Return the current indent
*
*/
public String
toString()
{
return mIndent;
}
}
/** use a two space indent */
public static final String INDENT = " ";
/** Write to XML document */
protected PrintWriter mOut;
/** indent */
protected Indent mIndent;
/** writes PCDATA replacing XML characters with escape entities */
protected PCDATAFilterWriter mFilter;
/**
* The AnnotationMap to use for getting
* AGAVE XML attributes from a Sequence Annotation.
*/
protected AGAVEAnnotFilter mAnnotFilter;
/** write DOCTYPE if true */
protected boolean mWriteDocType = true;
/**
* Default constructor uses generic annotation to attribute mapping.
*
*/
public AgaveWriter()
{
mAnnotFilter = SimpleAnnotFilter.SIMPLE_ANNOT_FILTER_FACTORY.getInstance();
mIndent = new Indent();
}
/**
* Construct with data source specific annotation to attribute
* mapping.
*
*/
public AgaveWriter(AGAVEAnnotFilter filter)
{
mAnnotFilter = filter;
mIndent = new Indent();
}
/**
* Set flag that determines if XML DOCTYPE is written
* or not. Default is true.
*
*/
public void
setWriteDocType(boolean writeDocType)
{
mWriteDocType = writeDocType;
}
/**
* Write sequence into AGAVE XML format.
* @param seq maybe the or simple sequence
*
* if annotation of seq has chromosome information , generate tag
* if seq is SimpleAssembly, generate tag
* otherwise, generate tag
* currently each top-level sequence is wrapped into seperated sciobj xml file
*
*/
public void writeSequence(Sequence seq, PrintStream os)
throws IOException
{
mOut = new PrintWriter(os);
mFilter = new PCDATAFilterWriter(mOut);
mOut.println("");
if (mWriteDocType)
{
mOut.println("");
}
writeHeader();
write(seq);
writeFooter();
}
/**
* Write <sciobj>
*
*/
protected void
writeHeader()
{
mOut.println("");
}
/**
* Write </sciobj>
*/
protected void
writeFooter()
{
mOut.println("");
mOut.flush();
}
/**
*
* Writing Sequence.
* @param seq is simple sequence or simple assembly
*
*/
protected void
write(Sequence seq) throws IOException
{
String chrom_num = mAnnotFilter.getChromNum( seq.getAnnotation() );
if( chrom_num != null )
{
mIndent.indent();
mOut.print(mIndent);
mOut.println("");
writeContig((Annotatable) seq );
mOut.print(mIndent);
mOut.println("");
mIndent.unIndent();
}
else
{
if( seq instanceof SimpleAssembly)
{
writeContig( (Annotatable)seq ) ;
}
else
{
writeBioSequence((Annotatable)seq);
}
}
}
/**
*
*
*/
protected void
writeContig(Annotatable seq ) throws IOException
{
/**
*/
mIndent.indent();
mOut.print(mIndent);
mOut.print("");
writeDbId(seq);
writeNote(seq);
writeAssembly(seq);
writeDNA(seq) ;
writeMapLocation(seq) ;
mOut.print(mIndent);
mOut.println("");
mIndent.unIndent();
}
/**
*
*
*/
protected void
writeAssembly(Annotatable seq) throws IOException
{
/** */
mIndent.indent();
mOut.print(mIndent);
mOut.println("");
if(seq instanceof SimpleSequence)
write((Sequence) seq ) ;
else if( seq instanceof SimpleAssembly)
{
for (Iterator i =((Sequence) seq).features(); i.hasNext(); )
{
Feature subf = (Feature)i.next();
if( subf instanceof ComponentFeature)
writeBioSequence((Annotatable) ((ComponentFeature)subf).getComponentSequence() ) ;
}
}
mOut.print(mIndent);
mOut.println("");
mIndent.unIndent();
}
/**
*
*
*/
protected void
writeBioSequence(Annotatable seq ) throws IOException
{
String s;
mIndent.indent();
mOut.print(mIndent);
mOut.print(""); // close bio_sequence tag
// write content
writeDbId(seq) ;
writeDNA( seq ) ;
writeAltIds( seq ) ;
writeXrefs( seq ) ;
writeSequenceMap2(seq); // THOMASD hacked this....
writeMapLocation(seq) ;
writeClassification(seq);
mIndent.unIndent();
mOut.print(mIndent);
mOut.println("");
}
/**
* group sequence_map by getSource()
*/
protected void
writeSequenceMap(Annotatable seq) throws IOException
{
for (Iterator i = ((FeatureHolder)seq).features(); i.hasNext();)
{
Feature f = (Feature) i.next();
String type = f.getSource();
if( type.equalsIgnoreCase("classification") )
continue ;
// writeFeature( f );
writeSequenceMap2( f );
}
}
/**
*
*
*/
protected void
writeClassification(Annotatable seq) throws IOException
{
for (Iterator i = ((FeatureHolder)seq).features(); i.hasNext();)
{
Feature f = (Feature) i.next();
String type = f.getSource();
if( type.equalsIgnoreCase("classification") )
{
writeClassification2(f) ;
}
}
}
/**
*
*
*/
private void
writeClassification2(Annotatable f) throws IOException
{
/**
*/
mOut.print(mIndent);
mOut.print(""); // close map tag
writeDescription( f ) ;
writeIdAlias( f ) ;
writeEvidence( f ) ;
mOut.print(mIndent);
mOut.println("");
mIndent.unIndent();
}
/**
*
*
*/
private void
writeIdAlias(Annotatable f) throws IOException
{
AGAVEIdAlias[] annots = mAnnotFilter.getIdAlias(f.getAnnotation());
if( annots != null )
{
mIndent.indent();
for(int i = 0 ; i < annots.length; i++)
mOut.print( annots[i].toString(mIndent.toString(), INDENT ));
mIndent.unIndent();
}
}
/**
* Write SequenceMap XML
*
*/
protected void
writeSequenceMap2(Annotatable f) throws IOException
{
/*
*/
mIndent.indent();
mOut.print(mIndent);
mOut.print(""); // close map tag
// write content
//
//write note
//
writeNote(f) ;
//ignore write computation
writeAnnotations((FeatureHolder) f);
mOut.print(mIndent);
mOut.println("");
mIndent.unIndent();
}
/**
*
*
*/
protected void writeAnnotations(FeatureHolder f) throws IOException // changed to FeatureHolder THOMASD
{
//write annotation
//
mIndent.indent();
mOut.print(mIndent);
mOut.println("");
/* for (Iterator i = f.features(); i.hasNext(); )
{
Feature feature = (Feature) i.next();
if( feature.getSource().equalsIgnoreCase("annotations") )
{
f = feature ;
break;
}
} */
for (Iterator i = f.features(); i.hasNext(); )
{
Feature feature = (Feature) i.next();
String type = feature.getSource() ;
if( type == null || type.equalsIgnoreCase( "seq_feature" ) )
writeSeqFeature(feature);
else if( type.equalsIgnoreCase( "gene") )
writeGene( feature);
else { //default mapping to comp_result
// writeCompResult( feature);
writeSeqFeature(feature); // THOMASD
}
}
mOut.print(mIndent);
mOut.println("");
mIndent.unIndent();
}
/**
*
*
*/
protected void
writeGene(Annotatable f) throws IOException
{
/**
**/
mIndent.indent();
mOut.print(mIndent);
mOut.print("');
// write content
writeNote(f) ;
writeSeqLocation( f ) ;
writeXrefs( f ) ;
writeEvidence(f) ;
writeProperty(f, AGAVEProperty.QUALIFIER ) ;
writeSubSeqFeature( f ) ;
writeRelatedAnnot( f ) ;
writeTranscript( f ) ;
mOut.print(mIndent);
mOut.println("");
mIndent.unIndent();
}
/**
*
*
*/
protected void
writeTranscript( Annotatable f) throws IOException
{
/**
*
*/
for (Iterator i = ((FeatureHolder)f).features(); i.hasNext(); )
{
Feature subf = (Feature)i.next();
if( subf.getSource().equalsIgnoreCase("transcript") )
writeTranscript2(subf);
}
}
/**
*
*
*/
private void
writeTranscript2(Annotatable f) throws IOException
{
mIndent.indent();
mOut.print(mIndent);
mOut.println("");
writeExons(f);
for (Iterator i = ((FeatureHolder)f).features(); i.hasNext(); )
{
Feature subf = (Feature)i.next();
String type = subf.getSource() ;
if( type.equalsIgnoreCase("cds") )
writeCds(subf);
else if( type.equalsIgnoreCase("mrna") )
writeMrna(subf);
else if( type.equalsIgnoreCase("predicted_protein") )
writePredictedProtein(subf);
}
mOut.print(mIndent);
mOut.println("");
mIndent.unIndent();
}
/**
*
*
*/
private void
writeExons(Annotatable f) throws IOException
{
String[] ids = mAnnotFilter.getExonIds(f.getAnnotation());
if( ids != null )
{
mIndent.indent();
mOut.print(mIndent);
mOut.println("");
for(int i = 0 ; i < ids.length; i++)
{
mOut.println(mIndent + INDENT + "");
}
mOut.print(mIndent);
mOut.println("") ;
mIndent.unIndent();
}
}
/**
*
*
*/
private void writeCds(Annotatable f) throws IOException
{
mIndent.indent();
mOut.print(mIndent);
mOut.println("");
writeBioSequence( f) ;
mOut.print(mIndent);
mOut.println("");
mIndent.unIndent();
}
/**
*
*
*/
private void writeMrna(Annotatable f) throws IOException
{
mIndent.indent();
mOut.print(mIndent);
mOut.println("");
writeBioSequence( f) ;
mOut.print(mIndent);
mOut.println("");
mIndent.unIndent();
}
/**
*
*
*/
private void writePredictedProtein(Annotatable f) throws IOException
{
mIndent.indent();
mOut.print(mIndent);
mOut.println("");
writeBioSequence( f) ;
mOut.print(mIndent);
mOut.println("");
mIndent.unIndent();
}
/**
* Write SeqFeature XML
*/
protected void
writeSeqFeature( Annotatable f) throws IOException
{
/*
*/
mIndent.indent();
mOut.print(mIndent);
mOut.print("');
// write content
writeNote(f) ;
writeSeqLocation( f ) ;
writeXrefs( f ) ;
writeEvidence(f) ;
writeProperty(f, AGAVEProperty.QUALIFIER ) ;
writeSubSeqFeature( f ) ;
writeRelatedAnnot( f ) ;
mOut.print(mIndent);
mOut.println("");
mIndent.unIndent();
}
/**
*
*
*/
private void
writeRelatedAnnot( Annotatable f)
{
AGAVERelatedAnnot[] annots = mAnnotFilter.getRelatedAnnot(f.getAnnotation());
if( annots != null )
{
for(int i = 0 ; i < annots.length; i++)
mOut.print( annots[i].toString(mIndent + INDENT, INDENT));
}
}
/**
*
*
*/
private void
writeEvidence(Annotatable f) throws IOException
{
for (Iterator i = ((FeatureHolder)f).features(); i.hasNext(); )
{
Feature subf = (Feature)i.next();
if( subf.getSource().equalsIgnoreCase("evidence") )
writeEvidence2(subf);
}
}
/**
*
*
*/
private void
writeEvidence2(Annotatable f) throws IOException
{
//element_ids
writeElementIds( f ) ;
//comp_result
for (Iterator i = ((FeatureHolder)f).features(); i.hasNext(); )
{
Feature subf = (Feature)i.next();
writeCompResult( subf );
}
}
/**
*
*
*/
private void
writeElementIds(Annotatable f) throws IOException
{
String[] ids = mAnnotFilter.getElementIds(f.getAnnotation());
if( ids != null )
{
for(int i = 0 ; i < ids.length; i++)
{
mOut.println(mIndent + INDENT + "");
}
}
}
/*
*/
protected
void writeCompResult(Annotatable f) throws IOException
{
mIndent.indent();
mOut.print(mIndent);
mOut.print("");
writeNote( f ) ;
writeMatchDesc( f ) ;
writeMatchAlign( f ) ;
writeQueryRegion( f ) ;
writeMatchRegion( f ) ;
writeProperty( f, AGAVEProperty.RESULT_PROPERTY) ;
writeResultGroup( f ) ;
writeRelatedAnnot(f);
mOut.print(mIndent);
mOut.println("");
mIndent.unIndent();
}
/**
*
*
*/
private void
writeResultGroup(Annotatable f) throws IOException
{
Iterator i = ((FeatureHolder)f).features() ;
if( i == null ) //void
return ;
while( i.hasNext() )
{
Feature subf = (Feature)i.next();
String type = subf.getSource();
if( type != null && type.equalsIgnoreCase("result_group") )
{
mIndent.indent();
mOut.println( mIndent + "");
for(Iterator k = subf.features(); k.hasNext();)
writeCompResult( (Feature)k.next() ) ;
mOut.println(mIndent + "");
mIndent.unIndent();
}
else
{
mIndent.indent();
mOut.println(mIndent + "");
writeCompResult( subf ) ;
mOut.println(mIndent + "");
mIndent.unIndent();
}
}
}
/**
*
*
*/
private void
writeQueryRegion(Annotatable f) throws IOException
{
AGAVEQueryRegion s = mAnnotFilter.getQueryRegion( f.getAnnotation() );
if( s != null )
{
mIndent.indent();
mOut.println( s.toString(mIndent.toString() , INDENT ) );
mIndent.unIndent();
}
}
/**
*
*
*/
private void
writeMatchRegion(Annotatable f) throws IOException
{
AGAVEMatchRegion s = mAnnotFilter.getMatchRegion( f.getAnnotation() );
if( s != null )
{
mIndent.indent();
mOut.println( s.toString(mIndent.toString() , INDENT ) );
mIndent.unIndent();
}
}
/**
*
*
*/
private void
writeMatchAlign(Annotatable f) throws IOException
{
String s = mAnnotFilter.getMatchAlign( f.getAnnotation() );
if( s != null )
{
if (s.startsWith("");
mFilter.write(s);
mOut.println("");
mIndent.unIndent();
}
}
}
/**
*
*
*/
private void
writeMatchDesc(Annotatable f) throws IOException
{
String s = mAnnotFilter.getMatchDesc( f.getAnnotation() );
if( s != null )
{
if (s.startsWith("");
mFilter.write(s);
mOut.println("");
mIndent.unIndent();
}
}
}
/**
*
*
*/
private void
writeSubSeqFeature(Annotatable f ) throws IOException
{
for (Iterator i = ((FeatureHolder)f).features(); i.hasNext(); )
{
Feature subf = (Feature)i.next();
//if the feature is not declared as
//treated as seq_feature
if( subf.getSource().equalsIgnoreCase("evidence") )
continue ;
if( subf.getSource().equalsIgnoreCase("transcript") )
continue ;
writeSeqFeature( subf);
}
}
/**
*
*
*/
private void
writeSeqLocation( Annotatable f) throws IOException
{
int min = ((Feature)f).getLocation().getMin();
int max = ((Feature)f).getLocation().getMax();
boolean on_complement_strand = false;
if( f instanceof StrandedFeature)
{
int type = ((StrandedFeature)f).getStrand().getValue() ;
if( type == 1 )
on_complement_strand = false ;
else if( type == -1 )
on_complement_strand = true ;
}
mIndent.indent();
mOut.print(mIndent);
mOut.print("");
mOut.print(min + ".." + max);
mOut.println("");
mIndent.unIndent();
}
/**
*
*
*/
private void
writeDNA(Annotatable seq) throws IOException
{
if( seq instanceof Sequence)
{
int i = ((Sequence)seq).length();
if (i > 0)
{
mIndent.indent();
mOut.print(mIndent);
mOut.print("");
int j ;
for (j = 0 ; j < i / 80; j ++)
{
mOut.print(((Sequence)seq).subList(80 * j + 1, 80 * (j+1)).seqString() + "\n");
}
mOut.print(((Sequence)seq).subList(80 * j + 1, i ).seqString());
mOut.println("");
mIndent.unIndent();
}
}
}
/**
*
*
*/
private void writeXrefs(Annotatable f)
{
AGAVEXrefs[] xrefs = mAnnotFilter.getXrefs(f.getAnnotation());
if( xrefs != null )
{
mIndent.indent();
for(int i = 0 ; i < xrefs.length; i++)
mOut.print( xrefs[i].toString(mIndent.toString(), INDENT));
mIndent.unIndent();
}
}
/**
*
*
*/
private void
writeAltIds(Annotatable f) throws IOException
{
AGAVEDbId[] db_id = mAnnotFilter.getAltIds(f.getAnnotation());
if( db_id!= null )
{
mIndent.indent();
mOut.println(mIndent + "");
mIndent.indent();
for(int i = 0 ; i < db_id.length; i++)
mOut.print( db_id[i].toString(mIndent.toString(), INDENT));
mIndent.unIndent();
mOut.println(mIndent + "");
mIndent.unIndent();
}
}
/**
*
*
*/
private void
writeProperty(Annotatable f, String type)
{
AGAVEProperty[] aps = mAnnotFilter.getProperty( f.getAnnotation(),type) ;
if( aps != null )
{
mIndent.indent();
for( int index = 0 ; index < aps.length; index++)
mOut.print( aps[index].toString(mIndent.toString(), INDENT));
mIndent.unIndent();
}
}
/**
*
*
*/
private void
writeMapLocation(Annotatable f) throws IOException
{
AGAVEMapLocation[] mls = mAnnotFilter.getMapLocation(f.getAnnotation());
if( mls != null )
{
mIndent.indent();
for(int i = 0 ; i < mls.length; i++)
mOut.print( mls[i].toString(mIndent.toString(),INDENT));
mIndent.unIndent();
}
}
/**
*
*
*/
private void
writeDbId(Annotatable f) throws IOException
{
AGAVEDbId db_id = (AGAVEDbId)mAnnotFilter.getDbId(f.getAnnotation());
if( db_id!= null )
{
mIndent.indent();
mOut.println( db_id.toString(mIndent.toString(), INDENT) );
mIndent.unIndent();
}
}
/**
*
*
*/
private void
writeDescription( Annotatable f) throws IOException
{
String s = mAnnotFilter.getDescription( f.getAnnotation() );
if( s != null )
{
if (s.startsWith("");
mFilter.write(s);
mOut.println("");
mIndent.unIndent();
}
}
}
/**
*
*
*/
private void
writeNote( Annotatable f) throws IOException
{
String note = mAnnotFilter.getNote(f.getAnnotation());
if( note!= null )
{
if (note.startsWith("");
mFilter.write(note);
mOut.println("");
mIndent.unIndent();
}
}
}
}