/*
* 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.search;
import java.io.Serializable;
import org.biojava.utils.TriState;
import org.biojava.utils.walker.WalkerFactory;
/**
* A SearchContentHandler class that implements filtering
* in chains of SearchContentHandler instances.
*
* The SearchContentHandler organise Blast-like searches
* as a hierarchy of search/hit/subhit. Each search
* is conducted with a single query sequence. Hits
* of the query sequence are reported against different
* target sequences. The hit is further subdivided into
* one of more subhits which represent the positions
* within the target sequence that alignments of the query
* sequence were achieved against the query sequence
* (e.g. HSPs).
*
* This implementation depends on the a well ordered use
* of the SearchContentHandler interface. In particular,
* it requires that search/hit/subhit properties are
* reported immediately following the associated
* startSearch/startHit/startSubHit call. For example,
* search properties should not be reported following
* the corresponding startHit() call.
*
* Semantics of this interface
* BlastLikeSearchFilters test different levels of the
* SearchContentHandler property hierarchy and each
* filter should be seen as being applied when a full
* set of events from that level is received. So the
* ByHitProperty filter is applied when endHit() is
* called and determines whether all events received
* between startHit() and endHit() are to be passed on
* or discarded.
*
* Some keys used by SearchContentHandlers
* SearchProperties
*
*
* KEY_QUERY_ID |
* String. Value from setQueryID |
*
*
* queryDescription |
* String. FASTA description line |
*
*
* program |
* String. variant of BLAST used |
*
*
* version |
* software version |
*
*
*
* HitProperties
*
*
* subjectId |
* String. Identity of subject (target) sequence. |
*
*
* subjectSequenceLength |
* String representation of integer value |
*
*
* subjectDescription |
* String. |
*
*
* |
* |
*
*
*
* SubHitProperties
*
*
* bitScore |
* String representation of real value |
*
*
* queryStrand |
* plus/minus |
*
*
* percentageIdentity |
* String representation of real value |
*
*
* querySequenceEnd |
* String representation of integer value |
*
*
* expectValue |
* String representation of real value |
*
*
* subjectStrand |
* plus/minus |
*
*
* subjectSequenceEnd |
* String representation of integer value |
*
*
* numberOfPositives |
* String representation of integer value |
*
*
* score |
* String representation of integer value |
*
*
* subjectSequence |
* String representation of sequence |
*
*
* alignmentSize |
* String representation of integer value |
*
*
* querySequenceStart |
* String representation of integer value |
*
*
* subjectSequenceStart |
* String representation of integer value |
*
*
* numberOfIdentities |
* String representation of integer value |
*
*
* querySequence |
* String representation of sequence |
*
*
*
*
* @author David Huen
*/
public interface BlastLikeSearchFilter
extends Serializable
{
public interface Node
{
public Object getSearchProperty(Object key);
public Object getHitProperty(Object key);
public Object getSubHitProperty(Object key);
}
public static final String KEY_QUERY_ID = "___QUERY_ID___";
/**
* returns a TriState indicating the current outcome
* of evaluating this filter. This is usually the
* outcome saved when evaluate(FilteringContentHandler fch) was called.
*/
public TriState accept();
/**
* computes the outcome of this filter on the
* specified node and stores it. This method
* is only exposed to permit it to be included
* in an interface. Users should not use it.
*/
public void evaluate(Node fch);
/**
* resets the internal state of this filter including
* any cached evaluations. This method
* is only exposed to permit it to be included
* in an interface. Users should not use it.
*/
public void reset();
public abstract static class AbstractBlastLikeSearchFilter
implements BlastLikeSearchFilter
{
protected TriState cachedOutcome = TriState.INDETERMINATE;
public TriState accept() { return cachedOutcome; }
abstract public void evaluate(Node fch);
public void reset() { cachedOutcome = TriState.INDETERMINATE; }
private AbstractBlastLikeSearchFilter() {}
}
public static final class And
{
static { WalkerFactory.getInstance().addTypeWithParent(And.class); }
private AbstractBlastLikeSearchFilter filter0;
private AbstractBlastLikeSearchFilter filter1;
public And(
AbstractBlastLikeSearchFilter filter0,
AbstractBlastLikeSearchFilter filter1)
{
this.filter0 = filter0;
this.filter1 = filter1;
}
public TriState accept()
{
TriState outcome0 = filter0.accept();
TriState outcome1 = filter1.accept();
if ((outcome0 == TriState.FALSE) || (outcome1 == TriState.FALSE))
return TriState.FALSE;
// neither can be false now
if ((outcome0 == TriState.INDETERMINATE) || (outcome1 == TriState.INDETERMINATE))
return TriState.INDETERMINATE;
// neither is false nor indeterminate so it must be true!
return TriState.TRUE;
}
}
public static final class Or
{
static { WalkerFactory.getInstance().addTypeWithParent(Or.class); }
private AbstractBlastLikeSearchFilter filter0;
private AbstractBlastLikeSearchFilter filter1;
public Or(
AbstractBlastLikeSearchFilter filter0,
AbstractBlastLikeSearchFilter filter1)
{
this.filter0 = filter0;
this.filter1 = filter1;
}
public TriState accept()
{
TriState outcome0 = filter0.accept();
TriState outcome1 = filter1.accept();
if ((outcome0 == TriState.TRUE) || (outcome1 == TriState.TRUE))
return TriState.TRUE;
// neither can be false now
if ((outcome0 == TriState.INDETERMINATE) || (outcome1 == TriState.INDETERMINATE))
return TriState.INDETERMINATE;
// neither is true nor indeterminate so it must be false!
return TriState.FALSE;
}
}
public static final class Not
extends AbstractBlastLikeSearchFilter
{
static { WalkerFactory.getInstance().addTypeWithParent(Not.class); }
private AbstractBlastLikeSearchFilter filter;
public Not(AbstractBlastLikeSearchFilter filter)
{
this.filter = filter;
}
public TriState accept()
{
TriState outcome = filter.accept();
if (outcome == TriState.INDETERMINATE)
return TriState.INDETERMINATE;
if (outcome == TriState.TRUE)
return TriState.FALSE;
else
return TriState.TRUE;
}
public void evaluate(Node fch) {}
}
/**
* Applies test to the value specified by the key in search properties.
*/
public static final class BySearchProperty
extends AbstractBlastLikeSearchFilter
{
private Object key;
private FilterTest test;
public BySearchProperty(String key, FilterTest test)
{
this.key = key;
this.test = test;
}
public void evaluate(Node fch)
{
Object propertyValue = fch.getSearchProperty(key);
cachedOutcome = ((propertyValue != null) && test.accept(propertyValue)) ? TriState.TRUE : TriState.FALSE;
}
}
/**
* Applies test to the value specified by the key in hit properties.
*/
public static final class ByHitProperty
extends AbstractBlastLikeSearchFilter
{
private Object key;
private FilterTest test;
public ByHitProperty(String key, FilterTest test)
{
this.key = key;
this.test = test;
}
public void evaluate(Node fch)
{
Object propertyValue = fch.getHitProperty(key);
cachedOutcome = ((propertyValue != null) && test.accept(propertyValue)) ? TriState.TRUE : TriState.FALSE;
}
}
/**
* Applies test to the value specified by the key in subhit properties.
*/
public static final class BySubHitProperty
extends AbstractBlastLikeSearchFilter
{
private Object key;
private FilterTest test;
public BySubHitProperty(String key, FilterTest test)
{
this.key = key;
this.test = test;
}
public void evaluate(Node fch)
{
Object propertyValue = fch.getSubHitProperty(key);
//cachedOutcome = ((propertyValue == null)
// ? TriState.INDETERMINATE
// : (test.accept(propertyValue)) ? TriState.TRUE : TriState.FALSE);
cachedOutcome = ((propertyValue != null) && test.accept(propertyValue)) ? TriState.TRUE : TriState.FALSE;
}
}
}